@sonicjs-cms/core 3.0.0-beta.24 → 3.0.0-beta.26
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/{app-01M0dIwt.d.ts → app-BP5IlK94.d.ts} +7 -7
- package/dist/{app-aj39TGHB.d.cts → app-fdq4K3vw.d.cts} +7 -7
- package/dist/catalog-56DR6OXI.cjs +41 -0
- package/dist/catalog-56DR6OXI.cjs.map +1 -0
- package/dist/catalog-6MB37KY7.js +4 -0
- package/dist/catalog-6MB37KY7.js.map +1 -0
- package/dist/{chunk-QCJHCSOK.cjs → chunk-4DHPR7KR.cjs} +77 -17
- package/dist/chunk-4DHPR7KR.cjs.map +1 -0
- package/dist/{chunk-UIHIXTIS.js → chunk-5YSFQO7X.js} +40 -13
- package/dist/chunk-5YSFQO7X.js.map +1 -0
- package/dist/{chunk-GMMCCIQO.cjs → chunk-6UAI4SGN.cjs} +3 -3
- package/dist/{chunk-GMMCCIQO.cjs.map → chunk-6UAI4SGN.cjs.map} +1 -1
- package/dist/{chunk-2XAQTPAE.js → chunk-6X22VFEV.js} +8 -2
- package/dist/chunk-6X22VFEV.js.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-QJUJNTIU.cjs → chunk-A22RBHO7.cjs} +43 -12
- package/dist/chunk-A22RBHO7.cjs.map +1 -0
- package/dist/{chunk-QZGABF2M.js → chunk-AMP4BSJE.js} +18 -7
- package/dist/chunk-AMP4BSJE.js.map +1 -0
- package/dist/{chunk-37V3RET3.cjs → chunk-BRKXMRMB.cjs} +99 -98
- package/dist/chunk-BRKXMRMB.cjs.map +1 -0
- package/dist/{chunk-36Z3AKX3.cjs → chunk-C5LDQ3SH.cjs} +8 -2
- package/dist/chunk-C5LDQ3SH.cjs.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-BHND5PEV.js → chunk-E3TQG7AA.js} +3 -3
- package/dist/{chunk-BHND5PEV.js.map → chunk-E3TQG7AA.js.map} +1 -1
- package/dist/{chunk-FHPEM77Y.js → chunk-EEA476CJ.js} +88 -83
- package/dist/chunk-EEA476CJ.js.map +1 -0
- package/dist/chunk-F6BTBE4S.js +119 -0
- package/dist/chunk-F6BTBE4S.js.map +1 -0
- package/dist/chunk-FZGIU5AZ.cjs +128 -0
- package/dist/chunk-FZGIU5AZ.cjs.map +1 -0
- package/dist/{chunk-BJROXF4N.js → chunk-HSDJDWLV.js} +19 -4
- package/dist/chunk-HSDJDWLV.js.map +1 -0
- package/dist/{chunk-VGEZNFWH.js → chunk-JD7BZU3A.js} +5 -4
- package/dist/chunk-JD7BZU3A.js.map +1 -0
- package/dist/{chunk-SOZUG52O.js → chunk-JG5J434C.js} +3 -3
- package/dist/{chunk-SOZUG52O.js.map → chunk-JG5J434C.js.map} +1 -1
- package/dist/{chunk-BP52BFIV.cjs → chunk-KWQNB6UM.cjs} +6 -5
- package/dist/chunk-KWQNB6UM.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-VC5XVPLM.js → chunk-OJFIQGZB.js} +512 -148
- package/dist/chunk-OJFIQGZB.js.map +1 -0
- package/dist/{chunk-LTZ5WYOK.cjs → chunk-OLEOKHDX.cjs} +25 -2
- package/dist/chunk-OLEOKHDX.cjs.map +1 -0
- package/dist/{chunk-E66UVONV.cjs → chunk-OUBUS74I.cjs} +24 -9
- package/dist/chunk-OUBUS74I.cjs.map +1 -0
- package/dist/{chunk-A2SN3RVL.cjs → chunk-PAS7GZBS.cjs} +40 -13
- package/dist/chunk-PAS7GZBS.cjs.map +1 -0
- package/dist/{chunk-RJ2O5IIE.js → chunk-RVOX2WH2.js} +74 -18
- package/dist/chunk-RVOX2WH2.js.map +1 -0
- package/dist/{chunk-3TMTYJAJ.js → chunk-RXLI3ADU.js} +25 -2
- package/dist/chunk-RXLI3ADU.js.map +1 -0
- package/dist/{chunk-I767LVN7.cjs → chunk-S2QN4LFD.cjs} +881 -515
- package/dist/chunk-S2QN4LFD.cjs.map +1 -0
- package/dist/{chunk-IXUHXTHW.cjs → chunk-SFGYZUWU.cjs} +18 -7
- package/dist/chunk-SFGYZUWU.cjs.map +1 -0
- 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-LNI3FYSI.js → chunk-UB5QSRO7.js} +9 -14
- package/dist/chunk-UB5QSRO7.js.map +1 -0
- package/dist/{chunk-VYQVDL2M.js → chunk-UKIDWRA3.js} +36 -5
- package/dist/chunk-UKIDWRA3.js.map +1 -0
- package/dist/{chunk-KKNEYIZJ.cjs → chunk-XZUEGFXE.cjs} +9 -14
- package/dist/chunk-XZUEGFXE.cjs.map +1 -0
- package/dist/{collection-config-BTzAvKt2.d.cts → collection-config-U2dydD_O.d.cts} +14 -0
- package/dist/{collection-config-BTzAvKt2.d.ts → collection-config-U2dydD_O.d.ts} +14 -0
- package/dist/config-DOAWXZBG.js +6 -0
- package/dist/{config-6FB2BXMP.js.map → config-DOAWXZBG.js.map} +1 -1
- package/dist/{config-OCH7S4WK.cjs → config-VLU73ZW7.cjs} +5 -5
- package/dist/{config-OCH7S4WK.cjs.map → config-VLU73ZW7.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 +698 -392
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +27 -12
- package/dist/index.d.ts +27 -12
- package/dist/index.js +340 -35
- package/dist/index.js.map +1 -1
- package/dist/middleware.cjs +47 -47
- package/dist/middleware.d.cts +10 -10
- package/dist/middleware.d.ts +10 -10
- package/dist/middleware.js +6 -6
- package/dist/migrations-6M6772UC.cjs +13 -0
- package/dist/{migrations-FGXZPKDC.cjs.map → migrations-6M6772UC.cjs.map} +1 -1
- package/dist/migrations-GZ2HIB4I.js +4 -0
- package/dist/{migrations-Z6D27NAW.js.map → migrations-GZ2HIB4I.js.map} +1 -1
- package/dist/{plugin-bootstrap-BHWQ2df8.d.cts → plugin-bootstrap-CfVILQeP.d.ts} +1 -1
- package/dist/{plugin-bootstrap-Bj4fxX1q.d.ts → plugin-bootstrap-RY5pkoOT.d.cts} +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-TFUOYIVN.cjs +14 -0
- package/dist/{rbac-7QZ4JZ2E.cjs.map → rbac-TFUOYIVN.cjs.map} +1 -1
- package/dist/rbac-XSNP76CV.js +5 -0
- package/dist/{rbac-Y43IEQOP.js.map → rbac-XSNP76CV.js.map} +1 -1
- package/dist/routes.cjs +33 -32
- package/dist/routes.d.cts +3 -5
- package/dist/routes.d.ts +3 -5
- package/dist/routes.js +13 -12
- package/dist/services.cjs +30 -30
- package/dist/services.d.cts +10 -3
- package/dist/services.d.ts +10 -3
- package/dist/services.js +3 -3
- 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 +2 -2
- package/dist/types.d.ts +2 -2
- package/dist/utils.cjs +12 -12
- package/dist/utils.d.cts +2 -2
- package/dist/utils.d.ts +2 -2
- package/dist/utils.js +2 -2
- package/package.json +7 -12
- 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-2XAQTPAE.js.map +0 -1
- package/dist/chunk-36Z3AKX3.cjs.map +0 -1
- package/dist/chunk-37V3RET3.cjs.map +0 -1
- package/dist/chunk-3TMTYJAJ.js.map +0 -1
- package/dist/chunk-A2SN3RVL.cjs.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-QCJHCSOK.cjs.map +0 -1
- package/dist/chunk-QJUJNTIU.cjs.map +0 -1
- package/dist/chunk-QZGABF2M.js.map +0 -1
- package/dist/chunk-RJ2O5IIE.js.map +0 -1
- package/dist/chunk-THFZSDIU.js.map +0 -1
- package/dist/chunk-UIHIXTIS.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,21 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
var chunkTT3TQSCZ_cjs = require('./chunk-TT3TQSCZ.cjs');
|
|
4
|
+
var chunkFZGIU5AZ_cjs = require('./chunk-FZGIU5AZ.cjs');
|
|
3
5
|
var chunkXWVDSM2L_cjs = require('./chunk-XWVDSM2L.cjs');
|
|
4
|
-
var
|
|
5
|
-
var
|
|
6
|
-
var
|
|
7
|
-
var chunkLTZ5WYOK_cjs = require('./chunk-LTZ5WYOK.cjs');
|
|
6
|
+
var chunkC5LDQ3SH_cjs = require('./chunk-C5LDQ3SH.cjs');
|
|
7
|
+
var chunkBRKXMRMB_cjs = require('./chunk-BRKXMRMB.cjs');
|
|
8
|
+
var chunkOLEOKHDX_cjs = require('./chunk-OLEOKHDX.cjs');
|
|
8
9
|
var chunkKIGVVO6N_cjs = require('./chunk-KIGVVO6N.cjs');
|
|
9
|
-
var
|
|
10
|
-
var
|
|
11
|
-
var
|
|
12
|
-
var
|
|
13
|
-
var
|
|
10
|
+
var chunk4DHPR7KR_cjs = require('./chunk-4DHPR7KR.cjs');
|
|
11
|
+
var chunkPAS7GZBS_cjs = require('./chunk-PAS7GZBS.cjs');
|
|
12
|
+
var chunkOUBUS74I_cjs = require('./chunk-OUBUS74I.cjs');
|
|
13
|
+
var chunkMI2YXCK4_cjs = require('./chunk-MI2YXCK4.cjs');
|
|
14
|
+
var chunkKWQNB6UM_cjs = require('./chunk-KWQNB6UM.cjs');
|
|
14
15
|
var chunkJ6JTWD2A_cjs = require('./chunk-J6JTWD2A.cjs');
|
|
15
|
-
var
|
|
16
|
+
var chunkSFGYZUWU_cjs = require('./chunk-SFGYZUWU.cjs');
|
|
16
17
|
var chunkRCQ2HIQD_cjs = require('./chunk-RCQ2HIQD.cjs');
|
|
17
|
-
var
|
|
18
|
+
var chunkXZUEGFXE_cjs = require('./chunk-XZUEGFXE.cjs');
|
|
18
19
|
var chunkMNWKYY5E_cjs = require('./chunk-MNWKYY5E.cjs');
|
|
19
20
|
var hono = require('hono');
|
|
20
21
|
var zod = require('zod');
|
|
@@ -47,6 +48,7 @@ var DocumentPermissionsService = class {
|
|
|
47
48
|
const publicGrants = baseGrants["public"] ?? [];
|
|
48
49
|
if (publicGrants.includes(permission)) return true;
|
|
49
50
|
} else if (principal.type === "role") {
|
|
51
|
+
if (principal.id === "public") continue;
|
|
50
52
|
const roleGrants = baseGrants[principal.id] ?? [];
|
|
51
53
|
if (roleGrants.includes(permission)) return true;
|
|
52
54
|
}
|
|
@@ -271,7 +273,7 @@ function getDocumentRequestContext(c) {
|
|
|
271
273
|
|
|
272
274
|
// src/routes/api-documents.ts
|
|
273
275
|
async function aclAllowsRead(db, tenantId, principalSet, row, preloadedType) {
|
|
274
|
-
const docType = preloadedType ?? await new
|
|
276
|
+
const docType = preloadedType ?? await new chunkBRKXMRMB_cjs.DocumentTypeRegistry(db).findById(row.type_id);
|
|
275
277
|
if (!docType) return false;
|
|
276
278
|
return new DocumentRepository(db, tenantId).isAllowed(principalSet, row.root_id, "read", docType.settings);
|
|
277
279
|
}
|
|
@@ -289,7 +291,7 @@ apiDocumentsRoutes.get("/", async (c) => {
|
|
|
289
291
|
if (!typeId) {
|
|
290
292
|
return c.json({ error: "type query parameter is required" }, 400);
|
|
291
293
|
}
|
|
292
|
-
const registry = new
|
|
294
|
+
const registry = new chunkBRKXMRMB_cjs.DocumentTypeRegistry(db);
|
|
293
295
|
const docType = await registry.findById(typeId);
|
|
294
296
|
if (!docType || !docType.isActive) {
|
|
295
297
|
return c.json({ error: "Unknown document type" }, 400);
|
|
@@ -371,7 +373,7 @@ apiDocumentsRoutes.get("/root/:rootId", async (c) => {
|
|
|
371
373
|
AND (expires_at IS NULL OR expires_at > ?) LIMIT 1`
|
|
372
374
|
).bind(rootId, now, now).first();
|
|
373
375
|
if (!row) return c.json({ error: "Not found" }, 404);
|
|
374
|
-
const docType = await new
|
|
376
|
+
const docType = await new chunkBRKXMRMB_cjs.DocumentTypeRegistry(db).findById(row.type_id);
|
|
375
377
|
const effTenant = effectiveTenantForType(tenantId, docType?.settings);
|
|
376
378
|
if (row.tenant_id !== effTenant) return c.json({ error: "Not found" }, 404);
|
|
377
379
|
if (!await aclAllowsRead(db, effTenant, principalSet, row, docType)) {
|
|
@@ -407,7 +409,7 @@ apiDocumentsRoutes.get("/:id", async (c) => {
|
|
|
407
409
|
AND (expires_at IS NULL OR expires_at > ?) LIMIT 1`
|
|
408
410
|
).bind(id, now, now).first();
|
|
409
411
|
if (!row) return c.json({ error: "Not found" }, 404);
|
|
410
|
-
const docType = await new
|
|
412
|
+
const docType = await new chunkBRKXMRMB_cjs.DocumentTypeRegistry(db).findById(row.type_id);
|
|
411
413
|
const effTenant = effectiveTenantForType(tenantId, docType?.settings);
|
|
412
414
|
if (row.tenant_id !== effTenant) return c.json({ error: "Not found" }, 404);
|
|
413
415
|
if (!await aclAllowsRead(db, effTenant, principalSet, row, docType)) {
|
|
@@ -477,17 +479,17 @@ async function resolveDocScope(c, db, by, opts = {}) {
|
|
|
477
479
|
const draft = opts.currentDraftOnly ? " AND is_current_draft = 1" : "";
|
|
478
480
|
const row = await db.prepare(`SELECT type_id, root_id, tenant_id FROM documents WHERE ${col} = ?${draft} LIMIT 1`).bind(val).first();
|
|
479
481
|
if (!row) return null;
|
|
480
|
-
const docType = await new
|
|
482
|
+
const docType = await new chunkBRKXMRMB_cjs.DocumentTypeRegistry(db).findById(row.type_id);
|
|
481
483
|
const tenantId = effectiveTenantForType(getRequestTenant(c), docType?.settings);
|
|
482
484
|
if (row.tenant_id !== tenantId) return null;
|
|
483
485
|
return { typeId: row.type_id, rootId: row.root_id, tenantId, docType };
|
|
484
486
|
}
|
|
485
487
|
var adminDocumentsRoutes = new hono.Hono();
|
|
486
|
-
adminDocumentsRoutes.use("*",
|
|
487
|
-
adminDocumentsRoutes.use("*",
|
|
488
|
+
adminDocumentsRoutes.use("*", chunkBRKXMRMB_cjs.requireAuth());
|
|
489
|
+
adminDocumentsRoutes.use("*", chunkBRKXMRMB_cjs.requireRole(["admin", "editor"]));
|
|
488
490
|
adminDocumentsRoutes.get("/types", async (c) => {
|
|
489
491
|
try {
|
|
490
|
-
const registry = new
|
|
492
|
+
const registry = new chunkBRKXMRMB_cjs.DocumentTypeRegistry(c.env.DB);
|
|
491
493
|
const types = await registry.findAll();
|
|
492
494
|
return c.json({ data: types });
|
|
493
495
|
} catch (error) {
|
|
@@ -515,7 +517,7 @@ adminDocumentsRoutes.get("/", async (c) => {
|
|
|
515
517
|
if (!typeId) {
|
|
516
518
|
return c.json({ error: "type query parameter is required" }, 400);
|
|
517
519
|
}
|
|
518
|
-
const registry = new
|
|
520
|
+
const registry = new chunkBRKXMRMB_cjs.DocumentTypeRegistry(db);
|
|
519
521
|
const docType = await registry.findById(typeId);
|
|
520
522
|
if (!docType || !docType.isActive) {
|
|
521
523
|
return c.json({ error: "Unknown document type" }, 400);
|
|
@@ -626,7 +628,7 @@ adminDocumentsRoutes.post("/", async (c) => {
|
|
|
626
628
|
const input = validation.data;
|
|
627
629
|
const db = c.env.DB;
|
|
628
630
|
const user = c.get("user");
|
|
629
|
-
const registry = new
|
|
631
|
+
const registry = new chunkBRKXMRMB_cjs.DocumentTypeRegistry(db);
|
|
630
632
|
const docType = await registry.findById(input.typeId);
|
|
631
633
|
if (!docType || !docType.isActive) {
|
|
632
634
|
return c.json({ error: "Unknown document type" }, 400);
|
|
@@ -634,7 +636,7 @@ adminDocumentsRoutes.post("/", async (c) => {
|
|
|
634
636
|
const createDenied = await denyIfNotAllowed(c, db, "", "create", docType.settings);
|
|
635
637
|
if (createDenied) return createDenied;
|
|
636
638
|
const tenantId = effectiveTenantForType(getRequestTenant(c), docType.settings);
|
|
637
|
-
const svc = new
|
|
639
|
+
const svc = new chunkOLEOKHDX_cjs.DocumentsService(db, {
|
|
638
640
|
queryableFields: docType.queryableFields,
|
|
639
641
|
typeSchemaVersion: docType.schemaVersion,
|
|
640
642
|
maxVersionsPerRoot: docType.settings.maxVersionsPerRoot,
|
|
@@ -672,7 +674,7 @@ adminDocumentsRoutes.put("/:rootId", async (c) => {
|
|
|
672
674
|
const docType = scope.docType;
|
|
673
675
|
const updateDenied = await denyIfNotAllowed(c, db, rootId, "update", docType?.settings, scope.tenantId);
|
|
674
676
|
if (updateDenied) return updateDenied;
|
|
675
|
-
const svc = new
|
|
677
|
+
const svc = new chunkOLEOKHDX_cjs.DocumentsService(db, {
|
|
676
678
|
queryableFields: docType?.queryableFields ?? [],
|
|
677
679
|
typeSchemaVersion: docType?.schemaVersion,
|
|
678
680
|
maxVersionsPerRoot: docType?.settings.maxVersionsPerRoot,
|
|
@@ -697,7 +699,7 @@ adminDocumentsRoutes.post("/:id/publish", async (c) => {
|
|
|
697
699
|
const docType = scope.docType;
|
|
698
700
|
const publishDenied = await denyIfNotAllowed(c, db, scope.rootId, "publish", docType?.settings, scope.tenantId);
|
|
699
701
|
if (publishDenied) return publishDenied;
|
|
700
|
-
const svc = new
|
|
702
|
+
const svc = new chunkOLEOKHDX_cjs.DocumentsService(db, {
|
|
701
703
|
queryableFields: docType?.queryableFields ?? [],
|
|
702
704
|
typeSchemaVersion: docType?.schemaVersion,
|
|
703
705
|
tenantId: scope.tenantId,
|
|
@@ -720,7 +722,7 @@ adminDocumentsRoutes.post("/:id/unpublish", async (c) => {
|
|
|
720
722
|
const docType = scope.docType;
|
|
721
723
|
const unpublishDenied = await denyIfNotAllowed(c, db, scope.rootId, "publish", docType?.settings, scope.tenantId);
|
|
722
724
|
if (unpublishDenied) return unpublishDenied;
|
|
723
|
-
const svc = new
|
|
725
|
+
const svc = new chunkOLEOKHDX_cjs.DocumentsService(db, {
|
|
724
726
|
queryableFields: docType?.queryableFields ?? [],
|
|
725
727
|
tenantId: scope.tenantId
|
|
726
728
|
});
|
|
@@ -742,7 +744,7 @@ adminDocumentsRoutes.delete("/:id", async (c) => {
|
|
|
742
744
|
const docType = scope.docType;
|
|
743
745
|
const deleteDenied = await denyIfNotAllowed(c, db, scope.rootId, "delete", docType?.settings, scope.tenantId);
|
|
744
746
|
if (deleteDenied) return deleteDenied;
|
|
745
|
-
const svc = new
|
|
747
|
+
const svc = new chunkOLEOKHDX_cjs.DocumentsService(db, { queryableFields: docType?.queryableFields ?? [], tenantId: scope.tenantId });
|
|
746
748
|
if (docType?.settings.pii) {
|
|
747
749
|
if (scope.rootId) await svc.erase(scope.rootId, scope.tenantId);
|
|
748
750
|
} else {
|
|
@@ -758,7 +760,7 @@ adminDocumentsRoutes.post("/types/:typeId/reindex", async (c) => {
|
|
|
758
760
|
try {
|
|
759
761
|
const { typeId } = c.req.param();
|
|
760
762
|
const db = c.env.DB;
|
|
761
|
-
const registry = new
|
|
763
|
+
const registry = new chunkBRKXMRMB_cjs.DocumentTypeRegistry(db);
|
|
762
764
|
const docType = await registry.findById(typeId);
|
|
763
765
|
if (!docType) return c.json({ error: "Unknown document type" }, 400);
|
|
764
766
|
const reindexTenant = effectiveTenantForType(getRequestTenant(c), docType.settings);
|
|
@@ -844,6 +846,34 @@ async function dispatchHookEvent(c, event, payload, mode = "fire-and-forget") {
|
|
|
844
846
|
return hooks.dispatch(event, payload);
|
|
845
847
|
}
|
|
846
848
|
|
|
849
|
+
// src/plugins/cache/services/swr.ts
|
|
850
|
+
var STALE_TTL_MS = 3e4;
|
|
851
|
+
var staleMap = /* @__PURE__ */ new Map();
|
|
852
|
+
function markStale(cacheKey, data, collection) {
|
|
853
|
+
staleMap.set(cacheKey, {
|
|
854
|
+
data,
|
|
855
|
+
collection,
|
|
856
|
+
expiresAt: Date.now() + STALE_TTL_MS
|
|
857
|
+
});
|
|
858
|
+
}
|
|
859
|
+
function getAndConsumeStale(cacheKey) {
|
|
860
|
+
const entry = staleMap.get(cacheKey);
|
|
861
|
+
if (!entry) return null;
|
|
862
|
+
if (Date.now() > entry.expiresAt) {
|
|
863
|
+
staleMap.delete(cacheKey);
|
|
864
|
+
return null;
|
|
865
|
+
}
|
|
866
|
+
staleMap.delete(cacheKey);
|
|
867
|
+
return entry.data;
|
|
868
|
+
}
|
|
869
|
+
function swrStats() {
|
|
870
|
+
const now = Date.now();
|
|
871
|
+
for (const [key, entry] of staleMap.entries()) {
|
|
872
|
+
if (now > entry.expiresAt) staleMap.delete(key);
|
|
873
|
+
}
|
|
874
|
+
return { count: staleMap.size };
|
|
875
|
+
}
|
|
876
|
+
|
|
847
877
|
// src/plugins/core-plugins/global-variables-plugin/variable-resolver.ts
|
|
848
878
|
var TOKEN_PATTERN = /\{([a-z0-9_]+)\}/g;
|
|
849
879
|
function resolveVariables(text, variables) {
|
|
@@ -912,13 +942,13 @@ async function resolveContentVariables(contentData, db) {
|
|
|
912
942
|
// src/routes/api-content-crud.ts
|
|
913
943
|
var apiContentCrudRoutes = new hono.Hono();
|
|
914
944
|
async function resolveDocBacking(db, collectionIdOrName) {
|
|
915
|
-
const registry =
|
|
945
|
+
const registry = chunk4DHPR7KR_cjs.getCollectionRegistry();
|
|
916
946
|
const record = registry.getBySlugOrName(collectionIdOrName) ?? registry.getById(collectionIdOrName);
|
|
917
947
|
if (record) {
|
|
918
|
-
const docType2 = await new
|
|
948
|
+
const docType2 = await new chunkBRKXMRMB_cjs.DocumentTypeRegistry(db).findById(record.name);
|
|
919
949
|
return docType2 ? { coll: { id: record.id, name: record.name }, docType: docType2 } : null;
|
|
920
950
|
}
|
|
921
|
-
const docType = await new
|
|
951
|
+
const docType = await new chunkBRKXMRMB_cjs.DocumentTypeRegistry(db).findById(collectionIdOrName);
|
|
922
952
|
if (docType) {
|
|
923
953
|
return { coll: { id: collectionIdOrName, name: collectionIdOrName }, docType };
|
|
924
954
|
}
|
|
@@ -961,7 +991,7 @@ apiContentCrudRoutes.get("/check-slug", async (c) => {
|
|
|
961
991
|
}, 500);
|
|
962
992
|
}
|
|
963
993
|
});
|
|
964
|
-
apiContentCrudRoutes.get("/:id",
|
|
994
|
+
apiContentCrudRoutes.get("/:id", chunkBRKXMRMB_cjs.optionalAuth(), async (c) => {
|
|
965
995
|
try {
|
|
966
996
|
const id = c.req.param("id");
|
|
967
997
|
const db = c.env.DB;
|
|
@@ -971,7 +1001,7 @@ apiContentCrudRoutes.get("/:id", chunk37V3RET3_cjs.optionalAuth(), async (c) =>
|
|
|
971
1001
|
).bind(id, getRequestTenant(c)).first();
|
|
972
1002
|
let transformedContent;
|
|
973
1003
|
if (docRow) {
|
|
974
|
-
const coll =
|
|
1004
|
+
const coll = chunk4DHPR7KR_cjs.getCollectionRegistry().getByName(docRow.type_id);
|
|
975
1005
|
transformedContent = {
|
|
976
1006
|
id: docRow.root_id,
|
|
977
1007
|
title: docRow.title,
|
|
@@ -980,8 +1010,8 @@ apiContentCrudRoutes.get("/:id", chunk37V3RET3_cjs.optionalAuth(), async (c) =>
|
|
|
980
1010
|
collectionId: coll?.id ?? docRow.type_id,
|
|
981
1011
|
data: docRow.data ? JSON.parse(docRow.data) : {},
|
|
982
1012
|
// D29: document timestamps are SECONDS; legacy `content` API contract is MILLISECONDS.
|
|
983
|
-
created_at:
|
|
984
|
-
updated_at:
|
|
1013
|
+
created_at: chunkOLEOKHDX_cjs.documentSecondsToMs(docRow.created_at),
|
|
1014
|
+
updated_at: chunkOLEOKHDX_cjs.documentSecondsToMs(docRow.updated_at)
|
|
985
1015
|
};
|
|
986
1016
|
} else {
|
|
987
1017
|
return c.json({ error: "Content not found" }, 404);
|
|
@@ -996,6 +1026,32 @@ apiContentCrudRoutes.get("/:id", chunk37V3RET3_cjs.optionalAuth(), async (c) =>
|
|
|
996
1026
|
{ collection: docRow.type_id, id: docRow.root_id, data: transformedContent.data },
|
|
997
1027
|
"fire-and-forget"
|
|
998
1028
|
);
|
|
1029
|
+
const fieldsParam = c.req.query("fields");
|
|
1030
|
+
if (fieldsParam) {
|
|
1031
|
+
const projFields = fieldsParam.split(",").map((s) => s.trim()).filter(Boolean);
|
|
1032
|
+
if (projFields.length > 0) {
|
|
1033
|
+
const result = {};
|
|
1034
|
+
const dataSubFields = [];
|
|
1035
|
+
for (const f of projFields) {
|
|
1036
|
+
if (f === "data") {
|
|
1037
|
+
result.data = transformedContent.data;
|
|
1038
|
+
} else if (f.startsWith("data.")) {
|
|
1039
|
+
dataSubFields.push(f.slice(5));
|
|
1040
|
+
} else if (Object.prototype.hasOwnProperty.call(transformedContent, f)) {
|
|
1041
|
+
result[f] = transformedContent[f];
|
|
1042
|
+
}
|
|
1043
|
+
}
|
|
1044
|
+
if (dataSubFields.length > 0 && !result.data) {
|
|
1045
|
+
result.data = {};
|
|
1046
|
+
for (const sub of dataSubFields) {
|
|
1047
|
+
if (transformedContent.data && Object.prototype.hasOwnProperty.call(transformedContent.data, sub)) {
|
|
1048
|
+
result.data[sub] = transformedContent.data[sub];
|
|
1049
|
+
}
|
|
1050
|
+
}
|
|
1051
|
+
}
|
|
1052
|
+
return c.json({ data: result });
|
|
1053
|
+
}
|
|
1054
|
+
}
|
|
999
1055
|
return c.json({ data: transformedContent });
|
|
1000
1056
|
} catch (error) {
|
|
1001
1057
|
console.error("Error fetching content:", error);
|
|
@@ -1005,7 +1061,7 @@ apiContentCrudRoutes.get("/:id", chunk37V3RET3_cjs.optionalAuth(), async (c) =>
|
|
|
1005
1061
|
}, 500);
|
|
1006
1062
|
}
|
|
1007
1063
|
});
|
|
1008
|
-
apiContentCrudRoutes.post("/",
|
|
1064
|
+
apiContentCrudRoutes.post("/", chunkBRKXMRMB_cjs.requireAuth(), chunkBRKXMRMB_cjs.requireRole(["admin", "editor", "author"]), async (c) => {
|
|
1009
1065
|
try {
|
|
1010
1066
|
const db = c.env.DB;
|
|
1011
1067
|
const user = c.get("user");
|
|
@@ -1039,7 +1095,7 @@ apiContentCrudRoutes.post("/", chunk37V3RET3_cjs.requireAuth(), chunk37V3RET3_cj
|
|
|
1039
1095
|
return c.json({ error: "Write cancelled by plugin", details: String(err) }, 400);
|
|
1040
1096
|
}
|
|
1041
1097
|
const tenantId = getRequestTenant(c);
|
|
1042
|
-
const svc = new
|
|
1098
|
+
const svc = new chunkOLEOKHDX_cjs.DocumentsService(db, {
|
|
1043
1099
|
queryableFields: backing.docType.queryableFields ?? [],
|
|
1044
1100
|
typeSchemaVersion: backing.docType.schemaVersion ?? 1,
|
|
1045
1101
|
maxVersionsPerRoot: backing.docType.settings?.maxVersionsPerRoot ?? 50,
|
|
@@ -1058,9 +1114,9 @@ apiContentCrudRoutes.post("/", chunk37V3RET3_cjs.requireAuth(), chunk37V3RET3_cj
|
|
|
1058
1114
|
}),
|
|
1059
1115
|
user?.userId
|
|
1060
1116
|
);
|
|
1061
|
-
const cache =
|
|
1062
|
-
await cache.invalidate("content-filtered:*");
|
|
1063
|
-
await cache.invalidate(
|
|
1117
|
+
const cache = chunkC5LDQ3SH_cjs.getCacheService(chunkC5LDQ3SH_cjs.CACHE_CONFIGS.api);
|
|
1118
|
+
await cache.invalidate("api:content-filtered:*");
|
|
1119
|
+
await cache.invalidate(`api:collection-content-filtered:${backing.coll.name}:*`);
|
|
1064
1120
|
dispatchHookEvent(
|
|
1065
1121
|
c,
|
|
1066
1122
|
"content:after:create",
|
|
@@ -1068,7 +1124,7 @@ apiContentCrudRoutes.post("/", chunk37V3RET3_cjs.requireAuth(), chunk37V3RET3_cj
|
|
|
1068
1124
|
"fire-and-forget"
|
|
1069
1125
|
);
|
|
1070
1126
|
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:
|
|
1127
|
+
data: { id: doc.rootId, title: doc.title, slug: doc.slug, status: doc.status, collectionId: backing.coll.id, data: doc.data, created_at: chunkOLEOKHDX_cjs.documentSecondsToMs(doc.createdAt), updated_at: chunkOLEOKHDX_cjs.documentSecondsToMs(doc.updatedAt) }
|
|
1072
1128
|
}, 201);
|
|
1073
1129
|
}
|
|
1074
1130
|
return c.json({ error: "Collection is not document-backed" }, 400);
|
|
@@ -1080,7 +1136,7 @@ apiContentCrudRoutes.post("/", chunk37V3RET3_cjs.requireAuth(), chunk37V3RET3_cj
|
|
|
1080
1136
|
}, 500);
|
|
1081
1137
|
}
|
|
1082
1138
|
});
|
|
1083
|
-
apiContentCrudRoutes.put("/:id",
|
|
1139
|
+
apiContentCrudRoutes.put("/:id", chunkBRKXMRMB_cjs.requireAuth(), chunkBRKXMRMB_cjs.requireRole(["admin", "editor", "author"]), async (c) => {
|
|
1084
1140
|
try {
|
|
1085
1141
|
const id = c.req.param("id");
|
|
1086
1142
|
const db = c.env.DB;
|
|
@@ -1102,8 +1158,8 @@ apiContentCrudRoutes.put("/:id", chunk37V3RET3_cjs.requireAuth(), chunk37V3RET3_
|
|
|
1102
1158
|
} catch (err) {
|
|
1103
1159
|
return c.json({ error: "Write cancelled by plugin", details: String(err) }, 400);
|
|
1104
1160
|
}
|
|
1105
|
-
const docType = await new
|
|
1106
|
-
const svc = new
|
|
1161
|
+
const docType = await new chunkBRKXMRMB_cjs.DocumentTypeRegistry(db).findById(docRow.type_id);
|
|
1162
|
+
const svc = new chunkOLEOKHDX_cjs.DocumentsService(db, {
|
|
1107
1163
|
queryableFields: docType?.queryableFields ?? [],
|
|
1108
1164
|
typeSchemaVersion: docType?.schemaVersion ?? 1,
|
|
1109
1165
|
maxVersionsPerRoot: docType?.settings?.maxVersionsPerRoot ?? 50,
|
|
@@ -1122,10 +1178,10 @@ apiContentCrudRoutes.put("/:id", chunk37V3RET3_cjs.requireAuth(), chunk37V3RET3_
|
|
|
1122
1178
|
} else if (body.status === "draft" && pub) {
|
|
1123
1179
|
await svc.unpublish(pub.id);
|
|
1124
1180
|
}
|
|
1125
|
-
const cache =
|
|
1126
|
-
await cache.invalidate("content-filtered:*");
|
|
1127
|
-
await cache.invalidate(
|
|
1128
|
-
const coll =
|
|
1181
|
+
const cache = chunkC5LDQ3SH_cjs.getCacheService(chunkC5LDQ3SH_cjs.CACHE_CONFIGS.api);
|
|
1182
|
+
await cache.invalidate("api:content-filtered:*");
|
|
1183
|
+
await cache.invalidate(`api:collection-content-filtered:${docRow.type_id}:*`);
|
|
1184
|
+
const coll = chunk4DHPR7KR_cjs.getCollectionRegistry().getByName(docRow.type_id);
|
|
1129
1185
|
const saved = await db.prepare("SELECT * FROM documents WHERE id = ?").bind(newDraft.id).first();
|
|
1130
1186
|
const savedData = saved?.data ? JSON.parse(saved.data) : {};
|
|
1131
1187
|
dispatchHookEvent(c, "content:after:update", { collection: docRow.type_id, id, data: savedData, user: actor }, "fire-and-forget");
|
|
@@ -1134,7 +1190,7 @@ apiContentCrudRoutes.put("/:id", chunk37V3RET3_cjs.requireAuth(), chunk37V3RET3_
|
|
|
1134
1190
|
dispatchHookEvent(c, "content:after:publish", { collection: docRow.type_id, id, data: savedData, user: actor }, "fire-and-forget");
|
|
1135
1191
|
}
|
|
1136
1192
|
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:
|
|
1193
|
+
data: { id: saved.root_id, title: saved.title, slug: saved.slug, status: saved.status, collectionId: coll?.id ?? docRow.type_id, data: savedData, created_at: chunkOLEOKHDX_cjs.documentSecondsToMs(saved.created_at), updated_at: chunkOLEOKHDX_cjs.documentSecondsToMs(saved.updated_at) }
|
|
1138
1194
|
});
|
|
1139
1195
|
}
|
|
1140
1196
|
return c.json({ error: "Content not found" }, 404);
|
|
@@ -1146,7 +1202,7 @@ apiContentCrudRoutes.put("/:id", chunk37V3RET3_cjs.requireAuth(), chunk37V3RET3_
|
|
|
1146
1202
|
}, 500);
|
|
1147
1203
|
}
|
|
1148
1204
|
});
|
|
1149
|
-
apiContentCrudRoutes.delete("/:id",
|
|
1205
|
+
apiContentCrudRoutes.delete("/:id", chunkBRKXMRMB_cjs.requireAuth(), chunkBRKXMRMB_cjs.requireRole(["admin", "editor", "author"]), async (c) => {
|
|
1150
1206
|
try {
|
|
1151
1207
|
const id = c.req.param("id");
|
|
1152
1208
|
const db = c.env.DB;
|
|
@@ -1162,9 +1218,9 @@ apiContentCrudRoutes.delete("/:id", chunk37V3RET3_cjs.requireAuth(), chunk37V3RE
|
|
|
1162
1218
|
}
|
|
1163
1219
|
const now = Math.floor(Date.now() / 1e3);
|
|
1164
1220
|
await db.prepare("UPDATE documents SET deleted_at = ?, updated_at = ? WHERE root_id = ? AND tenant_id = ?").bind(now, now, id, tenantId).run();
|
|
1165
|
-
const cache =
|
|
1166
|
-
await cache.invalidate("content-filtered:*");
|
|
1167
|
-
await cache.invalidate(
|
|
1221
|
+
const cache = chunkC5LDQ3SH_cjs.getCacheService(chunkC5LDQ3SH_cjs.CACHE_CONFIGS.api);
|
|
1222
|
+
await cache.invalidate("api:content-filtered:*");
|
|
1223
|
+
await cache.invalidate(`api:collection-content-filtered:${docRow.type_id}:*`);
|
|
1168
1224
|
dispatchHookEvent(c, "content:after:delete", { collection: docRow.type_id, id, data: {}, user: actor }, "fire-and-forget");
|
|
1169
1225
|
return c.json({ success: true });
|
|
1170
1226
|
}
|
|
@@ -1180,6 +1236,22 @@ apiContentCrudRoutes.delete("/:id", chunk37V3RET3_cjs.requireAuth(), chunk37V3RE
|
|
|
1180
1236
|
var api_content_crud_default = apiContentCrudRoutes;
|
|
1181
1237
|
|
|
1182
1238
|
// src/routes/api.ts
|
|
1239
|
+
function isAnonPrincipal(principalSet) {
|
|
1240
|
+
return principalSet.length === 1 && principalSet[0]?.type === "public";
|
|
1241
|
+
}
|
|
1242
|
+
async function typeReadAllowed(db, principalSet, docType, typeName) {
|
|
1243
|
+
const perms = new DocumentPermissionsService(db);
|
|
1244
|
+
if (perms.isAllowedSync(principalSet, [], "read", docType?.settings ?? {})) return true;
|
|
1245
|
+
const rbac = new chunkOLEOKHDX_cjs.RbacService(db);
|
|
1246
|
+
let anyRbacRoleFound = false;
|
|
1247
|
+
for (const p of principalSet) {
|
|
1248
|
+
if (p.type !== "role") continue;
|
|
1249
|
+
if (!await rbac.hasRbacRole(p.id)) continue;
|
|
1250
|
+
anyRbacRoleFound = true;
|
|
1251
|
+
if (await rbac.isGrantedForRole(p.id, `document_type:${typeName}`, "read")) return true;
|
|
1252
|
+
}
|
|
1253
|
+
return !anyRbacRoleFound;
|
|
1254
|
+
}
|
|
1183
1255
|
var DOC_SORTABLE_COLUMNS = /* @__PURE__ */ new Set([
|
|
1184
1256
|
"created_at",
|
|
1185
1257
|
"updated_at",
|
|
@@ -1259,10 +1331,37 @@ function mapDocRowToContent(row, collectionId) {
|
|
|
1259
1331
|
collectionId,
|
|
1260
1332
|
data: row.data ? JSON.parse(row.data) : {},
|
|
1261
1333
|
// D29: document timestamps are SECONDS; the legacy `content` API contract is MILLISECONDS.
|
|
1262
|
-
created_at:
|
|
1263
|
-
updated_at:
|
|
1334
|
+
created_at: chunkOLEOKHDX_cjs.documentSecondsToMs(row.created_at),
|
|
1335
|
+
updated_at: chunkOLEOKHDX_cjs.documentSecondsToMs(row.updated_at)
|
|
1264
1336
|
};
|
|
1265
1337
|
}
|
|
1338
|
+
function projectFields(item, fields) {
|
|
1339
|
+
if (fields.length === 0) return item;
|
|
1340
|
+
const result = {};
|
|
1341
|
+
const dataSubFields = [];
|
|
1342
|
+
for (const f of fields) {
|
|
1343
|
+
if (f === "data") {
|
|
1344
|
+
result.data = item.data;
|
|
1345
|
+
} else if (f.startsWith("data.")) {
|
|
1346
|
+
dataSubFields.push(f.slice(5));
|
|
1347
|
+
} else if (Object.prototype.hasOwnProperty.call(item, f)) {
|
|
1348
|
+
result[f] = item[f];
|
|
1349
|
+
}
|
|
1350
|
+
}
|
|
1351
|
+
if (dataSubFields.length > 0 && !result.data) {
|
|
1352
|
+
result.data = {};
|
|
1353
|
+
for (const sub of dataSubFields) {
|
|
1354
|
+
if (item.data && Object.prototype.hasOwnProperty.call(item.data, sub)) {
|
|
1355
|
+
result.data[sub] = item.data[sub];
|
|
1356
|
+
}
|
|
1357
|
+
}
|
|
1358
|
+
}
|
|
1359
|
+
return result;
|
|
1360
|
+
}
|
|
1361
|
+
function parseFieldsParam(raw2) {
|
|
1362
|
+
if (!raw2) return [];
|
|
1363
|
+
return raw2.split(",").map((s) => s.trim()).filter(Boolean);
|
|
1364
|
+
}
|
|
1266
1365
|
var apiRoutes = new hono.Hono();
|
|
1267
1366
|
apiRoutes.use("*", async (c, next) => {
|
|
1268
1367
|
const startTime = Date.now();
|
|
@@ -1272,7 +1371,8 @@ apiRoutes.use("*", async (c, next) => {
|
|
|
1272
1371
|
c.header("X-Response-Time", `${totalTime}ms`);
|
|
1273
1372
|
});
|
|
1274
1373
|
apiRoutes.use("*", async (c, next) => {
|
|
1275
|
-
const
|
|
1374
|
+
const bypass = c.req.header("Cache-Control") === "no-cache";
|
|
1375
|
+
const cacheEnabled = !bypass && await chunk4DHPR7KR_cjs.isPluginActive(c.env.DB, "core-cache");
|
|
1276
1376
|
c.set("cacheEnabled", cacheEnabled);
|
|
1277
1377
|
await next();
|
|
1278
1378
|
});
|
|
@@ -1295,7 +1395,7 @@ apiRoutes.get("/", (c) => {
|
|
|
1295
1395
|
openapi: "3.0.0",
|
|
1296
1396
|
info: {
|
|
1297
1397
|
title: "SonicJS AI API",
|
|
1298
|
-
version:
|
|
1398
|
+
version: chunkXZUEGFXE_cjs.getCoreVersion(),
|
|
1299
1399
|
description: "RESTful API for SonicJS headless CMS - a modern, AI-powered content management system built on Cloudflare Workers",
|
|
1300
1400
|
contact: {
|
|
1301
1401
|
name: "SonicJS Support",
|
|
@@ -1699,7 +1799,7 @@ apiRoutes.get("/collections", async (c) => {
|
|
|
1699
1799
|
try {
|
|
1700
1800
|
const db = c.env.DB;
|
|
1701
1801
|
const cacheEnabled = c.get("cacheEnabled");
|
|
1702
|
-
const cache =
|
|
1802
|
+
const cache = chunkC5LDQ3SH_cjs.getCacheService(chunkC5LDQ3SH_cjs.CACHE_CONFIGS.api);
|
|
1703
1803
|
const cacheKey = cache.generateKey("collections", "all");
|
|
1704
1804
|
if (cacheEnabled) {
|
|
1705
1805
|
const cacheResult = await cache.getWithSource(cacheKey);
|
|
@@ -1725,8 +1825,8 @@ apiRoutes.get("/collections", async (c) => {
|
|
|
1725
1825
|
}
|
|
1726
1826
|
c.header("X-Cache-Status", "MISS");
|
|
1727
1827
|
c.header("X-Cache-Source", "registry");
|
|
1728
|
-
const records =
|
|
1729
|
-
const transformedResults = records.map(
|
|
1828
|
+
const records = chunk4DHPR7KR_cjs.getCollectionRegistry().listActive().filter((r) => !r.internal);
|
|
1829
|
+
const transformedResults = records.map(chunk4DHPR7KR_cjs.collectionRecordToRow);
|
|
1730
1830
|
const responseData = {
|
|
1731
1831
|
data: transformedResults,
|
|
1732
1832
|
meta: addTimingMeta(c, {
|
|
@@ -1747,16 +1847,21 @@ apiRoutes.get("/collections", async (c) => {
|
|
|
1747
1847
|
return c.json({ error: "Failed to fetch collections" }, 500);
|
|
1748
1848
|
}
|
|
1749
1849
|
});
|
|
1750
|
-
apiRoutes.get("/content",
|
|
1850
|
+
apiRoutes.get("/content", chunkBRKXMRMB_cjs.optionalAuth(), async (c) => {
|
|
1751
1851
|
const executionStart = Date.now();
|
|
1752
1852
|
try {
|
|
1753
1853
|
const db = c.env.DB;
|
|
1754
1854
|
const queryParams = c.req.query();
|
|
1855
|
+
const projFields = parseFieldsParam(queryParams.fields);
|
|
1856
|
+
if (queryParams.fields) delete queryParams.fields;
|
|
1755
1857
|
const role = c.get("user")?.role;
|
|
1858
|
+
const { tenantId: cTenantId, principalSet: cPrincipalSet } = getDocumentRequestContext(c);
|
|
1859
|
+
const cAnon = isAnonPrincipal(cPrincipalSet);
|
|
1860
|
+
const cNeedsAcl = !cAnon && !canReadNonPublicContent(role);
|
|
1756
1861
|
const collIdByName = /* @__PURE__ */ new Map();
|
|
1757
1862
|
let typeId;
|
|
1758
1863
|
let typeIds;
|
|
1759
|
-
const registry =
|
|
1864
|
+
const registry = chunk4DHPR7KR_cjs.getCollectionRegistry();
|
|
1760
1865
|
if (queryParams.collection) {
|
|
1761
1866
|
const collectionName = queryParams.collection;
|
|
1762
1867
|
const record = registry.getByName(collectionName);
|
|
@@ -1786,11 +1891,11 @@ apiRoutes.get("/content", chunk37V3RET3_cjs.optionalAuth(), async (c) => {
|
|
|
1786
1891
|
return r.name;
|
|
1787
1892
|
});
|
|
1788
1893
|
}
|
|
1789
|
-
const filter =
|
|
1894
|
+
const filter = chunkSFGYZUWU_cjs.QueryFilterBuilder.parseFromQuery(queryParams);
|
|
1790
1895
|
const normalizedFilter = augmentFilterForDocuments(filter, { typeId, typeIds, role });
|
|
1791
1896
|
if (!normalizedFilter.limit) normalizedFilter.limit = 50;
|
|
1792
1897
|
normalizedFilter.limit = Math.min(normalizedFilter.limit, 1e3);
|
|
1793
|
-
const builder = new
|
|
1898
|
+
const builder = new chunkSFGYZUWU_cjs.QueryFilterBuilder();
|
|
1794
1899
|
const queryResult = builder.build("documents", normalizedFilter);
|
|
1795
1900
|
if (queryResult.errors.length > 0) {
|
|
1796
1901
|
return c.json({
|
|
@@ -1798,8 +1903,8 @@ apiRoutes.get("/content", chunk37V3RET3_cjs.optionalAuth(), async (c) => {
|
|
|
1798
1903
|
details: queryResult.errors
|
|
1799
1904
|
}, 400);
|
|
1800
1905
|
}
|
|
1801
|
-
const cacheEnabled = c.get("cacheEnabled");
|
|
1802
|
-
const cache =
|
|
1906
|
+
const cacheEnabled = c.get("cacheEnabled") && !cNeedsAcl;
|
|
1907
|
+
const cache = chunkC5LDQ3SH_cjs.getCacheService(chunkC5LDQ3SH_cjs.CACHE_CONFIGS.api);
|
|
1803
1908
|
const cacheKey = cache.generateKey("content-filtered", JSON.stringify({ filter: normalizedFilter, query: queryResult.sql }));
|
|
1804
1909
|
if (cacheEnabled) {
|
|
1805
1910
|
const cacheResult = await cache.getWithSource(cacheKey);
|
|
@@ -1820,19 +1925,61 @@ apiRoutes.get("/content", chunk37V3RET3_cjs.optionalAuth(), async (c) => {
|
|
|
1820
1925
|
}
|
|
1821
1926
|
}, executionStart)
|
|
1822
1927
|
};
|
|
1928
|
+
chunkFZGIU5AZ_cjs.recordCatalogRequest({ cacheKey, collection: typeId ?? null, path: c.req.path, queryString: c.req.raw.url.split("?")[1] ?? "", source: cacheResult.source });
|
|
1929
|
+
chunkFZGIU5AZ_cjs.scheduleKvWrite(cacheKey, c.executionCtx);
|
|
1823
1930
|
return c.json(dataWithMeta);
|
|
1824
1931
|
}
|
|
1932
|
+
const swrData = getAndConsumeStale(cacheKey);
|
|
1933
|
+
if (swrData) {
|
|
1934
|
+
c.header("X-Cache-Status", "STALE");
|
|
1935
|
+
c.header("X-Cache-Source", "swr");
|
|
1936
|
+
chunkFZGIU5AZ_cjs.recordCatalogRequest({ cacheKey, collection: typeId ?? null, path: c.req.path, queryString: c.req.raw.url.split("?")[1] ?? "", source: "swr" });
|
|
1937
|
+
chunkFZGIU5AZ_cjs.scheduleKvWrite(cacheKey, c.executionCtx);
|
|
1938
|
+
return c.json({ ...swrData, meta: addTimingMeta(c, { ...swrData.meta, cache: { hit: true, source: "swr", stale: true } }, executionStart) });
|
|
1939
|
+
}
|
|
1940
|
+
chunkFZGIU5AZ_cjs.recordCatalogRequest({ cacheKey, collection: typeId ?? null, path: c.req.path, queryString: c.req.raw.url.split("?")[1] ?? "", source: "miss" });
|
|
1941
|
+
chunkFZGIU5AZ_cjs.scheduleKvWrite(cacheKey, c.executionCtx);
|
|
1825
1942
|
}
|
|
1826
1943
|
c.header("X-Cache-Status", "MISS");
|
|
1827
1944
|
c.header("X-Cache-Source", "database");
|
|
1828
1945
|
const stmt = db.prepare(queryResult.sql);
|
|
1829
1946
|
const boundStmt = queryResult.params.length > 0 ? stmt.bind(...queryResult.params) : stmt;
|
|
1830
1947
|
const { results } = await boundStmt.all();
|
|
1831
|
-
|
|
1948
|
+
let aclResults = results;
|
|
1949
|
+
if (cNeedsAcl) {
|
|
1950
|
+
const typeReg = new chunkBRKXMRMB_cjs.DocumentTypeRegistry(db);
|
|
1951
|
+
const repo = new DocumentRepository(db, cTenantId);
|
|
1952
|
+
const uniqueTypeIds = [...new Set(results.map((r) => r.type_id))];
|
|
1953
|
+
const typeSettingsMap = /* @__PURE__ */ new Map();
|
|
1954
|
+
const typeRbacOnlyMap = /* @__PURE__ */ new Map();
|
|
1955
|
+
const typeDeniedMap = /* @__PURE__ */ new Map();
|
|
1956
|
+
await Promise.all(uniqueTypeIds.map(async (tid) => {
|
|
1957
|
+
const dt = await typeReg.findById(tid);
|
|
1958
|
+
const settings = dt?.settings ?? {};
|
|
1959
|
+
typeSettingsMap.set(tid, settings);
|
|
1960
|
+
const allowed2 = await typeReadAllowed(db, cPrincipalSet, dt, tid);
|
|
1961
|
+
if (!allowed2) {
|
|
1962
|
+
typeDeniedMap.set(tid, true);
|
|
1963
|
+
return;
|
|
1964
|
+
}
|
|
1965
|
+
const perms = new DocumentPermissionsService(db);
|
|
1966
|
+
typeRbacOnlyMap.set(tid, !perms.isAllowedSync(cPrincipalSet, [], "read", settings));
|
|
1967
|
+
}));
|
|
1968
|
+
const allowed = await Promise.all(
|
|
1969
|
+
results.map((row) => {
|
|
1970
|
+
const tid = row.type_id;
|
|
1971
|
+
if (typeDeniedMap.get(tid)) return Promise.resolve(false);
|
|
1972
|
+
if (typeRbacOnlyMap.get(tid)) return Promise.resolve(true);
|
|
1973
|
+
return repo.isAllowed(cPrincipalSet, row.root_id, "read", typeSettingsMap.get(tid) ?? {});
|
|
1974
|
+
})
|
|
1975
|
+
);
|
|
1976
|
+
aclResults = results.filter((_, i) => allowed[i]);
|
|
1977
|
+
}
|
|
1978
|
+
const transformedResults = aclResults.map((row) => mapDocRowToContent(row, collIdByName.get(row.type_id) ?? null));
|
|
1832
1979
|
const responseData = {
|
|
1833
|
-
data: transformedResults,
|
|
1980
|
+
data: projFields.length ? transformedResults.map((item) => projectFields(item, projFields)) : transformedResults,
|
|
1834
1981
|
meta: addTimingMeta(c, {
|
|
1835
|
-
count:
|
|
1982
|
+
count: aclResults.length,
|
|
1836
1983
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1837
1984
|
// D44: echo the caller's filter with the access policy applied (status=published forced for
|
|
1838
1985
|
// anonymous callers — the visible enforcement proof), NOT the internal doc-augmented where-tree.
|
|
@@ -1843,7 +1990,7 @@ apiRoutes.get("/content", chunk37V3RET3_cjs.optionalAuth(), async (c) => {
|
|
|
1843
1990
|
}
|
|
1844
1991
|
}, executionStart)
|
|
1845
1992
|
};
|
|
1846
|
-
if (cacheEnabled) {
|
|
1993
|
+
if (cacheEnabled && projFields.length === 0) {
|
|
1847
1994
|
await cache.set(cacheKey, responseData);
|
|
1848
1995
|
}
|
|
1849
1996
|
return c.json(responseData);
|
|
@@ -1855,26 +2002,36 @@ apiRoutes.get("/content", chunk37V3RET3_cjs.optionalAuth(), async (c) => {
|
|
|
1855
2002
|
}, 500);
|
|
1856
2003
|
}
|
|
1857
2004
|
});
|
|
1858
|
-
apiRoutes.get("/collections/:collection/content",
|
|
2005
|
+
apiRoutes.get("/collections/:collection/content", chunkBRKXMRMB_cjs.optionalAuth(), async (c) => {
|
|
1859
2006
|
const executionStart = Date.now();
|
|
1860
2007
|
try {
|
|
1861
2008
|
const collection = c.req.param("collection");
|
|
1862
2009
|
const db = c.env.DB;
|
|
1863
2010
|
const queryParams = c.req.query();
|
|
1864
|
-
const record =
|
|
2011
|
+
const record = chunk4DHPR7KR_cjs.getCollectionRegistry().getBySlugOrName(collection);
|
|
1865
2012
|
if (!record || record.isActive === false) {
|
|
1866
2013
|
return c.json({ error: "Collection not found" }, 404);
|
|
1867
2014
|
}
|
|
1868
2015
|
const collIdByName = /* @__PURE__ */ new Map();
|
|
1869
2016
|
collIdByName.set(collection, record.id);
|
|
1870
2017
|
const role = c.get("user")?.role;
|
|
1871
|
-
const
|
|
2018
|
+
const { tenantId: ccTenantId, principalSet: ccPrincipalSet } = getDocumentRequestContext(c);
|
|
2019
|
+
const ccAnon = isAnonPrincipal(ccPrincipalSet);
|
|
2020
|
+
const ccNeedsAcl = !ccAnon && !canReadNonPublicContent(role);
|
|
2021
|
+
let ccDocType;
|
|
2022
|
+
if (ccNeedsAcl) {
|
|
2023
|
+
ccDocType = await new chunkBRKXMRMB_cjs.DocumentTypeRegistry(db).findById(record.name);
|
|
2024
|
+
if (!await typeReadAllowed(db, ccPrincipalSet, ccDocType, record.name)) {
|
|
2025
|
+
return c.json({ error: "Forbidden" }, 403);
|
|
2026
|
+
}
|
|
2027
|
+
}
|
|
2028
|
+
const filter = chunkSFGYZUWU_cjs.QueryFilterBuilder.parseFromQuery(queryParams);
|
|
1872
2029
|
const normalizedFilter = augmentFilterForDocuments(filter, { typeId: collection, role });
|
|
1873
2030
|
if (!normalizedFilter.limit) {
|
|
1874
2031
|
normalizedFilter.limit = 50;
|
|
1875
2032
|
}
|
|
1876
2033
|
normalizedFilter.limit = Math.min(normalizedFilter.limit, 1e3);
|
|
1877
|
-
const builder = new
|
|
2034
|
+
const builder = new chunkSFGYZUWU_cjs.QueryFilterBuilder();
|
|
1878
2035
|
const queryResult = builder.build("documents", normalizedFilter);
|
|
1879
2036
|
if (queryResult.errors.length > 0) {
|
|
1880
2037
|
return c.json({
|
|
@@ -1882,8 +2039,8 @@ apiRoutes.get("/collections/:collection/content", chunk37V3RET3_cjs.optionalAuth
|
|
|
1882
2039
|
details: queryResult.errors
|
|
1883
2040
|
}, 400);
|
|
1884
2041
|
}
|
|
1885
|
-
const cacheEnabled = c.get("cacheEnabled");
|
|
1886
|
-
const cache =
|
|
2042
|
+
const cacheEnabled = c.get("cacheEnabled") && !ccNeedsAcl;
|
|
2043
|
+
const cache = chunkC5LDQ3SH_cjs.getCacheService(chunkC5LDQ3SH_cjs.CACHE_CONFIGS.api);
|
|
1887
2044
|
const includeCollection = queryParams.include?.split(",").map((s) => s.trim()).includes("collection");
|
|
1888
2045
|
const cacheKey = cache.generateKey("collection-content-filtered", `${collection}:${JSON.stringify({ filter: normalizedFilter, query: queryResult.sql, includeCollection })}`);
|
|
1889
2046
|
if (cacheEnabled) {
|
|
@@ -1905,20 +2062,44 @@ apiRoutes.get("/collections/:collection/content", chunk37V3RET3_cjs.optionalAuth
|
|
|
1905
2062
|
}
|
|
1906
2063
|
}, executionStart)
|
|
1907
2064
|
};
|
|
2065
|
+
chunkFZGIU5AZ_cjs.recordCatalogRequest({ cacheKey, collection: collection ?? null, path: c.req.path, queryString: c.req.raw.url.split("?")[1] ?? "", source: cacheResult.source });
|
|
2066
|
+
chunkFZGIU5AZ_cjs.scheduleKvWrite(cacheKey, c.executionCtx);
|
|
1908
2067
|
return c.json(dataWithMeta);
|
|
1909
2068
|
}
|
|
2069
|
+
const swrData = getAndConsumeStale(cacheKey);
|
|
2070
|
+
if (swrData) {
|
|
2071
|
+
c.header("X-Cache-Status", "STALE");
|
|
2072
|
+
c.header("X-Cache-Source", "swr");
|
|
2073
|
+
chunkFZGIU5AZ_cjs.recordCatalogRequest({ cacheKey, collection: collection ?? null, path: c.req.path, queryString: c.req.raw.url.split("?")[1] ?? "", source: "swr" });
|
|
2074
|
+
chunkFZGIU5AZ_cjs.scheduleKvWrite(cacheKey, c.executionCtx);
|
|
2075
|
+
return c.json({ ...swrData, meta: addTimingMeta(c, { ...swrData.meta, cache: { hit: true, source: "swr", stale: true } }, executionStart) });
|
|
2076
|
+
}
|
|
2077
|
+
chunkFZGIU5AZ_cjs.recordCatalogRequest({ cacheKey, collection: collection ?? null, path: c.req.path, queryString: c.req.raw.url.split("?")[1] ?? "", source: "miss" });
|
|
2078
|
+
chunkFZGIU5AZ_cjs.scheduleKvWrite(cacheKey, c.executionCtx);
|
|
1910
2079
|
}
|
|
1911
2080
|
c.header("X-Cache-Status", "MISS");
|
|
1912
2081
|
c.header("X-Cache-Source", "database");
|
|
1913
2082
|
const stmt = db.prepare(queryResult.sql);
|
|
1914
2083
|
const boundStmt = queryResult.params.length > 0 ? stmt.bind(...queryResult.params) : stmt;
|
|
1915
2084
|
const { results } = await boundStmt.all();
|
|
1916
|
-
|
|
2085
|
+
let ccAclResults = results;
|
|
2086
|
+
if (ccNeedsAcl) {
|
|
2087
|
+
const ccPerms = new DocumentPermissionsService(db);
|
|
2088
|
+
const ccBaseGrantsPass = ccPerms.isAllowedSync(ccPrincipalSet, [], "read", ccDocType?.settings ?? {});
|
|
2089
|
+
if (ccBaseGrantsPass) {
|
|
2090
|
+
const repo = new DocumentRepository(db, ccTenantId);
|
|
2091
|
+
const allowed = await Promise.all(
|
|
2092
|
+
results.map((row) => repo.isAllowed(ccPrincipalSet, row.root_id, "read", ccDocType?.settings ?? {}))
|
|
2093
|
+
);
|
|
2094
|
+
ccAclResults = results.filter((_, i) => allowed[i]);
|
|
2095
|
+
}
|
|
2096
|
+
}
|
|
2097
|
+
const transformedResults = ccAclResults.map((row) => mapDocRowToContent(row, collIdByName.get(row.type_id) ?? null));
|
|
1917
2098
|
const responseData = {
|
|
1918
2099
|
data: transformedResults,
|
|
1919
2100
|
meta: addTimingMeta(c, {
|
|
1920
|
-
...includeCollection ? { collection:
|
|
1921
|
-
count:
|
|
2101
|
+
...includeCollection ? { collection: chunk4DHPR7KR_cjs.collectionRecordToRow(record) } : {},
|
|
2102
|
+
count: ccAclResults.length,
|
|
1922
2103
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1923
2104
|
// D44: echo the caller's filter with the access policy applied (status=published forced for
|
|
1924
2105
|
// anonymous callers — the visible enforcement proof), NOT the internal doc-augmented where-tree.
|
|
@@ -1942,32 +2123,44 @@ apiRoutes.get("/collections/:collection/content", chunk37V3RET3_cjs.optionalAuth
|
|
|
1942
2123
|
}
|
|
1943
2124
|
});
|
|
1944
2125
|
apiRoutes.route("/content", api_content_crud_default);
|
|
1945
|
-
apiRoutes.get("/:collection",
|
|
2126
|
+
apiRoutes.get("/:collection", chunkBRKXMRMB_cjs.optionalAuth(), async (c) => {
|
|
1946
2127
|
const executionStart = Date.now();
|
|
1947
2128
|
try {
|
|
1948
2129
|
const collection = c.req.param("collection");
|
|
1949
2130
|
const db = c.env.DB;
|
|
1950
2131
|
const queryParams = c.req.query();
|
|
1951
|
-
const
|
|
2132
|
+
const projFields = parseFieldsParam(queryParams.fields);
|
|
2133
|
+
if (queryParams.fields) delete queryParams.fields;
|
|
2134
|
+
const record = chunk4DHPR7KR_cjs.getCollectionRegistry().getBySlugOrName(collection);
|
|
1952
2135
|
if (!record || record.isActive === false) {
|
|
1953
2136
|
return c.json({ error: "Collection not found" }, 404);
|
|
1954
2137
|
}
|
|
1955
2138
|
const collIdByName = /* @__PURE__ */ new Map();
|
|
1956
2139
|
collIdByName.set(record.name, record.id);
|
|
1957
2140
|
const role = c.get("user")?.role;
|
|
1958
|
-
const
|
|
2141
|
+
const { tenantId, principalSet } = getDocumentRequestContext(c);
|
|
2142
|
+
const anon = isAnonPrincipal(principalSet);
|
|
2143
|
+
const needsAcl = !anon && !canReadNonPublicContent(role);
|
|
2144
|
+
let docTypeForCheck;
|
|
2145
|
+
if (needsAcl) {
|
|
2146
|
+
docTypeForCheck = await new chunkBRKXMRMB_cjs.DocumentTypeRegistry(db).findById(record.name);
|
|
2147
|
+
if (!await typeReadAllowed(db, principalSet, docTypeForCheck, record.name)) {
|
|
2148
|
+
return c.json({ error: "Forbidden" }, 403);
|
|
2149
|
+
}
|
|
2150
|
+
}
|
|
2151
|
+
const filter = chunkSFGYZUWU_cjs.QueryFilterBuilder.parseFromQuery(queryParams);
|
|
1959
2152
|
const normalizedFilter = augmentFilterForDocuments(filter, { typeId: record.name, role });
|
|
1960
2153
|
if (!normalizedFilter.limit) normalizedFilter.limit = 50;
|
|
1961
2154
|
normalizedFilter.limit = Math.min(normalizedFilter.limit, 1e3);
|
|
1962
|
-
const builder = new
|
|
2155
|
+
const builder = new chunkSFGYZUWU_cjs.QueryFilterBuilder();
|
|
1963
2156
|
const queryResult = builder.build("documents", normalizedFilter);
|
|
1964
2157
|
if (queryResult.errors.length > 0) {
|
|
1965
2158
|
return c.json({ error: "Invalid filter parameters", details: queryResult.errors }, 400);
|
|
1966
2159
|
}
|
|
1967
2160
|
const collectionCache = record.cache;
|
|
1968
2161
|
const collectionCacheDisabled = collectionCache?.enabled === false;
|
|
1969
|
-
const cacheEnabled = c.get("cacheEnabled") && !collectionCacheDisabled;
|
|
1970
|
-
const cache =
|
|
2162
|
+
const cacheEnabled = c.get("cacheEnabled") && !collectionCacheDisabled && projFields.length === 0 && !needsAcl;
|
|
2163
|
+
const cache = chunkC5LDQ3SH_cjs.getCacheService(chunkC5LDQ3SH_cjs.CACHE_CONFIGS.api);
|
|
1971
2164
|
const includeCollection = queryParams.include?.split(",").map((s) => s.trim()).includes("collection");
|
|
1972
2165
|
const cacheKey = cache.generateKey("collection-content-filtered", `${collection}:${JSON.stringify({ filter: normalizedFilter, query: queryResult.sql, includeCollection })}`);
|
|
1973
2166
|
if (cacheEnabled) {
|
|
@@ -1976,20 +2169,45 @@ apiRoutes.get("/:collection", chunk37V3RET3_cjs.optionalAuth(), async (c) => {
|
|
|
1976
2169
|
c.header("X-Cache-Status", "HIT");
|
|
1977
2170
|
c.header("X-Cache-Source", cacheResult.source);
|
|
1978
2171
|
if (cacheResult.ttl) c.header("X-Cache-TTL", Math.floor(cacheResult.ttl).toString());
|
|
2172
|
+
chunkFZGIU5AZ_cjs.recordCatalogRequest({ cacheKey, collection: collection ?? null, path: c.req.path, queryString: c.req.raw.url.split("?")[1] ?? "", source: cacheResult.source });
|
|
2173
|
+
chunkFZGIU5AZ_cjs.scheduleKvWrite(cacheKey, c.executionCtx);
|
|
1979
2174
|
return c.json({ ...cacheResult.data, meta: addTimingMeta(c, { ...cacheResult.data.meta, cache: { hit: true, source: cacheResult.source, ttl: cacheResult.ttl ? Math.floor(cacheResult.ttl) : void 0 } }, executionStart) });
|
|
1980
2175
|
}
|
|
2176
|
+
const swrData = getAndConsumeStale(cacheKey);
|
|
2177
|
+
if (swrData) {
|
|
2178
|
+
c.header("X-Cache-Status", "STALE");
|
|
2179
|
+
c.header("X-Cache-Source", "swr");
|
|
2180
|
+
chunkFZGIU5AZ_cjs.recordCatalogRequest({ cacheKey, collection: collection ?? null, path: c.req.path, queryString: c.req.raw.url.split("?")[1] ?? "", source: "swr" });
|
|
2181
|
+
chunkFZGIU5AZ_cjs.scheduleKvWrite(cacheKey, c.executionCtx);
|
|
2182
|
+
return c.json({ ...swrData, meta: addTimingMeta(c, { ...swrData.meta, cache: { hit: true, source: "swr", stale: true } }, executionStart) });
|
|
2183
|
+
}
|
|
2184
|
+
chunkFZGIU5AZ_cjs.recordCatalogRequest({ cacheKey, collection: collection ?? null, path: c.req.path, queryString: c.req.raw.url.split("?")[1] ?? "", source: "miss" });
|
|
2185
|
+
chunkFZGIU5AZ_cjs.scheduleKvWrite(cacheKey, c.executionCtx);
|
|
1981
2186
|
}
|
|
1982
2187
|
c.header("X-Cache-Status", "MISS");
|
|
1983
2188
|
c.header("X-Cache-Source", "database");
|
|
1984
2189
|
const stmt = db.prepare(queryResult.sql);
|
|
1985
2190
|
const boundStmt = queryResult.params.length > 0 ? stmt.bind(...queryResult.params) : stmt;
|
|
1986
2191
|
const { results } = await boundStmt.all();
|
|
1987
|
-
|
|
2192
|
+
let aclResults = results;
|
|
2193
|
+
if (needsAcl) {
|
|
2194
|
+
const perms = new DocumentPermissionsService(db);
|
|
2195
|
+
const baseGrantsPass = perms.isAllowedSync(principalSet, [], "read", docTypeForCheck?.settings ?? {});
|
|
2196
|
+
if (!baseGrantsPass) {
|
|
2197
|
+
} else {
|
|
2198
|
+
const repo = new DocumentRepository(db, tenantId);
|
|
2199
|
+
const allowed = await Promise.all(
|
|
2200
|
+
results.map((row) => repo.isAllowed(principalSet, row.root_id, "read", docTypeForCheck?.settings ?? {}))
|
|
2201
|
+
);
|
|
2202
|
+
aclResults = results.filter((_, i) => allowed[i]);
|
|
2203
|
+
}
|
|
2204
|
+
}
|
|
2205
|
+
const transformedResults = aclResults.map((row) => mapDocRowToContent(row, collIdByName.get(row.type_id) ?? null));
|
|
1988
2206
|
const responseData = {
|
|
1989
|
-
data: transformedResults,
|
|
2207
|
+
data: projFields.length ? transformedResults.map((item) => projectFields(item, projFields)) : transformedResults,
|
|
1990
2208
|
meta: addTimingMeta(c, {
|
|
1991
|
-
...includeCollection ? { collection:
|
|
1992
|
-
count:
|
|
2209
|
+
...includeCollection ? { collection: chunk4DHPR7KR_cjs.collectionRecordToRow(record) } : {},
|
|
2210
|
+
count: aclResults.length,
|
|
1993
2211
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1994
2212
|
filter: normalizePublicContentFilter(filter, role),
|
|
1995
2213
|
cache: { hit: false, source: "database" }
|
|
@@ -2006,12 +2224,12 @@ apiRoutes.get("/:collection", chunk37V3RET3_cjs.optionalAuth(), async (c) => {
|
|
|
2006
2224
|
return c.json({ error: "Failed to fetch content", details: error instanceof Error ? error.message : String(error) }, 500);
|
|
2007
2225
|
}
|
|
2008
2226
|
});
|
|
2009
|
-
apiRoutes.get("/:collection/:id",
|
|
2227
|
+
apiRoutes.get("/:collection/:id", chunkBRKXMRMB_cjs.optionalAuth(), async (c) => {
|
|
2010
2228
|
try {
|
|
2011
2229
|
const collection = c.req.param("collection");
|
|
2012
2230
|
const id = c.req.param("id");
|
|
2013
2231
|
const db = c.env.DB;
|
|
2014
|
-
const record =
|
|
2232
|
+
const record = chunk4DHPR7KR_cjs.getCollectionRegistry().getBySlugOrName(collection);
|
|
2015
2233
|
if (!record || record.isActive === false) {
|
|
2016
2234
|
return c.json({ error: "Collection not found" }, 404);
|
|
2017
2235
|
}
|
|
@@ -2020,7 +2238,24 @@ apiRoutes.get("/:collection/:id", chunk37V3RET3_cjs.optionalAuth(), async (c) =>
|
|
|
2020
2238
|
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
2239
|
).bind(id, record.name).first();
|
|
2022
2240
|
if (!docRow) return c.json({ error: "Content not found" }, 404);
|
|
2023
|
-
const
|
|
2241
|
+
const colRole = c.get("user")?.role;
|
|
2242
|
+
const { tenantId: colTenantId, principalSet: colPrincipalSet } = getDocumentRequestContext(c);
|
|
2243
|
+
const colNeedsAcl = !isAnonPrincipal(colPrincipalSet) && !canReadNonPublicContent(colRole);
|
|
2244
|
+
if (colNeedsAcl) {
|
|
2245
|
+
const docType = await new chunkBRKXMRMB_cjs.DocumentTypeRegistry(db).findById(record.name);
|
|
2246
|
+
if (!await typeReadAllowed(db, colPrincipalSet, docType, record.name)) {
|
|
2247
|
+
return c.json({ error: "Content not found" }, 404);
|
|
2248
|
+
}
|
|
2249
|
+
const perms = new DocumentPermissionsService(db);
|
|
2250
|
+
if (perms.isAllowedSync(colPrincipalSet, [], "read", docType?.settings ?? {})) {
|
|
2251
|
+
const repo = new DocumentRepository(db, colTenantId);
|
|
2252
|
+
if (!await repo.isAllowed(colPrincipalSet, docRow.root_id, "read", docType?.settings ?? {})) {
|
|
2253
|
+
return c.json({ error: "Content not found" }, 404);
|
|
2254
|
+
}
|
|
2255
|
+
}
|
|
2256
|
+
}
|
|
2257
|
+
const projFields = parseFieldsParam(c.req.query("fields"));
|
|
2258
|
+
const coll = chunk4DHPR7KR_cjs.getCollectionRegistry().getByName(docRow.type_id);
|
|
2024
2259
|
const transformedContent = {
|
|
2025
2260
|
id: docRow.root_id,
|
|
2026
2261
|
title: docRow.title,
|
|
@@ -2028,17 +2263,17 @@ apiRoutes.get("/:collection/:id", chunk37V3RET3_cjs.optionalAuth(), async (c) =>
|
|
|
2028
2263
|
status: docRow.status,
|
|
2029
2264
|
collectionId: coll?.id ?? docRow.type_id,
|
|
2030
2265
|
data: docRow.data ? JSON.parse(docRow.data) : {},
|
|
2031
|
-
created_at:
|
|
2032
|
-
updated_at:
|
|
2266
|
+
created_at: chunkOLEOKHDX_cjs.documentSecondsToMs(docRow.created_at),
|
|
2267
|
+
updated_at: chunkOLEOKHDX_cjs.documentSecondsToMs(docRow.updated_at)
|
|
2033
2268
|
};
|
|
2034
2269
|
dispatchHookEvent(c, "content:read", { collection: docRow.type_id, id: docRow.root_id, data: transformedContent.data }, "fire-and-forget");
|
|
2035
|
-
return c.json({ data: transformedContent });
|
|
2270
|
+
return c.json({ data: projFields.length ? projectFields(transformedContent, projFields) : transformedContent });
|
|
2036
2271
|
} catch (error) {
|
|
2037
2272
|
console.error("Error fetching content:", error);
|
|
2038
2273
|
return c.json({ error: "Failed to fetch content", details: error instanceof Error ? error.message : String(error) }, 500);
|
|
2039
2274
|
}
|
|
2040
2275
|
});
|
|
2041
|
-
apiRoutes.post("/:collection",
|
|
2276
|
+
apiRoutes.post("/:collection", chunkBRKXMRMB_cjs.requireAuth(), chunkBRKXMRMB_cjs.requireRole(["admin", "editor", "author"]), async (c) => {
|
|
2042
2277
|
try {
|
|
2043
2278
|
const collection = c.req.param("collection");
|
|
2044
2279
|
const db = c.env.DB;
|
|
@@ -2059,26 +2294,29 @@ apiRoutes.post("/:collection", chunk37V3RET3_cjs.requireAuth(), chunk37V3RET3_cj
|
|
|
2059
2294
|
} catch (err) {
|
|
2060
2295
|
return c.json({ error: "Write cancelled by plugin", details: String(err) }, 400);
|
|
2061
2296
|
}
|
|
2062
|
-
const svc = new
|
|
2297
|
+
const svc = new chunkOLEOKHDX_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
2298
|
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
|
-
const cache =
|
|
2065
|
-
await cache.
|
|
2066
|
-
await cache.
|
|
2299
|
+
const cache = chunkC5LDQ3SH_cjs.getCacheService(chunkC5LDQ3SH_cjs.CACHE_CONFIGS.api);
|
|
2300
|
+
const createAffectedKeys = (await cache.listKeys()).map((k) => k.key).filter((k) => k.startsWith("api:content-filtered:") || k.startsWith(`api:collection-content-filtered:${backing.coll.name}:`));
|
|
2301
|
+
const createStaleValues = await cache.getMany(createAffectedKeys);
|
|
2302
|
+
for (const [key, val] of createStaleValues) markStale(key, val, backing.coll.name);
|
|
2303
|
+
await cache.invalidate("api:content-filtered:*");
|
|
2304
|
+
await cache.invalidate(`api:collection-content-filtered:${backing.coll.name}:*`);
|
|
2067
2305
|
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:
|
|
2306
|
+
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: chunkOLEOKHDX_cjs.documentSecondsToMs(doc.createdAt), updated_at: chunkOLEOKHDX_cjs.documentSecondsToMs(doc.updatedAt) } }, 201);
|
|
2069
2307
|
} catch (error) {
|
|
2070
2308
|
console.error("Error creating content:", error);
|
|
2071
2309
|
return c.json({ error: "Failed to create content", details: error instanceof Error ? error.message : String(error) }, 500);
|
|
2072
2310
|
}
|
|
2073
2311
|
});
|
|
2074
|
-
apiRoutes.put("/:collection/:id",
|
|
2312
|
+
apiRoutes.put("/:collection/:id", chunkBRKXMRMB_cjs.requireAuth(), chunkBRKXMRMB_cjs.requireRole(["admin", "editor", "author"]), async (c) => {
|
|
2075
2313
|
try {
|
|
2076
2314
|
const collection = c.req.param("collection");
|
|
2077
2315
|
const id = c.req.param("id");
|
|
2078
2316
|
const db = c.env.DB;
|
|
2079
2317
|
const user = c.get("user");
|
|
2080
2318
|
const body = await c.req.json();
|
|
2081
|
-
const collRecord =
|
|
2319
|
+
const collRecord = chunk4DHPR7KR_cjs.getCollectionRegistry().getBySlugOrName(collection);
|
|
2082
2320
|
const typeName = collRecord?.name ?? collection;
|
|
2083
2321
|
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
2322
|
if (!docRow) return c.json({ error: "Content not found" }, 404);
|
|
@@ -2090,8 +2328,8 @@ apiRoutes.put("/:collection/:id", chunk37V3RET3_cjs.requireAuth(), chunk37V3RET3
|
|
|
2090
2328
|
} catch (err) {
|
|
2091
2329
|
return c.json({ error: "Write cancelled by plugin", details: String(err) }, 400);
|
|
2092
2330
|
}
|
|
2093
|
-
const docType = await new
|
|
2094
|
-
const svc = new
|
|
2331
|
+
const docType = await new chunkBRKXMRMB_cjs.DocumentTypeRegistry(db).findById(docRow.type_id);
|
|
2332
|
+
const svc = new chunkOLEOKHDX_cjs.DocumentsService(db, { queryableFields: docType?.queryableFields ?? [], typeSchemaVersion: docType?.schemaVersion ?? 1, maxVersionsPerRoot: docType?.settings?.maxVersionsPerRoot ?? 50, tenantId: "default", versioning: docType?.settings?.versioning ?? false });
|
|
2095
2333
|
const input = {};
|
|
2096
2334
|
if (body.title !== void 0) input.title = body.title;
|
|
2097
2335
|
if (body.slug !== void 0) input.slug = slugify(body.slug);
|
|
@@ -2104,28 +2342,31 @@ apiRoutes.put("/:collection/:id", chunk37V3RET3_cjs.requireAuth(), chunk37V3RET3
|
|
|
2104
2342
|
} else if (body.status === "draft" && pub) {
|
|
2105
2343
|
await svc.unpublish(pub.id);
|
|
2106
2344
|
}
|
|
2107
|
-
const cache =
|
|
2108
|
-
await cache.
|
|
2109
|
-
await cache.
|
|
2110
|
-
const
|
|
2345
|
+
const cache = chunkC5LDQ3SH_cjs.getCacheService(chunkC5LDQ3SH_cjs.CACHE_CONFIGS.api);
|
|
2346
|
+
const updateAffectedKeys = (await cache.listKeys()).map((k) => k.key).filter((k) => k.startsWith("api:content-filtered:") || k.startsWith(`api:collection-content-filtered:${docRow.type_id}:`));
|
|
2347
|
+
const updateStaleValues = await cache.getMany(updateAffectedKeys);
|
|
2348
|
+
for (const [key, val] of updateStaleValues) markStale(key, val, docRow.type_id);
|
|
2349
|
+
await cache.invalidate("api:content-filtered:*");
|
|
2350
|
+
await cache.invalidate(`api:collection-content-filtered:${docRow.type_id}:*`);
|
|
2351
|
+
const coll = chunk4DHPR7KR_cjs.getCollectionRegistry().getByName(docRow.type_id);
|
|
2111
2352
|
const saved = await db.prepare("SELECT * FROM documents WHERE id = ?").bind(newDraft.id).first();
|
|
2112
2353
|
const savedData = saved?.data ? JSON.parse(saved.data) : {};
|
|
2113
2354
|
dispatchHookEvent(c, "content:after:update", { collection: docRow.type_id, id, data: savedData, user: actor }, "fire-and-forget");
|
|
2114
2355
|
const nowPublished = body.status === "published" || body.status === void 0 && wasPublished;
|
|
2115
2356
|
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:
|
|
2357
|
+
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: chunkOLEOKHDX_cjs.documentSecondsToMs(saved.created_at), updated_at: chunkOLEOKHDX_cjs.documentSecondsToMs(saved.updated_at) } });
|
|
2117
2358
|
} catch (error) {
|
|
2118
2359
|
console.error("Error updating content:", error);
|
|
2119
2360
|
return c.json({ error: "Failed to update content", details: error instanceof Error ? error.message : String(error) }, 500);
|
|
2120
2361
|
}
|
|
2121
2362
|
});
|
|
2122
|
-
apiRoutes.delete("/:collection/:id",
|
|
2363
|
+
apiRoutes.delete("/:collection/:id", chunkBRKXMRMB_cjs.requireAuth(), chunkBRKXMRMB_cjs.requireRole(["admin", "editor", "author"]), async (c) => {
|
|
2123
2364
|
try {
|
|
2124
2365
|
const collection = c.req.param("collection");
|
|
2125
2366
|
const id = c.req.param("id");
|
|
2126
2367
|
const db = c.env.DB;
|
|
2127
2368
|
const user = c.get("user");
|
|
2128
|
-
const collRecord =
|
|
2369
|
+
const collRecord = chunk4DHPR7KR_cjs.getCollectionRegistry().getBySlugOrName(collection);
|
|
2129
2370
|
const typeName = collRecord?.name ?? collection;
|
|
2130
2371
|
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
2372
|
if (!docRow) return c.json({ error: "Content not found" }, 404);
|
|
@@ -2137,9 +2378,12 @@ apiRoutes.delete("/:collection/:id", chunk37V3RET3_cjs.requireAuth(), chunk37V3R
|
|
|
2137
2378
|
}
|
|
2138
2379
|
const now = Math.floor(Date.now() / 1e3);
|
|
2139
2380
|
await db.prepare("UPDATE documents SET deleted_at = ?, updated_at = ? WHERE root_id = ? AND tenant_id = 'default'").bind(now, now, id).run();
|
|
2140
|
-
const cache =
|
|
2141
|
-
await cache.
|
|
2142
|
-
await cache.
|
|
2381
|
+
const cache = chunkC5LDQ3SH_cjs.getCacheService(chunkC5LDQ3SH_cjs.CACHE_CONFIGS.api);
|
|
2382
|
+
const deleteAffectedKeys = (await cache.listKeys()).map((k) => k.key).filter((k) => k.startsWith("api:content-filtered:") || k.startsWith(`api:collection-content-filtered:${docRow.type_id}:`));
|
|
2383
|
+
const deleteStaleValues = await cache.getMany(deleteAffectedKeys);
|
|
2384
|
+
for (const [key, val] of deleteStaleValues) markStale(key, val, docRow.type_id);
|
|
2385
|
+
await cache.invalidate("api:content-filtered:*");
|
|
2386
|
+
await cache.invalidate(`api:collection-content-filtered:${docRow.type_id}:*`);
|
|
2143
2387
|
dispatchHookEvent(c, "content:after:delete", { collection: docRow.type_id, id, data: {}, user: actor }, "fire-and-forget");
|
|
2144
2388
|
return c.json({ success: true });
|
|
2145
2389
|
} catch (error) {
|
|
@@ -2212,7 +2456,7 @@ var MediaDocumentService = class {
|
|
|
2212
2456
|
tenantId;
|
|
2213
2457
|
/** Create a media_asset document from R2 upload metadata. Published-on-create (immediately usable). */
|
|
2214
2458
|
async createFromUpload(meta, createdBy) {
|
|
2215
|
-
const svc = new
|
|
2459
|
+
const svc = new chunkOLEOKHDX_cjs.DocumentsService(this.db, { queryableFields: MEDIA_QUERYABLE, tenantId: this.tenantId, maxVersionsPerRoot: 5 });
|
|
2216
2460
|
return svc.create(
|
|
2217
2461
|
createDocumentSchema.parse({
|
|
2218
2462
|
typeId: "media_asset",
|
|
@@ -2290,7 +2534,7 @@ var MediaDocumentService = class {
|
|
|
2290
2534
|
}
|
|
2291
2535
|
/** Update alt/caption/tags on a media_asset document (saveDraft + publish atomically). */
|
|
2292
2536
|
async updateMetadata(rootId, meta, updatedBy) {
|
|
2293
|
-
const svc = new
|
|
2537
|
+
const svc = new chunkOLEOKHDX_cjs.DocumentsService(this.db, { queryableFields: MEDIA_QUERYABLE, tenantId: this.tenantId, maxVersionsPerRoot: 5 });
|
|
2294
2538
|
const newDraft = await svc.saveDraft(rootId, { data: meta }, updatedBy);
|
|
2295
2539
|
return svc.publish(newDraft.id, updatedBy);
|
|
2296
2540
|
}
|
|
@@ -2347,7 +2591,7 @@ var fileValidationSchema = zod.z.object({
|
|
|
2347
2591
|
// 50MB max
|
|
2348
2592
|
});
|
|
2349
2593
|
var apiMediaRoutes = new hono.Hono();
|
|
2350
|
-
apiMediaRoutes.use("*",
|
|
2594
|
+
apiMediaRoutes.use("*", chunkBRKXMRMB_cjs.requireAuth());
|
|
2351
2595
|
apiMediaRoutes.post("/upload", async (c) => {
|
|
2352
2596
|
try {
|
|
2353
2597
|
const user = c.get("user");
|
|
@@ -2701,9 +2945,13 @@ apiMediaRoutes.post("/create-folder", async (c) => {
|
|
|
2701
2945
|
error: "Folder name can only contain lowercase letters, numbers, hyphens, and underscores"
|
|
2702
2946
|
}, 400);
|
|
2703
2947
|
}
|
|
2704
|
-
|
|
2705
|
-
|
|
2706
|
-
|
|
2948
|
+
let folderExists = false;
|
|
2949
|
+
try {
|
|
2950
|
+
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();
|
|
2951
|
+
folderExists = (existing?.count ?? 0) > 0;
|
|
2952
|
+
} catch {
|
|
2953
|
+
}
|
|
2954
|
+
if (folderExists) {
|
|
2707
2955
|
return c.json({
|
|
2708
2956
|
success: false,
|
|
2709
2957
|
error: `Folder "${folderName}" already exists`
|
|
@@ -3045,7 +3293,7 @@ apiSystemRoutes.get("/info", (c) => {
|
|
|
3045
3293
|
apiSystemRoutes.get("/stats", async (c) => {
|
|
3046
3294
|
try {
|
|
3047
3295
|
const db = c.env.DB;
|
|
3048
|
-
const typeIds =
|
|
3296
|
+
const typeIds = chunk4DHPR7KR_cjs.getCollectionRegistry().listActive().filter((r) => !r.internal).map((r) => r.name);
|
|
3049
3297
|
let contentStats = null;
|
|
3050
3298
|
if (typeIds.length > 0) {
|
|
3051
3299
|
const placeholders = typeIds.map(() => "?").join(",");
|
|
@@ -3120,12 +3368,12 @@ apiSystemRoutes.get("/env", (c) => {
|
|
|
3120
3368
|
});
|
|
3121
3369
|
var api_system_default = apiSystemRoutes;
|
|
3122
3370
|
var adminApiRoutes = new hono.Hono();
|
|
3123
|
-
adminApiRoutes.use("*",
|
|
3124
|
-
adminApiRoutes.use("*",
|
|
3371
|
+
adminApiRoutes.use("*", chunkBRKXMRMB_cjs.requireAuth());
|
|
3372
|
+
adminApiRoutes.use("*", chunkBRKXMRMB_cjs.requireRole(["admin", "editor"]));
|
|
3125
3373
|
adminApiRoutes.get("/stats", async (c) => {
|
|
3126
3374
|
try {
|
|
3127
3375
|
const db = c.env.DB;
|
|
3128
|
-
const userCollections =
|
|
3376
|
+
const userCollections = chunk4DHPR7KR_cjs.getCollectionRegistry().listActive().filter((r) => !r.internal);
|
|
3129
3377
|
const collectionsCount = userCollections.length;
|
|
3130
3378
|
let contentCount = 0;
|
|
3131
3379
|
if (userCollections.length > 0) {
|
|
@@ -3216,7 +3464,7 @@ adminApiRoutes.get("/collections", async (c) => {
|
|
|
3216
3464
|
try {
|
|
3217
3465
|
const search = c.req.query("search") || "";
|
|
3218
3466
|
const includeInactive = c.req.query("includeInactive") === "true";
|
|
3219
|
-
let records =
|
|
3467
|
+
let records = chunk4DHPR7KR_cjs.getCollectionRegistry().list().filter((r) => !r.internal);
|
|
3220
3468
|
if (!includeInactive) records = records.filter((r) => r.isActive !== false);
|
|
3221
3469
|
if (search) {
|
|
3222
3470
|
const needle = search.toLowerCase();
|
|
@@ -3248,7 +3496,7 @@ adminApiRoutes.get("/collections", async (c) => {
|
|
|
3248
3496
|
adminApiRoutes.get("/collections/:id", async (c) => {
|
|
3249
3497
|
try {
|
|
3250
3498
|
const id = c.req.param("id");
|
|
3251
|
-
const registry =
|
|
3499
|
+
const registry = chunk4DHPR7KR_cjs.getCollectionRegistry();
|
|
3252
3500
|
const record = registry.getById(id) ?? registry.getByName(id);
|
|
3253
3501
|
if (!record) {
|
|
3254
3502
|
return c.json({ error: "Collection not found" }, 404);
|
|
@@ -3298,7 +3546,7 @@ adminApiRoutes.get("/references", async (c) => {
|
|
|
3298
3546
|
if (collectionParams.length === 0) {
|
|
3299
3547
|
return c.json({ error: "Collection is required" }, 400);
|
|
3300
3548
|
}
|
|
3301
|
-
const registry =
|
|
3549
|
+
const registry = chunk4DHPR7KR_cjs.getCollectionRegistry();
|
|
3302
3550
|
const matched = collectionParams.map((param) => registry.getById(param) ?? registry.getByName(param)).filter((r) => !!r);
|
|
3303
3551
|
const seen = /* @__PURE__ */ new Set();
|
|
3304
3552
|
const collections = matched.filter((r) => {
|
|
@@ -3413,7 +3661,7 @@ adminApiRoutes.patch("/collections/:id", collectionsReadOnly);
|
|
|
3413
3661
|
adminApiRoutes.delete("/collections/:id", collectionsReadOnly);
|
|
3414
3662
|
adminApiRoutes.get("/migrations/status", async (c) => {
|
|
3415
3663
|
try {
|
|
3416
|
-
const { MigrationService: MigrationService2 } = await import('./migrations-
|
|
3664
|
+
const { MigrationService: MigrationService2 } = await import('./migrations-6M6772UC.cjs');
|
|
3417
3665
|
const db = c.env.DB;
|
|
3418
3666
|
const migrationService = new MigrationService2(db);
|
|
3419
3667
|
const status = await migrationService.getMigrationStatus();
|
|
@@ -3456,7 +3704,7 @@ adminApiRoutes.post("/migrations/run", async (c) => {
|
|
|
3456
3704
|
});
|
|
3457
3705
|
adminApiRoutes.get("/migrations/validate", async (c) => {
|
|
3458
3706
|
try {
|
|
3459
|
-
const { MigrationService: MigrationService2 } = await import('./migrations-
|
|
3707
|
+
const { MigrationService: MigrationService2 } = await import('./migrations-6M6772UC.cjs');
|
|
3460
3708
|
const db = c.env.DB;
|
|
3461
3709
|
const migrationService = new MigrationService2(db);
|
|
3462
3710
|
const validation = await migrationService.validateSchema();
|
|
@@ -3606,8 +3854,8 @@ function renderLoginPage(data, demoLoginActive = false) {
|
|
|
3606
3854
|
<div class="mt-8 sm:mx-auto sm:w-full sm:max-w-md">
|
|
3607
3855
|
<div class="bg-zinc-900 shadow-sm ring-1 ring-white/10 rounded-xl px-6 py-8 sm:px-10">
|
|
3608
3856
|
<!-- Alerts -->
|
|
3609
|
-
${data.error ? `<div class="mb-6">${
|
|
3610
|
-
${data.message ? `<div class="mb-6">${
|
|
3857
|
+
${data.error ? `<div class="mb-6">${chunkOUBUS74I_cjs.renderAlert({ type: "error", message: data.error })}</div>` : ""}
|
|
3858
|
+
${data.message ? `<div class="mb-6">${chunkOUBUS74I_cjs.renderAlert({ type: "success", message: data.message })}</div>` : ""}
|
|
3611
3859
|
|
|
3612
3860
|
<!-- Form Response (HTMX target) -->
|
|
3613
3861
|
<div id="form-response" class="mb-6"></div>
|
|
@@ -3615,6 +3863,8 @@ function renderLoginPage(data, demoLoginActive = false) {
|
|
|
3615
3863
|
<!-- Form -->
|
|
3616
3864
|
<form
|
|
3617
3865
|
id="login-form"
|
|
3866
|
+
action="/auth/login/form${data.redirect ? `?redirect=${encodeURIComponent(data.redirect)}` : ""}"
|
|
3867
|
+
method="post"
|
|
3618
3868
|
hx-post="/auth/login/form${data.redirect ? `?redirect=${encodeURIComponent(data.redirect)}` : ""}"
|
|
3619
3869
|
hx-target="#form-response"
|
|
3620
3870
|
hx-swap="innerHTML"
|
|
@@ -3771,7 +4021,7 @@ function renderRegisterPage(data) {
|
|
|
3771
4021
|
<div class="mt-8 sm:mx-auto sm:w-full sm:max-w-md">
|
|
3772
4022
|
<div class="bg-zinc-900 shadow-sm ring-1 ring-white/10 rounded-xl px-6 py-8 sm:px-10">
|
|
3773
4023
|
<!-- Alerts -->
|
|
3774
|
-
${data.error ? `<div class="mb-6">${
|
|
4024
|
+
${data.error ? `<div class="mb-6">${chunkOUBUS74I_cjs.renderAlert({ type: "error", message: data.error })}</div>` : ""}
|
|
3775
4025
|
|
|
3776
4026
|
<!-- Form -->
|
|
3777
4027
|
<form
|
|
@@ -3871,7 +4121,7 @@ function renderRegisterPage(data) {
|
|
|
3871
4121
|
}
|
|
3872
4122
|
|
|
3873
4123
|
// src/services/email/email-service-singleton.ts
|
|
3874
|
-
var singleton =
|
|
4124
|
+
var singleton = chunkKWQNB6UM_cjs.createServiceSingleton("EmailService");
|
|
3875
4125
|
function setEmailService(service2) {
|
|
3876
4126
|
singleton.set(service2);
|
|
3877
4127
|
}
|
|
@@ -3915,7 +4165,7 @@ function emptyProfile() {
|
|
|
3915
4165
|
return { custom: {} };
|
|
3916
4166
|
}
|
|
3917
4167
|
function service(db) {
|
|
3918
|
-
return new
|
|
4168
|
+
return new chunkOLEOKHDX_cjs.DocumentsService(db, { tenantId: "default", maxVersionsPerRoot: 1, queryableFields: [] });
|
|
3919
4169
|
}
|
|
3920
4170
|
async function readProfileData(db, userId) {
|
|
3921
4171
|
const row = await db.prepare(
|
|
@@ -4679,7 +4929,7 @@ function getLexicalInitScript(settings = {}) {
|
|
|
4679
4929
|
</script>
|
|
4680
4930
|
`;
|
|
4681
4931
|
}
|
|
4682
|
-
var lexicalEditorPlugin =
|
|
4932
|
+
var lexicalEditorPlugin = chunkKWQNB6UM_cjs.definePlugin({
|
|
4683
4933
|
id: "lexical-editor",
|
|
4684
4934
|
version: "1.0.0",
|
|
4685
4935
|
name: "Lexical Editor",
|
|
@@ -5130,9 +5380,11 @@ function renderDynamicField(field, options = {}) {
|
|
|
5130
5380
|
min="${opts.min || ""}"
|
|
5131
5381
|
max="${opts.max || ""}"
|
|
5132
5382
|
class="${baseClasses} ${errorClasses} !w-auto dark:[color-scheme:dark]"
|
|
5383
|
+
placeholder="YYYY-MM-DD"
|
|
5133
5384
|
${required}
|
|
5134
5385
|
${disabled ? "disabled" : ""}
|
|
5135
5386
|
>
|
|
5387
|
+
<p class="mt-1 text-xs text-zinc-500 dark:text-zinc-400">Format: YYYY-MM-DD</p>
|
|
5136
5388
|
`;
|
|
5137
5389
|
break;
|
|
5138
5390
|
case "datetime":
|
|
@@ -5148,6 +5400,7 @@ function renderDynamicField(field, options = {}) {
|
|
|
5148
5400
|
${required}
|
|
5149
5401
|
${disabled ? "disabled" : ""}
|
|
5150
5402
|
>
|
|
5403
|
+
<p class="mt-1 text-xs text-zinc-500 dark:text-zinc-400">Format: YYYY-MM-DD HH:MM</p>
|
|
5151
5404
|
`;
|
|
5152
5405
|
break;
|
|
5153
5406
|
case "slug":
|
|
@@ -7085,7 +7338,7 @@ api.put("/:userId", async (c) => {
|
|
|
7085
7338
|
await saveCustomData(db, userId, sanitized);
|
|
7086
7339
|
return c.json({ success: true });
|
|
7087
7340
|
});
|
|
7088
|
-
var userProfilesPlugin =
|
|
7341
|
+
var userProfilesPlugin = chunkKWQNB6UM_cjs.definePlugin({
|
|
7089
7342
|
id: "user-profiles",
|
|
7090
7343
|
version: "1.0.0",
|
|
7091
7344
|
name: "User Profiles",
|
|
@@ -7102,8 +7355,32 @@ function createUserProfilesPlugin() {
|
|
|
7102
7355
|
return userProfilesPlugin;
|
|
7103
7356
|
}
|
|
7104
7357
|
|
|
7358
|
+
// src/services/demo-mode.ts
|
|
7359
|
+
var _demoModeActive = false;
|
|
7360
|
+
function setDemoModeActive() {
|
|
7361
|
+
_demoModeActive = true;
|
|
7362
|
+
}
|
|
7363
|
+
function isDemoModeActive() {
|
|
7364
|
+
return _demoModeActive;
|
|
7365
|
+
}
|
|
7366
|
+
|
|
7105
7367
|
// src/routes/auth.ts
|
|
7106
7368
|
var JWT_SECRET_FALLBACK = "your-super-secret-jwt-key-change-in-production";
|
|
7369
|
+
var DEMO_EMAIL = "admin@sonicjs.com";
|
|
7370
|
+
var STATS_EVENTS_ENDPOINT = "https://stats.sonicjs.com/v1/events";
|
|
7371
|
+
async function trackDemoLogin(kv) {
|
|
7372
|
+
try {
|
|
7373
|
+
const installationId = await kv?.get("_sonicjs_installation_id") ?? "demo-unknown";
|
|
7374
|
+
await fetch(STATS_EVENTS_ENDPOINT, {
|
|
7375
|
+
method: "POST",
|
|
7376
|
+
headers: { "Content-Type": "application/json" },
|
|
7377
|
+
body: JSON.stringify({
|
|
7378
|
+
data: { installation_id: installationId, event_type: "demo_login", properties: {}, timestamp: (/* @__PURE__ */ new Date()).toISOString() }
|
|
7379
|
+
})
|
|
7380
|
+
});
|
|
7381
|
+
} catch {
|
|
7382
|
+
}
|
|
7383
|
+
}
|
|
7107
7384
|
function renderPasswordResetEmail(resetLink, firstName) {
|
|
7108
7385
|
const greeting = firstName ? `Hi ${firstName},` : "Hello,";
|
|
7109
7386
|
return `<!DOCTYPE html>
|
|
@@ -7123,8 +7400,8 @@ function renderPasswordResetEmail(resetLink, firstName) {
|
|
|
7123
7400
|
async function setCsrfCookie(c, maxAge) {
|
|
7124
7401
|
const secret = c.env?.JWT_SECRET || JWT_SECRET_FALLBACK;
|
|
7125
7402
|
const isDev = c.env?.ENVIRONMENT === "development" || !c.env?.ENVIRONMENT;
|
|
7126
|
-
const csrfToken = await
|
|
7127
|
-
const cookieMaxAge = await
|
|
7403
|
+
const csrfToken = await chunkBRKXMRMB_cjs.generateCsrfToken(secret);
|
|
7404
|
+
const cookieMaxAge = await chunkBRKXMRMB_cjs.getJwtExpirySecondsFromDb(c.env?.DB, c.env);
|
|
7128
7405
|
cookie.setCookie(c, "csrf_token", csrfToken, {
|
|
7129
7406
|
httpOnly: false,
|
|
7130
7407
|
secure: !isDev,
|
|
@@ -7153,13 +7430,7 @@ authRoutes.get("/login", async (c) => {
|
|
|
7153
7430
|
version: c.get("appVersion"),
|
|
7154
7431
|
redirect: redirect && redirect.startsWith("/") ? redirect : void 0
|
|
7155
7432
|
};
|
|
7156
|
-
const
|
|
7157
|
-
let demoLoginActive = false;
|
|
7158
|
-
try {
|
|
7159
|
-
const plugin = await db.prepare("SELECT * FROM plugins WHERE id = ? AND status = ?").bind("demo-login-prefill", "active").first();
|
|
7160
|
-
demoLoginActive = !!plugin;
|
|
7161
|
-
} catch (error2) {
|
|
7162
|
-
}
|
|
7433
|
+
const demoLoginActive = isDemoModeActive();
|
|
7163
7434
|
return c.html(renderLoginPage(pageData, demoLoginActive));
|
|
7164
7435
|
});
|
|
7165
7436
|
authRoutes.get("/register", async (c) => {
|
|
@@ -7183,7 +7454,7 @@ var loginSchema = zod.z.object({
|
|
|
7183
7454
|
});
|
|
7184
7455
|
authRoutes.post(
|
|
7185
7456
|
"/register",
|
|
7186
|
-
|
|
7457
|
+
chunkBRKXMRMB_cjs.rateLimit({ max: 30, windowMs: 60 * 1e3, keyPrefix: "register" }),
|
|
7187
7458
|
async (c) => {
|
|
7188
7459
|
try {
|
|
7189
7460
|
const db = c.env.DB;
|
|
@@ -7219,7 +7490,7 @@ authRoutes.post(
|
|
|
7219
7490
|
if (existingUser) {
|
|
7220
7491
|
return c.json({ error: "User with this email already exists" }, 400);
|
|
7221
7492
|
}
|
|
7222
|
-
const passwordHash = await
|
|
7493
|
+
const passwordHash = await chunkBRKXMRMB_cjs.AuthManager.hashPassword(password);
|
|
7223
7494
|
const userId = crypto.randomUUID();
|
|
7224
7495
|
const now = /* @__PURE__ */ new Date();
|
|
7225
7496
|
const nowSec = Math.floor(now.getTime() / 1e3);
|
|
@@ -7252,8 +7523,8 @@ authRoutes.post(
|
|
|
7252
7523
|
{ user: { id: userId, email: normalizedEmail, role: "viewer" } },
|
|
7253
7524
|
"fire-and-forget"
|
|
7254
7525
|
);
|
|
7255
|
-
const tokenTtl = await
|
|
7256
|
-
const token = await
|
|
7526
|
+
const tokenTtl = await chunkBRKXMRMB_cjs.getJwtExpirySecondsFromDb(c.env.DB, c.env);
|
|
7527
|
+
const token = await chunkBRKXMRMB_cjs.AuthManager.generateToken(userId, normalizedEmail, "viewer", c.env.JWT_SECRET, tokenTtl);
|
|
7257
7528
|
cookie.setCookie(c, "auth_token", token, {
|
|
7258
7529
|
httpOnly: true,
|
|
7259
7530
|
secure: true,
|
|
@@ -7285,7 +7556,7 @@ authRoutes.post(
|
|
|
7285
7556
|
);
|
|
7286
7557
|
authRoutes.post(
|
|
7287
7558
|
"/login",
|
|
7288
|
-
|
|
7559
|
+
chunkBRKXMRMB_cjs.rateLimit({ max: 30, windowMs: 60 * 1e3, keyPrefix: "login" }),
|
|
7289
7560
|
async (c) => {
|
|
7290
7561
|
try {
|
|
7291
7562
|
const body = await c.req.json();
|
|
@@ -7295,8 +7566,8 @@ authRoutes.post(
|
|
|
7295
7566
|
}
|
|
7296
7567
|
const { email, password } = validation.data;
|
|
7297
7568
|
const normalizedEmail = email.toLowerCase();
|
|
7298
|
-
const { createAuth } = await import('./config-
|
|
7299
|
-
const auth = createAuth(c.env);
|
|
7569
|
+
const { createAuth } = await import('./config-VLU73ZW7.cjs');
|
|
7570
|
+
const auth = createAuth(c.env, void 0, new URL(c.req.url).origin);
|
|
7300
7571
|
const baReq = new Request(new URL("/auth/sign-in/email", c.req.url).href, {
|
|
7301
7572
|
method: "POST",
|
|
7302
7573
|
headers: { "Content-Type": "application/json", "Origin": new URL(c.req.url).origin },
|
|
@@ -7306,19 +7577,21 @@ authRoutes.post(
|
|
|
7306
7577
|
if (!baRes.ok) {
|
|
7307
7578
|
return c.json({ error: "Invalid email or password" }, 401);
|
|
7308
7579
|
}
|
|
7309
|
-
|
|
7310
|
-
if (rawSetCookie) {
|
|
7311
|
-
c.res.headers.append("Set-Cookie", rawSetCookie);
|
|
7312
|
-
} else if (baRes.headers.getSetCookie) {
|
|
7580
|
+
if (baRes.headers.getSetCookie) {
|
|
7313
7581
|
for (const sc of baRes.headers.getSetCookie()) {
|
|
7314
|
-
c.
|
|
7582
|
+
c.header("Set-Cookie", sc, { append: true });
|
|
7583
|
+
}
|
|
7584
|
+
} else {
|
|
7585
|
+
const rawSetCookie = baRes.headers.get("set-cookie");
|
|
7586
|
+
if (rawSetCookie) {
|
|
7587
|
+
c.header("Set-Cookie", rawSetCookie, { append: true });
|
|
7315
7588
|
}
|
|
7316
7589
|
}
|
|
7317
7590
|
await setCsrfCookie(c);
|
|
7318
7591
|
const baBody = await baRes.json();
|
|
7319
7592
|
const user = baBody.user ?? {};
|
|
7320
|
-
const tokenTtl = await
|
|
7321
|
-
const token = await
|
|
7593
|
+
const tokenTtl = await chunkBRKXMRMB_cjs.getJwtExpirySecondsFromDb(c.env.DB, c.env);
|
|
7594
|
+
const token = await chunkBRKXMRMB_cjs.AuthManager.generateToken(
|
|
7322
7595
|
user.id,
|
|
7323
7596
|
user.email,
|
|
7324
7597
|
user.role ?? "viewer",
|
|
@@ -7331,6 +7604,9 @@ authRoutes.post(
|
|
|
7331
7604
|
sameSite: "Strict",
|
|
7332
7605
|
maxAge: tokenTtl
|
|
7333
7606
|
});
|
|
7607
|
+
if (normalizedEmail === DEMO_EMAIL) {
|
|
7608
|
+
c.executionCtx?.waitUntil(trackDemoLogin(c.env.CACHE_KV));
|
|
7609
|
+
}
|
|
7334
7610
|
return c.json({
|
|
7335
7611
|
user: {
|
|
7336
7612
|
id: user.id,
|
|
@@ -7349,8 +7625,8 @@ authRoutes.post(
|
|
|
7349
7625
|
);
|
|
7350
7626
|
authRoutes.post("/logout", async (c) => {
|
|
7351
7627
|
try {
|
|
7352
|
-
const { createAuth } = await import('./config-
|
|
7353
|
-
const auth = createAuth(c.env);
|
|
7628
|
+
const { createAuth } = await import('./config-VLU73ZW7.cjs');
|
|
7629
|
+
const auth = createAuth(c.env, void 0, new URL(c.req.url).origin);
|
|
7354
7630
|
const baReq = new Request(new URL("/auth/sign-out", c.req.url).href, {
|
|
7355
7631
|
method: "POST",
|
|
7356
7632
|
headers: { "Content-Type": "application/json", "Origin": new URL(c.req.url).origin, "Cookie": c.req.header("Cookie") || "" },
|
|
@@ -7359,14 +7635,15 @@ authRoutes.post("/logout", async (c) => {
|
|
|
7359
7635
|
await auth.handler(baReq);
|
|
7360
7636
|
} catch {
|
|
7361
7637
|
}
|
|
7362
|
-
|
|
7638
|
+
const isSecure = new URL(c.req.url).protocol === "https:";
|
|
7639
|
+
cookie.setCookie(c, "better-auth.session_token", "", { httpOnly: true, sameSite: "Lax", path: "/", maxAge: 0, secure: isSecure });
|
|
7363
7640
|
clearCsrfCookie(c);
|
|
7364
7641
|
return c.json({ message: "Logged out successfully" });
|
|
7365
7642
|
});
|
|
7366
7643
|
authRoutes.get("/logout", async (c) => {
|
|
7367
7644
|
try {
|
|
7368
|
-
const { createAuth } = await import('./config-
|
|
7369
|
-
const auth = createAuth(c.env);
|
|
7645
|
+
const { createAuth } = await import('./config-VLU73ZW7.cjs');
|
|
7646
|
+
const auth = createAuth(c.env, void 0, new URL(c.req.url).origin);
|
|
7370
7647
|
const baReq = new Request(new URL("/auth/sign-out", c.req.url).href, {
|
|
7371
7648
|
method: "POST",
|
|
7372
7649
|
headers: { "Content-Type": "application/json", "Origin": new URL(c.req.url).origin, "Cookie": c.req.header("Cookie") || "" },
|
|
@@ -7375,11 +7652,12 @@ authRoutes.get("/logout", async (c) => {
|
|
|
7375
7652
|
await auth.handler(baReq);
|
|
7376
7653
|
} catch {
|
|
7377
7654
|
}
|
|
7378
|
-
|
|
7655
|
+
const isSecure = new URL(c.req.url).protocol === "https:";
|
|
7656
|
+
cookie.setCookie(c, "better-auth.session_token", "", { httpOnly: true, sameSite: "Lax", path: "/", maxAge: 0, secure: isSecure });
|
|
7379
7657
|
clearCsrfCookie(c);
|
|
7380
7658
|
return c.redirect("/auth/login?message=You have been logged out successfully");
|
|
7381
7659
|
});
|
|
7382
|
-
authRoutes.get("/me",
|
|
7660
|
+
authRoutes.get("/me", chunkBRKXMRMB_cjs.requireAuth(), async (c) => {
|
|
7383
7661
|
try {
|
|
7384
7662
|
const user = c.get("user");
|
|
7385
7663
|
if (!user) {
|
|
@@ -7399,7 +7677,7 @@ authRoutes.get("/me", chunk37V3RET3_cjs.requireAuth(), async (c) => {
|
|
|
7399
7677
|
});
|
|
7400
7678
|
authRoutes.post(
|
|
7401
7679
|
"/refresh",
|
|
7402
|
-
|
|
7680
|
+
chunkBRKXMRMB_cjs.rateLimit({ max: 60, windowMs: 60 * 1e3, keyPrefix: "refresh" }),
|
|
7403
7681
|
async (c) => {
|
|
7404
7682
|
try {
|
|
7405
7683
|
let token = c.req.header("Authorization")?.replace("Bearer ", "");
|
|
@@ -7408,8 +7686,8 @@ authRoutes.post(
|
|
|
7408
7686
|
return c.json({ error: "Authentication required" }, 401);
|
|
7409
7687
|
}
|
|
7410
7688
|
const db = c.env.DB;
|
|
7411
|
-
const grace = await
|
|
7412
|
-
const payload = await
|
|
7689
|
+
const grace = await chunkBRKXMRMB_cjs.getJwtRefreshGraceSecondsFromDb(db, c.env);
|
|
7690
|
+
const payload = await chunkBRKXMRMB_cjs.AuthManager.verifyToken(token, c.env.JWT_SECRET, grace);
|
|
7413
7691
|
if (!payload) {
|
|
7414
7692
|
return c.json({ error: "Invalid or expired token" }, 401);
|
|
7415
7693
|
}
|
|
@@ -7417,8 +7695,8 @@ authRoutes.post(
|
|
|
7417
7695
|
if (!row || !row.is_active) {
|
|
7418
7696
|
return c.json({ error: "User is not active" }, 401);
|
|
7419
7697
|
}
|
|
7420
|
-
const tokenTtl = await
|
|
7421
|
-
const newToken = await
|
|
7698
|
+
const tokenTtl = await chunkBRKXMRMB_cjs.getJwtExpirySecondsFromDb(db, c.env);
|
|
7699
|
+
const newToken = await chunkBRKXMRMB_cjs.AuthManager.generateToken(row.id, row.email, row.role, c.env.JWT_SECRET, tokenTtl);
|
|
7422
7700
|
cookie.setCookie(c, "auth_token", newToken, {
|
|
7423
7701
|
httpOnly: true,
|
|
7424
7702
|
secure: true,
|
|
@@ -7438,7 +7716,7 @@ authRoutes.post(
|
|
|
7438
7716
|
);
|
|
7439
7717
|
authRoutes.post(
|
|
7440
7718
|
"/register/form",
|
|
7441
|
-
|
|
7719
|
+
chunkBRKXMRMB_cjs.rateLimit({ max: 30, windowMs: 60 * 1e3, keyPrefix: "register" }),
|
|
7442
7720
|
async (c) => {
|
|
7443
7721
|
try {
|
|
7444
7722
|
const db = c.env.DB;
|
|
@@ -7483,7 +7761,7 @@ authRoutes.post(
|
|
|
7483
7761
|
</div>
|
|
7484
7762
|
`);
|
|
7485
7763
|
}
|
|
7486
|
-
const passwordHash = await
|
|
7764
|
+
const passwordHash = await chunkBRKXMRMB_cjs.AuthManager.hashPassword(password);
|
|
7487
7765
|
const role = isFirstUser ? "admin" : "viewer";
|
|
7488
7766
|
const userId = crypto.randomUUID();
|
|
7489
7767
|
const now = /* @__PURE__ */ new Date();
|
|
@@ -7517,7 +7795,7 @@ authRoutes.post(
|
|
|
7517
7795
|
await saveCustomData(db, userId, sanitized);
|
|
7518
7796
|
}
|
|
7519
7797
|
}
|
|
7520
|
-
const rbacService = new
|
|
7798
|
+
const rbacService = new chunkOLEOKHDX_cjs.RbacService(db);
|
|
7521
7799
|
await rbacService.addUserRoleByName(userId, role);
|
|
7522
7800
|
dispatchHookEvent(
|
|
7523
7801
|
c,
|
|
@@ -7525,8 +7803,8 @@ authRoutes.post(
|
|
|
7525
7803
|
{ user: { id: userId, email: normalizedEmail, role } },
|
|
7526
7804
|
"fire-and-forget"
|
|
7527
7805
|
);
|
|
7528
|
-
const tokenTtl = await
|
|
7529
|
-
const token = await
|
|
7806
|
+
const tokenTtl = await chunkBRKXMRMB_cjs.getJwtExpirySecondsFromDb(c.env.DB, c.env);
|
|
7807
|
+
const token = await chunkBRKXMRMB_cjs.AuthManager.generateToken(userId, normalizedEmail, role, c.env.JWT_SECRET, tokenTtl);
|
|
7530
7808
|
cookie.setCookie(c, "auth_token", token, {
|
|
7531
7809
|
httpOnly: true,
|
|
7532
7810
|
secure: false,
|
|
@@ -7558,7 +7836,7 @@ authRoutes.post(
|
|
|
7558
7836
|
);
|
|
7559
7837
|
authRoutes.post(
|
|
7560
7838
|
"/login/form",
|
|
7561
|
-
|
|
7839
|
+
chunkBRKXMRMB_cjs.rateLimit({ max: 30, windowMs: 60 * 1e3, keyPrefix: "login" }),
|
|
7562
7840
|
async (c) => {
|
|
7563
7841
|
try {
|
|
7564
7842
|
const formData = await c.req.formData();
|
|
@@ -7572,8 +7850,8 @@ authRoutes.post(
|
|
|
7572
7850
|
</div>
|
|
7573
7851
|
`);
|
|
7574
7852
|
}
|
|
7575
|
-
const { createAuth } = await import('./config-
|
|
7576
|
-
const auth = createAuth(c.env);
|
|
7853
|
+
const { createAuth } = await import('./config-VLU73ZW7.cjs');
|
|
7854
|
+
const auth = createAuth(c.env, void 0, new URL(c.req.url).origin);
|
|
7577
7855
|
const baReq = new Request(new URL("/auth/sign-in/email", c.req.url).href, {
|
|
7578
7856
|
method: "POST",
|
|
7579
7857
|
headers: { "Content-Type": "application/json", "Origin": new URL(c.req.url).origin },
|
|
@@ -7587,17 +7865,27 @@ authRoutes.post(
|
|
|
7587
7865
|
</div>
|
|
7588
7866
|
`);
|
|
7589
7867
|
}
|
|
7590
|
-
|
|
7591
|
-
if (rawSetCookie) {
|
|
7592
|
-
c.res.headers.append("Set-Cookie", rawSetCookie);
|
|
7593
|
-
} else if (baRes.headers.getSetCookie) {
|
|
7868
|
+
if (baRes.headers.getSetCookie) {
|
|
7594
7869
|
for (const sc of baRes.headers.getSetCookie()) {
|
|
7595
|
-
c.
|
|
7870
|
+
c.header("Set-Cookie", sc, { append: true });
|
|
7871
|
+
}
|
|
7872
|
+
} else {
|
|
7873
|
+
const rawSetCookie = baRes.headers.get("set-cookie");
|
|
7874
|
+
if (rawSetCookie) {
|
|
7875
|
+
c.header("Set-Cookie", rawSetCookie, { append: true });
|
|
7596
7876
|
}
|
|
7597
7877
|
}
|
|
7598
7878
|
await setCsrfCookie(c);
|
|
7879
|
+
if (email === DEMO_EMAIL) {
|
|
7880
|
+
c.executionCtx?.waitUntil(trackDemoLogin(c.env.CACHE_KV));
|
|
7881
|
+
}
|
|
7599
7882
|
const rawRedirect = c.req.query("redirect");
|
|
7600
7883
|
const redirectUrl = rawRedirect && rawRedirect.startsWith("/") ? rawRedirect : "/admin/content";
|
|
7884
|
+
const isHtmx = c.req.header("HX-Request") === "true";
|
|
7885
|
+
if (isHtmx) {
|
|
7886
|
+
c.header("HX-Redirect", redirectUrl);
|
|
7887
|
+
return c.html(html.html`<div id="form-response"><p class="text-sm text-green-600">Login successful! Redirecting...</p></div>`);
|
|
7888
|
+
}
|
|
7601
7889
|
return c.html(html.html`
|
|
7602
7890
|
<div id="form-response">
|
|
7603
7891
|
<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 +7915,14 @@ authRoutes.post(
|
|
|
7627
7915
|
);
|
|
7628
7916
|
authRoutes.post(
|
|
7629
7917
|
"/seed-admin",
|
|
7630
|
-
|
|
7918
|
+
chunkBRKXMRMB_cjs.rateLimit({ max: 10, windowMs: 60 * 1e3, keyPrefix: "seed-admin" }),
|
|
7631
7919
|
async (c) => {
|
|
7632
7920
|
try {
|
|
7633
7921
|
const db = c.env.DB;
|
|
7634
|
-
const rbac = new
|
|
7922
|
+
const rbac = new chunkOLEOKHDX_cjs.RbacService(db);
|
|
7635
7923
|
const results = [];
|
|
7636
7924
|
const upsertSeedUser = async (opts) => {
|
|
7637
|
-
const passwordHash = await
|
|
7925
|
+
const passwordHash = await chunkBRKXMRMB_cjs.AuthManager.hashPassword(opts.password);
|
|
7638
7926
|
const nowMs = Date.now();
|
|
7639
7927
|
const nowSec = Math.floor(nowMs / 1e3);
|
|
7640
7928
|
const existing = await db.prepare("SELECT id FROM auth_user WHERE email = ?").bind(opts.email).first();
|
|
@@ -7859,7 +8147,7 @@ authRoutes.post("/accept-invitation", async (c) => {
|
|
|
7859
8147
|
if (invitationAge > maxAge) {
|
|
7860
8148
|
return c.json({ error: "Invitation has expired" }, 400);
|
|
7861
8149
|
}
|
|
7862
|
-
const passwordHash = await
|
|
8150
|
+
const passwordHash = await chunkBRKXMRMB_cjs.AuthManager.hashPassword(password);
|
|
7863
8151
|
const updateStmt = db.prepare(`
|
|
7864
8152
|
UPDATE auth_user SET
|
|
7865
8153
|
password_hash = ?,
|
|
@@ -7876,8 +8164,8 @@ authRoutes.post("/accept-invitation", async (c) => {
|
|
|
7876
8164
|
Date.now(),
|
|
7877
8165
|
invitedUser.id
|
|
7878
8166
|
).run();
|
|
7879
|
-
const tokenTtl = await
|
|
7880
|
-
const authToken = await
|
|
8167
|
+
const tokenTtl = await chunkBRKXMRMB_cjs.getJwtExpirySecondsFromDb(c.env.DB, c.env);
|
|
8168
|
+
const authToken = await chunkBRKXMRMB_cjs.AuthManager.generateToken(invitedUser.id, invitedUser.email, invitedUser.role, c.env.JWT_SECRET, tokenTtl);
|
|
7881
8169
|
cookie.setCookie(c, "auth_token", authToken, {
|
|
7882
8170
|
httpOnly: true,
|
|
7883
8171
|
secure: true,
|
|
@@ -7893,7 +8181,7 @@ authRoutes.post("/accept-invitation", async (c) => {
|
|
|
7893
8181
|
});
|
|
7894
8182
|
authRoutes.post(
|
|
7895
8183
|
"/request-password-reset",
|
|
7896
|
-
|
|
8184
|
+
chunkBRKXMRMB_cjs.rateLimit({ max: 3, windowMs: 15 * 60 * 1e3, keyPrefix: "password-reset" }),
|
|
7897
8185
|
async (c) => {
|
|
7898
8186
|
try {
|
|
7899
8187
|
const formData = await c.req.formData();
|
|
@@ -8130,7 +8418,7 @@ authRoutes.post("/reset-password", async (c) => {
|
|
|
8130
8418
|
if (Date.now() > user.password_reset_expires) {
|
|
8131
8419
|
return c.json({ error: "Reset token has expired" }, 400);
|
|
8132
8420
|
}
|
|
8133
|
-
const newPasswordHash = await
|
|
8421
|
+
const newPasswordHash = await chunkBRKXMRMB_cjs.AuthManager.hashPassword(password);
|
|
8134
8422
|
try {
|
|
8135
8423
|
const historyStmt = db.prepare(`
|
|
8136
8424
|
INSERT INTO auth_password_history (id, user_id, password_hash, created_at)
|
|
@@ -8344,7 +8632,7 @@ app.post("/test-seed-defaults", async (c) => {
|
|
|
8344
8632
|
var test_cleanup_default = app;
|
|
8345
8633
|
|
|
8346
8634
|
// src/plugins/available/easy-mdx/index.ts
|
|
8347
|
-
|
|
8635
|
+
chunkKWQNB6UM_cjs.definePlugin({
|
|
8348
8636
|
id: "easy-mdx",
|
|
8349
8637
|
version: "1.0.0",
|
|
8350
8638
|
name: "EasyMDE Markdown Editor",
|
|
@@ -8544,7 +8832,7 @@ function getMDXEditorInitScript(config) {
|
|
|
8544
8832
|
}
|
|
8545
8833
|
|
|
8546
8834
|
// src/plugins/available/tinymce-plugin/index.ts
|
|
8547
|
-
|
|
8835
|
+
chunkKWQNB6UM_cjs.definePlugin({
|
|
8548
8836
|
id: "tinymce-plugin",
|
|
8549
8837
|
version: "1.0.0",
|
|
8550
8838
|
name: "TinyMCE",
|
|
@@ -8814,7 +9102,7 @@ function getQuillCDN(version = "2.0.2") {
|
|
|
8814
9102
|
</style>
|
|
8815
9103
|
`;
|
|
8816
9104
|
}
|
|
8817
|
-
|
|
9105
|
+
chunkKWQNB6UM_cjs.definePlugin({
|
|
8818
9106
|
id: "quill-editor",
|
|
8819
9107
|
version: "1.0.0",
|
|
8820
9108
|
name: "Quill Editor",
|
|
@@ -8826,7 +9114,7 @@ chunkBP52BFIV_cjs.definePlugin({
|
|
|
8826
9114
|
});
|
|
8827
9115
|
|
|
8828
9116
|
// src/templates/pages/admin-content-form.template.ts
|
|
8829
|
-
|
|
9117
|
+
chunkMI2YXCK4_cjs.init_admin_layout_catalyst_template();
|
|
8830
9118
|
function renderContentFormPage(data, opts) {
|
|
8831
9119
|
const isEdit = data.isEdit || !!data.id;
|
|
8832
9120
|
const title = isEdit ? `Edit: ${data.title || "Content"}` : `New ${data.collection.display_name}`;
|
|
@@ -8908,8 +9196,8 @@ function renderContentFormPage(data, opts) {
|
|
|
8908
9196
|
<!-- Form Content -->
|
|
8909
9197
|
<div class="px-6 py-6">
|
|
8910
9198
|
<div id="form-messages">
|
|
8911
|
-
${data.error ?
|
|
8912
|
-
${data.success ?
|
|
9199
|
+
${data.error ? chunkOUBUS74I_cjs.renderAlert({ type: "error", message: data.error, dismissible: true }) : ""}
|
|
9200
|
+
${data.success ? chunkOUBUS74I_cjs.renderAlert({ type: "success", message: data.success, dismissible: true }) : ""}
|
|
8913
9201
|
</div>
|
|
8914
9202
|
|
|
8915
9203
|
<div class="grid grid-cols-1 lg:grid-cols-3 gap-6">
|
|
@@ -9109,33 +9397,44 @@ function renderContentFormPage(data, opts) {
|
|
|
9109
9397
|
</a>
|
|
9110
9398
|
|
|
9111
9399
|
<div class="flex items-center gap-x-3">
|
|
9112
|
-
|
|
9113
|
-
|
|
9114
|
-
|
|
9115
|
-
|
|
9116
|
-
|
|
9117
|
-
|
|
9118
|
-
|
|
9119
|
-
>
|
|
9120
|
-
<
|
|
9121
|
-
|
|
9122
|
-
|
|
9123
|
-
|
|
9124
|
-
|
|
9125
|
-
|
|
9400
|
+
<button
|
|
9401
|
+
type="submit"
|
|
9402
|
+
form="content-form"
|
|
9403
|
+
name="action"
|
|
9404
|
+
value="save"
|
|
9405
|
+
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"
|
|
9406
|
+
>
|
|
9407
|
+
<svg class="h-5 w-5" fill="none" stroke="currentColor" viewBox="0 0 24 24" stroke-width="1.5">
|
|
9408
|
+
<path stroke-linecap="round" stroke-linejoin="round" d="M5 13l4 4L19 7"/>
|
|
9409
|
+
</svg>
|
|
9410
|
+
Save
|
|
9411
|
+
</button>
|
|
9412
|
+
|
|
9413
|
+
<button
|
|
9414
|
+
type="submit"
|
|
9415
|
+
form="content-form"
|
|
9416
|
+
name="action"
|
|
9417
|
+
value="save_and_close"
|
|
9418
|
+
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"
|
|
9419
|
+
>
|
|
9420
|
+
<svg class="h-5 w-5" fill="none" stroke="currentColor" viewBox="0 0 24 24" stroke-width="1.5">
|
|
9421
|
+
<path stroke-linecap="round" stroke-linejoin="round" d="M6 18L18 6M6 6l12 12"/>
|
|
9422
|
+
</svg>
|
|
9423
|
+
Save & close
|
|
9424
|
+
</button>
|
|
9126
9425
|
|
|
9127
|
-
${data.user?.role !== "viewer" ? `
|
|
9426
|
+
${data.user?.role !== "viewer" && data.versioningEnabled ? `
|
|
9128
9427
|
<button
|
|
9129
9428
|
type="submit"
|
|
9130
9429
|
form="content-form"
|
|
9131
9430
|
name="action"
|
|
9132
9431
|
value="save_and_publish"
|
|
9133
|
-
class="inline-flex items-center justify-center gap-x-1.5 rounded-lg
|
|
9432
|
+
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
9433
|
>
|
|
9135
9434
|
<svg class="h-5 w-5" fill="none" stroke="currentColor" viewBox="0 0 24 24" stroke-width="1.5">
|
|
9136
9435
|
<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
9436
|
</svg>
|
|
9138
|
-
|
|
9437
|
+
Publish
|
|
9139
9438
|
</button>
|
|
9140
9439
|
` : ""}
|
|
9141
9440
|
</div>
|
|
@@ -9145,7 +9444,7 @@ function renderContentFormPage(data, opts) {
|
|
|
9145
9444
|
</div>
|
|
9146
9445
|
|
|
9147
9446
|
<!-- Confirmation Dialogs -->
|
|
9148
|
-
${
|
|
9447
|
+
${chunkOUBUS74I_cjs.renderConfirmationDialog({
|
|
9149
9448
|
id: "duplicate-content-confirm",
|
|
9150
9449
|
title: "Duplicate Content",
|
|
9151
9450
|
message: "Create a copy of this content?",
|
|
@@ -9156,7 +9455,7 @@ function renderContentFormPage(data, opts) {
|
|
|
9156
9455
|
onConfirm: "performDuplicateContent()"
|
|
9157
9456
|
})}
|
|
9158
9457
|
|
|
9159
|
-
${
|
|
9458
|
+
${chunkOUBUS74I_cjs.renderConfirmationDialog({
|
|
9160
9459
|
id: "delete-content-confirm",
|
|
9161
9460
|
title: "Delete Content",
|
|
9162
9461
|
message: "Are you sure you want to delete this content? This action cannot be undone.",
|
|
@@ -9167,7 +9466,7 @@ function renderContentFormPage(data, opts) {
|
|
|
9167
9466
|
onConfirm: `performDeleteContent('${data.id}')`
|
|
9168
9467
|
})}
|
|
9169
9468
|
|
|
9170
|
-
${
|
|
9469
|
+
${chunkOUBUS74I_cjs.renderConfirmationDialog({
|
|
9171
9470
|
id: "delete-repeater-item-confirm",
|
|
9172
9471
|
title: "Delete Item",
|
|
9173
9472
|
message: "Are you sure you want to delete this item? This action cannot be undone.",
|
|
@@ -9178,7 +9477,7 @@ function renderContentFormPage(data, opts) {
|
|
|
9178
9477
|
onConfirm: "performRepeaterDelete()"
|
|
9179
9478
|
})}
|
|
9180
9479
|
|
|
9181
|
-
${
|
|
9480
|
+
${chunkOUBUS74I_cjs.renderConfirmationDialog({
|
|
9182
9481
|
id: "delete-block-confirm",
|
|
9183
9482
|
title: "Delete Block",
|
|
9184
9483
|
message: "Are you sure you want to delete this block? This action cannot be undone.",
|
|
@@ -9189,7 +9488,7 @@ function renderContentFormPage(data, opts) {
|
|
|
9189
9488
|
onConfirm: "performRepeaterDelete()"
|
|
9190
9489
|
})}
|
|
9191
9490
|
|
|
9192
|
-
${
|
|
9491
|
+
${chunkOUBUS74I_cjs.getConfirmationDialogScript()}
|
|
9193
9492
|
|
|
9194
9493
|
${data.lexicalEnabled ? getLexicalStyles() : "<!-- Lexical plugin not active -->"}
|
|
9195
9494
|
|
|
@@ -10275,11 +10574,11 @@ function renderContentFormPage(data, opts) {
|
|
|
10275
10574
|
content: pageContent,
|
|
10276
10575
|
version: data.version
|
|
10277
10576
|
};
|
|
10278
|
-
return
|
|
10577
|
+
return chunkMI2YXCK4_cjs.renderAdminLayoutCatalyst(layoutData);
|
|
10279
10578
|
}
|
|
10280
10579
|
|
|
10281
10580
|
// src/templates/pages/admin-content-list.template.ts
|
|
10282
|
-
|
|
10581
|
+
chunkMI2YXCK4_cjs.init_admin_layout_catalyst_template();
|
|
10283
10582
|
function renderContentListPage(data) {
|
|
10284
10583
|
const urlParams = new URLSearchParams();
|
|
10285
10584
|
if (data.modelName && data.modelName !== "all") urlParams.set("model", data.modelName);
|
|
@@ -10713,8 +11012,8 @@ function renderContentListPage(data) {
|
|
|
10713
11012
|
|
|
10714
11013
|
<!-- Content List -->
|
|
10715
11014
|
<div id="content-list">
|
|
10716
|
-
${
|
|
10717
|
-
${
|
|
11015
|
+
${chunkOUBUS74I_cjs.renderTable(tableData)}
|
|
11016
|
+
${chunkOUBUS74I_cjs.renderPagination(paginationData)}
|
|
10718
11017
|
</div>
|
|
10719
11018
|
|
|
10720
11019
|
</div>
|
|
@@ -10924,7 +11223,7 @@ function renderContentListPage(data) {
|
|
|
10924
11223
|
</script>
|
|
10925
11224
|
|
|
10926
11225
|
<!-- Confirmation Dialog for Bulk Actions -->
|
|
10927
|
-
${
|
|
11226
|
+
${chunkOUBUS74I_cjs.renderConfirmationDialog({
|
|
10928
11227
|
id: "bulk-action-confirm",
|
|
10929
11228
|
title: "Confirm Bulk Action",
|
|
10930
11229
|
message: "Are you sure you want to perform this action? This operation will affect multiple items.",
|
|
@@ -10936,7 +11235,7 @@ function renderContentListPage(data) {
|
|
|
10936
11235
|
})}
|
|
10937
11236
|
|
|
10938
11237
|
<!-- Confirmation Dialog Script -->
|
|
10939
|
-
${
|
|
11238
|
+
${chunkOUBUS74I_cjs.getConfirmationDialogScript()}
|
|
10940
11239
|
|
|
10941
11240
|
<!-- Advanced Search Modal -->
|
|
10942
11241
|
<div id="advancedSearchModal" class="hidden fixed inset-0 z-50 overflow-y-auto" aria-labelledby="modal-title" role="dialog" aria-modal="true">
|
|
@@ -11233,7 +11532,7 @@ function renderContentListPage(data) {
|
|
|
11233
11532
|
version: data.version,
|
|
11234
11533
|
content: pageContent
|
|
11235
11534
|
};
|
|
11236
|
-
return
|
|
11535
|
+
return chunkMI2YXCK4_cjs.renderAdminLayoutCatalyst(layoutData);
|
|
11237
11536
|
}
|
|
11238
11537
|
|
|
11239
11538
|
// src/routes/admin-content-field-types.ts
|
|
@@ -11276,9 +11575,9 @@ function parseFieldValue(field, formData, options = {}) {
|
|
|
11276
11575
|
const { skipValidation = false } = options;
|
|
11277
11576
|
const value = formData.get(field.field_name);
|
|
11278
11577
|
const errors = [];
|
|
11279
|
-
const blocksConfig =
|
|
11578
|
+
const blocksConfig = chunkSFGYZUWU_cjs.getBlocksFieldConfig(field.field_options);
|
|
11280
11579
|
if (blocksConfig) {
|
|
11281
|
-
const parsed =
|
|
11580
|
+
const parsed = chunkSFGYZUWU_cjs.parseBlocksValue(value, blocksConfig);
|
|
11282
11581
|
if (!skipValidation && field.is_required && parsed.value.length === 0) {
|
|
11283
11582
|
parsed.errors.push(`${field.field_label} is required`);
|
|
11284
11583
|
}
|
|
@@ -11388,7 +11687,7 @@ function extractFieldData(fields, formData, options = {}) {
|
|
|
11388
11687
|
}
|
|
11389
11688
|
return { data, errors };
|
|
11390
11689
|
}
|
|
11391
|
-
adminContentRoutes.use("*",
|
|
11690
|
+
adminContentRoutes.use("*", chunkBRKXMRMB_cjs.requireAuth());
|
|
11392
11691
|
async function getCollectionFields(db, collectionId) {
|
|
11393
11692
|
console.log(`[getCollectionFields] Loading fields for collection: ${collectionId}`);
|
|
11394
11693
|
const collectionStmt = db.prepare("SELECT schema, queryable_fields FROM document_types WHERE id = ?");
|
|
@@ -11415,7 +11714,7 @@ async function getCollectionFields(db, collectionId) {
|
|
|
11415
11714
|
};
|
|
11416
11715
|
});
|
|
11417
11716
|
}
|
|
11418
|
-
const codeCollections2 = await
|
|
11717
|
+
const codeCollections2 = await chunk4DHPR7KR_cjs.loadCollectionConfigs();
|
|
11419
11718
|
const codeMatch = codeCollections2.find((c) => c.name === collectionId);
|
|
11420
11719
|
if (codeMatch && codeMatch.schema?.properties) {
|
|
11421
11720
|
console.log(`[getCollectionFields] DB doc type has no properties \u2014 using code collection schema`);
|
|
@@ -11447,7 +11746,7 @@ async function getCollectionFields(db, collectionId) {
|
|
|
11447
11746
|
}
|
|
11448
11747
|
}
|
|
11449
11748
|
console.log(`[getCollectionFields] Not in database, checking code collections`);
|
|
11450
|
-
const codeCollections = await
|
|
11749
|
+
const codeCollections = await chunk4DHPR7KR_cjs.loadCollectionConfigs();
|
|
11451
11750
|
console.log(`[getCollectionFields] Found ${codeCollections.length} code collections`);
|
|
11452
11751
|
const codeCollection = codeCollections.find((c) => c.name === collectionId);
|
|
11453
11752
|
if (codeCollection && codeCollection.schema) {
|
|
@@ -11483,7 +11782,7 @@ async function getCollectionFields(db, collectionId) {
|
|
|
11483
11782
|
}
|
|
11484
11783
|
async function getCollection(db, collectionId) {
|
|
11485
11784
|
console.log(`[getCollection] Loading collection by ID: ${collectionId}`);
|
|
11486
|
-
const cache =
|
|
11785
|
+
const cache = chunkC5LDQ3SH_cjs.getCacheService(chunkC5LDQ3SH_cjs.CACHE_CONFIGS.collection);
|
|
11487
11786
|
return cache.getOrSet(
|
|
11488
11787
|
cache.generateKey("collection", collectionId),
|
|
11489
11788
|
async () => {
|
|
@@ -11501,7 +11800,7 @@ async function getCollection(db, collectionId) {
|
|
|
11501
11800
|
};
|
|
11502
11801
|
}
|
|
11503
11802
|
console.log(`[getCollection] Not in database, checking code collections`);
|
|
11504
|
-
const codeCollections = await
|
|
11803
|
+
const codeCollections = await chunk4DHPR7KR_cjs.loadCollectionConfigs();
|
|
11505
11804
|
const codeCollection = codeCollections.find((c) => c.name === collectionId);
|
|
11506
11805
|
if (codeCollection) {
|
|
11507
11806
|
console.log(`[getCollection] Found code collection: ${collectionId}`);
|
|
@@ -11520,7 +11819,7 @@ async function getCollection(db, collectionId) {
|
|
|
11520
11819
|
}
|
|
11521
11820
|
async function getDocBackingType(db, collectionName) {
|
|
11522
11821
|
if (!collectionName) return null;
|
|
11523
|
-
const dt = await new
|
|
11822
|
+
const dt = await new chunkBRKXMRMB_cjs.DocumentTypeRegistry(db).findById(collectionName);
|
|
11524
11823
|
return dt && dt.isActive ? dt : null;
|
|
11525
11824
|
}
|
|
11526
11825
|
async function getCollectionByName(db, name) {
|
|
@@ -11537,7 +11836,7 @@ async function getCollectionByName(db, name) {
|
|
|
11537
11836
|
};
|
|
11538
11837
|
}
|
|
11539
11838
|
console.log(`[getCollectionByName] Not in database, checking code collections`);
|
|
11540
|
-
const codeCollections = await
|
|
11839
|
+
const codeCollections = await chunk4DHPR7KR_cjs.loadCollectionConfigs();
|
|
11541
11840
|
const codeCollection = codeCollections.find((c) => c.name === name);
|
|
11542
11841
|
if (codeCollection) {
|
|
11543
11842
|
console.log(`[getCollectionByName] Found code collection: ${name}`);
|
|
@@ -11553,7 +11852,7 @@ async function getCollectionByName(db, name) {
|
|
|
11553
11852
|
return null;
|
|
11554
11853
|
}
|
|
11555
11854
|
async function loadContentEditorFlags(db) {
|
|
11556
|
-
const flags = { workflowEnabled: await
|
|
11855
|
+
const flags = { workflowEnabled: await chunk4DHPR7KR_cjs.isPluginActive(db, "workflow") };
|
|
11557
11856
|
const editors = [
|
|
11558
11857
|
["tinymce-plugin", "tinymce"],
|
|
11559
11858
|
["quill-editor", "quill"],
|
|
@@ -11561,10 +11860,10 @@ async function loadContentEditorFlags(db) {
|
|
|
11561
11860
|
["lexical-editor", "lexical"]
|
|
11562
11861
|
];
|
|
11563
11862
|
for (const [plugin, key] of editors) {
|
|
11564
|
-
const enabled = await
|
|
11863
|
+
const enabled = await chunk4DHPR7KR_cjs.isPluginActive(db, plugin);
|
|
11565
11864
|
flags[`${key}Enabled`] = enabled;
|
|
11566
11865
|
if (enabled) {
|
|
11567
|
-
const ps = new
|
|
11866
|
+
const ps = new chunk4DHPR7KR_cjs.PluginService(db);
|
|
11568
11867
|
const p = await ps.getPlugin(plugin);
|
|
11569
11868
|
flags[`${key}Settings`] = p?.settings;
|
|
11570
11869
|
}
|
|
@@ -11572,7 +11871,7 @@ async function loadContentEditorFlags(db) {
|
|
|
11572
11871
|
return flags;
|
|
11573
11872
|
}
|
|
11574
11873
|
function makeDocService(db, docType, tenantId) {
|
|
11575
|
-
return new
|
|
11874
|
+
return new chunkOLEOKHDX_cjs.DocumentsService(db, {
|
|
11576
11875
|
queryableFields: docType.queryableFields ?? [],
|
|
11577
11876
|
typeSchemaVersion: docType.schemaVersion ?? 1,
|
|
11578
11877
|
maxVersionsPerRoot: docType.settings?.maxVersionsPerRoot ?? 50,
|
|
@@ -11600,9 +11899,9 @@ adminContentRoutes.get("/", async (c) => {
|
|
|
11600
11899
|
const offset = (page - 1) * limit;
|
|
11601
11900
|
const collectionsStmt = db.prepare("SELECT id, name, display_name FROM document_types WHERE is_active = 1 ORDER BY display_name");
|
|
11602
11901
|
const { results: collectionsResults } = await collectionsStmt.all();
|
|
11603
|
-
const codeCollections = await
|
|
11902
|
+
const codeCollections = await chunk4DHPR7KR_cjs.loadCollectionConfigs();
|
|
11604
11903
|
const codeCollectionMap = new Map(codeCollections.map((c2) => [c2.name, c2]));
|
|
11605
|
-
const docTypeRegistry = new
|
|
11904
|
+
const docTypeRegistry = new chunkBRKXMRMB_cjs.DocumentTypeRegistry(db);
|
|
11606
11905
|
const docTypes = (await docTypeRegistry.findAll()).filter((dt) => !dt.settings?.internal && !dt.isAuth);
|
|
11607
11906
|
const visibleTypeIds = new Set(docTypes.map((dt) => dt.id));
|
|
11608
11907
|
const allCollections = [
|
|
@@ -11614,7 +11913,7 @@ adminContentRoutes.get("/", async (c) => {
|
|
|
11614
11913
|
...allCollections.map((c2) => ({ name: c2.name, displayName: c2.displayName })),
|
|
11615
11914
|
...docTypes.filter((dt) => !collectionNames.has(dt.id)).map((dt) => ({ name: `doc:${dt.id}`, displayName: dt.displayName }))
|
|
11616
11915
|
];
|
|
11617
|
-
const newContentCollections = await
|
|
11916
|
+
const newContentCollections = await chunk4DHPR7KR_cjs.getVisibleCollections(db);
|
|
11618
11917
|
const docBackedCollection = !modelName.startsWith("doc:") && modelName !== "all" ? docTypes.find((dt) => dt.id === modelName) : void 0;
|
|
11619
11918
|
const isDocModel = modelName.startsWith("doc:") || !!docBackedCollection;
|
|
11620
11919
|
if (isDocModel) {
|
|
@@ -11899,9 +12198,9 @@ adminContentRoutes.get("/new", async (c) => {
|
|
|
11899
12198
|
const collectionsStmt = db2.prepare("SELECT id, name, display_name, description FROM document_types WHERE is_active = 1 ORDER BY display_name");
|
|
11900
12199
|
const { results } = await collectionsStmt.all();
|
|
11901
12200
|
const visibleTypeIds = new Set(
|
|
11902
|
-
(await new
|
|
12201
|
+
(await new chunkBRKXMRMB_cjs.DocumentTypeRegistry(db2).findAll()).filter((dt) => !dt.settings?.internal && !dt.isAuth).map((dt) => dt.id)
|
|
11903
12202
|
);
|
|
11904
|
-
const codeCollections = await
|
|
12203
|
+
const codeCollections = await chunk4DHPR7KR_cjs.loadCollectionConfigs();
|
|
11905
12204
|
const dbCollectionNames = new Set((results || []).map((r) => r.name));
|
|
11906
12205
|
const allCollections = [
|
|
11907
12206
|
...codeCollections.filter((c2) => !dbCollectionNames.has(c2.name)).map((c2) => ({
|
|
@@ -11967,32 +12266,32 @@ adminContentRoutes.get("/new", async (c) => {
|
|
|
11967
12266
|
return c.html(renderContentFormPage(formData2));
|
|
11968
12267
|
}
|
|
11969
12268
|
const fields = await getCollectionFields(db, collection.id);
|
|
11970
|
-
const workflowEnabled = await
|
|
11971
|
-
const tinymceEnabled = await
|
|
12269
|
+
const workflowEnabled = await chunk4DHPR7KR_cjs.isPluginActive(db, "workflow");
|
|
12270
|
+
const tinymceEnabled = await chunk4DHPR7KR_cjs.isPluginActive(db, "tinymce-plugin");
|
|
11972
12271
|
let tinymceSettings;
|
|
11973
12272
|
if (tinymceEnabled) {
|
|
11974
|
-
const pluginService = new
|
|
12273
|
+
const pluginService = new chunk4DHPR7KR_cjs.PluginService(db);
|
|
11975
12274
|
const tinymcePlugin2 = await pluginService.getPlugin("tinymce-plugin");
|
|
11976
12275
|
tinymceSettings = tinymcePlugin2?.settings;
|
|
11977
12276
|
}
|
|
11978
|
-
const quillEnabled = await
|
|
12277
|
+
const quillEnabled = await chunk4DHPR7KR_cjs.isPluginActive(db, "quill-editor");
|
|
11979
12278
|
let quillSettings;
|
|
11980
12279
|
if (quillEnabled) {
|
|
11981
|
-
const pluginService = new
|
|
12280
|
+
const pluginService = new chunk4DHPR7KR_cjs.PluginService(db);
|
|
11982
12281
|
const quillPlugin = await pluginService.getPlugin("quill-editor");
|
|
11983
12282
|
quillSettings = quillPlugin?.settings;
|
|
11984
12283
|
}
|
|
11985
|
-
const mdxeditorEnabled = await
|
|
12284
|
+
const mdxeditorEnabled = await chunk4DHPR7KR_cjs.isPluginActive(db, "easy-mdx");
|
|
11986
12285
|
let mdxeditorSettings;
|
|
11987
12286
|
if (mdxeditorEnabled) {
|
|
11988
|
-
const pluginService = new
|
|
12287
|
+
const pluginService = new chunk4DHPR7KR_cjs.PluginService(db);
|
|
11989
12288
|
const mdxeditorPlugin = await pluginService.getPlugin("easy-mdx");
|
|
11990
12289
|
mdxeditorSettings = mdxeditorPlugin?.settings;
|
|
11991
12290
|
}
|
|
11992
|
-
const lexicalEnabled = await
|
|
12291
|
+
const lexicalEnabled = await chunk4DHPR7KR_cjs.isPluginActive(db, "lexical-editor");
|
|
11993
12292
|
let lexicalSettings;
|
|
11994
12293
|
if (lexicalEnabled) {
|
|
11995
|
-
const pluginService = new
|
|
12294
|
+
const pluginService = new chunk4DHPR7KR_cjs.PluginService(db);
|
|
11996
12295
|
const lexicalPlugin = await pluginService.getPlugin("lexical-editor");
|
|
11997
12296
|
lexicalSettings = lexicalPlugin?.settings;
|
|
11998
12297
|
}
|
|
@@ -12091,7 +12390,7 @@ adminContentRoutes.get("/:id/edit", async (c) => {
|
|
|
12091
12390
|
} : void 0
|
|
12092
12391
|
};
|
|
12093
12392
|
return c.html(renderContentFormPage(notFoundData));
|
|
12094
|
-
const cache =
|
|
12393
|
+
const cache = chunkC5LDQ3SH_cjs.getCacheService(chunkC5LDQ3SH_cjs.CACHE_CONFIGS.content);
|
|
12095
12394
|
const content = await cache.getOrSet(
|
|
12096
12395
|
cache.generateKey("content", id),
|
|
12097
12396
|
async () => {
|
|
@@ -12128,32 +12427,32 @@ adminContentRoutes.get("/:id/edit", async (c) => {
|
|
|
12128
12427
|
};
|
|
12129
12428
|
const fields = await getCollectionFields(db, content.collection_id);
|
|
12130
12429
|
const contentData = content.data ? JSON.parse(content.data) : {};
|
|
12131
|
-
const workflowEnabled = await
|
|
12132
|
-
const tinymceEnabled = await
|
|
12430
|
+
const workflowEnabled = await chunk4DHPR7KR_cjs.isPluginActive(db, "workflow");
|
|
12431
|
+
const tinymceEnabled = await chunk4DHPR7KR_cjs.isPluginActive(db, "tinymce-plugin");
|
|
12133
12432
|
let tinymceSettings;
|
|
12134
12433
|
if (tinymceEnabled) {
|
|
12135
|
-
const pluginService = new
|
|
12434
|
+
const pluginService = new chunk4DHPR7KR_cjs.PluginService(db);
|
|
12136
12435
|
const tinymcePlugin2 = await pluginService.getPlugin("tinymce-plugin");
|
|
12137
12436
|
tinymceSettings = tinymcePlugin2?.settings;
|
|
12138
12437
|
}
|
|
12139
|
-
const quillEnabled = await
|
|
12438
|
+
const quillEnabled = await chunk4DHPR7KR_cjs.isPluginActive(db, "quill-editor");
|
|
12140
12439
|
let quillSettings;
|
|
12141
12440
|
if (quillEnabled) {
|
|
12142
|
-
const pluginService = new
|
|
12441
|
+
const pluginService = new chunk4DHPR7KR_cjs.PluginService(db);
|
|
12143
12442
|
const quillPlugin = await pluginService.getPlugin("quill-editor");
|
|
12144
12443
|
quillSettings = quillPlugin?.settings;
|
|
12145
12444
|
}
|
|
12146
|
-
const mdxeditorEnabled = await
|
|
12445
|
+
const mdxeditorEnabled = await chunk4DHPR7KR_cjs.isPluginActive(db, "easy-mdx");
|
|
12147
12446
|
let mdxeditorSettings;
|
|
12148
12447
|
if (mdxeditorEnabled) {
|
|
12149
|
-
const pluginService = new
|
|
12448
|
+
const pluginService = new chunk4DHPR7KR_cjs.PluginService(db);
|
|
12150
12449
|
const mdxeditorPlugin = await pluginService.getPlugin("easy-mdx");
|
|
12151
12450
|
mdxeditorSettings = mdxeditorPlugin?.settings;
|
|
12152
12451
|
}
|
|
12153
|
-
const lexicalEnabled = await
|
|
12452
|
+
const lexicalEnabled = await chunk4DHPR7KR_cjs.isPluginActive(db, "lexical-editor");
|
|
12154
12453
|
let lexicalSettings;
|
|
12155
12454
|
if (lexicalEnabled) {
|
|
12156
|
-
const pluginService = new
|
|
12455
|
+
const pluginService = new chunk4DHPR7KR_cjs.PluginService(db);
|
|
12157
12456
|
const lexicalPlugin = await pluginService.getPlugin("lexical-editor");
|
|
12158
12457
|
lexicalSettings = lexicalPlugin?.settings;
|
|
12159
12458
|
}
|
|
@@ -12276,8 +12575,11 @@ adminContentRoutes.post("/", async (c) => {
|
|
|
12276
12575
|
data,
|
|
12277
12576
|
publishOnCreate: status === "published"
|
|
12278
12577
|
}), user?.userId);
|
|
12279
|
-
const cache2 =
|
|
12578
|
+
const cache2 = chunkC5LDQ3SH_cjs.getCacheService(chunkC5LDQ3SH_cjs.CACHE_CONFIGS.content);
|
|
12280
12579
|
await cache2.invalidate(`content:list:${collectionId}:*`);
|
|
12580
|
+
const apiCacheCreate = chunkC5LDQ3SH_cjs.getCacheService(chunkC5LDQ3SH_cjs.CACHE_CONFIGS.api);
|
|
12581
|
+
await apiCacheCreate.invalidate("api:content-filtered:*");
|
|
12582
|
+
await apiCacheCreate.invalidate(`api:collection-content-filtered:${createDocType.id}:*`);
|
|
12281
12583
|
const redirectUrl2 = `/admin/content/${doc.rootId}/edit?success=Content created successfully!`;
|
|
12282
12584
|
return c.req.header("HX-Request") === "true" ? c.text("", 200, { "HX-Redirect": redirectUrl2 }) : c.redirect(redirectUrl2);
|
|
12283
12585
|
}
|
|
@@ -12306,7 +12608,7 @@ adminContentRoutes.post("/", async (c) => {
|
|
|
12306
12608
|
now,
|
|
12307
12609
|
now
|
|
12308
12610
|
).run();
|
|
12309
|
-
const cache =
|
|
12611
|
+
const cache = chunkC5LDQ3SH_cjs.getCacheService(chunkC5LDQ3SH_cjs.CACHE_CONFIGS.content);
|
|
12310
12612
|
await cache.invalidate(`content:list:${collectionId}:*`);
|
|
12311
12613
|
const versionStmt = db.prepare(`
|
|
12312
12614
|
INSERT INTO content_versions (id, content_id, version, data, author_id, created_at)
|
|
@@ -12395,9 +12697,29 @@ adminContentRoutes.put("/:id", async (c) => {
|
|
|
12395
12697
|
const pub = await db.prepare("SELECT id FROM documents WHERE root_id = ? AND is_published = 1 AND tenant_id = ?").bind(id, tenantId).first();
|
|
12396
12698
|
if (status2 === "published") await svc.publish(newDraft.id, user?.userId);
|
|
12397
12699
|
else if (pub) await svc.unpublish(pub.id);
|
|
12398
|
-
await
|
|
12700
|
+
await chunkC5LDQ3SH_cjs.getCacheService(chunkC5LDQ3SH_cjs.CACHE_CONFIGS.content).invalidate(`content:list:*`);
|
|
12701
|
+
const apiCacheEdit = chunkC5LDQ3SH_cjs.getCacheService(chunkC5LDQ3SH_cjs.CACHE_CONFIGS.api);
|
|
12702
|
+
await apiCacheEdit.invalidate("api:content-filtered:*");
|
|
12703
|
+
await apiCacheEdit.invalidate(`api:collection-content-filtered:${docRowU.type_id}:*`);
|
|
12704
|
+
const isHTMX2 = c.req.header("HX-Request") === "true";
|
|
12705
|
+
const referrerParams = formData.get("referrer_params");
|
|
12706
|
+
const listUrl = referrerParams ? `/admin/content?${referrerParams}` : `/admin/content?collection=${dcoll.id}`;
|
|
12707
|
+
if (action === "save_and_close") {
|
|
12708
|
+
return isHTMX2 ? c.text("", 200, { "HX-Redirect": listUrl }) : c.redirect(listUrl);
|
|
12709
|
+
}
|
|
12710
|
+
if (isHTMX2) {
|
|
12711
|
+
const label = status2 === "published" ? "Content published successfully!" : "Content saved successfully!";
|
|
12712
|
+
return c.html(html.html`<div id="form-messages">
|
|
12713
|
+
<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">
|
|
12714
|
+
<svg class="h-5 w-5 text-green-500 shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24" stroke-width="1.5">
|
|
12715
|
+
<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"/>
|
|
12716
|
+
</svg>
|
|
12717
|
+
<span class="text-sm font-medium text-green-800 dark:text-green-200">${label}</span>
|
|
12718
|
+
</div>
|
|
12719
|
+
</div>`);
|
|
12720
|
+
}
|
|
12399
12721
|
const redirectUrl2 = `/admin/content/${id}/edit?success=Content updated successfully!`;
|
|
12400
|
-
return c.
|
|
12722
|
+
return c.redirect(redirectUrl2);
|
|
12401
12723
|
}
|
|
12402
12724
|
}
|
|
12403
12725
|
return c.html(html.html`
|
|
@@ -12478,7 +12800,7 @@ adminContentRoutes.put("/:id", async (c) => {
|
|
|
12478
12800
|
now,
|
|
12479
12801
|
id
|
|
12480
12802
|
).run();
|
|
12481
|
-
const cache =
|
|
12803
|
+
const cache = chunkC5LDQ3SH_cjs.getCacheService(chunkC5LDQ3SH_cjs.CACHE_CONFIGS.content);
|
|
12482
12804
|
await cache.delete(cache.generateKey("content", id));
|
|
12483
12805
|
await cache.invalidate(`content:list:${existingContent.collection_id}:*`);
|
|
12484
12806
|
const existingData = JSON.parse(existingContent.data || "{}");
|
|
@@ -12530,7 +12852,7 @@ adminContentRoutes.put("/:id", async (c) => {
|
|
|
12530
12852
|
`);
|
|
12531
12853
|
}
|
|
12532
12854
|
});
|
|
12533
|
-
adminContentRoutes.post("/preview",
|
|
12855
|
+
adminContentRoutes.post("/preview", chunkBRKXMRMB_cjs.requireRole(["admin", "editor", "author"]), async (c) => {
|
|
12534
12856
|
try {
|
|
12535
12857
|
const formData = await c.req.formData();
|
|
12536
12858
|
const collectionId = formData.get("collection_id");
|
|
@@ -12785,14 +13107,14 @@ adminContentRoutes.post("/bulk-action", async (c) => {
|
|
|
12785
13107
|
}
|
|
12786
13108
|
}
|
|
12787
13109
|
}
|
|
12788
|
-
const cache =
|
|
13110
|
+
const cache = chunkC5LDQ3SH_cjs.getCacheService(chunkC5LDQ3SH_cjs.CACHE_CONFIGS.content);
|
|
12789
13111
|
for (const contentId of ids) {
|
|
12790
13112
|
await cache.delete(cache.generateKey("content", contentId));
|
|
12791
13113
|
}
|
|
12792
13114
|
await cache.invalidate("content:list:*");
|
|
12793
|
-
const apiCache =
|
|
12794
|
-
await apiCache.invalidate("content-filtered:*");
|
|
12795
|
-
await apiCache.invalidate("collection-content-filtered:*");
|
|
13115
|
+
const apiCache = chunkC5LDQ3SH_cjs.getCacheService(chunkC5LDQ3SH_cjs.CACHE_CONFIGS.api);
|
|
13116
|
+
await apiCache.invalidate("api:content-filtered:*");
|
|
13117
|
+
await apiCache.invalidate("api:collection-content-filtered:*");
|
|
12796
13118
|
return c.json({ success: true, count: ids.length });
|
|
12797
13119
|
} catch (error) {
|
|
12798
13120
|
console.error("Bulk action error:", error);
|
|
@@ -12809,7 +13131,10 @@ adminContentRoutes.delete("/:id", async (c) => {
|
|
|
12809
13131
|
if (docDel && await getDocBackingType(db, docDel.type_id)) {
|
|
12810
13132
|
const now2 = Math.floor(Date.now() / 1e3);
|
|
12811
13133
|
await db.prepare("UPDATE documents SET deleted_at = ?, updated_at = ? WHERE root_id = ? AND tenant_id = ?").bind(now2, now2, id, tenantId).run();
|
|
12812
|
-
await
|
|
13134
|
+
await chunkC5LDQ3SH_cjs.getCacheService(chunkC5LDQ3SH_cjs.CACHE_CONFIGS.content).invalidate("content:list:*");
|
|
13135
|
+
const apiCacheDel = chunkC5LDQ3SH_cjs.getCacheService(chunkC5LDQ3SH_cjs.CACHE_CONFIGS.api);
|
|
13136
|
+
await apiCacheDel.invalidate("api:content-filtered:*");
|
|
13137
|
+
await apiCacheDel.invalidate(`api:collection-content-filtered:${docDel.type_id}:*`);
|
|
12813
13138
|
return c.html(`
|
|
12814
13139
|
<div id="content-list" hx-get="/admin/content?model=${docDel.type_id}" hx-trigger="load" hx-swap="outerHTML">
|
|
12815
13140
|
<div class="flex items-center justify-center p-8"><span class="text-zinc-500">Deleting\u2026</span></div>
|
|
@@ -12829,7 +13154,7 @@ adminContentRoutes.delete("/:id", async (c) => {
|
|
|
12829
13154
|
WHERE id = ?
|
|
12830
13155
|
`);
|
|
12831
13156
|
await deleteStmt.bind(now, id).run();
|
|
12832
|
-
const cache =
|
|
13157
|
+
const cache = chunkC5LDQ3SH_cjs.getCacheService(chunkC5LDQ3SH_cjs.CACHE_CONFIGS.content);
|
|
12833
13158
|
await cache.delete(cache.generateKey("content", id));
|
|
12834
13159
|
await cache.invalidate("content:list:*");
|
|
12835
13160
|
return c.html(`
|
|
@@ -12849,7 +13174,7 @@ adminContentRoutes.delete("/:id", async (c) => {
|
|
|
12849
13174
|
return c.json({ success: false, error: "Failed to delete content" }, 500);
|
|
12850
13175
|
}
|
|
12851
13176
|
});
|
|
12852
|
-
adminContentRoutes.get("/:id/version/:version/preview",
|
|
13177
|
+
adminContentRoutes.get("/:id/version/:version/preview", chunkBRKXMRMB_cjs.requireRole(["admin", "editor", "author"]), async (c) => {
|
|
12853
13178
|
try {
|
|
12854
13179
|
const id = c.req.param("id");
|
|
12855
13180
|
const version = parseInt(c.req.param("version") || "0");
|
|
@@ -12945,9 +13270,9 @@ function parseDocFormData(formData, queryableFields = []) {
|
|
|
12945
13270
|
return { title, slug, data };
|
|
12946
13271
|
}
|
|
12947
13272
|
async function getDocService(db, typeId, tenantId) {
|
|
12948
|
-
const registry = new
|
|
13273
|
+
const registry = new chunkBRKXMRMB_cjs.DocumentTypeRegistry(db);
|
|
12949
13274
|
const docType = await registry.findById(typeId);
|
|
12950
|
-
const svc = new
|
|
13275
|
+
const svc = new chunkOLEOKHDX_cjs.DocumentsService(db, {
|
|
12951
13276
|
queryableFields: docType?.queryableFields ?? [],
|
|
12952
13277
|
typeSchemaVersion: docType?.schemaVersion ?? 1,
|
|
12953
13278
|
maxVersionsPerRoot: docType?.settings?.maxVersionsPerRoot ?? 50,
|
|
@@ -12958,10 +13283,10 @@ async function getDocService(db, typeId, tenantId) {
|
|
|
12958
13283
|
}
|
|
12959
13284
|
adminContentRoutes.get("/documents/:typeId/new", async (c) => {
|
|
12960
13285
|
const { typeId } = c.req.param();
|
|
12961
|
-
const registry = new
|
|
13286
|
+
const registry = new chunkBRKXMRMB_cjs.DocumentTypeRegistry(c.env.DB);
|
|
12962
13287
|
const docType = await registry.findById(typeId);
|
|
12963
13288
|
if (!docType) return c.html("<p>Unknown document type.</p>", 404);
|
|
12964
|
-
return c.html(
|
|
13289
|
+
return c.html(chunkTT3TQSCZ_cjs.renderDocumentFormPage({ docType, isEdit: false, user: userCtx(c) }));
|
|
12965
13290
|
});
|
|
12966
13291
|
adminContentRoutes.post("/documents/:typeId/new", async (c) => {
|
|
12967
13292
|
const { typeId } = c.req.param();
|
|
@@ -12983,17 +13308,17 @@ adminContentRoutes.post("/documents/:typeId/new", async (c) => {
|
|
|
12983
13308
|
}), user?.userId);
|
|
12984
13309
|
return c.redirect(`/admin/content/documents/${typeId}/${doc.rootId}/edit?message=Created+successfully`);
|
|
12985
13310
|
} catch (err) {
|
|
12986
|
-
const registry = new
|
|
13311
|
+
const registry = new chunkBRKXMRMB_cjs.DocumentTypeRegistry(c.env.DB);
|
|
12987
13312
|
const docType = await registry.findById(typeId);
|
|
12988
13313
|
if (!docType) return c.html("<p>Unknown document type.</p>", 404);
|
|
12989
|
-
return c.html(
|
|
13314
|
+
return c.html(chunkTT3TQSCZ_cjs.renderDocumentFormPage({ docType, isEdit: false, user: userCtx(c), message: err?.message ?? "Failed to create", messageType: "error" }));
|
|
12990
13315
|
}
|
|
12991
13316
|
});
|
|
12992
13317
|
adminContentRoutes.get("/documents/:typeId/:rootId/edit", async (c) => {
|
|
12993
13318
|
const { typeId, rootId } = c.req.param();
|
|
12994
13319
|
const db = c.env.DB;
|
|
12995
13320
|
const message = c.req.query("message");
|
|
12996
|
-
const registry = new
|
|
13321
|
+
const registry = new chunkBRKXMRMB_cjs.DocumentTypeRegistry(db);
|
|
12997
13322
|
const docType = await registry.findById(typeId);
|
|
12998
13323
|
if (!docType) return c.html("<p>Unknown document type.</p>", 404);
|
|
12999
13324
|
const tenantId = reqTenant(c);
|
|
@@ -13040,7 +13365,7 @@ adminContentRoutes.get("/documents/:typeId/:rootId/edit", async (c) => {
|
|
|
13040
13365
|
createdAt: draftRow.created_at,
|
|
13041
13366
|
updatedAt: draftRow.updated_at
|
|
13042
13367
|
};
|
|
13043
|
-
return c.html(
|
|
13368
|
+
return c.html(chunkTT3TQSCZ_cjs.renderDocumentFormPage({ docType, doc, publishedDoc, isEdit: true, message, user: userCtx(c), versioningEnabled: docType?.settings?.versioning === true }));
|
|
13044
13369
|
});
|
|
13045
13370
|
adminContentRoutes.post("/documents/:typeId/:rootId", async (c) => {
|
|
13046
13371
|
const { typeId, rootId } = c.req.param();
|
|
@@ -13105,8 +13430,8 @@ adminContentRoutes.post("/documents/:typeId/:documentId/delete", async (c) => {
|
|
|
13105
13430
|
adminContentRoutes.get("/documents/:typeId/:rootId/versions", async (c) => {
|
|
13106
13431
|
const { typeId, rootId } = c.req.param();
|
|
13107
13432
|
const db = c.env.DB;
|
|
13108
|
-
const { renderVersionHistoryFragment } = await import('./admin-documents-form.template-
|
|
13109
|
-
const registry = new
|
|
13433
|
+
const { renderVersionHistoryFragment } = await import('./admin-documents-form.template-UWKGVAMW.cjs');
|
|
13434
|
+
const registry = new chunkBRKXMRMB_cjs.DocumentTypeRegistry(db);
|
|
13110
13435
|
const docType = await registry.findById(typeId);
|
|
13111
13436
|
if (!docType) return c.html("<div>Unknown type.</div>", 404);
|
|
13112
13437
|
const result = await db.prepare(
|
|
@@ -13126,7 +13451,7 @@ adminContentRoutes.get("/documents/:typeId/:rootId/versions", async (c) => {
|
|
|
13126
13451
|
var admin_content_default = adminContentRoutes;
|
|
13127
13452
|
|
|
13128
13453
|
// src/templates/pages/admin-profile.template.ts
|
|
13129
|
-
|
|
13454
|
+
chunkMI2YXCK4_cjs.init_admin_layout_catalyst_template();
|
|
13130
13455
|
function renderAvatarImage(avatarUrl, firstName, lastName) {
|
|
13131
13456
|
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
13457
|
${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 +13471,8 @@ function renderProfilePage(data) {
|
|
|
13146
13471
|
</div>
|
|
13147
13472
|
|
|
13148
13473
|
<!-- Alert Messages -->
|
|
13149
|
-
${data.error ?
|
|
13150
|
-
${data.success ?
|
|
13474
|
+
${data.error ? chunkOUBUS74I_cjs.renderAlert({ type: "error", message: data.error, dismissible: true }) : ""}
|
|
13475
|
+
${data.success ? chunkOUBUS74I_cjs.renderAlert({ type: "success", message: data.success, dismissible: true }) : ""}
|
|
13151
13476
|
|
|
13152
13477
|
<!-- Profile Form -->
|
|
13153
13478
|
<div class="grid grid-cols-1 lg:grid-cols-3 gap-8">
|
|
@@ -13524,7 +13849,7 @@ function renderProfilePage(data) {
|
|
|
13524
13849
|
version: data.version,
|
|
13525
13850
|
content: pageContent
|
|
13526
13851
|
};
|
|
13527
|
-
return
|
|
13852
|
+
return chunkMI2YXCK4_cjs.renderAdminLayoutCatalyst(layoutData);
|
|
13528
13853
|
}
|
|
13529
13854
|
|
|
13530
13855
|
// src/templates/pages/admin-activity-logs.template.ts
|
|
@@ -13734,7 +14059,7 @@ function renderActivityLogsPage(data) {
|
|
|
13734
14059
|
user: data.user,
|
|
13735
14060
|
content: pageContent
|
|
13736
14061
|
};
|
|
13737
|
-
return
|
|
14062
|
+
return chunkOUBUS74I_cjs.renderAdminLayout(layoutData);
|
|
13738
14063
|
}
|
|
13739
14064
|
function getActionBadgeClass(action) {
|
|
13740
14065
|
if (action.includes("login") || action.includes("logout")) {
|
|
@@ -13754,7 +14079,7 @@ function formatAction(action) {
|
|
|
13754
14079
|
}
|
|
13755
14080
|
|
|
13756
14081
|
// src/templates/pages/admin-user-edit.template.ts
|
|
13757
|
-
|
|
14082
|
+
chunkMI2YXCK4_cjs.init_admin_layout_catalyst_template();
|
|
13758
14083
|
|
|
13759
14084
|
// src/templates/components/confirmation-dialog.template.ts
|
|
13760
14085
|
function renderConfirmationDialog2(options) {
|
|
@@ -13950,8 +14275,8 @@ function renderUserEditPage(data) {
|
|
|
13950
14275
|
|
|
13951
14276
|
<!-- Alert Messages -->
|
|
13952
14277
|
<div id="form-messages" class="mb-6 empty:mb-0">
|
|
13953
|
-
${data.error ?
|
|
13954
|
-
${data.success ?
|
|
14278
|
+
${data.error ? chunkOUBUS74I_cjs.renderAlert({ type: "error", message: data.error, dismissible: true }) : ""}
|
|
14279
|
+
${data.success ? chunkOUBUS74I_cjs.renderAlert({ type: "success", message: data.success, dismissible: true }) : ""}
|
|
13955
14280
|
</div>
|
|
13956
14281
|
|
|
13957
14282
|
<!-- User Edit Form -->
|
|
@@ -14273,11 +14598,11 @@ function renderUserEditPage(data) {
|
|
|
14273
14598
|
user: data.user,
|
|
14274
14599
|
content: pageContent
|
|
14275
14600
|
};
|
|
14276
|
-
return
|
|
14601
|
+
return chunkMI2YXCK4_cjs.renderAdminLayoutCatalyst(layoutData);
|
|
14277
14602
|
}
|
|
14278
14603
|
|
|
14279
14604
|
// src/templates/pages/admin-user-new.template.ts
|
|
14280
|
-
|
|
14605
|
+
chunkMI2YXCK4_cjs.init_admin_layout_catalyst_template();
|
|
14281
14606
|
function renderUserNewPage(data) {
|
|
14282
14607
|
const pageContent = `
|
|
14283
14608
|
<div>
|
|
@@ -14316,8 +14641,8 @@ function renderUserNewPage(data) {
|
|
|
14316
14641
|
|
|
14317
14642
|
<!-- Alert Messages -->
|
|
14318
14643
|
<div id="form-messages">
|
|
14319
|
-
${data.error ?
|
|
14320
|
-
${data.success ?
|
|
14644
|
+
${data.error ? chunkOUBUS74I_cjs.renderAlert({ type: "error", message: data.error, dismissible: true }) : ""}
|
|
14645
|
+
${data.success ? chunkOUBUS74I_cjs.renderAlert({ type: "success", message: data.success, dismissible: true }) : ""}
|
|
14321
14646
|
</div>
|
|
14322
14647
|
|
|
14323
14648
|
<!-- User New Form -->
|
|
@@ -14547,11 +14872,11 @@ function renderUserNewPage(data) {
|
|
|
14547
14872
|
user: data.user,
|
|
14548
14873
|
content: pageContent
|
|
14549
14874
|
};
|
|
14550
|
-
return
|
|
14875
|
+
return chunkMI2YXCK4_cjs.renderAdminLayoutCatalyst(layoutData);
|
|
14551
14876
|
}
|
|
14552
14877
|
|
|
14553
14878
|
// src/templates/pages/admin-users-list.template.ts
|
|
14554
|
-
|
|
14879
|
+
chunkMI2YXCK4_cjs.init_admin_layout_catalyst_template();
|
|
14555
14880
|
function renderUsersListPage(data) {
|
|
14556
14881
|
const columns = [
|
|
14557
14882
|
{
|
|
@@ -14707,8 +15032,8 @@ function renderUsersListPage(data) {
|
|
|
14707
15032
|
</div>
|
|
14708
15033
|
|
|
14709
15034
|
<!-- Alert Messages -->
|
|
14710
|
-
${data.error ?
|
|
14711
|
-
${data.success ?
|
|
15035
|
+
${data.error ? chunkOUBUS74I_cjs.renderAlert({ type: "error", message: data.error, dismissible: true }) : ""}
|
|
15036
|
+
${data.success ? chunkOUBUS74I_cjs.renderAlert({ type: "success", message: data.success, dismissible: true }) : ""}
|
|
14712
15037
|
|
|
14713
15038
|
<!-- Stats -->
|
|
14714
15039
|
<div class="mb-6">
|
|
@@ -14885,10 +15210,10 @@ function renderUsersListPage(data) {
|
|
|
14885
15210
|
</div>
|
|
14886
15211
|
|
|
14887
15212
|
<!-- Users Table -->
|
|
14888
|
-
${
|
|
15213
|
+
${chunkOUBUS74I_cjs.renderTable(tableData)}
|
|
14889
15214
|
|
|
14890
15215
|
<!-- Pagination -->
|
|
14891
|
-
${data.pagination ?
|
|
15216
|
+
${data.pagination ? chunkOUBUS74I_cjs.renderPagination(data.pagination) : ""}
|
|
14892
15217
|
</div>
|
|
14893
15218
|
|
|
14894
15219
|
<script>
|
|
@@ -14959,7 +15284,7 @@ function renderUsersListPage(data) {
|
|
|
14959
15284
|
version: data.version,
|
|
14960
15285
|
content: pageContent
|
|
14961
15286
|
};
|
|
14962
|
-
return
|
|
15287
|
+
return chunkMI2YXCK4_cjs.renderAdminLayoutCatalyst(layoutData);
|
|
14963
15288
|
}
|
|
14964
15289
|
|
|
14965
15290
|
// src/plugins/core-plugins/multi-tenant-plugin/services/tenant-service.ts
|
|
@@ -15039,7 +15364,7 @@ var TenantService = class {
|
|
|
15039
15364
|
SET name = ?, domain = ?, status = ?, notes = ?, updated_at = ?
|
|
15040
15365
|
WHERE slug = ?
|
|
15041
15366
|
`).bind(name, domain, status, notes, now, slug).run();
|
|
15042
|
-
|
|
15367
|
+
chunk4DHPR7KR_cjs.invalidateTenantCache();
|
|
15043
15368
|
const updated = await this.getTenantBySlug(slug);
|
|
15044
15369
|
if (!updated) throw new Error("Tenant not found");
|
|
15045
15370
|
return updated;
|
|
@@ -15057,7 +15382,7 @@ var TenantService = class {
|
|
|
15057
15382
|
throw new Error(`Tenant '${slug}' still owns ${docCount} document(s). Delete or migrate its content first.`);
|
|
15058
15383
|
}
|
|
15059
15384
|
await this.db.prepare(`DELETE FROM auth_tenant WHERE slug = ?`).bind(slug).run();
|
|
15060
|
-
|
|
15385
|
+
chunk4DHPR7KR_cjs.invalidateTenantCache();
|
|
15061
15386
|
}
|
|
15062
15387
|
// ─── Membership (auth_tenant_member) ───────────────────────────────────────
|
|
15063
15388
|
// Tenant resolution and the admin switcher are gated on membership: an authed user may only
|
|
@@ -15301,7 +15626,7 @@ var TenantService = class {
|
|
|
15301
15626
|
INSERT INTO auth_tenant (id, name, slug, status, domain, notes, metadata, created_at, updated_at)
|
|
15302
15627
|
VALUES (?, ?, ?, 'active', ?, ?, '{}', ?, ?)
|
|
15303
15628
|
`).bind(id, input.name, input.slug, input.domain, input.notes, now, now).run();
|
|
15304
|
-
|
|
15629
|
+
chunk4DHPR7KR_cjs.invalidateTenantCache();
|
|
15305
15630
|
const created = await this.getTenantBySlug(input.slug);
|
|
15306
15631
|
if (!created) throw new Error("Failed to create tenant");
|
|
15307
15632
|
return created;
|
|
@@ -15325,14 +15650,14 @@ function mapRowToTenant(row) {
|
|
|
15325
15650
|
|
|
15326
15651
|
// src/routes/admin-users.ts
|
|
15327
15652
|
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/*",
|
|
15653
|
+
userRoutes.use("*", chunkBRKXMRMB_cjs.requireAuth());
|
|
15654
|
+
userRoutes.use("/users/*", chunkBRKXMRMB_cjs.requireRole(["admin"]));
|
|
15655
|
+
userRoutes.use("/users", chunkBRKXMRMB_cjs.requireRole(["admin"]));
|
|
15656
|
+
userRoutes.use("/invite-user", chunkBRKXMRMB_cjs.requireRole(["admin"]));
|
|
15657
|
+
userRoutes.use("/resend-invitation/*", chunkBRKXMRMB_cjs.requireRole(["admin"]));
|
|
15658
|
+
userRoutes.use("/cancel-invitation/*", chunkBRKXMRMB_cjs.requireRole(["admin"]));
|
|
15659
|
+
userRoutes.use("/activity-logs", chunkBRKXMRMB_cjs.requireRole(["admin"]));
|
|
15660
|
+
userRoutes.use("/activity-logs/*", chunkBRKXMRMB_cjs.requireRole(["admin"]));
|
|
15336
15661
|
userRoutes.get("/", (c) => {
|
|
15337
15662
|
return c.redirect("/admin/dashboard");
|
|
15338
15663
|
});
|
|
@@ -15360,12 +15685,10 @@ var LANGUAGES = [
|
|
|
15360
15685
|
{ value: "ko", label: "Korean" },
|
|
15361
15686
|
{ value: "zh", label: "Chinese" }
|
|
15362
15687
|
];
|
|
15363
|
-
|
|
15364
|
-
|
|
15365
|
-
{ value:
|
|
15366
|
-
|
|
15367
|
-
{ value: "viewer", label: "Viewer" }
|
|
15368
|
-
];
|
|
15688
|
+
async function fetchRoleOptions(db) {
|
|
15689
|
+
const roles = await new chunkOLEOKHDX_cjs.RbacService(db).getRoles();
|
|
15690
|
+
return roles.map((r) => ({ value: r.id, label: r.display_name }));
|
|
15691
|
+
}
|
|
15369
15692
|
userRoutes.get("/profile", async (c) => {
|
|
15370
15693
|
const user = c.get("user");
|
|
15371
15694
|
const db = c.env.DB;
|
|
@@ -15443,7 +15766,7 @@ userRoutes.put("/profile", async (c) => {
|
|
|
15443
15766
|
const language = formData.get("language")?.toString() || "en";
|
|
15444
15767
|
const emailNotifications = formData.get("email_notifications") === "1";
|
|
15445
15768
|
if (!firstName || !lastName || !email) {
|
|
15446
|
-
return c.html(
|
|
15769
|
+
return c.html(chunkTT3TQSCZ_cjs.renderAlert({
|
|
15447
15770
|
type: "error",
|
|
15448
15771
|
message: "First name, last name, and email are required.",
|
|
15449
15772
|
dismissible: true
|
|
@@ -15451,7 +15774,7 @@ userRoutes.put("/profile", async (c) => {
|
|
|
15451
15774
|
}
|
|
15452
15775
|
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
15453
15776
|
if (!emailRegex.test(email)) {
|
|
15454
|
-
return c.html(
|
|
15777
|
+
return c.html(chunkTT3TQSCZ_cjs.renderAlert({
|
|
15455
15778
|
type: "error",
|
|
15456
15779
|
message: "Please enter a valid email address.",
|
|
15457
15780
|
dismissible: true
|
|
@@ -15463,7 +15786,7 @@ userRoutes.put("/profile", async (c) => {
|
|
|
15463
15786
|
`);
|
|
15464
15787
|
const existingUser = await checkStmt.bind(email, user.userId).first();
|
|
15465
15788
|
if (existingUser) {
|
|
15466
|
-
return c.html(
|
|
15789
|
+
return c.html(chunkTT3TQSCZ_cjs.renderAlert({
|
|
15467
15790
|
type: "error",
|
|
15468
15791
|
message: "Email is already taken by another user.",
|
|
15469
15792
|
dismissible: true
|
|
@@ -15495,11 +15818,11 @@ userRoutes.put("/profile", async (c) => {
|
|
|
15495
15818
|
const validation = validateCustomData(sanitized, profileConfig);
|
|
15496
15819
|
if (!validation.valid) {
|
|
15497
15820
|
const errorMessages = Object.values(validation.errors).join(", ");
|
|
15498
|
-
return c.html(
|
|
15821
|
+
return c.html(chunkTT3TQSCZ_cjs.renderAlert({ type: "error", message: errorMessages, dismissible: true }), 400);
|
|
15499
15822
|
}
|
|
15500
15823
|
await saveCustomData(db, user.userId, sanitized);
|
|
15501
15824
|
}
|
|
15502
|
-
await
|
|
15825
|
+
await chunkBRKXMRMB_cjs.logActivity(
|
|
15503
15826
|
db,
|
|
15504
15827
|
user.userId,
|
|
15505
15828
|
"profile.update",
|
|
@@ -15509,14 +15832,14 @@ userRoutes.put("/profile", async (c) => {
|
|
|
15509
15832
|
c.req.header("x-forwarded-for") || c.req.header("cf-connecting-ip"),
|
|
15510
15833
|
c.req.header("user-agent")
|
|
15511
15834
|
);
|
|
15512
|
-
return c.html(
|
|
15835
|
+
return c.html(chunkTT3TQSCZ_cjs.renderAlert({
|
|
15513
15836
|
type: "success",
|
|
15514
15837
|
message: "Profile updated successfully!",
|
|
15515
15838
|
dismissible: true
|
|
15516
15839
|
}));
|
|
15517
15840
|
} catch (error) {
|
|
15518
15841
|
console.error("Profile update error:", error);
|
|
15519
|
-
return c.html(
|
|
15842
|
+
return c.html(chunkTT3TQSCZ_cjs.renderAlert({
|
|
15520
15843
|
type: "error",
|
|
15521
15844
|
message: "Failed to update profile. Please try again.",
|
|
15522
15845
|
dismissible: true
|
|
@@ -15530,7 +15853,7 @@ userRoutes.post("/profile/avatar", async (c) => {
|
|
|
15530
15853
|
const formData = await c.req.formData();
|
|
15531
15854
|
const avatarFile = formData.get("avatar");
|
|
15532
15855
|
if (!avatarFile || typeof avatarFile === "string" || !avatarFile.name) {
|
|
15533
|
-
return c.html(
|
|
15856
|
+
return c.html(chunkTT3TQSCZ_cjs.renderAlert({
|
|
15534
15857
|
type: "error",
|
|
15535
15858
|
message: "Please select an image file.",
|
|
15536
15859
|
dismissible: true
|
|
@@ -15538,7 +15861,7 @@ userRoutes.post("/profile/avatar", async (c) => {
|
|
|
15538
15861
|
}
|
|
15539
15862
|
const allowedTypes = ["image/jpeg", "image/png", "image/gif", "image/webp"];
|
|
15540
15863
|
if (!allowedTypes.includes(avatarFile.type)) {
|
|
15541
|
-
return c.html(
|
|
15864
|
+
return c.html(chunkTT3TQSCZ_cjs.renderAlert({
|
|
15542
15865
|
type: "error",
|
|
15543
15866
|
message: "Please upload a valid image file (JPEG, PNG, GIF, or WebP).",
|
|
15544
15867
|
dismissible: true
|
|
@@ -15546,7 +15869,7 @@ userRoutes.post("/profile/avatar", async (c) => {
|
|
|
15546
15869
|
}
|
|
15547
15870
|
const maxSize = 5 * 1024 * 1024;
|
|
15548
15871
|
if (avatarFile.size > maxSize) {
|
|
15549
|
-
return c.html(
|
|
15872
|
+
return c.html(chunkTT3TQSCZ_cjs.renderAlert({
|
|
15550
15873
|
type: "error",
|
|
15551
15874
|
message: "Image file must be smaller than 5MB.",
|
|
15552
15875
|
dismissible: true
|
|
@@ -15562,7 +15885,7 @@ userRoutes.post("/profile/avatar", async (c) => {
|
|
|
15562
15885
|
SELECT first_name, last_name FROM auth_user WHERE id = ?
|
|
15563
15886
|
`);
|
|
15564
15887
|
const userData = await userStmt.bind(user.userId).first();
|
|
15565
|
-
await
|
|
15888
|
+
await chunkBRKXMRMB_cjs.logActivity(
|
|
15566
15889
|
db,
|
|
15567
15890
|
user.userId,
|
|
15568
15891
|
"profile.avatar_update",
|
|
@@ -15572,7 +15895,7 @@ userRoutes.post("/profile/avatar", async (c) => {
|
|
|
15572
15895
|
c.req.header("x-forwarded-for") || c.req.header("cf-connecting-ip"),
|
|
15573
15896
|
c.req.header("user-agent")
|
|
15574
15897
|
);
|
|
15575
|
-
const alertHtml =
|
|
15898
|
+
const alertHtml = chunkTT3TQSCZ_cjs.renderAlert({
|
|
15576
15899
|
type: "success",
|
|
15577
15900
|
message: "Profile picture updated successfully!",
|
|
15578
15901
|
dismissible: true
|
|
@@ -15586,7 +15909,7 @@ userRoutes.post("/profile/avatar", async (c) => {
|
|
|
15586
15909
|
return c.html(alertHtml + avatarImageWithOob);
|
|
15587
15910
|
} catch (error) {
|
|
15588
15911
|
console.error("Avatar upload error:", error);
|
|
15589
|
-
return c.html(
|
|
15912
|
+
return c.html(chunkTT3TQSCZ_cjs.renderAlert({
|
|
15590
15913
|
type: "error",
|
|
15591
15914
|
message: "Failed to upload profile picture. Please try again.",
|
|
15592
15915
|
dismissible: true
|
|
@@ -15602,21 +15925,21 @@ userRoutes.post("/profile/password", async (c) => {
|
|
|
15602
15925
|
const newPassword = formData.get("new_password")?.toString() || "";
|
|
15603
15926
|
const confirmPassword = formData.get("confirm_password")?.toString() || "";
|
|
15604
15927
|
if (!currentPassword || !newPassword || !confirmPassword) {
|
|
15605
|
-
return c.html(
|
|
15928
|
+
return c.html(chunkTT3TQSCZ_cjs.renderAlert({
|
|
15606
15929
|
type: "error",
|
|
15607
15930
|
message: "All password fields are required.",
|
|
15608
15931
|
dismissible: true
|
|
15609
15932
|
}));
|
|
15610
15933
|
}
|
|
15611
15934
|
if (newPassword !== confirmPassword) {
|
|
15612
|
-
return c.html(
|
|
15935
|
+
return c.html(chunkTT3TQSCZ_cjs.renderAlert({
|
|
15613
15936
|
type: "error",
|
|
15614
15937
|
message: "New passwords do not match.",
|
|
15615
15938
|
dismissible: true
|
|
15616
15939
|
}));
|
|
15617
15940
|
}
|
|
15618
15941
|
if (newPassword.length < 8) {
|
|
15619
|
-
return c.html(
|
|
15942
|
+
return c.html(chunkTT3TQSCZ_cjs.renderAlert({
|
|
15620
15943
|
type: "error",
|
|
15621
15944
|
message: "New password must be at least 8 characters long.",
|
|
15622
15945
|
dismissible: true
|
|
@@ -15627,21 +15950,21 @@ userRoutes.post("/profile/password", async (c) => {
|
|
|
15627
15950
|
`);
|
|
15628
15951
|
const userData = await userStmt.bind(user.userId).first();
|
|
15629
15952
|
if (!userData) {
|
|
15630
|
-
return c.html(
|
|
15953
|
+
return c.html(chunkTT3TQSCZ_cjs.renderAlert({
|
|
15631
15954
|
type: "error",
|
|
15632
15955
|
message: "User not found.",
|
|
15633
15956
|
dismissible: true
|
|
15634
15957
|
}));
|
|
15635
15958
|
}
|
|
15636
|
-
const validPassword = await
|
|
15959
|
+
const validPassword = await chunkBRKXMRMB_cjs.AuthManager.verifyPassword(currentPassword, userData.password_hash);
|
|
15637
15960
|
if (!validPassword) {
|
|
15638
|
-
return c.html(
|
|
15961
|
+
return c.html(chunkTT3TQSCZ_cjs.renderAlert({
|
|
15639
15962
|
type: "error",
|
|
15640
15963
|
message: "Current password is incorrect.",
|
|
15641
15964
|
dismissible: true
|
|
15642
15965
|
}));
|
|
15643
15966
|
}
|
|
15644
|
-
const newPasswordHash = await
|
|
15967
|
+
const newPasswordHash = await chunkBRKXMRMB_cjs.AuthManager.hashPassword(newPassword);
|
|
15645
15968
|
const historyStmt = db.prepare(`
|
|
15646
15969
|
INSERT INTO auth_password_history (id, user_id, password_hash, created_at)
|
|
15647
15970
|
VALUES (?, ?, ?, ?)
|
|
@@ -15657,7 +15980,7 @@ userRoutes.post("/profile/password", async (c) => {
|
|
|
15657
15980
|
WHERE id = ?
|
|
15658
15981
|
`);
|
|
15659
15982
|
await updateStmt.bind(newPasswordHash, Date.now(), user.userId).run();
|
|
15660
|
-
await
|
|
15983
|
+
await chunkBRKXMRMB_cjs.logActivity(
|
|
15661
15984
|
db,
|
|
15662
15985
|
user.userId,
|
|
15663
15986
|
"profile.password_change",
|
|
@@ -15667,14 +15990,14 @@ userRoutes.post("/profile/password", async (c) => {
|
|
|
15667
15990
|
c.req.header("x-forwarded-for") || c.req.header("cf-connecting-ip"),
|
|
15668
15991
|
c.req.header("user-agent")
|
|
15669
15992
|
);
|
|
15670
|
-
return c.html(
|
|
15993
|
+
return c.html(chunkTT3TQSCZ_cjs.renderAlert({
|
|
15671
15994
|
type: "success",
|
|
15672
15995
|
message: "Password updated successfully!",
|
|
15673
15996
|
dismissible: true
|
|
15674
15997
|
}));
|
|
15675
15998
|
} catch (error) {
|
|
15676
15999
|
console.error("Password change error:", error);
|
|
15677
|
-
return c.html(
|
|
16000
|
+
return c.html(chunkTT3TQSCZ_cjs.renderAlert({
|
|
15678
16001
|
type: "error",
|
|
15679
16002
|
message: "Failed to update password. Please try again.",
|
|
15680
16003
|
dismissible: true
|
|
@@ -15724,7 +16047,7 @@ userRoutes.get("/users", async (c) => {
|
|
|
15724
16047
|
`);
|
|
15725
16048
|
const countResult = await countStmt.bind(...params).first();
|
|
15726
16049
|
const totalUsers = countResult?.total || 0;
|
|
15727
|
-
await
|
|
16050
|
+
await chunkBRKXMRMB_cjs.logActivity(
|
|
15728
16051
|
db,
|
|
15729
16052
|
user.userId,
|
|
15730
16053
|
"users.list_view",
|
|
@@ -15795,7 +16118,7 @@ userRoutes.get("/users", async (c) => {
|
|
|
15795
16118
|
if (isApiRequest) {
|
|
15796
16119
|
return c.json({ error: "Failed to load users" }, 500);
|
|
15797
16120
|
}
|
|
15798
|
-
return c.html(
|
|
16121
|
+
return c.html(chunkTT3TQSCZ_cjs.renderAlert({
|
|
15799
16122
|
type: "error",
|
|
15800
16123
|
message: "Failed to load users. Please try again.",
|
|
15801
16124
|
dismissible: true
|
|
@@ -15814,8 +16137,9 @@ userRoutes.get("/users/new", async (c) => {
|
|
|
15814
16137
|
const regFieldNames = profileConfig?.registrationFields ?? [];
|
|
15815
16138
|
const regFields = profileConfig && upRow ? regFieldNames.length > 0 ? profileConfig.fields.filter((f) => regFieldNames.includes(f.name)) : profileConfig.fields : [];
|
|
15816
16139
|
const registrationFieldsHtml = regFields.length > 0 ? renderCustomProfileSection({ fields: regFields }, {}) : void 0;
|
|
16140
|
+
const roles = await fetchRoleOptions(db);
|
|
15817
16141
|
const pageData = {
|
|
15818
|
-
roles
|
|
16142
|
+
roles,
|
|
15819
16143
|
registrationFieldsHtml,
|
|
15820
16144
|
user: {
|
|
15821
16145
|
name: user.email.split("@")[0] || user.email,
|
|
@@ -15826,7 +16150,7 @@ userRoutes.get("/users/new", async (c) => {
|
|
|
15826
16150
|
return c.html(renderUserNewPage(pageData));
|
|
15827
16151
|
} catch (error) {
|
|
15828
16152
|
console.error("User new page error:", error);
|
|
15829
|
-
return c.html(
|
|
16153
|
+
return c.html(chunkTT3TQSCZ_cjs.renderAlert({
|
|
15830
16154
|
type: "error",
|
|
15831
16155
|
message: "Failed to load user creation page. Please try again.",
|
|
15832
16156
|
dismissible: true
|
|
@@ -15843,9 +16167,9 @@ userRoutes.post("/users/new", async (c) => {
|
|
|
15843
16167
|
const email = formData.get("email")?.toString()?.trim().toLowerCase() || "";
|
|
15844
16168
|
const phone = chunkMNWKYY5E_cjs.sanitizeInput(formData.get("phone")?.toString()) || null;
|
|
15845
16169
|
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 : "
|
|
16170
|
+
const roleInput = formData.get("role")?.toString() || "";
|
|
16171
|
+
const validRoles = (await new chunkOLEOKHDX_cjs.RbacService(db).getRoles()).map((r) => r.id);
|
|
16172
|
+
const role = validRoles.includes(roleInput) ? roleInput : validRoles[0] ?? "admin";
|
|
15849
16173
|
const password = formData.get("password")?.toString() || "";
|
|
15850
16174
|
const confirmPassword = formData.get("confirm_password")?.toString() || "";
|
|
15851
16175
|
const isActive = formData.get("is_active") === "1";
|
|
@@ -15860,12 +16184,12 @@ userRoutes.post("/users/new", async (c) => {
|
|
|
15860
16184
|
const validation = validateCustomData(sanitized, profileConfig);
|
|
15861
16185
|
if (!validation.valid) {
|
|
15862
16186
|
const errorMessages = Object.values(validation.errors).join(", ");
|
|
15863
|
-
return c.html(
|
|
16187
|
+
return c.html(chunkTT3TQSCZ_cjs.renderAlert({ type: "error", message: errorMessages, dismissible: true }), 400);
|
|
15864
16188
|
}
|
|
15865
16189
|
sanitizedRegistrationCustom = sanitized;
|
|
15866
16190
|
}
|
|
15867
16191
|
if (!firstName || !lastName || !email || !password) {
|
|
15868
|
-
return c.html(
|
|
16192
|
+
return c.html(chunkTT3TQSCZ_cjs.renderAlert({
|
|
15869
16193
|
type: "error",
|
|
15870
16194
|
message: "First name, last name, email, and password are required.",
|
|
15871
16195
|
dismissible: true
|
|
@@ -15873,21 +16197,21 @@ userRoutes.post("/users/new", async (c) => {
|
|
|
15873
16197
|
}
|
|
15874
16198
|
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
15875
16199
|
if (!emailRegex.test(email)) {
|
|
15876
|
-
return c.html(
|
|
16200
|
+
return c.html(chunkTT3TQSCZ_cjs.renderAlert({
|
|
15877
16201
|
type: "error",
|
|
15878
16202
|
message: "Please enter a valid email address.",
|
|
15879
16203
|
dismissible: true
|
|
15880
16204
|
}));
|
|
15881
16205
|
}
|
|
15882
16206
|
if (password.length < 8) {
|
|
15883
|
-
return c.html(
|
|
16207
|
+
return c.html(chunkTT3TQSCZ_cjs.renderAlert({
|
|
15884
16208
|
type: "error",
|
|
15885
16209
|
message: "Password must be at least 8 characters long.",
|
|
15886
16210
|
dismissible: true
|
|
15887
16211
|
}));
|
|
15888
16212
|
}
|
|
15889
16213
|
if (password !== confirmPassword) {
|
|
15890
|
-
return c.html(
|
|
16214
|
+
return c.html(chunkTT3TQSCZ_cjs.renderAlert({
|
|
15891
16215
|
type: "error",
|
|
15892
16216
|
message: "Passwords do not match.",
|
|
15893
16217
|
dismissible: true
|
|
@@ -15899,13 +16223,13 @@ userRoutes.post("/users/new", async (c) => {
|
|
|
15899
16223
|
`);
|
|
15900
16224
|
const existingUser = await checkStmt.bind(email).first();
|
|
15901
16225
|
if (existingUser) {
|
|
15902
|
-
return c.html(
|
|
16226
|
+
return c.html(chunkTT3TQSCZ_cjs.renderAlert({
|
|
15903
16227
|
type: "error",
|
|
15904
16228
|
message: "Email is already taken.",
|
|
15905
16229
|
dismissible: true
|
|
15906
16230
|
}));
|
|
15907
16231
|
}
|
|
15908
|
-
const passwordHash = await
|
|
16232
|
+
const passwordHash = await chunkBRKXMRMB_cjs.AuthManager.hashPassword(password);
|
|
15909
16233
|
const userId = crypto.randomUUID();
|
|
15910
16234
|
const createStmt = db.prepare(`
|
|
15911
16235
|
INSERT INTO auth_user (
|
|
@@ -15930,7 +16254,7 @@ userRoutes.post("/users/new", async (c) => {
|
|
|
15930
16254
|
if (sanitizedRegistrationCustom !== null && Object.keys(sanitizedRegistrationCustom).length > 0) {
|
|
15931
16255
|
await writeProfileData(db, userId, { custom: sanitizedRegistrationCustom }, user.userId);
|
|
15932
16256
|
}
|
|
15933
|
-
await
|
|
16257
|
+
await chunkBRKXMRMB_cjs.logActivity(
|
|
15934
16258
|
db,
|
|
15935
16259
|
user.userId,
|
|
15936
16260
|
"user!.create",
|
|
@@ -15944,7 +16268,7 @@ userRoutes.post("/users/new", async (c) => {
|
|
|
15944
16268
|
return c.body(null, 200);
|
|
15945
16269
|
} catch (error) {
|
|
15946
16270
|
console.error("User creation error:", error);
|
|
15947
|
-
return c.html(
|
|
16271
|
+
return c.html(chunkTT3TQSCZ_cjs.renderAlert({
|
|
15948
16272
|
type: "error",
|
|
15949
16273
|
message: "Failed to create user!. Please try again.",
|
|
15950
16274
|
dismissible: true
|
|
@@ -15969,7 +16293,7 @@ userRoutes.get("/users/:id", async (c) => {
|
|
|
15969
16293
|
if (!userRecord) {
|
|
15970
16294
|
return c.json({ error: "User not found" }, 404);
|
|
15971
16295
|
}
|
|
15972
|
-
await
|
|
16296
|
+
await chunkBRKXMRMB_cjs.logActivity(
|
|
15973
16297
|
db,
|
|
15974
16298
|
user.userId,
|
|
15975
16299
|
"user!.view",
|
|
@@ -16014,7 +16338,7 @@ userRoutes.get("/users/:id/edit", async (c) => {
|
|
|
16014
16338
|
`);
|
|
16015
16339
|
const userToEdit = await userStmt.bind(userId).first();
|
|
16016
16340
|
if (!userToEdit) {
|
|
16017
|
-
return c.html(
|
|
16341
|
+
return c.html(chunkTT3TQSCZ_cjs.renderAlert({
|
|
16018
16342
|
type: "error",
|
|
16019
16343
|
message: "User not found",
|
|
16020
16344
|
dismissible: true
|
|
@@ -16067,9 +16391,10 @@ userRoutes.get("/users/:id/edit", async (c) => {
|
|
|
16067
16391
|
}
|
|
16068
16392
|
const queryMessage = c.req.query("message");
|
|
16069
16393
|
const queryType = c.req.query("type") === "error" ? "error" : "success";
|
|
16394
|
+
const roles = await fetchRoleOptions(db);
|
|
16070
16395
|
const pageData = {
|
|
16071
16396
|
userToEdit: editData,
|
|
16072
|
-
roles
|
|
16397
|
+
roles,
|
|
16073
16398
|
hasProfilePlugin: profileConfig !== null && upRow !== null,
|
|
16074
16399
|
customProfileFieldsHtml,
|
|
16075
16400
|
tenantMemberships,
|
|
@@ -16084,7 +16409,7 @@ userRoutes.get("/users/:id/edit", async (c) => {
|
|
|
16084
16409
|
return c.html(renderUserEditPage(pageData));
|
|
16085
16410
|
} catch (error) {
|
|
16086
16411
|
console.error("User edit page error:", error);
|
|
16087
|
-
return c.html(
|
|
16412
|
+
return c.html(chunkTT3TQSCZ_cjs.renderAlert({
|
|
16088
16413
|
type: "error",
|
|
16089
16414
|
message: "Failed to load user. Please try again.",
|
|
16090
16415
|
dismissible: true
|
|
@@ -16101,9 +16426,9 @@ userRoutes.put("/users/:id", async (c) => {
|
|
|
16101
16426
|
const lastName = chunkMNWKYY5E_cjs.sanitizeInput(formData.get("last_name")?.toString());
|
|
16102
16427
|
const email = formData.get("email")?.toString()?.trim().toLowerCase() || "";
|
|
16103
16428
|
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 : "
|
|
16429
|
+
const roleInput = formData.get("role")?.toString() || "";
|
|
16430
|
+
const validRoles = (await new chunkOLEOKHDX_cjs.RbacService(db).getRoles()).map((r) => r.id);
|
|
16431
|
+
const role = validRoles.includes(roleInput) ? roleInput : validRoles[0] ?? "admin";
|
|
16107
16432
|
const isActive = formData.get("is_active") === "1";
|
|
16108
16433
|
const emailVerified = formData.get("email_verified") === "1";
|
|
16109
16434
|
const newPassword = formData.get("new_password")?.toString() || "";
|
|
@@ -16117,12 +16442,12 @@ userRoutes.put("/users/:id", async (c) => {
|
|
|
16117
16442
|
const validation = validateCustomData(sanitized, profileConfig);
|
|
16118
16443
|
if (!validation.valid) {
|
|
16119
16444
|
const errorMessages = Object.values(validation.errors).join(", ");
|
|
16120
|
-
return c.html(
|
|
16445
|
+
return c.html(chunkTT3TQSCZ_cjs.renderAlert({ type: "error", message: errorMessages, dismissible: true }), 400);
|
|
16121
16446
|
}
|
|
16122
16447
|
sanitizedCustom = sanitized;
|
|
16123
16448
|
}
|
|
16124
16449
|
if (!email) {
|
|
16125
|
-
return c.html(
|
|
16450
|
+
return c.html(chunkTT3TQSCZ_cjs.renderAlert({
|
|
16126
16451
|
type: "error",
|
|
16127
16452
|
message: "Email is required.",
|
|
16128
16453
|
dismissible: true
|
|
@@ -16130,7 +16455,7 @@ userRoutes.put("/users/:id", async (c) => {
|
|
|
16130
16455
|
}
|
|
16131
16456
|
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
16132
16457
|
if (!emailRegex.test(email)) {
|
|
16133
|
-
return c.html(
|
|
16458
|
+
return c.html(chunkTT3TQSCZ_cjs.renderAlert({
|
|
16134
16459
|
type: "error",
|
|
16135
16460
|
message: "Please enter a valid email address.",
|
|
16136
16461
|
dismissible: true
|
|
@@ -16138,14 +16463,14 @@ userRoutes.put("/users/:id", async (c) => {
|
|
|
16138
16463
|
}
|
|
16139
16464
|
if (newPassword) {
|
|
16140
16465
|
if (newPassword.length < 8) {
|
|
16141
|
-
return c.html(
|
|
16466
|
+
return c.html(chunkTT3TQSCZ_cjs.renderAlert({
|
|
16142
16467
|
type: "error",
|
|
16143
16468
|
message: "Password must be at least 8 characters long.",
|
|
16144
16469
|
dismissible: true
|
|
16145
16470
|
}));
|
|
16146
16471
|
}
|
|
16147
16472
|
if (newPassword !== confirmPassword) {
|
|
16148
|
-
return c.html(
|
|
16473
|
+
return c.html(chunkTT3TQSCZ_cjs.renderAlert({
|
|
16149
16474
|
type: "error",
|
|
16150
16475
|
message: "Passwords do not match.",
|
|
16151
16476
|
dismissible: true
|
|
@@ -16158,7 +16483,7 @@ userRoutes.put("/users/:id", async (c) => {
|
|
|
16158
16483
|
`);
|
|
16159
16484
|
const existingUser = await checkStmt.bind(email, userId).first();
|
|
16160
16485
|
if (existingUser) {
|
|
16161
|
-
return c.html(
|
|
16486
|
+
return c.html(chunkTT3TQSCZ_cjs.renderAlert({
|
|
16162
16487
|
type: "error",
|
|
16163
16488
|
message: "Email is already taken by another user.",
|
|
16164
16489
|
dismissible: true
|
|
@@ -16183,7 +16508,7 @@ userRoutes.put("/users/:id", async (c) => {
|
|
|
16183
16508
|
userId
|
|
16184
16509
|
).run();
|
|
16185
16510
|
if (newPassword) {
|
|
16186
|
-
const passwordHash = await
|
|
16511
|
+
const passwordHash = await chunkBRKXMRMB_cjs.AuthManager.hashPassword(newPassword);
|
|
16187
16512
|
const updatePasswordStmt = db.prepare(`
|
|
16188
16513
|
UPDATE auth_user SET password_hash = ?, updated_at = ? WHERE id = ?
|
|
16189
16514
|
`);
|
|
@@ -16196,7 +16521,7 @@ userRoutes.put("/users/:id", async (c) => {
|
|
|
16196
16521
|
...sanitizedCustom !== null ? { custom: sanitizedCustom } : {}
|
|
16197
16522
|
}, user.userId);
|
|
16198
16523
|
}
|
|
16199
|
-
await
|
|
16524
|
+
await chunkBRKXMRMB_cjs.logActivity(
|
|
16200
16525
|
db,
|
|
16201
16526
|
user.userId,
|
|
16202
16527
|
"user.update",
|
|
@@ -16206,7 +16531,7 @@ userRoutes.put("/users/:id", async (c) => {
|
|
|
16206
16531
|
c.req.header("x-forwarded-for") || c.req.header("cf-connecting-ip"),
|
|
16207
16532
|
c.req.header("user-agent")
|
|
16208
16533
|
);
|
|
16209
|
-
return c.html(
|
|
16534
|
+
return c.html(chunkTT3TQSCZ_cjs.renderAlert({
|
|
16210
16535
|
type: "success",
|
|
16211
16536
|
message: "User updated successfully!",
|
|
16212
16537
|
dismissible: true,
|
|
@@ -16214,7 +16539,7 @@ userRoutes.put("/users/:id", async (c) => {
|
|
|
16214
16539
|
}));
|
|
16215
16540
|
} catch (error) {
|
|
16216
16541
|
console.error("User update error:", error);
|
|
16217
|
-
return c.html(
|
|
16542
|
+
return c.html(chunkTT3TQSCZ_cjs.renderAlert({
|
|
16218
16543
|
type: "error",
|
|
16219
16544
|
message: "Failed to update user. Please try again.",
|
|
16220
16545
|
dismissible: true
|
|
@@ -16242,7 +16567,7 @@ userRoutes.post("/users/:id/toggle", async (c) => {
|
|
|
16242
16567
|
UPDATE auth_user SET is_active = ?, updated_at = ? WHERE id = ?
|
|
16243
16568
|
`);
|
|
16244
16569
|
await toggleStmt.bind(active ? 1 : 0, Date.now(), userId).run();
|
|
16245
|
-
await
|
|
16570
|
+
await chunkBRKXMRMB_cjs.logActivity(
|
|
16246
16571
|
db,
|
|
16247
16572
|
user.userId,
|
|
16248
16573
|
active ? "user.activate" : "user.deactivate",
|
|
@@ -16283,7 +16608,7 @@ userRoutes.delete("/users/:id", async (c) => {
|
|
|
16283
16608
|
DELETE FROM auth_user WHERE id = ?
|
|
16284
16609
|
`);
|
|
16285
16610
|
await deleteStmt.bind(userId).run();
|
|
16286
|
-
await
|
|
16611
|
+
await chunkBRKXMRMB_cjs.logActivity(
|
|
16287
16612
|
db,
|
|
16288
16613
|
user.userId,
|
|
16289
16614
|
"user!.hard_delete",
|
|
@@ -16302,7 +16627,7 @@ userRoutes.delete("/users/:id", async (c) => {
|
|
|
16302
16627
|
UPDATE auth_user SET is_active = 0, updated_at = ? WHERE id = ?
|
|
16303
16628
|
`);
|
|
16304
16629
|
await deleteStmt.bind(Date.now(), userId).run();
|
|
16305
|
-
await
|
|
16630
|
+
await chunkBRKXMRMB_cjs.logActivity(
|
|
16306
16631
|
db,
|
|
16307
16632
|
user.userId,
|
|
16308
16633
|
"user!.soft_delete",
|
|
@@ -16368,7 +16693,7 @@ userRoutes.post("/invite-user", async (c) => {
|
|
|
16368
16693
|
Date.now(),
|
|
16369
16694
|
Date.now()
|
|
16370
16695
|
).run();
|
|
16371
|
-
await
|
|
16696
|
+
await chunkBRKXMRMB_cjs.logActivity(
|
|
16372
16697
|
db,
|
|
16373
16698
|
user.userId,
|
|
16374
16699
|
"user!.invite_sent",
|
|
@@ -16425,7 +16750,7 @@ userRoutes.post("/resend-invitation/:id", async (c) => {
|
|
|
16425
16750
|
Date.now(),
|
|
16426
16751
|
userId
|
|
16427
16752
|
).run();
|
|
16428
|
-
await
|
|
16753
|
+
await chunkBRKXMRMB_cjs.logActivity(
|
|
16429
16754
|
db,
|
|
16430
16755
|
user.userId,
|
|
16431
16756
|
"user!.invitation_resent",
|
|
@@ -16461,7 +16786,7 @@ userRoutes.delete("/cancel-invitation/:id", async (c) => {
|
|
|
16461
16786
|
}
|
|
16462
16787
|
const deleteStmt = db.prepare(`DELETE FROM auth_user WHERE id = ?`);
|
|
16463
16788
|
await deleteStmt.bind(userId).run();
|
|
16464
|
-
await
|
|
16789
|
+
await chunkBRKXMRMB_cjs.logActivity(
|
|
16465
16790
|
db,
|
|
16466
16791
|
user.userId,
|
|
16467
16792
|
"user!.invitation_cancelled",
|
|
@@ -16710,7 +17035,7 @@ function getFileIcon(mimeType) {
|
|
|
16710
17035
|
}
|
|
16711
17036
|
|
|
16712
17037
|
// src/templates/pages/admin-media-library.template.ts
|
|
16713
|
-
|
|
17038
|
+
chunkMI2YXCK4_cjs.init_admin_layout_catalyst_template();
|
|
16714
17039
|
function renderMediaLibraryPage(data) {
|
|
16715
17040
|
const pageContent = `
|
|
16716
17041
|
<div>
|
|
@@ -17645,7 +17970,7 @@ function renderMediaLibraryPage(data) {
|
|
|
17645
17970
|
version: data.version,
|
|
17646
17971
|
content: pageContent
|
|
17647
17972
|
};
|
|
17648
|
-
return
|
|
17973
|
+
return chunkMI2YXCK4_cjs.renderAdminLayoutCatalyst(layoutData);
|
|
17649
17974
|
}
|
|
17650
17975
|
|
|
17651
17976
|
// src/templates/components/media-file-details.template.ts
|
|
@@ -17842,7 +18167,7 @@ var fileValidationSchema2 = zod.z.object({
|
|
|
17842
18167
|
// 50MB max
|
|
17843
18168
|
});
|
|
17844
18169
|
var adminMediaRoutes = new hono.Hono();
|
|
17845
|
-
adminMediaRoutes.use("*",
|
|
18170
|
+
adminMediaRoutes.use("*", chunkBRKXMRMB_cjs.requireAuth());
|
|
17846
18171
|
adminMediaRoutes.get("/", async (c) => {
|
|
17847
18172
|
try {
|
|
17848
18173
|
const user = c.get("user");
|
|
@@ -17884,7 +18209,7 @@ adminMediaRoutes.get("/selector", async (c) => {
|
|
|
17884
18209
|
const { searchParams } = new URL(c.req.url);
|
|
17885
18210
|
const search = searchParams.get("search") || "";
|
|
17886
18211
|
const db = c.env.DB;
|
|
17887
|
-
const pluginService = new
|
|
18212
|
+
const pluginService = new chunk4DHPR7KR_cjs.PluginService(db);
|
|
17888
18213
|
const mediaPlugin = await pluginService.getPlugin("core-media");
|
|
17889
18214
|
if (!mediaPlugin || mediaPlugin.status !== "active") {
|
|
17890
18215
|
return c.html(html.html`
|
|
@@ -18260,7 +18585,7 @@ adminMediaRoutes.put("/:id", async (c) => {
|
|
|
18260
18585
|
`);
|
|
18261
18586
|
}
|
|
18262
18587
|
});
|
|
18263
|
-
adminMediaRoutes.delete("/cleanup",
|
|
18588
|
+
adminMediaRoutes.delete("/cleanup", chunkBRKXMRMB_cjs.requireRole("admin"), async (c) => {
|
|
18264
18589
|
try {
|
|
18265
18590
|
const db = c.env.DB;
|
|
18266
18591
|
const allMediaStmt = db.prepare("SELECT id, r2_key, filename FROM media WHERE deleted_at IS NULL");
|
|
@@ -18518,7 +18843,7 @@ function generateMediaItemHTML(file) {
|
|
|
18518
18843
|
}
|
|
18519
18844
|
|
|
18520
18845
|
// src/templates/pages/admin-plugins-list.template.ts
|
|
18521
|
-
|
|
18846
|
+
chunkMI2YXCK4_cjs.init_admin_layout_catalyst_template();
|
|
18522
18847
|
function renderPluginsListPage(data) {
|
|
18523
18848
|
const categories = [
|
|
18524
18849
|
{ value: "content", label: "Content Management" },
|
|
@@ -18690,15 +19015,6 @@ function renderPluginsListPage(data) {
|
|
|
18690
19015
|
</div>
|
|
18691
19016
|
|
|
18692
19017
|
<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
19018
|
<button
|
|
18703
19019
|
onclick="location.reload()"
|
|
18704
19020
|
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 +19178,6 @@ function renderPluginsListPage(data) {
|
|
|
18862
19178
|
.forEach(cb => params.append('status', cb.value));
|
|
18863
19179
|
const search = document.getElementById('search-input').value;
|
|
18864
19180
|
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
19181
|
const url = new URL(window.location.href);
|
|
18868
19182
|
url.search = params.toString();
|
|
18869
19183
|
history.replaceState(null, '', url.toString());
|
|
@@ -18881,8 +19195,6 @@ function renderPluginsListPage(data) {
|
|
|
18881
19195
|
});
|
|
18882
19196
|
const search = params.get('search');
|
|
18883
19197
|
if (search) document.getElementById('search-input').value = search;
|
|
18884
|
-
const sort = params.get('sort');
|
|
18885
|
-
if (sort) document.getElementById('sort-filter').value = sort;
|
|
18886
19198
|
if (params.toString()) filterAndSortPlugins();
|
|
18887
19199
|
}
|
|
18888
19200
|
|
|
@@ -18898,7 +19210,6 @@ function renderPluginsListPage(data) {
|
|
|
18898
19210
|
.map(cb => cb.value.toLowerCase());
|
|
18899
19211
|
|
|
18900
19212
|
const searchInput = document.getElementById('search-input').value.toLowerCase();
|
|
18901
|
-
const sortValue = document.getElementById('sort-filter').value;
|
|
18902
19213
|
|
|
18903
19214
|
const pluginsGrid = document.getElementById('plugins-grid');
|
|
18904
19215
|
const pluginCards = Array.from(pluginsGrid.querySelectorAll('.plugin-card'));
|
|
@@ -18922,30 +19233,6 @@ function renderPluginsListPage(data) {
|
|
|
18922
19233
|
return true;
|
|
18923
19234
|
});
|
|
18924
19235
|
|
|
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
19236
|
// Re-append
|
|
18950
19237
|
pluginCards.forEach(card => card.style.display = 'none'); // Hide all first
|
|
18951
19238
|
|
|
@@ -19001,7 +19288,7 @@ function renderPluginsListPage(data) {
|
|
|
19001
19288
|
version: data.version,
|
|
19002
19289
|
content: pageContent
|
|
19003
19290
|
};
|
|
19004
|
-
return
|
|
19291
|
+
return chunkMI2YXCK4_cjs.renderAdminLayoutCatalyst(layoutData);
|
|
19005
19292
|
}
|
|
19006
19293
|
function renderPluginCard(plugin) {
|
|
19007
19294
|
const statusColors = {
|
|
@@ -19379,8 +19666,9 @@ function escapeHtmlAttr(value) {
|
|
|
19379
19666
|
}
|
|
19380
19667
|
function renderPluginSettingsPage(data) {
|
|
19381
19668
|
const { plugin, activity = [], user, settingsTabData } = data;
|
|
19382
|
-
const pluginDef =
|
|
19383
|
-
const
|
|
19669
|
+
const pluginDef = chunkKWQNB6UM_cjs.getPluginDefinition(plugin.id || plugin.name);
|
|
19670
|
+
const pluginId = plugin.id || plugin.name;
|
|
19671
|
+
const hasUserSettings = pluginDef?.settingsTabContent != null || Object.keys(plugin.settings || {}).some((k) => !k.startsWith("_")) || hasCustomSettingsComponent(pluginId);
|
|
19384
19672
|
const defaultTab = hasUserSettings ? "settings" : "info";
|
|
19385
19673
|
const pageContent = `
|
|
19386
19674
|
<div class="w-full px-4 sm:px-6 lg:px-8 py-6">
|
|
@@ -19545,9 +19833,28 @@ function renderPluginSettingsPage(data) {
|
|
|
19545
19833
|
const form = document.getElementById('settings-form');
|
|
19546
19834
|
const formData = new FormData(form);
|
|
19547
19835
|
const isAuthPlugin = '${plugin.id}' === 'core-auth';
|
|
19836
|
+
const isOAuthPlugin = '${plugin.id}' === 'oauth-providers';
|
|
19548
19837
|
let settings = {};
|
|
19549
19838
|
|
|
19550
|
-
if (
|
|
19839
|
+
if (isOAuthPlugin) {
|
|
19840
|
+
// Build nested provider settings structure
|
|
19841
|
+
const getVal = id => (document.getElementById(id) || {}).value || '';
|
|
19842
|
+
const getChecked = id => !!(document.getElementById(id) || {}).checked;
|
|
19843
|
+
settings = {
|
|
19844
|
+
providers: {
|
|
19845
|
+
github: {
|
|
19846
|
+
clientId: getVal('oauth_github_clientId'),
|
|
19847
|
+
clientSecret: getVal('oauth_github_clientSecret'),
|
|
19848
|
+
enabled: getChecked('oauth_github_enabled'),
|
|
19849
|
+
},
|
|
19850
|
+
google: {
|
|
19851
|
+
clientId: getVal('oauth_google_clientId'),
|
|
19852
|
+
clientSecret: getVal('oauth_google_clientSecret'),
|
|
19853
|
+
enabled: getChecked('oauth_google_enabled'),
|
|
19854
|
+
},
|
|
19855
|
+
}
|
|
19856
|
+
};
|
|
19857
|
+
} else if (isAuthPlugin) {
|
|
19551
19858
|
// Handle nested auth settings structure
|
|
19552
19859
|
settings = {
|
|
19553
19860
|
requiredFields: {},
|
|
@@ -19656,7 +19963,7 @@ function renderPluginSettingsPage(data) {
|
|
|
19656
19963
|
user,
|
|
19657
19964
|
content: pageContent
|
|
19658
19965
|
};
|
|
19659
|
-
return
|
|
19966
|
+
return chunkOUBUS74I_cjs.renderAdminLayout(layoutData);
|
|
19660
19967
|
}
|
|
19661
19968
|
function renderStatusBadge(status) {
|
|
19662
19969
|
const statusColors = {
|
|
@@ -19685,7 +19992,7 @@ function renderSettingsTab(plugin, settingsTabData) {
|
|
|
19685
19992
|
const settings = plugin.settings || {};
|
|
19686
19993
|
const pluginId = plugin.id || plugin.name;
|
|
19687
19994
|
const hasUserKeys = Object.keys(settings).some((k) => !k.startsWith("_"));
|
|
19688
|
-
const pluginDef =
|
|
19995
|
+
const pluginDef = chunkKWQNB6UM_cjs.getPluginDefinition(pluginId);
|
|
19689
19996
|
if (pluginDef?.settingsTabContent) {
|
|
19690
19997
|
return pluginDef.settingsTabContent.render({ plugin, settings, data: settingsTabData });
|
|
19691
19998
|
}
|
|
@@ -20035,7 +20342,8 @@ function formatTimestamp(timestamp) {
|
|
|
20035
20342
|
}
|
|
20036
20343
|
var pluginSettingsComponents = {
|
|
20037
20344
|
"otp-login": renderOTPLoginSettingsContent,
|
|
20038
|
-
"email": renderEmailSettingsContent
|
|
20345
|
+
"email": renderEmailSettingsContent,
|
|
20346
|
+
"oauth-providers": renderOAuthProvidersSettingsContent
|
|
20039
20347
|
};
|
|
20040
20348
|
function renderOTPLoginSettingsContent(plugin, settings) {
|
|
20041
20349
|
const siteName = settings.siteName || "SonicJS";
|
|
@@ -20758,6 +21066,62 @@ defineUserProfile({
|
|
|
20758
21066
|
</div>
|
|
20759
21067
|
`;
|
|
20760
21068
|
}
|
|
21069
|
+
function renderOAuthProvidersSettingsContent(plugin, settings) {
|
|
21070
|
+
const providers = settings.providers || {};
|
|
21071
|
+
const gh = providers.github || {};
|
|
21072
|
+
const gg = providers.google || {};
|
|
21073
|
+
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";
|
|
21074
|
+
return `
|
|
21075
|
+
<div class="space-y-6">
|
|
21076
|
+
<form id="settings-form">
|
|
21077
|
+
<div class="backdrop-blur-md bg-white/5 rounded-xl border border-white/10 p-6 space-y-6">
|
|
21078
|
+
<h3 class="text-lg font-semibold text-white">GitHub OAuth</h3>
|
|
21079
|
+
<div>
|
|
21080
|
+
<label for="oauth_github_clientId" class="block text-sm font-medium text-gray-300 mb-2">Client ID</label>
|
|
21081
|
+
<input type="text" id="oauth_github_clientId" name="oauth_github_clientId"
|
|
21082
|
+
value="${escapeHtmlAttr(gh.clientId || "")}"
|
|
21083
|
+
placeholder="GitHub OAuth App Client ID" class="${inputClass}" />
|
|
21084
|
+
</div>
|
|
21085
|
+
<div>
|
|
21086
|
+
<label for="oauth_github_clientSecret" class="block text-sm font-medium text-gray-300 mb-2">Client Secret</label>
|
|
21087
|
+
<input type="password" id="oauth_github_clientSecret" name="oauth_github_clientSecret"
|
|
21088
|
+
value="${escapeHtmlAttr(gh.clientSecret || "")}"
|
|
21089
|
+
placeholder="GitHub OAuth App Client Secret" class="${inputClass}" />
|
|
21090
|
+
</div>
|
|
21091
|
+
<div class="flex items-center gap-3">
|
|
21092
|
+
<input type="checkbox" id="oauth_github_enabled" name="oauth_github_enabled"
|
|
21093
|
+
${gh.enabled ? "checked" : ""} class="w-4 h-4 rounded border-white/10" />
|
|
21094
|
+
<label for="oauth_github_enabled" class="text-sm text-gray-300">Enable GitHub login</label>
|
|
21095
|
+
</div>
|
|
21096
|
+
</div>
|
|
21097
|
+
|
|
21098
|
+
<div class="backdrop-blur-md bg-white/5 rounded-xl border border-white/10 p-6 space-y-6 mt-6">
|
|
21099
|
+
<h3 class="text-lg font-semibold text-white">Google OAuth</h3>
|
|
21100
|
+
<div>
|
|
21101
|
+
<label for="oauth_google_clientId" class="block text-sm font-medium text-gray-300 mb-2">Client ID</label>
|
|
21102
|
+
<input type="text" id="oauth_google_clientId" name="oauth_google_clientId"
|
|
21103
|
+
value="${escapeHtmlAttr(gg.clientId || "")}"
|
|
21104
|
+
placeholder="Google OAuth Client ID" class="${inputClass}" />
|
|
21105
|
+
</div>
|
|
21106
|
+
<div>
|
|
21107
|
+
<label for="oauth_google_clientSecret" class="block text-sm font-medium text-gray-300 mb-2">Client Secret</label>
|
|
21108
|
+
<input type="password" id="oauth_google_clientSecret" name="oauth_google_clientSecret"
|
|
21109
|
+
value="${escapeHtmlAttr(gg.clientSecret || "")}"
|
|
21110
|
+
placeholder="Google OAuth Client Secret" class="${inputClass}" />
|
|
21111
|
+
</div>
|
|
21112
|
+
<div class="flex items-center gap-3">
|
|
21113
|
+
<input type="checkbox" id="oauth_google_enabled" name="oauth_google_enabled"
|
|
21114
|
+
${gg.enabled ? "checked" : ""} class="w-4 h-4 rounded border-white/10" />
|
|
21115
|
+
<label for="oauth_google_enabled" class="text-sm text-gray-300">Enable Google login</label>
|
|
21116
|
+
</div>
|
|
21117
|
+
</div>
|
|
21118
|
+
</form>
|
|
21119
|
+
</div>
|
|
21120
|
+
`;
|
|
21121
|
+
}
|
|
21122
|
+
function hasCustomSettingsComponent(pluginId) {
|
|
21123
|
+
return pluginId in pluginSettingsComponents;
|
|
21124
|
+
}
|
|
20761
21125
|
|
|
20762
21126
|
// src/plugins/core-plugins/menu-plugin/services/menu-reconcile.ts
|
|
20763
21127
|
async function upsertPluginRow(db, slug, entry, visible) {
|
|
@@ -20875,8 +21239,8 @@ async function fetchActivePluginIds(db) {
|
|
|
20875
21239
|
}
|
|
20876
21240
|
async function reconcileMenuFromPlugins(db) {
|
|
20877
21241
|
try {
|
|
20878
|
-
const singletonEntries =
|
|
20879
|
-
const manifestEntries = Object.values(
|
|
21242
|
+
const singletonEntries = chunkKWQNB6UM_cjs.getPluginMenu();
|
|
21243
|
+
const manifestEntries = Object.values(chunk4DHPR7KR_cjs.PLUGIN_REGISTRY).filter(
|
|
20880
21244
|
(p) => p.adminMenu !== null
|
|
20881
21245
|
);
|
|
20882
21246
|
const byPluginId = /* @__PURE__ */ new Map();
|
|
@@ -20913,8 +21277,8 @@ async function reconcileMenuFromPlugins(db) {
|
|
|
20913
21277
|
|
|
20914
21278
|
// src/routes/admin-plugins.ts
|
|
20915
21279
|
var adminPluginRoutes = new hono.Hono();
|
|
20916
|
-
adminPluginRoutes.use("*",
|
|
20917
|
-
var AVAILABLE_PLUGINS = Object.values(
|
|
21280
|
+
adminPluginRoutes.use("*", chunkBRKXMRMB_cjs.requireAuth());
|
|
21281
|
+
var AVAILABLE_PLUGINS = Object.values(chunk4DHPR7KR_cjs.PLUGIN_REGISTRY).map((p) => ({
|
|
20918
21282
|
id: p.id,
|
|
20919
21283
|
name: p.codeName,
|
|
20920
21284
|
display_name: p.displayName,
|
|
@@ -20934,7 +21298,7 @@ adminPluginRoutes.get("/", async (c) => {
|
|
|
20934
21298
|
if (user?.role !== "admin") {
|
|
20935
21299
|
return c.text("Access denied", 403);
|
|
20936
21300
|
}
|
|
20937
|
-
const pluginService = new
|
|
21301
|
+
const pluginService = new chunk4DHPR7KR_cjs.PluginService(db);
|
|
20938
21302
|
let installedPlugins = [];
|
|
20939
21303
|
let stats = { total: 0, active: 0, inactive: 0, errors: 0, uninstalled: 0 };
|
|
20940
21304
|
try {
|
|
@@ -21008,10 +21372,10 @@ adminPluginRoutes.get("/:id", async (c) => {
|
|
|
21008
21372
|
if (user?.role !== "admin") {
|
|
21009
21373
|
return c.redirect("/admin/plugins");
|
|
21010
21374
|
}
|
|
21011
|
-
const pluginService = new
|
|
21375
|
+
const pluginService = new chunk4DHPR7KR_cjs.PluginService(db);
|
|
21012
21376
|
let plugin = await pluginService.getPlugin(pluginId);
|
|
21013
21377
|
if (!plugin) {
|
|
21014
|
-
const def =
|
|
21378
|
+
const def = chunkKWQNB6UM_cjs.getPluginDefinition(pluginId);
|
|
21015
21379
|
if (!def) return c.text("Plugin not found", 404);
|
|
21016
21380
|
plugin = await pluginService.ensurePlugin(pluginId, {
|
|
21017
21381
|
displayName: def.displayName ?? pluginId,
|
|
@@ -21023,7 +21387,7 @@ adminPluginRoutes.get("/:id", async (c) => {
|
|
|
21023
21387
|
const activity = await pluginService.getPluginActivity(pluginId, 20);
|
|
21024
21388
|
let enrichedSettings = plugin.settings || {};
|
|
21025
21389
|
if (pluginId === "otp-login") {
|
|
21026
|
-
const settingsService = new
|
|
21390
|
+
const settingsService = new chunkC5LDQ3SH_cjs.SettingsService(db);
|
|
21027
21391
|
const generalSettings = await settingsService.getGeneralSettings();
|
|
21028
21392
|
const siteName = generalSettings.siteName || "SonicJS";
|
|
21029
21393
|
const emailPlugin = await db.prepare(`
|
|
@@ -21082,7 +21446,7 @@ adminPluginRoutes.get("/:id", async (c) => {
|
|
|
21082
21446
|
timestamp: item.timestamp,
|
|
21083
21447
|
user: item.userId || null
|
|
21084
21448
|
}));
|
|
21085
|
-
const pluginDef =
|
|
21449
|
+
const pluginDef = chunkKWQNB6UM_cjs.getPluginDefinition(pluginId);
|
|
21086
21450
|
let settingsTabData = void 0;
|
|
21087
21451
|
if (pluginDef?.settingsTabContent?.loadData) {
|
|
21088
21452
|
try {
|
|
@@ -21112,14 +21476,14 @@ adminPluginRoutes.get("/:id/configure", async (c) => {
|
|
|
21112
21476
|
const user = c.get("user");
|
|
21113
21477
|
const pluginId = c.req.param("id");
|
|
21114
21478
|
if (user?.role !== "admin") return c.redirect("/admin/plugins");
|
|
21115
|
-
const def =
|
|
21479
|
+
const def = chunkKWQNB6UM_cjs.getPluginDefinition(pluginId);
|
|
21116
21480
|
if (!def?.configSchema) return c.text("No schema-driven settings for this plugin", 404);
|
|
21117
21481
|
const db = c.env.DB;
|
|
21118
|
-
const pluginService = new
|
|
21482
|
+
const pluginService = new chunk4DHPR7KR_cjs.PluginService(db);
|
|
21119
21483
|
const plugin = await pluginService.getPlugin(pluginId);
|
|
21120
21484
|
const stored = plugin?.settings ?? {};
|
|
21121
|
-
const values =
|
|
21122
|
-
const fieldsHtml =
|
|
21485
|
+
const values = chunkKWQNB6UM_cjs.applySchemaDefaults(def.configSchema, stored);
|
|
21486
|
+
const fieldsHtml = chunkKWQNB6UM_cjs.renderSchemaFields(def.configSchema, values);
|
|
21123
21487
|
const displayName = plugin?.display_name ?? def.displayName ?? def.id;
|
|
21124
21488
|
return c.html(`<!DOCTYPE html>
|
|
21125
21489
|
<html lang="en"><head>
|
|
@@ -21146,12 +21510,12 @@ adminPluginRoutes.post("/:id/configure", async (c) => {
|
|
|
21146
21510
|
const user = c.get("user");
|
|
21147
21511
|
const pluginId = c.req.param("id");
|
|
21148
21512
|
if (user?.role !== "admin") return c.json({ error: "Access denied" }, 403);
|
|
21149
|
-
const def =
|
|
21513
|
+
const def = chunkKWQNB6UM_cjs.getPluginDefinition(pluginId);
|
|
21150
21514
|
if (!def?.configSchema) return c.text("No schema-driven settings for this plugin", 404);
|
|
21151
21515
|
const form = await c.req.formData();
|
|
21152
|
-
const parsed =
|
|
21516
|
+
const parsed = chunkKWQNB6UM_cjs.parseFormDataToSettings(def.configSchema, form);
|
|
21153
21517
|
const db = c.env.DB;
|
|
21154
|
-
const pluginService = new
|
|
21518
|
+
const pluginService = new chunk4DHPR7KR_cjs.PluginService(db);
|
|
21155
21519
|
await pluginService.ensurePlugin(pluginId, {
|
|
21156
21520
|
displayName: def.displayName ?? pluginId,
|
|
21157
21521
|
version: def.version,
|
|
@@ -21175,7 +21539,7 @@ adminPluginRoutes.post("/:id/activate", async (c) => {
|
|
|
21175
21539
|
if (user?.role !== "admin") {
|
|
21176
21540
|
return c.json({ error: "Access denied" }, 403);
|
|
21177
21541
|
}
|
|
21178
|
-
const pluginService = new
|
|
21542
|
+
const pluginService = new chunk4DHPR7KR_cjs.PluginService(db);
|
|
21179
21543
|
await pluginService.activatePlugin(pluginId);
|
|
21180
21544
|
await reconcileMenuFromPlugins(db);
|
|
21181
21545
|
return c.json({ success: true });
|
|
@@ -21193,7 +21557,7 @@ adminPluginRoutes.post("/:id/deactivate", async (c) => {
|
|
|
21193
21557
|
if (user?.role !== "admin") {
|
|
21194
21558
|
return c.json({ error: "Access denied" }, 403);
|
|
21195
21559
|
}
|
|
21196
|
-
const pluginService = new
|
|
21560
|
+
const pluginService = new chunk4DHPR7KR_cjs.PluginService(db);
|
|
21197
21561
|
await pluginService.deactivatePlugin(pluginId);
|
|
21198
21562
|
await reconcileMenuFromPlugins(db);
|
|
21199
21563
|
return c.json({ success: true });
|
|
@@ -21211,8 +21575,8 @@ adminPluginRoutes.post("/install", async (c) => {
|
|
|
21211
21575
|
return c.json({ error: "Access denied" }, 403);
|
|
21212
21576
|
}
|
|
21213
21577
|
const body = await c.req.json();
|
|
21214
|
-
const pluginService = new
|
|
21215
|
-
const registryEntry =
|
|
21578
|
+
const pluginService = new chunk4DHPR7KR_cjs.PluginService(db);
|
|
21579
|
+
const registryEntry = chunk4DHPR7KR_cjs.findPluginByCodeName(body.name) || chunk4DHPR7KR_cjs.PLUGIN_REGISTRY[body.name] || chunk4DHPR7KR_cjs.PLUGIN_REGISTRY[body.id];
|
|
21216
21580
|
if (!registryEntry) {
|
|
21217
21581
|
return c.json({ error: "Plugin not found in registry" }, 404);
|
|
21218
21582
|
}
|
|
@@ -21245,7 +21609,7 @@ adminPluginRoutes.post("/:id/uninstall", async (c) => {
|
|
|
21245
21609
|
if (user?.role !== "admin") {
|
|
21246
21610
|
return c.json({ error: "Access denied" }, 403);
|
|
21247
21611
|
}
|
|
21248
|
-
const pluginService = new
|
|
21612
|
+
const pluginService = new chunk4DHPR7KR_cjs.PluginService(db);
|
|
21249
21613
|
await pluginService.uninstallPlugin(pluginId);
|
|
21250
21614
|
return c.json({ success: true });
|
|
21251
21615
|
} catch (error) {
|
|
@@ -21263,7 +21627,7 @@ adminPluginRoutes.post("/:id/settings", async (c) => {
|
|
|
21263
21627
|
return c.json({ error: "Access denied" }, 403);
|
|
21264
21628
|
}
|
|
21265
21629
|
const settings = await c.req.json();
|
|
21266
|
-
const pluginService = new
|
|
21630
|
+
const pluginService = new chunk4DHPR7KR_cjs.PluginService(db);
|
|
21267
21631
|
const existingPlugin = await pluginService.getPlugin(pluginId);
|
|
21268
21632
|
const existingSettings = existingPlugin?.settings ?? {};
|
|
21269
21633
|
await pluginService.updatePluginSettings(pluginId, { ...existingSettings, ...settings });
|
|
@@ -21298,7 +21662,7 @@ function formatLastUpdated(timestamp) {
|
|
|
21298
21662
|
}
|
|
21299
21663
|
|
|
21300
21664
|
// src/templates/pages/admin-logs-list.template.ts
|
|
21301
|
-
|
|
21665
|
+
chunkMI2YXCK4_cjs.init_admin_layout_catalyst_template();
|
|
21302
21666
|
function renderLogsListPage(data) {
|
|
21303
21667
|
const { logs, pagination, filters, user } = data;
|
|
21304
21668
|
const content = `
|
|
@@ -21609,7 +21973,7 @@ function renderLogsListPage(data) {
|
|
|
21609
21973
|
user,
|
|
21610
21974
|
content
|
|
21611
21975
|
};
|
|
21612
|
-
return
|
|
21976
|
+
return chunkMI2YXCK4_cjs.renderAdminLayoutCatalyst(layoutData);
|
|
21613
21977
|
}
|
|
21614
21978
|
function renderLogDetailsPage(data) {
|
|
21615
21979
|
const { log, user } = data;
|
|
@@ -21821,7 +22185,7 @@ function renderLogDetailsPage(data) {
|
|
|
21821
22185
|
</div>
|
|
21822
22186
|
</div>
|
|
21823
22187
|
`;
|
|
21824
|
-
return
|
|
22188
|
+
return chunkOUBUS74I_cjs.adminLayoutV2({
|
|
21825
22189
|
title: `Log Details - ${log.id}`,
|
|
21826
22190
|
user,
|
|
21827
22191
|
content
|
|
@@ -22064,7 +22428,7 @@ function renderLogConfigPage(data) {
|
|
|
22064
22428
|
|
|
22065
22429
|
<script src="https://unpkg.com/htmx.org@1.9.6"></script>
|
|
22066
22430
|
`;
|
|
22067
|
-
return
|
|
22431
|
+
return chunkOUBUS74I_cjs.adminLayoutV2({
|
|
22068
22432
|
title: "Log Configuration",
|
|
22069
22433
|
user,
|
|
22070
22434
|
content
|
|
@@ -22073,11 +22437,11 @@ function renderLogConfigPage(data) {
|
|
|
22073
22437
|
|
|
22074
22438
|
// src/routes/admin-logs.ts
|
|
22075
22439
|
var adminLogsRoutes = new hono.Hono();
|
|
22076
|
-
adminLogsRoutes.use("*",
|
|
22440
|
+
adminLogsRoutes.use("*", chunkBRKXMRMB_cjs.requireAuth());
|
|
22077
22441
|
adminLogsRoutes.get("/", async (c) => {
|
|
22078
22442
|
try {
|
|
22079
22443
|
const user = c.get("user");
|
|
22080
|
-
const logger =
|
|
22444
|
+
const logger = chunkC5LDQ3SH_cjs.getLogger(c.env.DB);
|
|
22081
22445
|
const query = c.req.query();
|
|
22082
22446
|
const page = parseInt(query.page || "1");
|
|
22083
22447
|
const limit = parseInt(query.limit || "50");
|
|
@@ -22157,7 +22521,7 @@ adminLogsRoutes.get("/:id", async (c) => {
|
|
|
22157
22521
|
try {
|
|
22158
22522
|
const id = c.req.param("id");
|
|
22159
22523
|
const user = c.get("user");
|
|
22160
|
-
const logger =
|
|
22524
|
+
const logger = chunkC5LDQ3SH_cjs.getLogger(c.env.DB);
|
|
22161
22525
|
const { logs } = await logger.getLogs({
|
|
22162
22526
|
limit: 1,
|
|
22163
22527
|
offset: 0,
|
|
@@ -22194,7 +22558,7 @@ adminLogsRoutes.get("/:id", async (c) => {
|
|
|
22194
22558
|
adminLogsRoutes.get("/config", async (c) => {
|
|
22195
22559
|
try {
|
|
22196
22560
|
const user = c.get("user");
|
|
22197
|
-
const logger =
|
|
22561
|
+
const logger = chunkC5LDQ3SH_cjs.getLogger(c.env.DB);
|
|
22198
22562
|
const configs = await logger.getAllConfigs();
|
|
22199
22563
|
const pageData = {
|
|
22200
22564
|
configs,
|
|
@@ -22218,7 +22582,7 @@ adminLogsRoutes.post("/config/:category", async (c) => {
|
|
|
22218
22582
|
const level = formData.get("level");
|
|
22219
22583
|
const retention = parseInt(formData.get("retention"));
|
|
22220
22584
|
const maxSize = parseInt(formData.get("max_size"));
|
|
22221
|
-
const logger =
|
|
22585
|
+
const logger = chunkC5LDQ3SH_cjs.getLogger(c.env.DB);
|
|
22222
22586
|
await logger.updateConfig(category, {
|
|
22223
22587
|
enabled,
|
|
22224
22588
|
level,
|
|
@@ -22247,7 +22611,7 @@ adminLogsRoutes.get("/export", async (c) => {
|
|
|
22247
22611
|
const category = query.category;
|
|
22248
22612
|
const startDate = query.start_date;
|
|
22249
22613
|
const endDate = query.end_date;
|
|
22250
|
-
const logger =
|
|
22614
|
+
const logger = chunkC5LDQ3SH_cjs.getLogger(c.env.DB);
|
|
22251
22615
|
const filter = {
|
|
22252
22616
|
limit: 1e4,
|
|
22253
22617
|
// Export up to 10k logs
|
|
@@ -22328,7 +22692,7 @@ adminLogsRoutes.post("/cleanup", async (c) => {
|
|
|
22328
22692
|
error: "Unauthorized. Admin access required."
|
|
22329
22693
|
}, 403);
|
|
22330
22694
|
}
|
|
22331
|
-
const logger =
|
|
22695
|
+
const logger = chunkC5LDQ3SH_cjs.getLogger(c.env.DB);
|
|
22332
22696
|
await logger.cleanupByRetention();
|
|
22333
22697
|
return c.html(html.html`
|
|
22334
22698
|
<div class="bg-green-100 border border-green-400 text-green-700 px-4 py-3 rounded">
|
|
@@ -22350,7 +22714,7 @@ adminLogsRoutes.post("/search", async (c) => {
|
|
|
22350
22714
|
const search = formData.get("search");
|
|
22351
22715
|
const level = formData.get("level");
|
|
22352
22716
|
const category = formData.get("category");
|
|
22353
|
-
const logger =
|
|
22717
|
+
const logger = chunkC5LDQ3SH_cjs.getLogger(c.env.DB);
|
|
22354
22718
|
const filter = {
|
|
22355
22719
|
limit: 20,
|
|
22356
22720
|
offset: 0,
|
|
@@ -22445,7 +22809,7 @@ adminCheckboxRoutes.get("/", (c) => {
|
|
|
22445
22809
|
role: user.role
|
|
22446
22810
|
} : void 0
|
|
22447
22811
|
};
|
|
22448
|
-
return c.html(
|
|
22812
|
+
return c.html(chunkOUBUS74I_cjs.renderCheckboxPage(pageData));
|
|
22449
22813
|
});
|
|
22450
22814
|
|
|
22451
22815
|
// src/templates/pages/admin-dashboard.template.ts
|
|
@@ -22517,7 +22881,7 @@ function renderDashboardPage(data) {
|
|
|
22517
22881
|
version: data.version,
|
|
22518
22882
|
content: pageContent
|
|
22519
22883
|
};
|
|
22520
|
-
return
|
|
22884
|
+
return chunkOUBUS74I_cjs.renderAdminLayout(layoutData);
|
|
22521
22885
|
}
|
|
22522
22886
|
function renderStatsCards(stats) {
|
|
22523
22887
|
const cards = [
|
|
@@ -23065,9 +23429,9 @@ function renderStorageUsage(databaseSizeBytes, mediaSizeBytes) {
|
|
|
23065
23429
|
}
|
|
23066
23430
|
|
|
23067
23431
|
// src/routes/admin-dashboard.ts
|
|
23068
|
-
var VERSION =
|
|
23432
|
+
var VERSION = chunkXZUEGFXE_cjs.getCoreVersion();
|
|
23069
23433
|
var router = new hono.Hono();
|
|
23070
|
-
router.use("*",
|
|
23434
|
+
router.use("*", chunkBRKXMRMB_cjs.requireAuth());
|
|
23071
23435
|
router.get("/", async (c) => {
|
|
23072
23436
|
const user = c.get("user");
|
|
23073
23437
|
try {
|
|
@@ -23257,7 +23621,7 @@ router.get("/system-status", async (c) => {
|
|
|
23257
23621
|
});
|
|
23258
23622
|
|
|
23259
23623
|
// src/templates/pages/admin-collections-list.template.ts
|
|
23260
|
-
|
|
23624
|
+
chunkMI2YXCK4_cjs.init_admin_layout_catalyst_template();
|
|
23261
23625
|
|
|
23262
23626
|
// src/templates/components/table.template.ts
|
|
23263
23627
|
function renderTable2(data) {
|
|
@@ -23739,11 +24103,11 @@ function renderCollectionsListPage(data) {
|
|
|
23739
24103
|
version: data.version,
|
|
23740
24104
|
content: pageContent
|
|
23741
24105
|
};
|
|
23742
|
-
return
|
|
24106
|
+
return chunkMI2YXCK4_cjs.renderAdminLayoutCatalyst(layoutData);
|
|
23743
24107
|
}
|
|
23744
24108
|
|
|
23745
24109
|
// src/templates/pages/admin-collections-form.template.ts
|
|
23746
|
-
|
|
24110
|
+
chunkMI2YXCK4_cjs.init_admin_layout_catalyst_template();
|
|
23747
24111
|
function getFieldTypeBadge(fieldType) {
|
|
23748
24112
|
const typeLabels = {
|
|
23749
24113
|
"text": "Text",
|
|
@@ -23916,8 +24280,8 @@ function renderCollectionFormPage(data) {
|
|
|
23916
24280
|
<!-- Form Content -->
|
|
23917
24281
|
<div class="px-6 py-6">
|
|
23918
24282
|
<div id="form-messages"></div>
|
|
23919
|
-
${data.error ?
|
|
23920
|
-
${data.success ?
|
|
24283
|
+
${data.error ? chunkTT3TQSCZ_cjs.renderAlert({ type: "error", message: data.error, dismissible: true }) : ""}
|
|
24284
|
+
${data.success ? chunkTT3TQSCZ_cjs.renderAlert({ type: "success", message: data.success, dismissible: true }) : ""}
|
|
23921
24285
|
|
|
23922
24286
|
<!-- Form Styling -->
|
|
23923
24287
|
<style>
|
|
@@ -24028,7 +24392,7 @@ function renderCollectionFormPage(data) {
|
|
|
24028
24392
|
}
|
|
24029
24393
|
</style>
|
|
24030
24394
|
|
|
24031
|
-
${
|
|
24395
|
+
${chunkOUBUS74I_cjs.renderForm(formData)}
|
|
24032
24396
|
|
|
24033
24397
|
${isEdit && data.managed ? `
|
|
24034
24398
|
<!-- Read-Only Fields Display for Managed Collections -->
|
|
@@ -25026,13 +25390,13 @@ function renderCollectionFormPage(data) {
|
|
|
25026
25390
|
version: data.version,
|
|
25027
25391
|
content: pageContent
|
|
25028
25392
|
};
|
|
25029
|
-
return
|
|
25393
|
+
return chunkMI2YXCK4_cjs.renderAdminLayoutCatalyst(layoutData);
|
|
25030
25394
|
}
|
|
25031
25395
|
|
|
25032
25396
|
// src/routes/admin-collections.ts
|
|
25033
|
-
|
|
25397
|
+
chunkMI2YXCK4_cjs.init_admin_layout_catalyst_template();
|
|
25034
25398
|
var adminCollectionsRoutes = new hono.Hono();
|
|
25035
|
-
adminCollectionsRoutes.use("*",
|
|
25399
|
+
adminCollectionsRoutes.use("*", chunkBRKXMRMB_cjs.requireAuth());
|
|
25036
25400
|
adminCollectionsRoutes.get("/", async (c) => {
|
|
25037
25401
|
try {
|
|
25038
25402
|
const user = c.get("user");
|
|
@@ -25049,7 +25413,7 @@ adminCollectionsRoutes.get("/", async (c) => {
|
|
|
25049
25413
|
results = queryResults.results ?? [];
|
|
25050
25414
|
} catch (e) {
|
|
25051
25415
|
}
|
|
25052
|
-
const codeCollections =
|
|
25416
|
+
const codeCollections = chunk4DHPR7KR_cjs.getCollectionRegistry().list();
|
|
25053
25417
|
const codeCollectionsMap = new Map(
|
|
25054
25418
|
codeCollections.map((cfg) => {
|
|
25055
25419
|
const fieldCount = cfg.schema?.properties ? Object.keys(cfg.schema.properties).length : 0;
|
|
@@ -25063,7 +25427,7 @@ adminCollectionsRoutes.get("/", async (c) => {
|
|
|
25063
25427
|
field_count: fieldCount,
|
|
25064
25428
|
managed: cfg.managed !== false,
|
|
25065
25429
|
source_type: "code",
|
|
25066
|
-
internal:
|
|
25430
|
+
internal: chunk4DHPR7KR_cjs.isCodeCollectionInternal(cfg),
|
|
25067
25431
|
versioning: cfg.versioning === true
|
|
25068
25432
|
}];
|
|
25069
25433
|
})
|
|
@@ -25102,7 +25466,7 @@ adminCollectionsRoutes.get("/", async (c) => {
|
|
|
25102
25466
|
field_count: fieldCount,
|
|
25103
25467
|
managed: false,
|
|
25104
25468
|
source_type: row.source === "code" || row.source === "system" || row.source === "plugin" ? "code" : "user",
|
|
25105
|
-
internal:
|
|
25469
|
+
internal: chunk4DHPR7KR_cjs.isDbDocTypeInternal(row.source),
|
|
25106
25470
|
versioning: dbVersioning
|
|
25107
25471
|
};
|
|
25108
25472
|
});
|
|
@@ -25259,11 +25623,11 @@ export const myPlugin = definePlugin({
|
|
|
25259
25623
|
`;
|
|
25260
25624
|
const u = user;
|
|
25261
25625
|
return c.html(
|
|
25262
|
-
|
|
25626
|
+
chunkMI2YXCK4_cjs.renderAdminLayoutCatalyst({
|
|
25263
25627
|
title: "Add a Collection",
|
|
25264
25628
|
pageTitle: "Add a Collection",
|
|
25265
25629
|
currentPath: "/admin/collections",
|
|
25266
|
-
version:
|
|
25630
|
+
version: chunkXZUEGFXE_cjs.getCoreVersion(),
|
|
25267
25631
|
user: u ? { name: u.email ?? "Admin", email: u.email ?? "", role: u.role ?? "admin" } : void 0,
|
|
25268
25632
|
content
|
|
25269
25633
|
})
|
|
@@ -25280,7 +25644,7 @@ adminCollectionsRoutes.get("/:id", async (c) => {
|
|
|
25280
25644
|
collection = await stmt.bind(id).first();
|
|
25281
25645
|
} catch {
|
|
25282
25646
|
}
|
|
25283
|
-
const registryRecord =
|
|
25647
|
+
const registryRecord = chunk4DHPR7KR_cjs.getCollectionRegistry().getById(id) ?? chunk4DHPR7KR_cjs.getCollectionRegistry().getByName(id);
|
|
25284
25648
|
if (!collection && !registryRecord) {
|
|
25285
25649
|
const formData2 = {
|
|
25286
25650
|
isEdit: true,
|
|
@@ -25327,9 +25691,9 @@ adminCollectionsRoutes.get("/:id", async (c) => {
|
|
|
25327
25691
|
isCodeDriven = true;
|
|
25328
25692
|
}
|
|
25329
25693
|
const [tinymceActive, quillActive, mdxeditorActive] = await Promise.all([
|
|
25330
|
-
|
|
25331
|
-
|
|
25332
|
-
|
|
25694
|
+
chunk4DHPR7KR_cjs.isPluginActive(db, "tinymce-plugin"),
|
|
25695
|
+
chunk4DHPR7KR_cjs.isPluginActive(db, "quill-editor"),
|
|
25696
|
+
chunk4DHPR7KR_cjs.isPluginActive(db, "easy-mdx")
|
|
25333
25697
|
]);
|
|
25334
25698
|
const displayName = collection?.display_name ?? registryRecord?.displayName ?? id;
|
|
25335
25699
|
const formData = {
|
|
@@ -25349,9 +25713,9 @@ adminCollectionsRoutes.get("/:id", async (c) => {
|
|
|
25349
25713
|
console.error("Error fetching collection:", error);
|
|
25350
25714
|
const user = c.get("user");
|
|
25351
25715
|
const [tinymceActive, quillActive, mdxeditorActive] = await Promise.all([
|
|
25352
|
-
|
|
25353
|
-
|
|
25354
|
-
|
|
25716
|
+
chunk4DHPR7KR_cjs.isPluginActive(db, "tinymce-plugin"),
|
|
25717
|
+
chunk4DHPR7KR_cjs.isPluginActive(db, "quill-editor"),
|
|
25718
|
+
chunk4DHPR7KR_cjs.isPluginActive(db, "easy-mdx")
|
|
25355
25719
|
]);
|
|
25356
25720
|
const formData = {
|
|
25357
25721
|
isEdit: true,
|
|
@@ -25365,7 +25729,7 @@ adminCollectionsRoutes.get("/:id", async (c) => {
|
|
|
25365
25729
|
});
|
|
25366
25730
|
|
|
25367
25731
|
// src/templates/pages/admin-settings.template.ts
|
|
25368
|
-
|
|
25732
|
+
chunkMI2YXCK4_cjs.init_admin_layout_catalyst_template();
|
|
25369
25733
|
function renderSettingsPage(data) {
|
|
25370
25734
|
const activeTab = data.activeTab || "general";
|
|
25371
25735
|
const pageContent = `
|
|
@@ -25755,7 +26119,7 @@ function renderSettingsPage(data) {
|
|
|
25755
26119
|
version: data.version,
|
|
25756
26120
|
content: pageContent
|
|
25757
26121
|
};
|
|
25758
|
-
return
|
|
26122
|
+
return chunkMI2YXCK4_cjs.renderAdminLayoutCatalyst(layoutData);
|
|
25759
26123
|
}
|
|
25760
26124
|
function renderTabButton(tabId, label, iconPath, activeTab) {
|
|
25761
26125
|
const isActive = activeTab === tabId;
|
|
@@ -26300,7 +26664,7 @@ function renderDatabaseToolsSettings(settings) {
|
|
|
26300
26664
|
|
|
26301
26665
|
// src/routes/admin-settings.ts
|
|
26302
26666
|
var adminSettingsRoutes = new hono.Hono();
|
|
26303
|
-
adminSettingsRoutes.use("*",
|
|
26667
|
+
adminSettingsRoutes.use("*", chunkBRKXMRMB_cjs.requireAuth());
|
|
26304
26668
|
function getMockSettings(user) {
|
|
26305
26669
|
return {
|
|
26306
26670
|
general: {
|
|
@@ -26334,7 +26698,7 @@ adminSettingsRoutes.get("/", (c) => {
|
|
|
26334
26698
|
adminSettingsRoutes.get("/general", async (c) => {
|
|
26335
26699
|
const user = c.get("user");
|
|
26336
26700
|
const db = c.env.DB;
|
|
26337
|
-
const settingsService = new
|
|
26701
|
+
const settingsService = new chunkC5LDQ3SH_cjs.SettingsService(db);
|
|
26338
26702
|
const generalSettings = await settingsService.getGeneralSettings(user?.email);
|
|
26339
26703
|
const mockSettings = getMockSettings(user);
|
|
26340
26704
|
mockSettings.general = generalSettings;
|
|
@@ -26353,7 +26717,7 @@ adminSettingsRoutes.get("/general", async (c) => {
|
|
|
26353
26717
|
adminSettingsRoutes.get("/security", async (c) => {
|
|
26354
26718
|
const user = c.get("user");
|
|
26355
26719
|
const db = c.env.DB;
|
|
26356
|
-
const settingsService = new
|
|
26720
|
+
const settingsService = new chunkC5LDQ3SH_cjs.SettingsService(db);
|
|
26357
26721
|
const persisted = await settingsService.getSecuritySettings();
|
|
26358
26722
|
const mockSettings = getMockSettings(user);
|
|
26359
26723
|
mockSettings.security = {
|
|
@@ -26403,7 +26767,7 @@ adminSettingsRoutes.get("/database-tools", (c) => {
|
|
|
26403
26767
|
adminSettingsRoutes.get("/api/migrations/status", async (c) => {
|
|
26404
26768
|
try {
|
|
26405
26769
|
const db = c.env.DB;
|
|
26406
|
-
const migrationService = new
|
|
26770
|
+
const migrationService = new chunkPAS7GZBS_cjs.MigrationService(db);
|
|
26407
26771
|
const status = await migrationService.getMigrationStatus();
|
|
26408
26772
|
return c.json({
|
|
26409
26773
|
success: true,
|
|
@@ -26443,7 +26807,7 @@ adminSettingsRoutes.post("/api/migrations/run", async (c) => {
|
|
|
26443
26807
|
adminSettingsRoutes.get("/api/migrations/validate", async (c) => {
|
|
26444
26808
|
try {
|
|
26445
26809
|
const db = c.env.DB;
|
|
26446
|
-
const migrationService = new
|
|
26810
|
+
const migrationService = new chunkPAS7GZBS_cjs.MigrationService(db);
|
|
26447
26811
|
const validation = await migrationService.validateSchema();
|
|
26448
26812
|
return c.json({
|
|
26449
26813
|
success: true,
|
|
@@ -26612,7 +26976,7 @@ adminSettingsRoutes.post("/general", async (c) => {
|
|
|
26612
26976
|
}
|
|
26613
26977
|
const formData = await c.req.formData();
|
|
26614
26978
|
const db = c.env.DB;
|
|
26615
|
-
const settingsService = new
|
|
26979
|
+
const settingsService = new chunkC5LDQ3SH_cjs.SettingsService(db);
|
|
26616
26980
|
const settings = {
|
|
26617
26981
|
siteName: formData.get("siteName"),
|
|
26618
26982
|
siteDescription: formData.get("siteDescription"),
|
|
@@ -26658,7 +27022,7 @@ adminSettingsRoutes.post("/security", async (c) => {
|
|
|
26658
27022
|
}
|
|
26659
27023
|
const formData = await c.req.formData();
|
|
26660
27024
|
const db = c.env.DB;
|
|
26661
|
-
const settingsService = new
|
|
27025
|
+
const settingsService = new chunkC5LDQ3SH_cjs.SettingsService(db);
|
|
26662
27026
|
const jwtExpiresInRaw = formData.get("jwtExpiresIn")?.trim() || "";
|
|
26663
27027
|
const graceRaw = formData.get("jwtRefreshGraceSeconds")?.trim() || "";
|
|
26664
27028
|
if (!/^\d+(?:s|m|h|d)?$/i.test(jwtExpiresInRaw)) {
|
|
@@ -26701,7 +27065,7 @@ adminSettingsRoutes.post("/", async (c) => {
|
|
|
26701
27065
|
});
|
|
26702
27066
|
|
|
26703
27067
|
// src/templates/pages/admin-api-reference.template.ts
|
|
26704
|
-
|
|
27068
|
+
chunkMI2YXCK4_cjs.init_admin_layout_catalyst_template();
|
|
26705
27069
|
function renderAuthBadge(auth) {
|
|
26706
27070
|
if (auth === true) {
|
|
26707
27071
|
return `
|
|
@@ -26842,7 +27206,7 @@ function renderAPIReferencePage(data) {
|
|
|
26842
27206
|
>
|
|
26843
27207
|
<option value="">All Categories</option>
|
|
26844
27208
|
${categories.map((category) => {
|
|
26845
|
-
const info =
|
|
27209
|
+
const info = chunkC5LDQ3SH_cjs.CATEGORY_INFO[category];
|
|
26846
27210
|
const title = info ? info.title : category;
|
|
26847
27211
|
return `<option value="${category}">${title}</option>`;
|
|
26848
27212
|
}).join("\n ")}
|
|
@@ -26859,7 +27223,7 @@ function renderAPIReferencePage(data) {
|
|
|
26859
27223
|
<!-- API Categories -->
|
|
26860
27224
|
<div class="space-y-6">
|
|
26861
27225
|
${Object.entries(endpointsByCategory).map(([category, endpoints]) => {
|
|
26862
|
-
const info =
|
|
27226
|
+
const info = chunkC5LDQ3SH_cjs.CATEGORY_INFO[category] || { title: category, description: "", icon: "📋" };
|
|
26863
27227
|
return `
|
|
26864
27228
|
<div class="api-category" data-category="${category}">
|
|
26865
27229
|
<div class="rounded-lg bg-white dark:bg-zinc-900 shadow-sm ring-1 ring-zinc-950/5 dark:ring-white/10 overflow-hidden">
|
|
@@ -27032,20 +27396,20 @@ function renderAPIReferencePage(data) {
|
|
|
27032
27396
|
version: data.version,
|
|
27033
27397
|
content: pageContent
|
|
27034
27398
|
};
|
|
27035
|
-
return
|
|
27399
|
+
return chunkMI2YXCK4_cjs.renderAdminLayoutCatalyst(layoutData);
|
|
27036
27400
|
}
|
|
27037
27401
|
|
|
27038
27402
|
// src/routes/admin-api-reference.ts
|
|
27039
|
-
var VERSION2 =
|
|
27403
|
+
var VERSION2 = chunkXZUEGFXE_cjs.getCoreVersion();
|
|
27040
27404
|
var router2 = new hono.Hono();
|
|
27041
|
-
router2.use("*",
|
|
27405
|
+
router2.use("*", chunkBRKXMRMB_cjs.requireAuth());
|
|
27042
27406
|
router2.get("/", async (c) => {
|
|
27043
27407
|
const user = c.get("user");
|
|
27044
27408
|
try {
|
|
27045
|
-
const app2 =
|
|
27046
|
-
const baseEndpoints =
|
|
27409
|
+
const app2 = chunkC5LDQ3SH_cjs.getAppInstance();
|
|
27410
|
+
const baseEndpoints = chunkC5LDQ3SH_cjs.buildRouteList(app2);
|
|
27047
27411
|
const collectionRoutes = [];
|
|
27048
|
-
const collections =
|
|
27412
|
+
const collections = chunk4DHPR7KR_cjs.getCollectionRegistry().listActive().filter((r) => !r.internal);
|
|
27049
27413
|
const methodOrder = { GET: 0, POST: 1, PUT: 2, PATCH: 3, DELETE: 4 };
|
|
27050
27414
|
for (const col of collections) {
|
|
27051
27415
|
const displayName = col.displayName || col.name;
|
|
@@ -27160,11 +27524,13 @@ exports.resolveDocScope = resolveDocScope;
|
|
|
27160
27524
|
exports.resolveVariablesInObject = resolveVariablesInObject;
|
|
27161
27525
|
exports.router = router;
|
|
27162
27526
|
exports.router2 = router2;
|
|
27527
|
+
exports.setDemoModeActive = setDemoModeActive;
|
|
27163
27528
|
exports.setEmailService = setEmailService;
|
|
27164
27529
|
exports.setVariablesCache = setVariablesCache;
|
|
27530
|
+
exports.swrStats = swrStats;
|
|
27165
27531
|
exports.test_cleanup_default = test_cleanup_default;
|
|
27166
27532
|
exports.updateDocumentSchema = updateDocumentSchema;
|
|
27167
27533
|
exports.userProfilesPlugin = userProfilesPlugin;
|
|
27168
27534
|
exports.userRoutes = userRoutes;
|
|
27169
|
-
//# sourceMappingURL=chunk-
|
|
27170
|
-
//# sourceMappingURL=chunk-
|
|
27535
|
+
//# sourceMappingURL=chunk-S2QN4LFD.cjs.map
|
|
27536
|
+
//# sourceMappingURL=chunk-S2QN4LFD.cjs.map
|