@sonicjs-cms/core 3.0.0-beta.23 → 3.0.0-beta.25
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/db-reset.js +39 -22
- package/dist/admin-documents-form.template-JWV5GITD.js +6 -0
- package/dist/{admin-documents-form.template-55V2ZGWT.js.map → admin-documents-form.template-JWV5GITD.js.map} +1 -1
- package/dist/admin-documents-form.template-UWKGVAMW.cjs +19 -0
- package/dist/{admin-layout-catalyst.template-6UQGLCKI.js.map → admin-documents-form.template-UWKGVAMW.cjs.map} +1 -1
- package/dist/admin-layout-catalyst.template-MOQ3BBXA.cjs +21 -0
- package/dist/{admin-layout-catalyst.template-3XZXDGF7.cjs.map → admin-layout-catalyst.template-MOQ3BBXA.cjs.map} +1 -1
- package/dist/admin-layout-catalyst.template-WCYMQVTZ.js +7 -0
- package/dist/{admin-documents-form.template-YNAVMJCV.cjs.map → admin-layout-catalyst.template-WCYMQVTZ.js.map} +1 -1
- package/dist/{chunk-KS24NPPL.js → chunk-2D3A4X52.js} +21 -2
- package/dist/chunk-2D3A4X52.js.map +1 -0
- package/dist/{chunk-DIBCKCUE.js → chunk-2OXFMMA3.js} +14 -29
- package/dist/chunk-2OXFMMA3.js.map +1 -0
- package/dist/{chunk-SOZUG52O.js → chunk-3KGY4IBW.js} +3 -3
- package/dist/{chunk-SOZUG52O.js.map → chunk-3KGY4IBW.js.map} +1 -1
- package/dist/{chunk-CTYLCWMO.cjs → chunk-6OA77UM7.cjs} +802 -481
- package/dist/chunk-6OA77UM7.cjs.map +1 -0
- package/dist/{chunk-URIBTX27.js → chunk-73RTFFMX.js} +3 -3
- package/dist/{chunk-URIBTX27.js.map → chunk-73RTFFMX.js.map} +1 -1
- package/dist/{chunk-SK5CHFJP.js → chunk-7P5OCUPS.js} +467 -149
- package/dist/chunk-7P5OCUPS.js.map +1 -0
- package/dist/{chunk-3TMTYJAJ.js → chunk-BDQ55MWV.js} +18 -2
- package/dist/chunk-BDQ55MWV.js.map +1 -0
- package/dist/{chunk-C3ZQP5NW.cjs → chunk-BJ6NJL2E.cjs} +7 -12
- package/dist/chunk-BJ6NJL2E.cjs.map +1 -0
- package/dist/{chunk-2MIYYAO4.js → chunk-C54MH5UI.js} +5 -4
- package/dist/chunk-C54MH5UI.js.map +1 -0
- package/dist/{chunk-BBEKHLTW.cjs → chunk-CN3T3TDI.cjs} +9 -9
- package/dist/{chunk-BBEKHLTW.cjs.map → chunk-CN3T3TDI.cjs.map} +1 -1
- package/dist/{chunk-DPLJYTHE.js → chunk-CWIGQYRR.js} +7 -12
- package/dist/chunk-CWIGQYRR.js.map +1 -0
- package/dist/{chunk-4WMZGHIC.cjs → chunk-D6FWEYQE.cjs} +6 -5
- package/dist/chunk-D6FWEYQE.cjs.map +1 -0
- package/dist/{chunk-A46IRC5A.js → chunk-D7RLBBHE.js} +2 -2
- package/dist/{chunk-A46IRC5A.js.map → chunk-D7RLBBHE.js.map} +1 -1
- package/dist/{chunk-IXUHXTHW.cjs → chunk-DLTT7QZU.cjs} +17 -6
- package/dist/chunk-DLTT7QZU.cjs.map +1 -0
- package/dist/{chunk-BHND5PEV.js → chunk-E3TQG7AA.js} +3 -3
- package/dist/{chunk-BHND5PEV.js.map → chunk-E3TQG7AA.js.map} +1 -1
- package/dist/{chunk-IS54FPB7.cjs → chunk-E7E3NL3Y.cjs} +27 -42
- package/dist/chunk-E7E3NL3Y.cjs.map +1 -0
- package/dist/{chunk-XXRR54AB.js → chunk-F26HP3B6.js} +36 -5
- package/dist/chunk-F26HP3B6.js.map +1 -0
- package/dist/{chunk-QZGABF2M.js → chunk-FVAK4C6L.js} +17 -6
- package/dist/chunk-FVAK4C6L.js.map +1 -0
- package/dist/{chunk-BJROXF4N.js → chunk-HSDJDWLV.js} +19 -4
- package/dist/chunk-HSDJDWLV.js.map +1 -0
- package/dist/{chunk-RFBW5RRH.cjs → chunk-I7MIRRFJ.cjs} +43 -12
- package/dist/chunk-I7MIRRFJ.cjs.map +1 -0
- package/dist/{chunk-LTZ5WYOK.cjs → chunk-JCBDXEY2.cjs} +18 -2
- package/dist/chunk-JCBDXEY2.cjs.map +1 -0
- package/dist/{chunk-UYJQDDEE.cjs → chunk-MI2YXCK4.cjs} +14 -8
- package/dist/chunk-MI2YXCK4.cjs.map +1 -0
- package/dist/{chunk-VGHEKIJL.cjs → chunk-MOGK3U4A.cjs} +2 -2
- package/dist/{chunk-VGHEKIJL.cjs.map → chunk-MOGK3U4A.cjs.map} +1 -1
- package/dist/{chunk-E66UVONV.cjs → chunk-OUBUS74I.cjs} +24 -9
- package/dist/chunk-OUBUS74I.cjs.map +1 -0
- package/dist/{chunk-GMMCCIQO.cjs → chunk-RSBZITK3.cjs} +3 -3
- package/dist/{chunk-GMMCCIQO.cjs.map → chunk-RSBZITK3.cjs.map} +1 -1
- package/dist/{chunk-THFZSDIU.js → chunk-SXC4HPK6.js} +14 -8
- package/dist/chunk-SXC4HPK6.js.map +1 -0
- package/dist/{chunk-JMJM7DMM.cjs → chunk-TT3TQSCZ.cjs} +5 -5
- package/dist/{chunk-JMJM7DMM.cjs.map → chunk-TT3TQSCZ.cjs.map} +1 -1
- package/dist/{chunk-AT4ZQGEZ.cjs → chunk-YAURVGUK.cjs} +21 -2
- package/dist/chunk-YAURVGUK.cjs.map +1 -0
- package/dist/config-4TIHSNW6.js +6 -0
- package/dist/{config-6FB2BXMP.js.map → config-4TIHSNW6.js.map} +1 -1
- package/dist/{config-OCH7S4WK.cjs → config-XN2ETAJ3.cjs} +5 -5
- package/dist/{config-OCH7S4WK.cjs.map → config-XN2ETAJ3.cjs.map} +1 -1
- package/dist/{define-plugin-D_6D9vVZ.d.ts → define-plugin-DDe8a_bh.d.ts} +3 -0
- package/dist/{define-plugin-DMcvEy_C.d.cts → define-plugin-rjXmGOgu.d.cts} +3 -0
- package/dist/index.cjs +1220 -353
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +38 -3
- package/dist/index.d.ts +38 -3
- package/dist/index.js +895 -30
- package/dist/index.js.map +1 -1
- package/dist/middleware.cjs +35 -35
- package/dist/middleware.d.cts +4 -1
- package/dist/middleware.d.ts +4 -1
- package/dist/middleware.js +6 -6
- package/dist/migrations-JAHMI5MK.js +4 -0
- package/dist/{migrations-XQ6EX6HX.js.map → migrations-JAHMI5MK.js.map} +1 -1
- package/dist/migrations-KU4V6T73.cjs +13 -0
- package/dist/{migrations-ZD7Y5NUC.cjs.map → migrations-KU4V6T73.cjs.map} +1 -1
- package/dist/plugins.cjs +40 -40
- package/dist/plugins.d.cts +1 -1
- package/dist/plugins.d.ts +1 -1
- package/dist/plugins.js +3 -3
- package/dist/rbac-AORZ6O3N.cjs +14 -0
- package/dist/{rbac-7QZ4JZ2E.cjs.map → rbac-AORZ6O3N.cjs.map} +1 -1
- package/dist/rbac-P44772FP.js +5 -0
- package/dist/{rbac-Y43IEQOP.js.map → rbac-P44772FP.js.map} +1 -1
- package/dist/routes.cjs +31 -31
- package/dist/routes.js +11 -11
- package/dist/services.cjs +18 -18
- package/dist/services.d.cts +1 -1
- package/dist/services.d.ts +1 -1
- package/dist/services.js +2 -2
- package/dist/{telemetry-Cku1ax74.d.cts → telemetry-QFlTv9f8.d.cts} +1 -1
- package/dist/{telemetry-Cku1ax74.d.ts → telemetry-QFlTv9f8.d.ts} +1 -1
- package/dist/templates.cjs +17 -17
- package/dist/templates.js +3 -3
- package/dist/types.d.cts +1 -1
- package/dist/types.d.ts +1 -1
- package/dist/utils.cjs +12 -12
- package/dist/utils.d.cts +1 -1
- package/dist/utils.d.ts +1 -1
- package/dist/utils.js +2 -2
- package/package.json +5 -10
- package/dist/admin-documents-form.template-55V2ZGWT.js +0 -6
- package/dist/admin-documents-form.template-YNAVMJCV.cjs +0 -19
- package/dist/admin-layout-catalyst.template-3XZXDGF7.cjs +0 -21
- package/dist/admin-layout-catalyst.template-6UQGLCKI.js +0 -7
- package/dist/chunk-2MIYYAO4.js.map +0 -1
- package/dist/chunk-3TMTYJAJ.js.map +0 -1
- package/dist/chunk-4WMZGHIC.cjs.map +0 -1
- package/dist/chunk-AT4ZQGEZ.cjs.map +0 -1
- package/dist/chunk-BJROXF4N.js.map +0 -1
- package/dist/chunk-C3ZQP5NW.cjs.map +0 -1
- package/dist/chunk-CTYLCWMO.cjs.map +0 -1
- package/dist/chunk-DIBCKCUE.js.map +0 -1
- package/dist/chunk-DPLJYTHE.js.map +0 -1
- package/dist/chunk-E66UVONV.cjs.map +0 -1
- package/dist/chunk-IS54FPB7.cjs.map +0 -1
- package/dist/chunk-IXUHXTHW.cjs.map +0 -1
- package/dist/chunk-KS24NPPL.js.map +0 -1
- package/dist/chunk-LTZ5WYOK.cjs.map +0 -1
- package/dist/chunk-QZGABF2M.js.map +0 -1
- package/dist/chunk-RFBW5RRH.cjs.map +0 -1
- package/dist/chunk-SK5CHFJP.js.map +0 -1
- package/dist/chunk-THFZSDIU.js.map +0 -1
- package/dist/chunk-UYJQDDEE.cjs.map +0 -1
- package/dist/chunk-XXRR54AB.js.map +0 -1
- package/dist/config-6FB2BXMP.js +0 -6
- package/dist/migrations-XQ6EX6HX.js +0 -4
- package/dist/migrations-ZD7Y5NUC.cjs +0 -13
- package/dist/rbac-7QZ4JZ2E.cjs +0 -14
- package/dist/rbac-Y43IEQOP.js +0 -5
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var chunkXWVDSM2L_cjs = require('./chunk-XWVDSM2L.cjs');
|
|
4
|
-
var
|
|
4
|
+
var chunkTT3TQSCZ_cjs = require('./chunk-TT3TQSCZ.cjs');
|
|
5
5
|
var chunk36Z3AKX3_cjs = require('./chunk-36Z3AKX3.cjs');
|
|
6
|
-
var
|
|
7
|
-
var
|
|
6
|
+
var chunkE7E3NL3Y_cjs = require('./chunk-E7E3NL3Y.cjs');
|
|
7
|
+
var chunkJCBDXEY2_cjs = require('./chunk-JCBDXEY2.cjs');
|
|
8
8
|
var chunkKIGVVO6N_cjs = require('./chunk-KIGVVO6N.cjs');
|
|
9
|
-
var
|
|
10
|
-
var
|
|
11
|
-
var
|
|
12
|
-
var
|
|
13
|
-
var
|
|
9
|
+
var chunkYAURVGUK_cjs = require('./chunk-YAURVGUK.cjs');
|
|
10
|
+
var chunkMOGK3U4A_cjs = require('./chunk-MOGK3U4A.cjs');
|
|
11
|
+
var chunkOUBUS74I_cjs = require('./chunk-OUBUS74I.cjs');
|
|
12
|
+
var chunkMI2YXCK4_cjs = require('./chunk-MI2YXCK4.cjs');
|
|
13
|
+
var chunkD6FWEYQE_cjs = require('./chunk-D6FWEYQE.cjs');
|
|
14
14
|
var chunkJ6JTWD2A_cjs = require('./chunk-J6JTWD2A.cjs');
|
|
15
|
-
var
|
|
15
|
+
var chunkDLTT7QZU_cjs = require('./chunk-DLTT7QZU.cjs');
|
|
16
16
|
var chunkRCQ2HIQD_cjs = require('./chunk-RCQ2HIQD.cjs');
|
|
17
|
-
var
|
|
17
|
+
var chunkBJ6NJL2E_cjs = require('./chunk-BJ6NJL2E.cjs');
|
|
18
18
|
var chunkMNWKYY5E_cjs = require('./chunk-MNWKYY5E.cjs');
|
|
19
19
|
var hono = require('hono');
|
|
20
20
|
var zod = require('zod');
|
|
@@ -47,6 +47,7 @@ var DocumentPermissionsService = class {
|
|
|
47
47
|
const publicGrants = baseGrants["public"] ?? [];
|
|
48
48
|
if (publicGrants.includes(permission)) return true;
|
|
49
49
|
} else if (principal.type === "role") {
|
|
50
|
+
if (principal.id === "public") continue;
|
|
50
51
|
const roleGrants = baseGrants[principal.id] ?? [];
|
|
51
52
|
if (roleGrants.includes(permission)) return true;
|
|
52
53
|
}
|
|
@@ -151,6 +152,18 @@ var DocumentRepository = class {
|
|
|
151
152
|
const row = await this.db.prepare("SELECT * FROM documents WHERE root_id = ? AND tenant_id = ? AND is_published = 1").bind(rootId, this.tenantId).first();
|
|
152
153
|
return row ? rowToDocument(row) : null;
|
|
153
154
|
}
|
|
155
|
+
// Slug lookup for a single doc. Prefer the published row; fall back to the current
|
|
156
|
+
// draft so a never-published doc is still reachable by slug (matches getById, which
|
|
157
|
+
// resolves drafts too). ORDER BY makes the preference deterministic when both exist.
|
|
158
|
+
async getBySlug(typeId, slug) {
|
|
159
|
+
const row = await this.db.prepare(
|
|
160
|
+
`SELECT * FROM documents
|
|
161
|
+
WHERE tenant_id = ? AND type_id = ? AND slug = ? AND deleted_at IS NULL
|
|
162
|
+
AND (is_published = 1 OR is_current_draft = 1)
|
|
163
|
+
ORDER BY is_published DESC LIMIT 1`
|
|
164
|
+
).bind(this.tenantId, typeId, slug).first();
|
|
165
|
+
return row ? rowToDocument(row) : null;
|
|
166
|
+
}
|
|
154
167
|
// Unified, tenant-scoped list with optional generated-column / facet filters and sort. This is the
|
|
155
168
|
// single place document list SQL is built — route handlers must call this, never inline SQL (R4).
|
|
156
169
|
async list(opts = {}) {
|
|
@@ -259,7 +272,7 @@ function getDocumentRequestContext(c) {
|
|
|
259
272
|
|
|
260
273
|
// src/routes/api-documents.ts
|
|
261
274
|
async function aclAllowsRead(db, tenantId, principalSet, row, preloadedType) {
|
|
262
|
-
const docType = preloadedType ?? await new
|
|
275
|
+
const docType = preloadedType ?? await new chunkE7E3NL3Y_cjs.DocumentTypeRegistry(db).findById(row.type_id);
|
|
263
276
|
if (!docType) return false;
|
|
264
277
|
return new DocumentRepository(db, tenantId).isAllowed(principalSet, row.root_id, "read", docType.settings);
|
|
265
278
|
}
|
|
@@ -277,7 +290,7 @@ apiDocumentsRoutes.get("/", async (c) => {
|
|
|
277
290
|
if (!typeId) {
|
|
278
291
|
return c.json({ error: "type query parameter is required" }, 400);
|
|
279
292
|
}
|
|
280
|
-
const registry = new
|
|
293
|
+
const registry = new chunkE7E3NL3Y_cjs.DocumentTypeRegistry(db);
|
|
281
294
|
const docType = await registry.findById(typeId);
|
|
282
295
|
if (!docType || !docType.isActive) {
|
|
283
296
|
return c.json({ error: "Unknown document type" }, 400);
|
|
@@ -359,7 +372,7 @@ apiDocumentsRoutes.get("/root/:rootId", async (c) => {
|
|
|
359
372
|
AND (expires_at IS NULL OR expires_at > ?) LIMIT 1`
|
|
360
373
|
).bind(rootId, now, now).first();
|
|
361
374
|
if (!row) return c.json({ error: "Not found" }, 404);
|
|
362
|
-
const docType = await new
|
|
375
|
+
const docType = await new chunkE7E3NL3Y_cjs.DocumentTypeRegistry(db).findById(row.type_id);
|
|
363
376
|
const effTenant = effectiveTenantForType(tenantId, docType?.settings);
|
|
364
377
|
if (row.tenant_id !== effTenant) return c.json({ error: "Not found" }, 404);
|
|
365
378
|
if (!await aclAllowsRead(db, effTenant, principalSet, row, docType)) {
|
|
@@ -395,7 +408,7 @@ apiDocumentsRoutes.get("/:id", async (c) => {
|
|
|
395
408
|
AND (expires_at IS NULL OR expires_at > ?) LIMIT 1`
|
|
396
409
|
).bind(id, now, now).first();
|
|
397
410
|
if (!row) return c.json({ error: "Not found" }, 404);
|
|
398
|
-
const docType = await new
|
|
411
|
+
const docType = await new chunkE7E3NL3Y_cjs.DocumentTypeRegistry(db).findById(row.type_id);
|
|
399
412
|
const effTenant = effectiveTenantForType(tenantId, docType?.settings);
|
|
400
413
|
if (row.tenant_id !== effTenant) return c.json({ error: "Not found" }, 404);
|
|
401
414
|
if (!await aclAllowsRead(db, effTenant, principalSet, row, docType)) {
|
|
@@ -465,17 +478,17 @@ async function resolveDocScope(c, db, by, opts = {}) {
|
|
|
465
478
|
const draft = opts.currentDraftOnly ? " AND is_current_draft = 1" : "";
|
|
466
479
|
const row = await db.prepare(`SELECT type_id, root_id, tenant_id FROM documents WHERE ${col} = ?${draft} LIMIT 1`).bind(val).first();
|
|
467
480
|
if (!row) return null;
|
|
468
|
-
const docType = await new
|
|
481
|
+
const docType = await new chunkE7E3NL3Y_cjs.DocumentTypeRegistry(db).findById(row.type_id);
|
|
469
482
|
const tenantId = effectiveTenantForType(getRequestTenant(c), docType?.settings);
|
|
470
483
|
if (row.tenant_id !== tenantId) return null;
|
|
471
484
|
return { typeId: row.type_id, rootId: row.root_id, tenantId, docType };
|
|
472
485
|
}
|
|
473
486
|
var adminDocumentsRoutes = new hono.Hono();
|
|
474
|
-
adminDocumentsRoutes.use("*",
|
|
475
|
-
adminDocumentsRoutes.use("*",
|
|
487
|
+
adminDocumentsRoutes.use("*", chunkE7E3NL3Y_cjs.requireAuth());
|
|
488
|
+
adminDocumentsRoutes.use("*", chunkE7E3NL3Y_cjs.requireRole(["admin", "editor"]));
|
|
476
489
|
adminDocumentsRoutes.get("/types", async (c) => {
|
|
477
490
|
try {
|
|
478
|
-
const registry = new
|
|
491
|
+
const registry = new chunkE7E3NL3Y_cjs.DocumentTypeRegistry(c.env.DB);
|
|
479
492
|
const types = await registry.findAll();
|
|
480
493
|
return c.json({ data: types });
|
|
481
494
|
} catch (error) {
|
|
@@ -503,7 +516,7 @@ adminDocumentsRoutes.get("/", async (c) => {
|
|
|
503
516
|
if (!typeId) {
|
|
504
517
|
return c.json({ error: "type query parameter is required" }, 400);
|
|
505
518
|
}
|
|
506
|
-
const registry = new
|
|
519
|
+
const registry = new chunkE7E3NL3Y_cjs.DocumentTypeRegistry(db);
|
|
507
520
|
const docType = await registry.findById(typeId);
|
|
508
521
|
if (!docType || !docType.isActive) {
|
|
509
522
|
return c.json({ error: "Unknown document type" }, 400);
|
|
@@ -614,7 +627,7 @@ adminDocumentsRoutes.post("/", async (c) => {
|
|
|
614
627
|
const input = validation.data;
|
|
615
628
|
const db = c.env.DB;
|
|
616
629
|
const user = c.get("user");
|
|
617
|
-
const registry = new
|
|
630
|
+
const registry = new chunkE7E3NL3Y_cjs.DocumentTypeRegistry(db);
|
|
618
631
|
const docType = await registry.findById(input.typeId);
|
|
619
632
|
if (!docType || !docType.isActive) {
|
|
620
633
|
return c.json({ error: "Unknown document type" }, 400);
|
|
@@ -622,7 +635,7 @@ adminDocumentsRoutes.post("/", async (c) => {
|
|
|
622
635
|
const createDenied = await denyIfNotAllowed(c, db, "", "create", docType.settings);
|
|
623
636
|
if (createDenied) return createDenied;
|
|
624
637
|
const tenantId = effectiveTenantForType(getRequestTenant(c), docType.settings);
|
|
625
|
-
const svc = new
|
|
638
|
+
const svc = new chunkJCBDXEY2_cjs.DocumentsService(db, {
|
|
626
639
|
queryableFields: docType.queryableFields,
|
|
627
640
|
typeSchemaVersion: docType.schemaVersion,
|
|
628
641
|
maxVersionsPerRoot: docType.settings.maxVersionsPerRoot,
|
|
@@ -660,7 +673,7 @@ adminDocumentsRoutes.put("/:rootId", async (c) => {
|
|
|
660
673
|
const docType = scope.docType;
|
|
661
674
|
const updateDenied = await denyIfNotAllowed(c, db, rootId, "update", docType?.settings, scope.tenantId);
|
|
662
675
|
if (updateDenied) return updateDenied;
|
|
663
|
-
const svc = new
|
|
676
|
+
const svc = new chunkJCBDXEY2_cjs.DocumentsService(db, {
|
|
664
677
|
queryableFields: docType?.queryableFields ?? [],
|
|
665
678
|
typeSchemaVersion: docType?.schemaVersion,
|
|
666
679
|
maxVersionsPerRoot: docType?.settings.maxVersionsPerRoot,
|
|
@@ -685,7 +698,7 @@ adminDocumentsRoutes.post("/:id/publish", async (c) => {
|
|
|
685
698
|
const docType = scope.docType;
|
|
686
699
|
const publishDenied = await denyIfNotAllowed(c, db, scope.rootId, "publish", docType?.settings, scope.tenantId);
|
|
687
700
|
if (publishDenied) return publishDenied;
|
|
688
|
-
const svc = new
|
|
701
|
+
const svc = new chunkJCBDXEY2_cjs.DocumentsService(db, {
|
|
689
702
|
queryableFields: docType?.queryableFields ?? [],
|
|
690
703
|
typeSchemaVersion: docType?.schemaVersion,
|
|
691
704
|
tenantId: scope.tenantId,
|
|
@@ -708,7 +721,7 @@ adminDocumentsRoutes.post("/:id/unpublish", async (c) => {
|
|
|
708
721
|
const docType = scope.docType;
|
|
709
722
|
const unpublishDenied = await denyIfNotAllowed(c, db, scope.rootId, "publish", docType?.settings, scope.tenantId);
|
|
710
723
|
if (unpublishDenied) return unpublishDenied;
|
|
711
|
-
const svc = new
|
|
724
|
+
const svc = new chunkJCBDXEY2_cjs.DocumentsService(db, {
|
|
712
725
|
queryableFields: docType?.queryableFields ?? [],
|
|
713
726
|
tenantId: scope.tenantId
|
|
714
727
|
});
|
|
@@ -730,7 +743,7 @@ adminDocumentsRoutes.delete("/:id", async (c) => {
|
|
|
730
743
|
const docType = scope.docType;
|
|
731
744
|
const deleteDenied = await denyIfNotAllowed(c, db, scope.rootId, "delete", docType?.settings, scope.tenantId);
|
|
732
745
|
if (deleteDenied) return deleteDenied;
|
|
733
|
-
const svc = new
|
|
746
|
+
const svc = new chunkJCBDXEY2_cjs.DocumentsService(db, { queryableFields: docType?.queryableFields ?? [], tenantId: scope.tenantId });
|
|
734
747
|
if (docType?.settings.pii) {
|
|
735
748
|
if (scope.rootId) await svc.erase(scope.rootId, scope.tenantId);
|
|
736
749
|
} else {
|
|
@@ -746,7 +759,7 @@ adminDocumentsRoutes.post("/types/:typeId/reindex", async (c) => {
|
|
|
746
759
|
try {
|
|
747
760
|
const { typeId } = c.req.param();
|
|
748
761
|
const db = c.env.DB;
|
|
749
|
-
const registry = new
|
|
762
|
+
const registry = new chunkE7E3NL3Y_cjs.DocumentTypeRegistry(db);
|
|
750
763
|
const docType = await registry.findById(typeId);
|
|
751
764
|
if (!docType) return c.json({ error: "Unknown document type" }, 400);
|
|
752
765
|
const reindexTenant = effectiveTenantForType(getRequestTenant(c), docType.settings);
|
|
@@ -900,13 +913,13 @@ async function resolveContentVariables(contentData, db) {
|
|
|
900
913
|
// src/routes/api-content-crud.ts
|
|
901
914
|
var apiContentCrudRoutes = new hono.Hono();
|
|
902
915
|
async function resolveDocBacking(db, collectionIdOrName) {
|
|
903
|
-
const registry =
|
|
916
|
+
const registry = chunkYAURVGUK_cjs.getCollectionRegistry();
|
|
904
917
|
const record = registry.getBySlugOrName(collectionIdOrName) ?? registry.getById(collectionIdOrName);
|
|
905
918
|
if (record) {
|
|
906
|
-
const docType2 = await new
|
|
919
|
+
const docType2 = await new chunkE7E3NL3Y_cjs.DocumentTypeRegistry(db).findById(record.name);
|
|
907
920
|
return docType2 ? { coll: { id: record.id, name: record.name }, docType: docType2 } : null;
|
|
908
921
|
}
|
|
909
|
-
const docType = await new
|
|
922
|
+
const docType = await new chunkE7E3NL3Y_cjs.DocumentTypeRegistry(db).findById(collectionIdOrName);
|
|
910
923
|
if (docType) {
|
|
911
924
|
return { coll: { id: collectionIdOrName, name: collectionIdOrName }, docType };
|
|
912
925
|
}
|
|
@@ -949,7 +962,7 @@ apiContentCrudRoutes.get("/check-slug", async (c) => {
|
|
|
949
962
|
}, 500);
|
|
950
963
|
}
|
|
951
964
|
});
|
|
952
|
-
apiContentCrudRoutes.get("/:id",
|
|
965
|
+
apiContentCrudRoutes.get("/:id", chunkE7E3NL3Y_cjs.optionalAuth(), async (c) => {
|
|
953
966
|
try {
|
|
954
967
|
const id = c.req.param("id");
|
|
955
968
|
const db = c.env.DB;
|
|
@@ -959,7 +972,7 @@ apiContentCrudRoutes.get("/:id", chunkIS54FPB7_cjs.optionalAuth(), async (c) =>
|
|
|
959
972
|
).bind(id, getRequestTenant(c)).first();
|
|
960
973
|
let transformedContent;
|
|
961
974
|
if (docRow) {
|
|
962
|
-
const coll =
|
|
975
|
+
const coll = chunkYAURVGUK_cjs.getCollectionRegistry().getByName(docRow.type_id);
|
|
963
976
|
transformedContent = {
|
|
964
977
|
id: docRow.root_id,
|
|
965
978
|
title: docRow.title,
|
|
@@ -968,8 +981,8 @@ apiContentCrudRoutes.get("/:id", chunkIS54FPB7_cjs.optionalAuth(), async (c) =>
|
|
|
968
981
|
collectionId: coll?.id ?? docRow.type_id,
|
|
969
982
|
data: docRow.data ? JSON.parse(docRow.data) : {},
|
|
970
983
|
// D29: document timestamps are SECONDS; legacy `content` API contract is MILLISECONDS.
|
|
971
|
-
created_at:
|
|
972
|
-
updated_at:
|
|
984
|
+
created_at: chunkJCBDXEY2_cjs.documentSecondsToMs(docRow.created_at),
|
|
985
|
+
updated_at: chunkJCBDXEY2_cjs.documentSecondsToMs(docRow.updated_at)
|
|
973
986
|
};
|
|
974
987
|
} else {
|
|
975
988
|
return c.json({ error: "Content not found" }, 404);
|
|
@@ -984,6 +997,32 @@ apiContentCrudRoutes.get("/:id", chunkIS54FPB7_cjs.optionalAuth(), async (c) =>
|
|
|
984
997
|
{ collection: docRow.type_id, id: docRow.root_id, data: transformedContent.data },
|
|
985
998
|
"fire-and-forget"
|
|
986
999
|
);
|
|
1000
|
+
const fieldsParam = c.req.query("fields");
|
|
1001
|
+
if (fieldsParam) {
|
|
1002
|
+
const projFields = fieldsParam.split(",").map((s) => s.trim()).filter(Boolean);
|
|
1003
|
+
if (projFields.length > 0) {
|
|
1004
|
+
const result = {};
|
|
1005
|
+
const dataSubFields = [];
|
|
1006
|
+
for (const f of projFields) {
|
|
1007
|
+
if (f === "data") {
|
|
1008
|
+
result.data = transformedContent.data;
|
|
1009
|
+
} else if (f.startsWith("data.")) {
|
|
1010
|
+
dataSubFields.push(f.slice(5));
|
|
1011
|
+
} else if (Object.prototype.hasOwnProperty.call(transformedContent, f)) {
|
|
1012
|
+
result[f] = transformedContent[f];
|
|
1013
|
+
}
|
|
1014
|
+
}
|
|
1015
|
+
if (dataSubFields.length > 0 && !result.data) {
|
|
1016
|
+
result.data = {};
|
|
1017
|
+
for (const sub of dataSubFields) {
|
|
1018
|
+
if (transformedContent.data && Object.prototype.hasOwnProperty.call(transformedContent.data, sub)) {
|
|
1019
|
+
result.data[sub] = transformedContent.data[sub];
|
|
1020
|
+
}
|
|
1021
|
+
}
|
|
1022
|
+
}
|
|
1023
|
+
return c.json({ data: result });
|
|
1024
|
+
}
|
|
1025
|
+
}
|
|
987
1026
|
return c.json({ data: transformedContent });
|
|
988
1027
|
} catch (error) {
|
|
989
1028
|
console.error("Error fetching content:", error);
|
|
@@ -993,7 +1032,7 @@ apiContentCrudRoutes.get("/:id", chunkIS54FPB7_cjs.optionalAuth(), async (c) =>
|
|
|
993
1032
|
}, 500);
|
|
994
1033
|
}
|
|
995
1034
|
});
|
|
996
|
-
apiContentCrudRoutes.post("/",
|
|
1035
|
+
apiContentCrudRoutes.post("/", chunkE7E3NL3Y_cjs.requireAuth(), chunkE7E3NL3Y_cjs.requireRole(["admin", "editor", "author"]), async (c) => {
|
|
997
1036
|
try {
|
|
998
1037
|
const db = c.env.DB;
|
|
999
1038
|
const user = c.get("user");
|
|
@@ -1027,7 +1066,7 @@ apiContentCrudRoutes.post("/", chunkIS54FPB7_cjs.requireAuth(), chunkIS54FPB7_cj
|
|
|
1027
1066
|
return c.json({ error: "Write cancelled by plugin", details: String(err) }, 400);
|
|
1028
1067
|
}
|
|
1029
1068
|
const tenantId = getRequestTenant(c);
|
|
1030
|
-
const svc = new
|
|
1069
|
+
const svc = new chunkJCBDXEY2_cjs.DocumentsService(db, {
|
|
1031
1070
|
queryableFields: backing.docType.queryableFields ?? [],
|
|
1032
1071
|
typeSchemaVersion: backing.docType.schemaVersion ?? 1,
|
|
1033
1072
|
maxVersionsPerRoot: backing.docType.settings?.maxVersionsPerRoot ?? 50,
|
|
@@ -1047,8 +1086,8 @@ apiContentCrudRoutes.post("/", chunkIS54FPB7_cjs.requireAuth(), chunkIS54FPB7_cj
|
|
|
1047
1086
|
user?.userId
|
|
1048
1087
|
);
|
|
1049
1088
|
const cache = chunk36Z3AKX3_cjs.getCacheService(chunk36Z3AKX3_cjs.CACHE_CONFIGS.api);
|
|
1050
|
-
await cache.invalidate("content-filtered:*");
|
|
1051
|
-
await cache.invalidate(
|
|
1089
|
+
await cache.invalidate("api:content-filtered:*");
|
|
1090
|
+
await cache.invalidate(`api:collection-content-filtered:${backing.coll.name}:*`);
|
|
1052
1091
|
dispatchHookEvent(
|
|
1053
1092
|
c,
|
|
1054
1093
|
"content:after:create",
|
|
@@ -1056,7 +1095,7 @@ apiContentCrudRoutes.post("/", chunkIS54FPB7_cjs.requireAuth(), chunkIS54FPB7_cj
|
|
|
1056
1095
|
"fire-and-forget"
|
|
1057
1096
|
);
|
|
1058
1097
|
return c.json({
|
|
1059
|
-
data: { id: doc.rootId, title: doc.title, slug: doc.slug, status: doc.status, collectionId: backing.coll.id, data: doc.data, created_at:
|
|
1098
|
+
data: { id: doc.rootId, title: doc.title, slug: doc.slug, status: doc.status, collectionId: backing.coll.id, data: doc.data, created_at: chunkJCBDXEY2_cjs.documentSecondsToMs(doc.createdAt), updated_at: chunkJCBDXEY2_cjs.documentSecondsToMs(doc.updatedAt) }
|
|
1060
1099
|
}, 201);
|
|
1061
1100
|
}
|
|
1062
1101
|
return c.json({ error: "Collection is not document-backed" }, 400);
|
|
@@ -1068,7 +1107,7 @@ apiContentCrudRoutes.post("/", chunkIS54FPB7_cjs.requireAuth(), chunkIS54FPB7_cj
|
|
|
1068
1107
|
}, 500);
|
|
1069
1108
|
}
|
|
1070
1109
|
});
|
|
1071
|
-
apiContentCrudRoutes.put("/:id",
|
|
1110
|
+
apiContentCrudRoutes.put("/:id", chunkE7E3NL3Y_cjs.requireAuth(), chunkE7E3NL3Y_cjs.requireRole(["admin", "editor", "author"]), async (c) => {
|
|
1072
1111
|
try {
|
|
1073
1112
|
const id = c.req.param("id");
|
|
1074
1113
|
const db = c.env.DB;
|
|
@@ -1090,8 +1129,8 @@ apiContentCrudRoutes.put("/:id", chunkIS54FPB7_cjs.requireAuth(), chunkIS54FPB7_
|
|
|
1090
1129
|
} catch (err) {
|
|
1091
1130
|
return c.json({ error: "Write cancelled by plugin", details: String(err) }, 400);
|
|
1092
1131
|
}
|
|
1093
|
-
const docType = await new
|
|
1094
|
-
const svc = new
|
|
1132
|
+
const docType = await new chunkE7E3NL3Y_cjs.DocumentTypeRegistry(db).findById(docRow.type_id);
|
|
1133
|
+
const svc = new chunkJCBDXEY2_cjs.DocumentsService(db, {
|
|
1095
1134
|
queryableFields: docType?.queryableFields ?? [],
|
|
1096
1135
|
typeSchemaVersion: docType?.schemaVersion ?? 1,
|
|
1097
1136
|
maxVersionsPerRoot: docType?.settings?.maxVersionsPerRoot ?? 50,
|
|
@@ -1111,9 +1150,9 @@ apiContentCrudRoutes.put("/:id", chunkIS54FPB7_cjs.requireAuth(), chunkIS54FPB7_
|
|
|
1111
1150
|
await svc.unpublish(pub.id);
|
|
1112
1151
|
}
|
|
1113
1152
|
const cache = chunk36Z3AKX3_cjs.getCacheService(chunk36Z3AKX3_cjs.CACHE_CONFIGS.api);
|
|
1114
|
-
await cache.invalidate("content-filtered:*");
|
|
1115
|
-
await cache.invalidate(
|
|
1116
|
-
const coll =
|
|
1153
|
+
await cache.invalidate("api:content-filtered:*");
|
|
1154
|
+
await cache.invalidate(`api:collection-content-filtered:${docRow.type_id}:*`);
|
|
1155
|
+
const coll = chunkYAURVGUK_cjs.getCollectionRegistry().getByName(docRow.type_id);
|
|
1117
1156
|
const saved = await db.prepare("SELECT * FROM documents WHERE id = ?").bind(newDraft.id).first();
|
|
1118
1157
|
const savedData = saved?.data ? JSON.parse(saved.data) : {};
|
|
1119
1158
|
dispatchHookEvent(c, "content:after:update", { collection: docRow.type_id, id, data: savedData, user: actor }, "fire-and-forget");
|
|
@@ -1122,7 +1161,7 @@ apiContentCrudRoutes.put("/:id", chunkIS54FPB7_cjs.requireAuth(), chunkIS54FPB7_
|
|
|
1122
1161
|
dispatchHookEvent(c, "content:after:publish", { collection: docRow.type_id, id, data: savedData, user: actor }, "fire-and-forget");
|
|
1123
1162
|
}
|
|
1124
1163
|
return c.json({
|
|
1125
|
-
data: { id: saved.root_id, title: saved.title, slug: saved.slug, status: saved.status, collectionId: coll?.id ?? docRow.type_id, data: savedData, created_at:
|
|
1164
|
+
data: { id: saved.root_id, title: saved.title, slug: saved.slug, status: saved.status, collectionId: coll?.id ?? docRow.type_id, data: savedData, created_at: chunkJCBDXEY2_cjs.documentSecondsToMs(saved.created_at), updated_at: chunkJCBDXEY2_cjs.documentSecondsToMs(saved.updated_at) }
|
|
1126
1165
|
});
|
|
1127
1166
|
}
|
|
1128
1167
|
return c.json({ error: "Content not found" }, 404);
|
|
@@ -1134,7 +1173,7 @@ apiContentCrudRoutes.put("/:id", chunkIS54FPB7_cjs.requireAuth(), chunkIS54FPB7_
|
|
|
1134
1173
|
}, 500);
|
|
1135
1174
|
}
|
|
1136
1175
|
});
|
|
1137
|
-
apiContentCrudRoutes.delete("/:id",
|
|
1176
|
+
apiContentCrudRoutes.delete("/:id", chunkE7E3NL3Y_cjs.requireAuth(), chunkE7E3NL3Y_cjs.requireRole(["admin", "editor", "author"]), async (c) => {
|
|
1138
1177
|
try {
|
|
1139
1178
|
const id = c.req.param("id");
|
|
1140
1179
|
const db = c.env.DB;
|
|
@@ -1151,8 +1190,8 @@ apiContentCrudRoutes.delete("/:id", chunkIS54FPB7_cjs.requireAuth(), chunkIS54FP
|
|
|
1151
1190
|
const now = Math.floor(Date.now() / 1e3);
|
|
1152
1191
|
await db.prepare("UPDATE documents SET deleted_at = ?, updated_at = ? WHERE root_id = ? AND tenant_id = ?").bind(now, now, id, tenantId).run();
|
|
1153
1192
|
const cache = chunk36Z3AKX3_cjs.getCacheService(chunk36Z3AKX3_cjs.CACHE_CONFIGS.api);
|
|
1154
|
-
await cache.invalidate("content-filtered:*");
|
|
1155
|
-
await cache.invalidate(
|
|
1193
|
+
await cache.invalidate("api:content-filtered:*");
|
|
1194
|
+
await cache.invalidate(`api:collection-content-filtered:${docRow.type_id}:*`);
|
|
1156
1195
|
dispatchHookEvent(c, "content:after:delete", { collection: docRow.type_id, id, data: {}, user: actor }, "fire-and-forget");
|
|
1157
1196
|
return c.json({ success: true });
|
|
1158
1197
|
}
|
|
@@ -1168,6 +1207,22 @@ apiContentCrudRoutes.delete("/:id", chunkIS54FPB7_cjs.requireAuth(), chunkIS54FP
|
|
|
1168
1207
|
var api_content_crud_default = apiContentCrudRoutes;
|
|
1169
1208
|
|
|
1170
1209
|
// src/routes/api.ts
|
|
1210
|
+
function isAnonPrincipal(principalSet) {
|
|
1211
|
+
return principalSet.length === 1 && principalSet[0]?.type === "public";
|
|
1212
|
+
}
|
|
1213
|
+
async function typeReadAllowed(db, principalSet, docType, typeName) {
|
|
1214
|
+
const perms = new DocumentPermissionsService(db);
|
|
1215
|
+
if (perms.isAllowedSync(principalSet, [], "read", docType?.settings ?? {})) return true;
|
|
1216
|
+
const rbac = new chunkJCBDXEY2_cjs.RbacService(db);
|
|
1217
|
+
let anyRbacRoleFound = false;
|
|
1218
|
+
for (const p of principalSet) {
|
|
1219
|
+
if (p.type !== "role") continue;
|
|
1220
|
+
if (!await rbac.hasRbacRole(p.id)) continue;
|
|
1221
|
+
anyRbacRoleFound = true;
|
|
1222
|
+
if (await rbac.isGrantedForRole(p.id, `document_type:${typeName}`, "read")) return true;
|
|
1223
|
+
}
|
|
1224
|
+
return !anyRbacRoleFound;
|
|
1225
|
+
}
|
|
1171
1226
|
var DOC_SORTABLE_COLUMNS = /* @__PURE__ */ new Set([
|
|
1172
1227
|
"created_at",
|
|
1173
1228
|
"updated_at",
|
|
@@ -1247,10 +1302,37 @@ function mapDocRowToContent(row, collectionId) {
|
|
|
1247
1302
|
collectionId,
|
|
1248
1303
|
data: row.data ? JSON.parse(row.data) : {},
|
|
1249
1304
|
// D29: document timestamps are SECONDS; the legacy `content` API contract is MILLISECONDS.
|
|
1250
|
-
created_at:
|
|
1251
|
-
updated_at:
|
|
1305
|
+
created_at: chunkJCBDXEY2_cjs.documentSecondsToMs(row.created_at),
|
|
1306
|
+
updated_at: chunkJCBDXEY2_cjs.documentSecondsToMs(row.updated_at)
|
|
1252
1307
|
};
|
|
1253
1308
|
}
|
|
1309
|
+
function projectFields(item, fields) {
|
|
1310
|
+
if (fields.length === 0) return item;
|
|
1311
|
+
const result = {};
|
|
1312
|
+
const dataSubFields = [];
|
|
1313
|
+
for (const f of fields) {
|
|
1314
|
+
if (f === "data") {
|
|
1315
|
+
result.data = item.data;
|
|
1316
|
+
} else if (f.startsWith("data.")) {
|
|
1317
|
+
dataSubFields.push(f.slice(5));
|
|
1318
|
+
} else if (Object.prototype.hasOwnProperty.call(item, f)) {
|
|
1319
|
+
result[f] = item[f];
|
|
1320
|
+
}
|
|
1321
|
+
}
|
|
1322
|
+
if (dataSubFields.length > 0 && !result.data) {
|
|
1323
|
+
result.data = {};
|
|
1324
|
+
for (const sub of dataSubFields) {
|
|
1325
|
+
if (item.data && Object.prototype.hasOwnProperty.call(item.data, sub)) {
|
|
1326
|
+
result.data[sub] = item.data[sub];
|
|
1327
|
+
}
|
|
1328
|
+
}
|
|
1329
|
+
}
|
|
1330
|
+
return result;
|
|
1331
|
+
}
|
|
1332
|
+
function parseFieldsParam(raw2) {
|
|
1333
|
+
if (!raw2) return [];
|
|
1334
|
+
return raw2.split(",").map((s) => s.trim()).filter(Boolean);
|
|
1335
|
+
}
|
|
1254
1336
|
var apiRoutes = new hono.Hono();
|
|
1255
1337
|
apiRoutes.use("*", async (c, next) => {
|
|
1256
1338
|
const startTime = Date.now();
|
|
@@ -1260,7 +1342,7 @@ apiRoutes.use("*", async (c, next) => {
|
|
|
1260
1342
|
c.header("X-Response-Time", `${totalTime}ms`);
|
|
1261
1343
|
});
|
|
1262
1344
|
apiRoutes.use("*", async (c, next) => {
|
|
1263
|
-
const cacheEnabled = await
|
|
1345
|
+
const cacheEnabled = await chunkE7E3NL3Y_cjs.isPluginActive(c.env.DB, "core-cache");
|
|
1264
1346
|
c.set("cacheEnabled", cacheEnabled);
|
|
1265
1347
|
await next();
|
|
1266
1348
|
});
|
|
@@ -1283,7 +1365,7 @@ apiRoutes.get("/", (c) => {
|
|
|
1283
1365
|
openapi: "3.0.0",
|
|
1284
1366
|
info: {
|
|
1285
1367
|
title: "SonicJS AI API",
|
|
1286
|
-
version:
|
|
1368
|
+
version: chunkBJ6NJL2E_cjs.getCoreVersion(),
|
|
1287
1369
|
description: "RESTful API for SonicJS headless CMS - a modern, AI-powered content management system built on Cloudflare Workers",
|
|
1288
1370
|
contact: {
|
|
1289
1371
|
name: "SonicJS Support",
|
|
@@ -1713,8 +1795,8 @@ apiRoutes.get("/collections", async (c) => {
|
|
|
1713
1795
|
}
|
|
1714
1796
|
c.header("X-Cache-Status", "MISS");
|
|
1715
1797
|
c.header("X-Cache-Source", "registry");
|
|
1716
|
-
const records =
|
|
1717
|
-
const transformedResults = records.map(
|
|
1798
|
+
const records = chunkYAURVGUK_cjs.getCollectionRegistry().listActive().filter((r) => !r.internal);
|
|
1799
|
+
const transformedResults = records.map(chunkYAURVGUK_cjs.collectionRecordToRow);
|
|
1718
1800
|
const responseData = {
|
|
1719
1801
|
data: transformedResults,
|
|
1720
1802
|
meta: addTimingMeta(c, {
|
|
@@ -1735,16 +1817,21 @@ apiRoutes.get("/collections", async (c) => {
|
|
|
1735
1817
|
return c.json({ error: "Failed to fetch collections" }, 500);
|
|
1736
1818
|
}
|
|
1737
1819
|
});
|
|
1738
|
-
apiRoutes.get("/content",
|
|
1820
|
+
apiRoutes.get("/content", chunkE7E3NL3Y_cjs.optionalAuth(), async (c) => {
|
|
1739
1821
|
const executionStart = Date.now();
|
|
1740
1822
|
try {
|
|
1741
1823
|
const db = c.env.DB;
|
|
1742
1824
|
const queryParams = c.req.query();
|
|
1825
|
+
const projFields = parseFieldsParam(queryParams.fields);
|
|
1826
|
+
if (queryParams.fields) delete queryParams.fields;
|
|
1743
1827
|
const role = c.get("user")?.role;
|
|
1828
|
+
const { tenantId: cTenantId, principalSet: cPrincipalSet } = getDocumentRequestContext(c);
|
|
1829
|
+
const cAnon = isAnonPrincipal(cPrincipalSet);
|
|
1830
|
+
const cNeedsAcl = !cAnon && !canReadNonPublicContent(role);
|
|
1744
1831
|
const collIdByName = /* @__PURE__ */ new Map();
|
|
1745
1832
|
let typeId;
|
|
1746
1833
|
let typeIds;
|
|
1747
|
-
const registry =
|
|
1834
|
+
const registry = chunkYAURVGUK_cjs.getCollectionRegistry();
|
|
1748
1835
|
if (queryParams.collection) {
|
|
1749
1836
|
const collectionName = queryParams.collection;
|
|
1750
1837
|
const record = registry.getByName(collectionName);
|
|
@@ -1774,11 +1861,11 @@ apiRoutes.get("/content", chunkIS54FPB7_cjs.optionalAuth(), async (c) => {
|
|
|
1774
1861
|
return r.name;
|
|
1775
1862
|
});
|
|
1776
1863
|
}
|
|
1777
|
-
const filter =
|
|
1864
|
+
const filter = chunkDLTT7QZU_cjs.QueryFilterBuilder.parseFromQuery(queryParams);
|
|
1778
1865
|
const normalizedFilter = augmentFilterForDocuments(filter, { typeId, typeIds, role });
|
|
1779
1866
|
if (!normalizedFilter.limit) normalizedFilter.limit = 50;
|
|
1780
1867
|
normalizedFilter.limit = Math.min(normalizedFilter.limit, 1e3);
|
|
1781
|
-
const builder = new
|
|
1868
|
+
const builder = new chunkDLTT7QZU_cjs.QueryFilterBuilder();
|
|
1782
1869
|
const queryResult = builder.build("documents", normalizedFilter);
|
|
1783
1870
|
if (queryResult.errors.length > 0) {
|
|
1784
1871
|
return c.json({
|
|
@@ -1786,7 +1873,7 @@ apiRoutes.get("/content", chunkIS54FPB7_cjs.optionalAuth(), async (c) => {
|
|
|
1786
1873
|
details: queryResult.errors
|
|
1787
1874
|
}, 400);
|
|
1788
1875
|
}
|
|
1789
|
-
const cacheEnabled = c.get("cacheEnabled");
|
|
1876
|
+
const cacheEnabled = c.get("cacheEnabled") && cAnon;
|
|
1790
1877
|
const cache = chunk36Z3AKX3_cjs.getCacheService(chunk36Z3AKX3_cjs.CACHE_CONFIGS.api);
|
|
1791
1878
|
const cacheKey = cache.generateKey("content-filtered", JSON.stringify({ filter: normalizedFilter, query: queryResult.sql }));
|
|
1792
1879
|
if (cacheEnabled) {
|
|
@@ -1816,11 +1903,41 @@ apiRoutes.get("/content", chunkIS54FPB7_cjs.optionalAuth(), async (c) => {
|
|
|
1816
1903
|
const stmt = db.prepare(queryResult.sql);
|
|
1817
1904
|
const boundStmt = queryResult.params.length > 0 ? stmt.bind(...queryResult.params) : stmt;
|
|
1818
1905
|
const { results } = await boundStmt.all();
|
|
1819
|
-
|
|
1906
|
+
let aclResults = results;
|
|
1907
|
+
if (cNeedsAcl) {
|
|
1908
|
+
const typeReg = new chunkE7E3NL3Y_cjs.DocumentTypeRegistry(db);
|
|
1909
|
+
const repo = new DocumentRepository(db, cTenantId);
|
|
1910
|
+
const uniqueTypeIds = [...new Set(results.map((r) => r.type_id))];
|
|
1911
|
+
const typeSettingsMap = /* @__PURE__ */ new Map();
|
|
1912
|
+
const typeRbacOnlyMap = /* @__PURE__ */ new Map();
|
|
1913
|
+
const typeDeniedMap = /* @__PURE__ */ new Map();
|
|
1914
|
+
await Promise.all(uniqueTypeIds.map(async (tid) => {
|
|
1915
|
+
const dt = await typeReg.findById(tid);
|
|
1916
|
+
const settings = dt?.settings ?? {};
|
|
1917
|
+
typeSettingsMap.set(tid, settings);
|
|
1918
|
+
const allowed2 = await typeReadAllowed(db, cPrincipalSet, dt, tid);
|
|
1919
|
+
if (!allowed2) {
|
|
1920
|
+
typeDeniedMap.set(tid, true);
|
|
1921
|
+
return;
|
|
1922
|
+
}
|
|
1923
|
+
const perms = new DocumentPermissionsService(db);
|
|
1924
|
+
typeRbacOnlyMap.set(tid, !perms.isAllowedSync(cPrincipalSet, [], "read", settings));
|
|
1925
|
+
}));
|
|
1926
|
+
const allowed = await Promise.all(
|
|
1927
|
+
results.map((row) => {
|
|
1928
|
+
const tid = row.type_id;
|
|
1929
|
+
if (typeDeniedMap.get(tid)) return Promise.resolve(false);
|
|
1930
|
+
if (typeRbacOnlyMap.get(tid)) return Promise.resolve(true);
|
|
1931
|
+
return repo.isAllowed(cPrincipalSet, row.root_id, "read", typeSettingsMap.get(tid) ?? {});
|
|
1932
|
+
})
|
|
1933
|
+
);
|
|
1934
|
+
aclResults = results.filter((_, i) => allowed[i]);
|
|
1935
|
+
}
|
|
1936
|
+
const transformedResults = aclResults.map((row) => mapDocRowToContent(row, collIdByName.get(row.type_id) ?? null));
|
|
1820
1937
|
const responseData = {
|
|
1821
|
-
data: transformedResults,
|
|
1938
|
+
data: projFields.length ? transformedResults.map((item) => projectFields(item, projFields)) : transformedResults,
|
|
1822
1939
|
meta: addTimingMeta(c, {
|
|
1823
|
-
count:
|
|
1940
|
+
count: aclResults.length,
|
|
1824
1941
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1825
1942
|
// D44: echo the caller's filter with the access policy applied (status=published forced for
|
|
1826
1943
|
// anonymous callers — the visible enforcement proof), NOT the internal doc-augmented where-tree.
|
|
@@ -1831,7 +1948,7 @@ apiRoutes.get("/content", chunkIS54FPB7_cjs.optionalAuth(), async (c) => {
|
|
|
1831
1948
|
}
|
|
1832
1949
|
}, executionStart)
|
|
1833
1950
|
};
|
|
1834
|
-
if (cacheEnabled) {
|
|
1951
|
+
if (cacheEnabled && projFields.length === 0) {
|
|
1835
1952
|
await cache.set(cacheKey, responseData);
|
|
1836
1953
|
}
|
|
1837
1954
|
return c.json(responseData);
|
|
@@ -1843,26 +1960,36 @@ apiRoutes.get("/content", chunkIS54FPB7_cjs.optionalAuth(), async (c) => {
|
|
|
1843
1960
|
}, 500);
|
|
1844
1961
|
}
|
|
1845
1962
|
});
|
|
1846
|
-
apiRoutes.get("/collections/:collection/content",
|
|
1963
|
+
apiRoutes.get("/collections/:collection/content", chunkE7E3NL3Y_cjs.optionalAuth(), async (c) => {
|
|
1847
1964
|
const executionStart = Date.now();
|
|
1848
1965
|
try {
|
|
1849
1966
|
const collection = c.req.param("collection");
|
|
1850
1967
|
const db = c.env.DB;
|
|
1851
1968
|
const queryParams = c.req.query();
|
|
1852
|
-
const record =
|
|
1969
|
+
const record = chunkYAURVGUK_cjs.getCollectionRegistry().getBySlugOrName(collection);
|
|
1853
1970
|
if (!record || record.isActive === false) {
|
|
1854
1971
|
return c.json({ error: "Collection not found" }, 404);
|
|
1855
1972
|
}
|
|
1856
1973
|
const collIdByName = /* @__PURE__ */ new Map();
|
|
1857
1974
|
collIdByName.set(collection, record.id);
|
|
1858
1975
|
const role = c.get("user")?.role;
|
|
1859
|
-
const
|
|
1976
|
+
const { tenantId: ccTenantId, principalSet: ccPrincipalSet } = getDocumentRequestContext(c);
|
|
1977
|
+
const ccAnon = isAnonPrincipal(ccPrincipalSet);
|
|
1978
|
+
const ccNeedsAcl = !ccAnon && !canReadNonPublicContent(role);
|
|
1979
|
+
let ccDocType;
|
|
1980
|
+
if (ccNeedsAcl) {
|
|
1981
|
+
ccDocType = await new chunkE7E3NL3Y_cjs.DocumentTypeRegistry(db).findById(record.name);
|
|
1982
|
+
if (!await typeReadAllowed(db, ccPrincipalSet, ccDocType, record.name)) {
|
|
1983
|
+
return c.json({ error: "Forbidden" }, 403);
|
|
1984
|
+
}
|
|
1985
|
+
}
|
|
1986
|
+
const filter = chunkDLTT7QZU_cjs.QueryFilterBuilder.parseFromQuery(queryParams);
|
|
1860
1987
|
const normalizedFilter = augmentFilterForDocuments(filter, { typeId: collection, role });
|
|
1861
1988
|
if (!normalizedFilter.limit) {
|
|
1862
1989
|
normalizedFilter.limit = 50;
|
|
1863
1990
|
}
|
|
1864
1991
|
normalizedFilter.limit = Math.min(normalizedFilter.limit, 1e3);
|
|
1865
|
-
const builder = new
|
|
1992
|
+
const builder = new chunkDLTT7QZU_cjs.QueryFilterBuilder();
|
|
1866
1993
|
const queryResult = builder.build("documents", normalizedFilter);
|
|
1867
1994
|
if (queryResult.errors.length > 0) {
|
|
1868
1995
|
return c.json({
|
|
@@ -1870,7 +1997,7 @@ apiRoutes.get("/collections/:collection/content", chunkIS54FPB7_cjs.optionalAuth
|
|
|
1870
1997
|
details: queryResult.errors
|
|
1871
1998
|
}, 400);
|
|
1872
1999
|
}
|
|
1873
|
-
const cacheEnabled = c.get("cacheEnabled");
|
|
2000
|
+
const cacheEnabled = c.get("cacheEnabled") && ccAnon;
|
|
1874
2001
|
const cache = chunk36Z3AKX3_cjs.getCacheService(chunk36Z3AKX3_cjs.CACHE_CONFIGS.api);
|
|
1875
2002
|
const includeCollection = queryParams.include?.split(",").map((s) => s.trim()).includes("collection");
|
|
1876
2003
|
const cacheKey = cache.generateKey("collection-content-filtered", `${collection}:${JSON.stringify({ filter: normalizedFilter, query: queryResult.sql, includeCollection })}`);
|
|
@@ -1901,12 +2028,24 @@ apiRoutes.get("/collections/:collection/content", chunkIS54FPB7_cjs.optionalAuth
|
|
|
1901
2028
|
const stmt = db.prepare(queryResult.sql);
|
|
1902
2029
|
const boundStmt = queryResult.params.length > 0 ? stmt.bind(...queryResult.params) : stmt;
|
|
1903
2030
|
const { results } = await boundStmt.all();
|
|
1904
|
-
|
|
2031
|
+
let ccAclResults = results;
|
|
2032
|
+
if (ccNeedsAcl) {
|
|
2033
|
+
const ccPerms = new DocumentPermissionsService(db);
|
|
2034
|
+
const ccBaseGrantsPass = ccPerms.isAllowedSync(ccPrincipalSet, [], "read", ccDocType?.settings ?? {});
|
|
2035
|
+
if (ccBaseGrantsPass) {
|
|
2036
|
+
const repo = new DocumentRepository(db, ccTenantId);
|
|
2037
|
+
const allowed = await Promise.all(
|
|
2038
|
+
results.map((row) => repo.isAllowed(ccPrincipalSet, row.root_id, "read", ccDocType?.settings ?? {}))
|
|
2039
|
+
);
|
|
2040
|
+
ccAclResults = results.filter((_, i) => allowed[i]);
|
|
2041
|
+
}
|
|
2042
|
+
}
|
|
2043
|
+
const transformedResults = ccAclResults.map((row) => mapDocRowToContent(row, collIdByName.get(row.type_id) ?? null));
|
|
1905
2044
|
const responseData = {
|
|
1906
2045
|
data: transformedResults,
|
|
1907
2046
|
meta: addTimingMeta(c, {
|
|
1908
|
-
...includeCollection ? { collection:
|
|
1909
|
-
count:
|
|
2047
|
+
...includeCollection ? { collection: chunkYAURVGUK_cjs.collectionRecordToRow(record) } : {},
|
|
2048
|
+
count: ccAclResults.length,
|
|
1910
2049
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1911
2050
|
// D44: echo the caller's filter with the access policy applied (status=published forced for
|
|
1912
2051
|
// anonymous callers — the visible enforcement proof), NOT the internal doc-augmented where-tree.
|
|
@@ -1930,31 +2069,43 @@ apiRoutes.get("/collections/:collection/content", chunkIS54FPB7_cjs.optionalAuth
|
|
|
1930
2069
|
}
|
|
1931
2070
|
});
|
|
1932
2071
|
apiRoutes.route("/content", api_content_crud_default);
|
|
1933
|
-
apiRoutes.get("/:collection",
|
|
2072
|
+
apiRoutes.get("/:collection", chunkE7E3NL3Y_cjs.optionalAuth(), async (c) => {
|
|
1934
2073
|
const executionStart = Date.now();
|
|
1935
2074
|
try {
|
|
1936
2075
|
const collection = c.req.param("collection");
|
|
1937
2076
|
const db = c.env.DB;
|
|
1938
2077
|
const queryParams = c.req.query();
|
|
1939
|
-
const
|
|
2078
|
+
const projFields = parseFieldsParam(queryParams.fields);
|
|
2079
|
+
if (queryParams.fields) delete queryParams.fields;
|
|
2080
|
+
const record = chunkYAURVGUK_cjs.getCollectionRegistry().getBySlugOrName(collection);
|
|
1940
2081
|
if (!record || record.isActive === false) {
|
|
1941
2082
|
return c.json({ error: "Collection not found" }, 404);
|
|
1942
2083
|
}
|
|
1943
2084
|
const collIdByName = /* @__PURE__ */ new Map();
|
|
1944
2085
|
collIdByName.set(record.name, record.id);
|
|
1945
2086
|
const role = c.get("user")?.role;
|
|
1946
|
-
const
|
|
2087
|
+
const { tenantId, principalSet } = getDocumentRequestContext(c);
|
|
2088
|
+
const anon = isAnonPrincipal(principalSet);
|
|
2089
|
+
const needsAcl = !anon && !canReadNonPublicContent(role);
|
|
2090
|
+
let docTypeForCheck;
|
|
2091
|
+
if (needsAcl) {
|
|
2092
|
+
docTypeForCheck = await new chunkE7E3NL3Y_cjs.DocumentTypeRegistry(db).findById(record.name);
|
|
2093
|
+
if (!await typeReadAllowed(db, principalSet, docTypeForCheck, record.name)) {
|
|
2094
|
+
return c.json({ error: "Forbidden" }, 403);
|
|
2095
|
+
}
|
|
2096
|
+
}
|
|
2097
|
+
const filter = chunkDLTT7QZU_cjs.QueryFilterBuilder.parseFromQuery(queryParams);
|
|
1947
2098
|
const normalizedFilter = augmentFilterForDocuments(filter, { typeId: record.name, role });
|
|
1948
2099
|
if (!normalizedFilter.limit) normalizedFilter.limit = 50;
|
|
1949
2100
|
normalizedFilter.limit = Math.min(normalizedFilter.limit, 1e3);
|
|
1950
|
-
const builder = new
|
|
2101
|
+
const builder = new chunkDLTT7QZU_cjs.QueryFilterBuilder();
|
|
1951
2102
|
const queryResult = builder.build("documents", normalizedFilter);
|
|
1952
2103
|
if (queryResult.errors.length > 0) {
|
|
1953
2104
|
return c.json({ error: "Invalid filter parameters", details: queryResult.errors }, 400);
|
|
1954
2105
|
}
|
|
1955
2106
|
const collectionCache = record.cache;
|
|
1956
2107
|
const collectionCacheDisabled = collectionCache?.enabled === false;
|
|
1957
|
-
const cacheEnabled = c.get("cacheEnabled") && !collectionCacheDisabled;
|
|
2108
|
+
const cacheEnabled = c.get("cacheEnabled") && !collectionCacheDisabled && projFields.length === 0 && anon;
|
|
1958
2109
|
const cache = chunk36Z3AKX3_cjs.getCacheService(chunk36Z3AKX3_cjs.CACHE_CONFIGS.api);
|
|
1959
2110
|
const includeCollection = queryParams.include?.split(",").map((s) => s.trim()).includes("collection");
|
|
1960
2111
|
const cacheKey = cache.generateKey("collection-content-filtered", `${collection}:${JSON.stringify({ filter: normalizedFilter, query: queryResult.sql, includeCollection })}`);
|
|
@@ -1972,12 +2123,25 @@ apiRoutes.get("/:collection", chunkIS54FPB7_cjs.optionalAuth(), async (c) => {
|
|
|
1972
2123
|
const stmt = db.prepare(queryResult.sql);
|
|
1973
2124
|
const boundStmt = queryResult.params.length > 0 ? stmt.bind(...queryResult.params) : stmt;
|
|
1974
2125
|
const { results } = await boundStmt.all();
|
|
1975
|
-
|
|
2126
|
+
let aclResults = results;
|
|
2127
|
+
if (needsAcl) {
|
|
2128
|
+
const perms = new DocumentPermissionsService(db);
|
|
2129
|
+
const baseGrantsPass = perms.isAllowedSync(principalSet, [], "read", docTypeForCheck?.settings ?? {});
|
|
2130
|
+
if (!baseGrantsPass) {
|
|
2131
|
+
} else {
|
|
2132
|
+
const repo = new DocumentRepository(db, tenantId);
|
|
2133
|
+
const allowed = await Promise.all(
|
|
2134
|
+
results.map((row) => repo.isAllowed(principalSet, row.root_id, "read", docTypeForCheck?.settings ?? {}))
|
|
2135
|
+
);
|
|
2136
|
+
aclResults = results.filter((_, i) => allowed[i]);
|
|
2137
|
+
}
|
|
2138
|
+
}
|
|
2139
|
+
const transformedResults = aclResults.map((row) => mapDocRowToContent(row, collIdByName.get(row.type_id) ?? null));
|
|
1976
2140
|
const responseData = {
|
|
1977
|
-
data: transformedResults,
|
|
2141
|
+
data: projFields.length ? transformedResults.map((item) => projectFields(item, projFields)) : transformedResults,
|
|
1978
2142
|
meta: addTimingMeta(c, {
|
|
1979
|
-
...includeCollection ? { collection:
|
|
1980
|
-
count:
|
|
2143
|
+
...includeCollection ? { collection: chunkYAURVGUK_cjs.collectionRecordToRow(record) } : {},
|
|
2144
|
+
count: aclResults.length,
|
|
1981
2145
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1982
2146
|
filter: normalizePublicContentFilter(filter, role),
|
|
1983
2147
|
cache: { hit: false, source: "database" }
|
|
@@ -1994,12 +2158,12 @@ apiRoutes.get("/:collection", chunkIS54FPB7_cjs.optionalAuth(), async (c) => {
|
|
|
1994
2158
|
return c.json({ error: "Failed to fetch content", details: error instanceof Error ? error.message : String(error) }, 500);
|
|
1995
2159
|
}
|
|
1996
2160
|
});
|
|
1997
|
-
apiRoutes.get("/:collection/:id",
|
|
2161
|
+
apiRoutes.get("/:collection/:id", chunkE7E3NL3Y_cjs.optionalAuth(), async (c) => {
|
|
1998
2162
|
try {
|
|
1999
2163
|
const collection = c.req.param("collection");
|
|
2000
2164
|
const id = c.req.param("id");
|
|
2001
2165
|
const db = c.env.DB;
|
|
2002
|
-
const record =
|
|
2166
|
+
const record = chunkYAURVGUK_cjs.getCollectionRegistry().getBySlugOrName(collection);
|
|
2003
2167
|
if (!record || record.isActive === false) {
|
|
2004
2168
|
return c.json({ error: "Collection not found" }, 404);
|
|
2005
2169
|
}
|
|
@@ -2008,7 +2172,24 @@ apiRoutes.get("/:collection/:id", chunkIS54FPB7_cjs.optionalAuth(), async (c) =>
|
|
|
2008
2172
|
privileged ? "SELECT * FROM documents WHERE root_id = ? AND type_id = ? AND tenant_id = 'default' AND is_current_draft = 1 AND deleted_at IS NULL" : "SELECT * FROM documents WHERE root_id = ? AND type_id = ? AND tenant_id = 'default' AND is_published = 1 AND deleted_at IS NULL"
|
|
2009
2173
|
).bind(id, record.name).first();
|
|
2010
2174
|
if (!docRow) return c.json({ error: "Content not found" }, 404);
|
|
2011
|
-
const
|
|
2175
|
+
const colRole = c.get("user")?.role;
|
|
2176
|
+
const { tenantId: colTenantId, principalSet: colPrincipalSet } = getDocumentRequestContext(c);
|
|
2177
|
+
const colNeedsAcl = !isAnonPrincipal(colPrincipalSet) && !canReadNonPublicContent(colRole);
|
|
2178
|
+
if (colNeedsAcl) {
|
|
2179
|
+
const docType = await new chunkE7E3NL3Y_cjs.DocumentTypeRegistry(db).findById(record.name);
|
|
2180
|
+
if (!await typeReadAllowed(db, colPrincipalSet, docType, record.name)) {
|
|
2181
|
+
return c.json({ error: "Content not found" }, 404);
|
|
2182
|
+
}
|
|
2183
|
+
const perms = new DocumentPermissionsService(db);
|
|
2184
|
+
if (perms.isAllowedSync(colPrincipalSet, [], "read", docType?.settings ?? {})) {
|
|
2185
|
+
const repo = new DocumentRepository(db, colTenantId);
|
|
2186
|
+
if (!await repo.isAllowed(colPrincipalSet, docRow.root_id, "read", docType?.settings ?? {})) {
|
|
2187
|
+
return c.json({ error: "Content not found" }, 404);
|
|
2188
|
+
}
|
|
2189
|
+
}
|
|
2190
|
+
}
|
|
2191
|
+
const projFields = parseFieldsParam(c.req.query("fields"));
|
|
2192
|
+
const coll = chunkYAURVGUK_cjs.getCollectionRegistry().getByName(docRow.type_id);
|
|
2012
2193
|
const transformedContent = {
|
|
2013
2194
|
id: docRow.root_id,
|
|
2014
2195
|
title: docRow.title,
|
|
@@ -2016,17 +2197,17 @@ apiRoutes.get("/:collection/:id", chunkIS54FPB7_cjs.optionalAuth(), async (c) =>
|
|
|
2016
2197
|
status: docRow.status,
|
|
2017
2198
|
collectionId: coll?.id ?? docRow.type_id,
|
|
2018
2199
|
data: docRow.data ? JSON.parse(docRow.data) : {},
|
|
2019
|
-
created_at:
|
|
2020
|
-
updated_at:
|
|
2200
|
+
created_at: chunkJCBDXEY2_cjs.documentSecondsToMs(docRow.created_at),
|
|
2201
|
+
updated_at: chunkJCBDXEY2_cjs.documentSecondsToMs(docRow.updated_at)
|
|
2021
2202
|
};
|
|
2022
2203
|
dispatchHookEvent(c, "content:read", { collection: docRow.type_id, id: docRow.root_id, data: transformedContent.data }, "fire-and-forget");
|
|
2023
|
-
return c.json({ data: transformedContent });
|
|
2204
|
+
return c.json({ data: projFields.length ? projectFields(transformedContent, projFields) : transformedContent });
|
|
2024
2205
|
} catch (error) {
|
|
2025
2206
|
console.error("Error fetching content:", error);
|
|
2026
2207
|
return c.json({ error: "Failed to fetch content", details: error instanceof Error ? error.message : String(error) }, 500);
|
|
2027
2208
|
}
|
|
2028
2209
|
});
|
|
2029
|
-
apiRoutes.post("/:collection",
|
|
2210
|
+
apiRoutes.post("/:collection", chunkE7E3NL3Y_cjs.requireAuth(), chunkE7E3NL3Y_cjs.requireRole(["admin", "editor", "author"]), async (c) => {
|
|
2030
2211
|
try {
|
|
2031
2212
|
const collection = c.req.param("collection");
|
|
2032
2213
|
const db = c.env.DB;
|
|
@@ -2047,26 +2228,26 @@ apiRoutes.post("/:collection", chunkIS54FPB7_cjs.requireAuth(), chunkIS54FPB7_cj
|
|
|
2047
2228
|
} catch (err) {
|
|
2048
2229
|
return c.json({ error: "Write cancelled by plugin", details: String(err) }, 400);
|
|
2049
2230
|
}
|
|
2050
|
-
const svc = new
|
|
2231
|
+
const svc = new chunkJCBDXEY2_cjs.DocumentsService(db, { queryableFields: backing.docType.queryableFields ?? [], typeSchemaVersion: backing.docType.schemaVersion ?? 1, maxVersionsPerRoot: backing.docType.settings?.maxVersionsPerRoot ?? 50, tenantId: "default", versioning: backing.docType.settings?.versioning ?? false });
|
|
2051
2232
|
const doc = await svc.create(createDocumentSchema.parse({ typeId: backing.coll.name, tenantId: "default", locale: "default", title, slug: finalSlug, data: hookData, publishOnCreate: (status || "draft") === "published" }), user?.userId);
|
|
2052
2233
|
const cache = chunk36Z3AKX3_cjs.getCacheService(chunk36Z3AKX3_cjs.CACHE_CONFIGS.api);
|
|
2053
|
-
await cache.invalidate("content-filtered:*");
|
|
2054
|
-
await cache.invalidate(
|
|
2234
|
+
await cache.invalidate("api:content-filtered:*");
|
|
2235
|
+
await cache.invalidate(`api:collection-content-filtered:${backing.coll.name}:*`);
|
|
2055
2236
|
dispatchHookEvent(c, "content:after:create", { collection: backing.coll.name, id: doc.rootId, data: doc.data ?? {}, user: actor }, "fire-and-forget");
|
|
2056
|
-
return c.json({ data: { id: doc.rootId, title: doc.title, slug: doc.slug, status: doc.status, collectionId: backing.coll.id, data: doc.data, created_at:
|
|
2237
|
+
return c.json({ data: { id: doc.rootId, title: doc.title, slug: doc.slug, status: doc.status, collectionId: backing.coll.id, data: doc.data, created_at: chunkJCBDXEY2_cjs.documentSecondsToMs(doc.createdAt), updated_at: chunkJCBDXEY2_cjs.documentSecondsToMs(doc.updatedAt) } }, 201);
|
|
2057
2238
|
} catch (error) {
|
|
2058
2239
|
console.error("Error creating content:", error);
|
|
2059
2240
|
return c.json({ error: "Failed to create content", details: error instanceof Error ? error.message : String(error) }, 500);
|
|
2060
2241
|
}
|
|
2061
2242
|
});
|
|
2062
|
-
apiRoutes.put("/:collection/:id",
|
|
2243
|
+
apiRoutes.put("/:collection/:id", chunkE7E3NL3Y_cjs.requireAuth(), chunkE7E3NL3Y_cjs.requireRole(["admin", "editor", "author"]), async (c) => {
|
|
2063
2244
|
try {
|
|
2064
2245
|
const collection = c.req.param("collection");
|
|
2065
2246
|
const id = c.req.param("id");
|
|
2066
2247
|
const db = c.env.DB;
|
|
2067
2248
|
const user = c.get("user");
|
|
2068
2249
|
const body = await c.req.json();
|
|
2069
|
-
const collRecord =
|
|
2250
|
+
const collRecord = chunkYAURVGUK_cjs.getCollectionRegistry().getBySlugOrName(collection);
|
|
2070
2251
|
const typeName = collRecord?.name ?? collection;
|
|
2071
2252
|
const docRow = await db.prepare("SELECT root_id, type_id FROM documents WHERE root_id = ? AND type_id = ? AND tenant_id = 'default' AND is_current_draft = 1 AND deleted_at IS NULL").bind(id, typeName).first();
|
|
2072
2253
|
if (!docRow) return c.json({ error: "Content not found" }, 404);
|
|
@@ -2078,8 +2259,8 @@ apiRoutes.put("/:collection/:id", chunkIS54FPB7_cjs.requireAuth(), chunkIS54FPB7
|
|
|
2078
2259
|
} catch (err) {
|
|
2079
2260
|
return c.json({ error: "Write cancelled by plugin", details: String(err) }, 400);
|
|
2080
2261
|
}
|
|
2081
|
-
const docType = await new
|
|
2082
|
-
const svc = new
|
|
2262
|
+
const docType = await new chunkE7E3NL3Y_cjs.DocumentTypeRegistry(db).findById(docRow.type_id);
|
|
2263
|
+
const svc = new chunkJCBDXEY2_cjs.DocumentsService(db, { queryableFields: docType?.queryableFields ?? [], typeSchemaVersion: docType?.schemaVersion ?? 1, maxVersionsPerRoot: docType?.settings?.maxVersionsPerRoot ?? 50, tenantId: "default", versioning: docType?.settings?.versioning ?? false });
|
|
2083
2264
|
const input = {};
|
|
2084
2265
|
if (body.title !== void 0) input.title = body.title;
|
|
2085
2266
|
if (body.slug !== void 0) input.slug = slugify(body.slug);
|
|
@@ -2093,27 +2274,27 @@ apiRoutes.put("/:collection/:id", chunkIS54FPB7_cjs.requireAuth(), chunkIS54FPB7
|
|
|
2093
2274
|
await svc.unpublish(pub.id);
|
|
2094
2275
|
}
|
|
2095
2276
|
const cache = chunk36Z3AKX3_cjs.getCacheService(chunk36Z3AKX3_cjs.CACHE_CONFIGS.api);
|
|
2096
|
-
await cache.invalidate("content-filtered:*");
|
|
2097
|
-
await cache.invalidate(
|
|
2098
|
-
const coll =
|
|
2277
|
+
await cache.invalidate("api:content-filtered:*");
|
|
2278
|
+
await cache.invalidate(`api:collection-content-filtered:${docRow.type_id}:*`);
|
|
2279
|
+
const coll = chunkYAURVGUK_cjs.getCollectionRegistry().getByName(docRow.type_id);
|
|
2099
2280
|
const saved = await db.prepare("SELECT * FROM documents WHERE id = ?").bind(newDraft.id).first();
|
|
2100
2281
|
const savedData = saved?.data ? JSON.parse(saved.data) : {};
|
|
2101
2282
|
dispatchHookEvent(c, "content:after:update", { collection: docRow.type_id, id, data: savedData, user: actor }, "fire-and-forget");
|
|
2102
2283
|
const nowPublished = body.status === "published" || body.status === void 0 && wasPublished;
|
|
2103
2284
|
if (nowPublished && !wasPublished) dispatchHookEvent(c, "content:after:publish", { collection: docRow.type_id, id, data: savedData, user: actor }, "fire-and-forget");
|
|
2104
|
-
return c.json({ data: { id: saved.root_id, title: saved.title, slug: saved.slug, status: saved.status, collectionId: coll?.id ?? docRow.type_id, data: savedData, created_at:
|
|
2285
|
+
return c.json({ data: { id: saved.root_id, title: saved.title, slug: saved.slug, status: saved.status, collectionId: coll?.id ?? docRow.type_id, data: savedData, created_at: chunkJCBDXEY2_cjs.documentSecondsToMs(saved.created_at), updated_at: chunkJCBDXEY2_cjs.documentSecondsToMs(saved.updated_at) } });
|
|
2105
2286
|
} catch (error) {
|
|
2106
2287
|
console.error("Error updating content:", error);
|
|
2107
2288
|
return c.json({ error: "Failed to update content", details: error instanceof Error ? error.message : String(error) }, 500);
|
|
2108
2289
|
}
|
|
2109
2290
|
});
|
|
2110
|
-
apiRoutes.delete("/:collection/:id",
|
|
2291
|
+
apiRoutes.delete("/:collection/:id", chunkE7E3NL3Y_cjs.requireAuth(), chunkE7E3NL3Y_cjs.requireRole(["admin", "editor", "author"]), async (c) => {
|
|
2111
2292
|
try {
|
|
2112
2293
|
const collection = c.req.param("collection");
|
|
2113
2294
|
const id = c.req.param("id");
|
|
2114
2295
|
const db = c.env.DB;
|
|
2115
2296
|
const user = c.get("user");
|
|
2116
|
-
const collRecord =
|
|
2297
|
+
const collRecord = chunkYAURVGUK_cjs.getCollectionRegistry().getBySlugOrName(collection);
|
|
2117
2298
|
const typeName = collRecord?.name ?? collection;
|
|
2118
2299
|
const docRow = await db.prepare("SELECT type_id FROM documents WHERE root_id = ? AND type_id = ? AND tenant_id = 'default' AND deleted_at IS NULL LIMIT 1").bind(id, typeName).first();
|
|
2119
2300
|
if (!docRow) return c.json({ error: "Content not found" }, 404);
|
|
@@ -2126,8 +2307,8 @@ apiRoutes.delete("/:collection/:id", chunkIS54FPB7_cjs.requireAuth(), chunkIS54F
|
|
|
2126
2307
|
const now = Math.floor(Date.now() / 1e3);
|
|
2127
2308
|
await db.prepare("UPDATE documents SET deleted_at = ?, updated_at = ? WHERE root_id = ? AND tenant_id = 'default'").bind(now, now, id).run();
|
|
2128
2309
|
const cache = chunk36Z3AKX3_cjs.getCacheService(chunk36Z3AKX3_cjs.CACHE_CONFIGS.api);
|
|
2129
|
-
await cache.invalidate("content-filtered:*");
|
|
2130
|
-
await cache.invalidate(
|
|
2310
|
+
await cache.invalidate("api:content-filtered:*");
|
|
2311
|
+
await cache.invalidate(`api:collection-content-filtered:${docRow.type_id}:*`);
|
|
2131
2312
|
dispatchHookEvent(c, "content:after:delete", { collection: docRow.type_id, id, data: {}, user: actor }, "fire-and-forget");
|
|
2132
2313
|
return c.json({ success: true });
|
|
2133
2314
|
} catch (error) {
|
|
@@ -2200,7 +2381,7 @@ var MediaDocumentService = class {
|
|
|
2200
2381
|
tenantId;
|
|
2201
2382
|
/** Create a media_asset document from R2 upload metadata. Published-on-create (immediately usable). */
|
|
2202
2383
|
async createFromUpload(meta, createdBy) {
|
|
2203
|
-
const svc = new
|
|
2384
|
+
const svc = new chunkJCBDXEY2_cjs.DocumentsService(this.db, { queryableFields: MEDIA_QUERYABLE, tenantId: this.tenantId, maxVersionsPerRoot: 5 });
|
|
2204
2385
|
return svc.create(
|
|
2205
2386
|
createDocumentSchema.parse({
|
|
2206
2387
|
typeId: "media_asset",
|
|
@@ -2278,7 +2459,7 @@ var MediaDocumentService = class {
|
|
|
2278
2459
|
}
|
|
2279
2460
|
/** Update alt/caption/tags on a media_asset document (saveDraft + publish atomically). */
|
|
2280
2461
|
async updateMetadata(rootId, meta, updatedBy) {
|
|
2281
|
-
const svc = new
|
|
2462
|
+
const svc = new chunkJCBDXEY2_cjs.DocumentsService(this.db, { queryableFields: MEDIA_QUERYABLE, tenantId: this.tenantId, maxVersionsPerRoot: 5 });
|
|
2282
2463
|
const newDraft = await svc.saveDraft(rootId, { data: meta }, updatedBy);
|
|
2283
2464
|
return svc.publish(newDraft.id, updatedBy);
|
|
2284
2465
|
}
|
|
@@ -2335,7 +2516,7 @@ var fileValidationSchema = zod.z.object({
|
|
|
2335
2516
|
// 50MB max
|
|
2336
2517
|
});
|
|
2337
2518
|
var apiMediaRoutes = new hono.Hono();
|
|
2338
|
-
apiMediaRoutes.use("*",
|
|
2519
|
+
apiMediaRoutes.use("*", chunkE7E3NL3Y_cjs.requireAuth());
|
|
2339
2520
|
apiMediaRoutes.post("/upload", async (c) => {
|
|
2340
2521
|
try {
|
|
2341
2522
|
const user = c.get("user");
|
|
@@ -2689,9 +2870,13 @@ apiMediaRoutes.post("/create-folder", async (c) => {
|
|
|
2689
2870
|
error: "Folder name can only contain lowercase letters, numbers, hyphens, and underscores"
|
|
2690
2871
|
}, 400);
|
|
2691
2872
|
}
|
|
2692
|
-
|
|
2693
|
-
|
|
2694
|
-
|
|
2873
|
+
let folderExists = false;
|
|
2874
|
+
try {
|
|
2875
|
+
const existing = await c.env.DB.prepare("SELECT COUNT(*) as count FROM documents WHERE type_id = 'media_asset' AND tenant_id = 'default' AND json_extract(data, '$.folder') = ? AND deleted_at IS NULL AND is_current_draft = 1").bind(folderName).first();
|
|
2876
|
+
folderExists = (existing?.count ?? 0) > 0;
|
|
2877
|
+
} catch {
|
|
2878
|
+
}
|
|
2879
|
+
if (folderExists) {
|
|
2695
2880
|
return c.json({
|
|
2696
2881
|
success: false,
|
|
2697
2882
|
error: `Folder "${folderName}" already exists`
|
|
@@ -3033,7 +3218,7 @@ apiSystemRoutes.get("/info", (c) => {
|
|
|
3033
3218
|
apiSystemRoutes.get("/stats", async (c) => {
|
|
3034
3219
|
try {
|
|
3035
3220
|
const db = c.env.DB;
|
|
3036
|
-
const typeIds =
|
|
3221
|
+
const typeIds = chunkYAURVGUK_cjs.getCollectionRegistry().listActive().filter((r) => !r.internal).map((r) => r.name);
|
|
3037
3222
|
let contentStats = null;
|
|
3038
3223
|
if (typeIds.length > 0) {
|
|
3039
3224
|
const placeholders = typeIds.map(() => "?").join(",");
|
|
@@ -3108,12 +3293,12 @@ apiSystemRoutes.get("/env", (c) => {
|
|
|
3108
3293
|
});
|
|
3109
3294
|
var api_system_default = apiSystemRoutes;
|
|
3110
3295
|
var adminApiRoutes = new hono.Hono();
|
|
3111
|
-
adminApiRoutes.use("*",
|
|
3112
|
-
adminApiRoutes.use("*",
|
|
3296
|
+
adminApiRoutes.use("*", chunkE7E3NL3Y_cjs.requireAuth());
|
|
3297
|
+
adminApiRoutes.use("*", chunkE7E3NL3Y_cjs.requireRole(["admin", "editor"]));
|
|
3113
3298
|
adminApiRoutes.get("/stats", async (c) => {
|
|
3114
3299
|
try {
|
|
3115
3300
|
const db = c.env.DB;
|
|
3116
|
-
const userCollections =
|
|
3301
|
+
const userCollections = chunkYAURVGUK_cjs.getCollectionRegistry().listActive().filter((r) => !r.internal);
|
|
3117
3302
|
const collectionsCount = userCollections.length;
|
|
3118
3303
|
let contentCount = 0;
|
|
3119
3304
|
if (userCollections.length > 0) {
|
|
@@ -3204,7 +3389,7 @@ adminApiRoutes.get("/collections", async (c) => {
|
|
|
3204
3389
|
try {
|
|
3205
3390
|
const search = c.req.query("search") || "";
|
|
3206
3391
|
const includeInactive = c.req.query("includeInactive") === "true";
|
|
3207
|
-
let records =
|
|
3392
|
+
let records = chunkYAURVGUK_cjs.getCollectionRegistry().list().filter((r) => !r.internal);
|
|
3208
3393
|
if (!includeInactive) records = records.filter((r) => r.isActive !== false);
|
|
3209
3394
|
if (search) {
|
|
3210
3395
|
const needle = search.toLowerCase();
|
|
@@ -3236,7 +3421,7 @@ adminApiRoutes.get("/collections", async (c) => {
|
|
|
3236
3421
|
adminApiRoutes.get("/collections/:id", async (c) => {
|
|
3237
3422
|
try {
|
|
3238
3423
|
const id = c.req.param("id");
|
|
3239
|
-
const registry =
|
|
3424
|
+
const registry = chunkYAURVGUK_cjs.getCollectionRegistry();
|
|
3240
3425
|
const record = registry.getById(id) ?? registry.getByName(id);
|
|
3241
3426
|
if (!record) {
|
|
3242
3427
|
return c.json({ error: "Collection not found" }, 404);
|
|
@@ -3286,7 +3471,7 @@ adminApiRoutes.get("/references", async (c) => {
|
|
|
3286
3471
|
if (collectionParams.length === 0) {
|
|
3287
3472
|
return c.json({ error: "Collection is required" }, 400);
|
|
3288
3473
|
}
|
|
3289
|
-
const registry =
|
|
3474
|
+
const registry = chunkYAURVGUK_cjs.getCollectionRegistry();
|
|
3290
3475
|
const matched = collectionParams.map((param) => registry.getById(param) ?? registry.getByName(param)).filter((r) => !!r);
|
|
3291
3476
|
const seen = /* @__PURE__ */ new Set();
|
|
3292
3477
|
const collections = matched.filter((r) => {
|
|
@@ -3401,7 +3586,7 @@ adminApiRoutes.patch("/collections/:id", collectionsReadOnly);
|
|
|
3401
3586
|
adminApiRoutes.delete("/collections/:id", collectionsReadOnly);
|
|
3402
3587
|
adminApiRoutes.get("/migrations/status", async (c) => {
|
|
3403
3588
|
try {
|
|
3404
|
-
const { MigrationService: MigrationService2 } = await import('./migrations-
|
|
3589
|
+
const { MigrationService: MigrationService2 } = await import('./migrations-KU4V6T73.cjs');
|
|
3405
3590
|
const db = c.env.DB;
|
|
3406
3591
|
const migrationService = new MigrationService2(db);
|
|
3407
3592
|
const status = await migrationService.getMigrationStatus();
|
|
@@ -3444,7 +3629,7 @@ adminApiRoutes.post("/migrations/run", async (c) => {
|
|
|
3444
3629
|
});
|
|
3445
3630
|
adminApiRoutes.get("/migrations/validate", async (c) => {
|
|
3446
3631
|
try {
|
|
3447
|
-
const { MigrationService: MigrationService2 } = await import('./migrations-
|
|
3632
|
+
const { MigrationService: MigrationService2 } = await import('./migrations-KU4V6T73.cjs');
|
|
3448
3633
|
const db = c.env.DB;
|
|
3449
3634
|
const migrationService = new MigrationService2(db);
|
|
3450
3635
|
const validation = await migrationService.validateSchema();
|
|
@@ -3594,8 +3779,8 @@ function renderLoginPage(data, demoLoginActive = false) {
|
|
|
3594
3779
|
<div class="mt-8 sm:mx-auto sm:w-full sm:max-w-md">
|
|
3595
3780
|
<div class="bg-zinc-900 shadow-sm ring-1 ring-white/10 rounded-xl px-6 py-8 sm:px-10">
|
|
3596
3781
|
<!-- Alerts -->
|
|
3597
|
-
${data.error ? `<div class="mb-6">${
|
|
3598
|
-
${data.message ? `<div class="mb-6">${
|
|
3782
|
+
${data.error ? `<div class="mb-6">${chunkOUBUS74I_cjs.renderAlert({ type: "error", message: data.error })}</div>` : ""}
|
|
3783
|
+
${data.message ? `<div class="mb-6">${chunkOUBUS74I_cjs.renderAlert({ type: "success", message: data.message })}</div>` : ""}
|
|
3599
3784
|
|
|
3600
3785
|
<!-- Form Response (HTMX target) -->
|
|
3601
3786
|
<div id="form-response" class="mb-6"></div>
|
|
@@ -3603,6 +3788,8 @@ function renderLoginPage(data, demoLoginActive = false) {
|
|
|
3603
3788
|
<!-- Form -->
|
|
3604
3789
|
<form
|
|
3605
3790
|
id="login-form"
|
|
3791
|
+
action="/auth/login/form${data.redirect ? `?redirect=${encodeURIComponent(data.redirect)}` : ""}"
|
|
3792
|
+
method="post"
|
|
3606
3793
|
hx-post="/auth/login/form${data.redirect ? `?redirect=${encodeURIComponent(data.redirect)}` : ""}"
|
|
3607
3794
|
hx-target="#form-response"
|
|
3608
3795
|
hx-swap="innerHTML"
|
|
@@ -3759,7 +3946,7 @@ function renderRegisterPage(data) {
|
|
|
3759
3946
|
<div class="mt-8 sm:mx-auto sm:w-full sm:max-w-md">
|
|
3760
3947
|
<div class="bg-zinc-900 shadow-sm ring-1 ring-white/10 rounded-xl px-6 py-8 sm:px-10">
|
|
3761
3948
|
<!-- Alerts -->
|
|
3762
|
-
${data.error ? `<div class="mb-6">${
|
|
3949
|
+
${data.error ? `<div class="mb-6">${chunkOUBUS74I_cjs.renderAlert({ type: "error", message: data.error })}</div>` : ""}
|
|
3763
3950
|
|
|
3764
3951
|
<!-- Form -->
|
|
3765
3952
|
<form
|
|
@@ -3859,7 +4046,7 @@ function renderRegisterPage(data) {
|
|
|
3859
4046
|
}
|
|
3860
4047
|
|
|
3861
4048
|
// src/services/email/email-service-singleton.ts
|
|
3862
|
-
var singleton =
|
|
4049
|
+
var singleton = chunkD6FWEYQE_cjs.createServiceSingleton("EmailService");
|
|
3863
4050
|
function setEmailService(service2) {
|
|
3864
4051
|
singleton.set(service2);
|
|
3865
4052
|
}
|
|
@@ -3903,7 +4090,7 @@ function emptyProfile() {
|
|
|
3903
4090
|
return { custom: {} };
|
|
3904
4091
|
}
|
|
3905
4092
|
function service(db) {
|
|
3906
|
-
return new
|
|
4093
|
+
return new chunkJCBDXEY2_cjs.DocumentsService(db, { tenantId: "default", maxVersionsPerRoot: 1, queryableFields: [] });
|
|
3907
4094
|
}
|
|
3908
4095
|
async function readProfileData(db, userId) {
|
|
3909
4096
|
const row = await db.prepare(
|
|
@@ -4667,7 +4854,7 @@ function getLexicalInitScript(settings = {}) {
|
|
|
4667
4854
|
</script>
|
|
4668
4855
|
`;
|
|
4669
4856
|
}
|
|
4670
|
-
var lexicalEditorPlugin =
|
|
4857
|
+
var lexicalEditorPlugin = chunkD6FWEYQE_cjs.definePlugin({
|
|
4671
4858
|
id: "lexical-editor",
|
|
4672
4859
|
version: "1.0.0",
|
|
4673
4860
|
name: "Lexical Editor",
|
|
@@ -5118,9 +5305,11 @@ function renderDynamicField(field, options = {}) {
|
|
|
5118
5305
|
min="${opts.min || ""}"
|
|
5119
5306
|
max="${opts.max || ""}"
|
|
5120
5307
|
class="${baseClasses} ${errorClasses} !w-auto dark:[color-scheme:dark]"
|
|
5308
|
+
placeholder="YYYY-MM-DD"
|
|
5121
5309
|
${required}
|
|
5122
5310
|
${disabled ? "disabled" : ""}
|
|
5123
5311
|
>
|
|
5312
|
+
<p class="mt-1 text-xs text-zinc-500 dark:text-zinc-400">Format: YYYY-MM-DD</p>
|
|
5124
5313
|
`;
|
|
5125
5314
|
break;
|
|
5126
5315
|
case "datetime":
|
|
@@ -5136,6 +5325,7 @@ function renderDynamicField(field, options = {}) {
|
|
|
5136
5325
|
${required}
|
|
5137
5326
|
${disabled ? "disabled" : ""}
|
|
5138
5327
|
>
|
|
5328
|
+
<p class="mt-1 text-xs text-zinc-500 dark:text-zinc-400">Format: YYYY-MM-DD HH:MM</p>
|
|
5139
5329
|
`;
|
|
5140
5330
|
break;
|
|
5141
5331
|
case "slug":
|
|
@@ -7073,7 +7263,7 @@ api.put("/:userId", async (c) => {
|
|
|
7073
7263
|
await saveCustomData(db, userId, sanitized);
|
|
7074
7264
|
return c.json({ success: true });
|
|
7075
7265
|
});
|
|
7076
|
-
var userProfilesPlugin =
|
|
7266
|
+
var userProfilesPlugin = chunkD6FWEYQE_cjs.definePlugin({
|
|
7077
7267
|
id: "user-profiles",
|
|
7078
7268
|
version: "1.0.0",
|
|
7079
7269
|
name: "User Profiles",
|
|
@@ -7092,6 +7282,21 @@ function createUserProfilesPlugin() {
|
|
|
7092
7282
|
|
|
7093
7283
|
// src/routes/auth.ts
|
|
7094
7284
|
var JWT_SECRET_FALLBACK = "your-super-secret-jwt-key-change-in-production";
|
|
7285
|
+
var DEMO_EMAIL = "admin@sonicjs.com";
|
|
7286
|
+
var STATS_EVENTS_ENDPOINT = "https://stats.sonicjs.com/v1/events";
|
|
7287
|
+
async function trackDemoLogin(kv) {
|
|
7288
|
+
try {
|
|
7289
|
+
const installationId = await kv?.get("_sonicjs_installation_id") ?? "demo-unknown";
|
|
7290
|
+
await fetch(STATS_EVENTS_ENDPOINT, {
|
|
7291
|
+
method: "POST",
|
|
7292
|
+
headers: { "Content-Type": "application/json" },
|
|
7293
|
+
body: JSON.stringify({
|
|
7294
|
+
data: { installation_id: installationId, event_type: "demo_login", properties: {}, timestamp: (/* @__PURE__ */ new Date()).toISOString() }
|
|
7295
|
+
})
|
|
7296
|
+
});
|
|
7297
|
+
} catch {
|
|
7298
|
+
}
|
|
7299
|
+
}
|
|
7095
7300
|
function renderPasswordResetEmail(resetLink, firstName) {
|
|
7096
7301
|
const greeting = firstName ? `Hi ${firstName},` : "Hello,";
|
|
7097
7302
|
return `<!DOCTYPE html>
|
|
@@ -7111,8 +7316,8 @@ function renderPasswordResetEmail(resetLink, firstName) {
|
|
|
7111
7316
|
async function setCsrfCookie(c, maxAge) {
|
|
7112
7317
|
const secret = c.env?.JWT_SECRET || JWT_SECRET_FALLBACK;
|
|
7113
7318
|
const isDev = c.env?.ENVIRONMENT === "development" || !c.env?.ENVIRONMENT;
|
|
7114
|
-
const csrfToken = await
|
|
7115
|
-
const cookieMaxAge = await
|
|
7319
|
+
const csrfToken = await chunkE7E3NL3Y_cjs.generateCsrfToken(secret);
|
|
7320
|
+
const cookieMaxAge = await chunkE7E3NL3Y_cjs.getJwtExpirySecondsFromDb(c.env?.DB, c.env);
|
|
7116
7321
|
cookie.setCookie(c, "csrf_token", csrfToken, {
|
|
7117
7322
|
httpOnly: false,
|
|
7118
7323
|
secure: !isDev,
|
|
@@ -7171,7 +7376,7 @@ var loginSchema = zod.z.object({
|
|
|
7171
7376
|
});
|
|
7172
7377
|
authRoutes.post(
|
|
7173
7378
|
"/register",
|
|
7174
|
-
|
|
7379
|
+
chunkE7E3NL3Y_cjs.rateLimit({ max: 30, windowMs: 60 * 1e3, keyPrefix: "register" }),
|
|
7175
7380
|
async (c) => {
|
|
7176
7381
|
try {
|
|
7177
7382
|
const db = c.env.DB;
|
|
@@ -7207,7 +7412,7 @@ authRoutes.post(
|
|
|
7207
7412
|
if (existingUser) {
|
|
7208
7413
|
return c.json({ error: "User with this email already exists" }, 400);
|
|
7209
7414
|
}
|
|
7210
|
-
const passwordHash = await
|
|
7415
|
+
const passwordHash = await chunkE7E3NL3Y_cjs.AuthManager.hashPassword(password);
|
|
7211
7416
|
const userId = crypto.randomUUID();
|
|
7212
7417
|
const now = /* @__PURE__ */ new Date();
|
|
7213
7418
|
const nowSec = Math.floor(now.getTime() / 1e3);
|
|
@@ -7240,8 +7445,8 @@ authRoutes.post(
|
|
|
7240
7445
|
{ user: { id: userId, email: normalizedEmail, role: "viewer" } },
|
|
7241
7446
|
"fire-and-forget"
|
|
7242
7447
|
);
|
|
7243
|
-
const tokenTtl = await
|
|
7244
|
-
const token = await
|
|
7448
|
+
const tokenTtl = await chunkE7E3NL3Y_cjs.getJwtExpirySecondsFromDb(c.env.DB, c.env);
|
|
7449
|
+
const token = await chunkE7E3NL3Y_cjs.AuthManager.generateToken(userId, normalizedEmail, "viewer", c.env.JWT_SECRET, tokenTtl);
|
|
7245
7450
|
cookie.setCookie(c, "auth_token", token, {
|
|
7246
7451
|
httpOnly: true,
|
|
7247
7452
|
secure: true,
|
|
@@ -7273,7 +7478,7 @@ authRoutes.post(
|
|
|
7273
7478
|
);
|
|
7274
7479
|
authRoutes.post(
|
|
7275
7480
|
"/login",
|
|
7276
|
-
|
|
7481
|
+
chunkE7E3NL3Y_cjs.rateLimit({ max: 30, windowMs: 60 * 1e3, keyPrefix: "login" }),
|
|
7277
7482
|
async (c) => {
|
|
7278
7483
|
try {
|
|
7279
7484
|
const body = await c.req.json();
|
|
@@ -7283,8 +7488,8 @@ authRoutes.post(
|
|
|
7283
7488
|
}
|
|
7284
7489
|
const { email, password } = validation.data;
|
|
7285
7490
|
const normalizedEmail = email.toLowerCase();
|
|
7286
|
-
const { createAuth } = await import('./config-
|
|
7287
|
-
const auth = createAuth(c.env);
|
|
7491
|
+
const { createAuth } = await import('./config-XN2ETAJ3.cjs');
|
|
7492
|
+
const auth = createAuth(c.env, void 0, new URL(c.req.url).origin);
|
|
7288
7493
|
const baReq = new Request(new URL("/auth/sign-in/email", c.req.url).href, {
|
|
7289
7494
|
method: "POST",
|
|
7290
7495
|
headers: { "Content-Type": "application/json", "Origin": new URL(c.req.url).origin },
|
|
@@ -7294,19 +7499,21 @@ authRoutes.post(
|
|
|
7294
7499
|
if (!baRes.ok) {
|
|
7295
7500
|
return c.json({ error: "Invalid email or password" }, 401);
|
|
7296
7501
|
}
|
|
7297
|
-
|
|
7298
|
-
if (rawSetCookie) {
|
|
7299
|
-
c.res.headers.append("Set-Cookie", rawSetCookie);
|
|
7300
|
-
} else if (baRes.headers.getSetCookie) {
|
|
7502
|
+
if (baRes.headers.getSetCookie) {
|
|
7301
7503
|
for (const sc of baRes.headers.getSetCookie()) {
|
|
7302
|
-
c.
|
|
7504
|
+
c.header("Set-Cookie", sc, { append: true });
|
|
7505
|
+
}
|
|
7506
|
+
} else {
|
|
7507
|
+
const rawSetCookie = baRes.headers.get("set-cookie");
|
|
7508
|
+
if (rawSetCookie) {
|
|
7509
|
+
c.header("Set-Cookie", rawSetCookie, { append: true });
|
|
7303
7510
|
}
|
|
7304
7511
|
}
|
|
7305
7512
|
await setCsrfCookie(c);
|
|
7306
7513
|
const baBody = await baRes.json();
|
|
7307
7514
|
const user = baBody.user ?? {};
|
|
7308
|
-
const tokenTtl = await
|
|
7309
|
-
const token = await
|
|
7515
|
+
const tokenTtl = await chunkE7E3NL3Y_cjs.getJwtExpirySecondsFromDb(c.env.DB, c.env);
|
|
7516
|
+
const token = await chunkE7E3NL3Y_cjs.AuthManager.generateToken(
|
|
7310
7517
|
user.id,
|
|
7311
7518
|
user.email,
|
|
7312
7519
|
user.role ?? "viewer",
|
|
@@ -7319,6 +7526,9 @@ authRoutes.post(
|
|
|
7319
7526
|
sameSite: "Strict",
|
|
7320
7527
|
maxAge: tokenTtl
|
|
7321
7528
|
});
|
|
7529
|
+
if (normalizedEmail === DEMO_EMAIL) {
|
|
7530
|
+
c.executionCtx?.waitUntil(trackDemoLogin(c.env.CACHE_KV));
|
|
7531
|
+
}
|
|
7322
7532
|
return c.json({
|
|
7323
7533
|
user: {
|
|
7324
7534
|
id: user.id,
|
|
@@ -7337,8 +7547,8 @@ authRoutes.post(
|
|
|
7337
7547
|
);
|
|
7338
7548
|
authRoutes.post("/logout", async (c) => {
|
|
7339
7549
|
try {
|
|
7340
|
-
const { createAuth } = await import('./config-
|
|
7341
|
-
const auth = createAuth(c.env);
|
|
7550
|
+
const { createAuth } = await import('./config-XN2ETAJ3.cjs');
|
|
7551
|
+
const auth = createAuth(c.env, void 0, new URL(c.req.url).origin);
|
|
7342
7552
|
const baReq = new Request(new URL("/auth/sign-out", c.req.url).href, {
|
|
7343
7553
|
method: "POST",
|
|
7344
7554
|
headers: { "Content-Type": "application/json", "Origin": new URL(c.req.url).origin, "Cookie": c.req.header("Cookie") || "" },
|
|
@@ -7347,14 +7557,15 @@ authRoutes.post("/logout", async (c) => {
|
|
|
7347
7557
|
await auth.handler(baReq);
|
|
7348
7558
|
} catch {
|
|
7349
7559
|
}
|
|
7350
|
-
|
|
7560
|
+
const isSecure = new URL(c.req.url).protocol === "https:";
|
|
7561
|
+
cookie.setCookie(c, "better-auth.session_token", "", { httpOnly: true, sameSite: "Lax", path: "/", maxAge: 0, secure: isSecure });
|
|
7351
7562
|
clearCsrfCookie(c);
|
|
7352
7563
|
return c.json({ message: "Logged out successfully" });
|
|
7353
7564
|
});
|
|
7354
7565
|
authRoutes.get("/logout", async (c) => {
|
|
7355
7566
|
try {
|
|
7356
|
-
const { createAuth } = await import('./config-
|
|
7357
|
-
const auth = createAuth(c.env);
|
|
7567
|
+
const { createAuth } = await import('./config-XN2ETAJ3.cjs');
|
|
7568
|
+
const auth = createAuth(c.env, void 0, new URL(c.req.url).origin);
|
|
7358
7569
|
const baReq = new Request(new URL("/auth/sign-out", c.req.url).href, {
|
|
7359
7570
|
method: "POST",
|
|
7360
7571
|
headers: { "Content-Type": "application/json", "Origin": new URL(c.req.url).origin, "Cookie": c.req.header("Cookie") || "" },
|
|
@@ -7363,11 +7574,12 @@ authRoutes.get("/logout", async (c) => {
|
|
|
7363
7574
|
await auth.handler(baReq);
|
|
7364
7575
|
} catch {
|
|
7365
7576
|
}
|
|
7366
|
-
|
|
7577
|
+
const isSecure = new URL(c.req.url).protocol === "https:";
|
|
7578
|
+
cookie.setCookie(c, "better-auth.session_token", "", { httpOnly: true, sameSite: "Lax", path: "/", maxAge: 0, secure: isSecure });
|
|
7367
7579
|
clearCsrfCookie(c);
|
|
7368
7580
|
return c.redirect("/auth/login?message=You have been logged out successfully");
|
|
7369
7581
|
});
|
|
7370
|
-
authRoutes.get("/me",
|
|
7582
|
+
authRoutes.get("/me", chunkE7E3NL3Y_cjs.requireAuth(), async (c) => {
|
|
7371
7583
|
try {
|
|
7372
7584
|
const user = c.get("user");
|
|
7373
7585
|
if (!user) {
|
|
@@ -7387,7 +7599,7 @@ authRoutes.get("/me", chunkIS54FPB7_cjs.requireAuth(), async (c) => {
|
|
|
7387
7599
|
});
|
|
7388
7600
|
authRoutes.post(
|
|
7389
7601
|
"/refresh",
|
|
7390
|
-
|
|
7602
|
+
chunkE7E3NL3Y_cjs.rateLimit({ max: 60, windowMs: 60 * 1e3, keyPrefix: "refresh" }),
|
|
7391
7603
|
async (c) => {
|
|
7392
7604
|
try {
|
|
7393
7605
|
let token = c.req.header("Authorization")?.replace("Bearer ", "");
|
|
@@ -7396,8 +7608,8 @@ authRoutes.post(
|
|
|
7396
7608
|
return c.json({ error: "Authentication required" }, 401);
|
|
7397
7609
|
}
|
|
7398
7610
|
const db = c.env.DB;
|
|
7399
|
-
const grace = await
|
|
7400
|
-
const payload = await
|
|
7611
|
+
const grace = await chunkE7E3NL3Y_cjs.getJwtRefreshGraceSecondsFromDb(db, c.env);
|
|
7612
|
+
const payload = await chunkE7E3NL3Y_cjs.AuthManager.verifyToken(token, c.env.JWT_SECRET, grace);
|
|
7401
7613
|
if (!payload) {
|
|
7402
7614
|
return c.json({ error: "Invalid or expired token" }, 401);
|
|
7403
7615
|
}
|
|
@@ -7405,8 +7617,8 @@ authRoutes.post(
|
|
|
7405
7617
|
if (!row || !row.is_active) {
|
|
7406
7618
|
return c.json({ error: "User is not active" }, 401);
|
|
7407
7619
|
}
|
|
7408
|
-
const tokenTtl = await
|
|
7409
|
-
const newToken = await
|
|
7620
|
+
const tokenTtl = await chunkE7E3NL3Y_cjs.getJwtExpirySecondsFromDb(db, c.env);
|
|
7621
|
+
const newToken = await chunkE7E3NL3Y_cjs.AuthManager.generateToken(row.id, row.email, row.role, c.env.JWT_SECRET, tokenTtl);
|
|
7410
7622
|
cookie.setCookie(c, "auth_token", newToken, {
|
|
7411
7623
|
httpOnly: true,
|
|
7412
7624
|
secure: true,
|
|
@@ -7426,7 +7638,7 @@ authRoutes.post(
|
|
|
7426
7638
|
);
|
|
7427
7639
|
authRoutes.post(
|
|
7428
7640
|
"/register/form",
|
|
7429
|
-
|
|
7641
|
+
chunkE7E3NL3Y_cjs.rateLimit({ max: 30, windowMs: 60 * 1e3, keyPrefix: "register" }),
|
|
7430
7642
|
async (c) => {
|
|
7431
7643
|
try {
|
|
7432
7644
|
const db = c.env.DB;
|
|
@@ -7471,7 +7683,7 @@ authRoutes.post(
|
|
|
7471
7683
|
</div>
|
|
7472
7684
|
`);
|
|
7473
7685
|
}
|
|
7474
|
-
const passwordHash = await
|
|
7686
|
+
const passwordHash = await chunkE7E3NL3Y_cjs.AuthManager.hashPassword(password);
|
|
7475
7687
|
const role = isFirstUser ? "admin" : "viewer";
|
|
7476
7688
|
const userId = crypto.randomUUID();
|
|
7477
7689
|
const now = /* @__PURE__ */ new Date();
|
|
@@ -7505,7 +7717,7 @@ authRoutes.post(
|
|
|
7505
7717
|
await saveCustomData(db, userId, sanitized);
|
|
7506
7718
|
}
|
|
7507
7719
|
}
|
|
7508
|
-
const rbacService = new
|
|
7720
|
+
const rbacService = new chunkJCBDXEY2_cjs.RbacService(db);
|
|
7509
7721
|
await rbacService.addUserRoleByName(userId, role);
|
|
7510
7722
|
dispatchHookEvent(
|
|
7511
7723
|
c,
|
|
@@ -7513,8 +7725,8 @@ authRoutes.post(
|
|
|
7513
7725
|
{ user: { id: userId, email: normalizedEmail, role } },
|
|
7514
7726
|
"fire-and-forget"
|
|
7515
7727
|
);
|
|
7516
|
-
const tokenTtl = await
|
|
7517
|
-
const token = await
|
|
7728
|
+
const tokenTtl = await chunkE7E3NL3Y_cjs.getJwtExpirySecondsFromDb(c.env.DB, c.env);
|
|
7729
|
+
const token = await chunkE7E3NL3Y_cjs.AuthManager.generateToken(userId, normalizedEmail, role, c.env.JWT_SECRET, tokenTtl);
|
|
7518
7730
|
cookie.setCookie(c, "auth_token", token, {
|
|
7519
7731
|
httpOnly: true,
|
|
7520
7732
|
secure: false,
|
|
@@ -7546,7 +7758,7 @@ authRoutes.post(
|
|
|
7546
7758
|
);
|
|
7547
7759
|
authRoutes.post(
|
|
7548
7760
|
"/login/form",
|
|
7549
|
-
|
|
7761
|
+
chunkE7E3NL3Y_cjs.rateLimit({ max: 30, windowMs: 60 * 1e3, keyPrefix: "login" }),
|
|
7550
7762
|
async (c) => {
|
|
7551
7763
|
try {
|
|
7552
7764
|
const formData = await c.req.formData();
|
|
@@ -7560,8 +7772,8 @@ authRoutes.post(
|
|
|
7560
7772
|
</div>
|
|
7561
7773
|
`);
|
|
7562
7774
|
}
|
|
7563
|
-
const { createAuth } = await import('./config-
|
|
7564
|
-
const auth = createAuth(c.env);
|
|
7775
|
+
const { createAuth } = await import('./config-XN2ETAJ3.cjs');
|
|
7776
|
+
const auth = createAuth(c.env, void 0, new URL(c.req.url).origin);
|
|
7565
7777
|
const baReq = new Request(new URL("/auth/sign-in/email", c.req.url).href, {
|
|
7566
7778
|
method: "POST",
|
|
7567
7779
|
headers: { "Content-Type": "application/json", "Origin": new URL(c.req.url).origin },
|
|
@@ -7575,17 +7787,27 @@ authRoutes.post(
|
|
|
7575
7787
|
</div>
|
|
7576
7788
|
`);
|
|
7577
7789
|
}
|
|
7578
|
-
|
|
7579
|
-
if (rawSetCookie) {
|
|
7580
|
-
c.res.headers.append("Set-Cookie", rawSetCookie);
|
|
7581
|
-
} else if (baRes.headers.getSetCookie) {
|
|
7790
|
+
if (baRes.headers.getSetCookie) {
|
|
7582
7791
|
for (const sc of baRes.headers.getSetCookie()) {
|
|
7583
|
-
c.
|
|
7792
|
+
c.header("Set-Cookie", sc, { append: true });
|
|
7793
|
+
}
|
|
7794
|
+
} else {
|
|
7795
|
+
const rawSetCookie = baRes.headers.get("set-cookie");
|
|
7796
|
+
if (rawSetCookie) {
|
|
7797
|
+
c.header("Set-Cookie", rawSetCookie, { append: true });
|
|
7584
7798
|
}
|
|
7585
7799
|
}
|
|
7586
7800
|
await setCsrfCookie(c);
|
|
7801
|
+
if (email === DEMO_EMAIL) {
|
|
7802
|
+
c.executionCtx?.waitUntil(trackDemoLogin(c.env.CACHE_KV));
|
|
7803
|
+
}
|
|
7587
7804
|
const rawRedirect = c.req.query("redirect");
|
|
7588
7805
|
const redirectUrl = rawRedirect && rawRedirect.startsWith("/") ? rawRedirect : "/admin/content";
|
|
7806
|
+
const isHtmx = c.req.header("HX-Request") === "true";
|
|
7807
|
+
if (isHtmx) {
|
|
7808
|
+
c.header("HX-Redirect", redirectUrl);
|
|
7809
|
+
return c.html(html.html`<div id="form-response"><p class="text-sm text-green-600">Login successful! Redirecting...</p></div>`);
|
|
7810
|
+
}
|
|
7589
7811
|
return c.html(html.html`
|
|
7590
7812
|
<div id="form-response">
|
|
7591
7813
|
<div class="rounded-lg bg-green-100 dark:bg-lime-500/10 p-4 ring-1 ring-green-400 dark:ring-lime-500/20">
|
|
@@ -7615,14 +7837,14 @@ authRoutes.post(
|
|
|
7615
7837
|
);
|
|
7616
7838
|
authRoutes.post(
|
|
7617
7839
|
"/seed-admin",
|
|
7618
|
-
|
|
7840
|
+
chunkE7E3NL3Y_cjs.rateLimit({ max: 10, windowMs: 60 * 1e3, keyPrefix: "seed-admin" }),
|
|
7619
7841
|
async (c) => {
|
|
7620
7842
|
try {
|
|
7621
7843
|
const db = c.env.DB;
|
|
7622
|
-
const rbac = new
|
|
7844
|
+
const rbac = new chunkJCBDXEY2_cjs.RbacService(db);
|
|
7623
7845
|
const results = [];
|
|
7624
7846
|
const upsertSeedUser = async (opts) => {
|
|
7625
|
-
const passwordHash = await
|
|
7847
|
+
const passwordHash = await chunkE7E3NL3Y_cjs.AuthManager.hashPassword(opts.password);
|
|
7626
7848
|
const nowMs = Date.now();
|
|
7627
7849
|
const nowSec = Math.floor(nowMs / 1e3);
|
|
7628
7850
|
const existing = await db.prepare("SELECT id FROM auth_user WHERE email = ?").bind(opts.email).first();
|
|
@@ -7847,7 +8069,7 @@ authRoutes.post("/accept-invitation", async (c) => {
|
|
|
7847
8069
|
if (invitationAge > maxAge) {
|
|
7848
8070
|
return c.json({ error: "Invitation has expired" }, 400);
|
|
7849
8071
|
}
|
|
7850
|
-
const passwordHash = await
|
|
8072
|
+
const passwordHash = await chunkE7E3NL3Y_cjs.AuthManager.hashPassword(password);
|
|
7851
8073
|
const updateStmt = db.prepare(`
|
|
7852
8074
|
UPDATE auth_user SET
|
|
7853
8075
|
password_hash = ?,
|
|
@@ -7864,8 +8086,8 @@ authRoutes.post("/accept-invitation", async (c) => {
|
|
|
7864
8086
|
Date.now(),
|
|
7865
8087
|
invitedUser.id
|
|
7866
8088
|
).run();
|
|
7867
|
-
const tokenTtl = await
|
|
7868
|
-
const authToken = await
|
|
8089
|
+
const tokenTtl = await chunkE7E3NL3Y_cjs.getJwtExpirySecondsFromDb(c.env.DB, c.env);
|
|
8090
|
+
const authToken = await chunkE7E3NL3Y_cjs.AuthManager.generateToken(invitedUser.id, invitedUser.email, invitedUser.role, c.env.JWT_SECRET, tokenTtl);
|
|
7869
8091
|
cookie.setCookie(c, "auth_token", authToken, {
|
|
7870
8092
|
httpOnly: true,
|
|
7871
8093
|
secure: true,
|
|
@@ -7881,7 +8103,7 @@ authRoutes.post("/accept-invitation", async (c) => {
|
|
|
7881
8103
|
});
|
|
7882
8104
|
authRoutes.post(
|
|
7883
8105
|
"/request-password-reset",
|
|
7884
|
-
|
|
8106
|
+
chunkE7E3NL3Y_cjs.rateLimit({ max: 3, windowMs: 15 * 60 * 1e3, keyPrefix: "password-reset" }),
|
|
7885
8107
|
async (c) => {
|
|
7886
8108
|
try {
|
|
7887
8109
|
const formData = await c.req.formData();
|
|
@@ -8118,7 +8340,7 @@ authRoutes.post("/reset-password", async (c) => {
|
|
|
8118
8340
|
if (Date.now() > user.password_reset_expires) {
|
|
8119
8341
|
return c.json({ error: "Reset token has expired" }, 400);
|
|
8120
8342
|
}
|
|
8121
|
-
const newPasswordHash = await
|
|
8343
|
+
const newPasswordHash = await chunkE7E3NL3Y_cjs.AuthManager.hashPassword(password);
|
|
8122
8344
|
try {
|
|
8123
8345
|
const historyStmt = db.prepare(`
|
|
8124
8346
|
INSERT INTO auth_password_history (id, user_id, password_hash, created_at)
|
|
@@ -8332,7 +8554,7 @@ app.post("/test-seed-defaults", async (c) => {
|
|
|
8332
8554
|
var test_cleanup_default = app;
|
|
8333
8555
|
|
|
8334
8556
|
// src/plugins/available/easy-mdx/index.ts
|
|
8335
|
-
|
|
8557
|
+
chunkD6FWEYQE_cjs.definePlugin({
|
|
8336
8558
|
id: "easy-mdx",
|
|
8337
8559
|
version: "1.0.0",
|
|
8338
8560
|
name: "EasyMDE Markdown Editor",
|
|
@@ -8532,7 +8754,7 @@ function getMDXEditorInitScript(config) {
|
|
|
8532
8754
|
}
|
|
8533
8755
|
|
|
8534
8756
|
// src/plugins/available/tinymce-plugin/index.ts
|
|
8535
|
-
|
|
8757
|
+
chunkD6FWEYQE_cjs.definePlugin({
|
|
8536
8758
|
id: "tinymce-plugin",
|
|
8537
8759
|
version: "1.0.0",
|
|
8538
8760
|
name: "TinyMCE",
|
|
@@ -8802,7 +9024,7 @@ function getQuillCDN(version = "2.0.2") {
|
|
|
8802
9024
|
</style>
|
|
8803
9025
|
`;
|
|
8804
9026
|
}
|
|
8805
|
-
|
|
9027
|
+
chunkD6FWEYQE_cjs.definePlugin({
|
|
8806
9028
|
id: "quill-editor",
|
|
8807
9029
|
version: "1.0.0",
|
|
8808
9030
|
name: "Quill Editor",
|
|
@@ -8814,7 +9036,7 @@ chunk4WMZGHIC_cjs.definePlugin({
|
|
|
8814
9036
|
});
|
|
8815
9037
|
|
|
8816
9038
|
// src/templates/pages/admin-content-form.template.ts
|
|
8817
|
-
|
|
9039
|
+
chunkMI2YXCK4_cjs.init_admin_layout_catalyst_template();
|
|
8818
9040
|
function renderContentFormPage(data, opts) {
|
|
8819
9041
|
const isEdit = data.isEdit || !!data.id;
|
|
8820
9042
|
const title = isEdit ? `Edit: ${data.title || "Content"}` : `New ${data.collection.display_name}`;
|
|
@@ -8896,8 +9118,8 @@ function renderContentFormPage(data, opts) {
|
|
|
8896
9118
|
<!-- Form Content -->
|
|
8897
9119
|
<div class="px-6 py-6">
|
|
8898
9120
|
<div id="form-messages">
|
|
8899
|
-
${data.error ?
|
|
8900
|
-
${data.success ?
|
|
9121
|
+
${data.error ? chunkOUBUS74I_cjs.renderAlert({ type: "error", message: data.error, dismissible: true }) : ""}
|
|
9122
|
+
${data.success ? chunkOUBUS74I_cjs.renderAlert({ type: "success", message: data.success, dismissible: true }) : ""}
|
|
8901
9123
|
</div>
|
|
8902
9124
|
|
|
8903
9125
|
<div class="grid grid-cols-1 lg:grid-cols-3 gap-6">
|
|
@@ -9010,20 +9232,20 @@ function renderContentFormPage(data, opts) {
|
|
|
9010
9232
|
<dl class="space-y-3 text-sm">
|
|
9011
9233
|
<div>
|
|
9012
9234
|
<dt class="text-zinc-500 dark:text-zinc-400">Created</dt>
|
|
9013
|
-
<dd class="mt-1 text-zinc-950 dark:text-white">${data.created_at ? new Date(data.created_at).toLocaleDateString() : "Unknown"}</dd>
|
|
9235
|
+
<dd class="mt-1 text-zinc-950 dark:text-white">${data.created_at ? new Date(data.created_at * 1e3).toLocaleDateString() : "Unknown"}</dd>
|
|
9014
9236
|
</div>
|
|
9015
9237
|
<div>
|
|
9016
9238
|
<dt class="text-zinc-500 dark:text-zinc-400">Last Modified</dt>
|
|
9017
|
-
<dd class="mt-1 text-zinc-950 dark:text-white">${data.updated_at ? new Date(data.updated_at).toLocaleDateString() : "Unknown"}</dd>
|
|
9239
|
+
<dd class="mt-1 text-zinc-950 dark:text-white">${data.updated_at ? new Date(data.updated_at * 1e3).toLocaleDateString() : "Unknown"}</dd>
|
|
9018
9240
|
</div>
|
|
9019
9241
|
<div>
|
|
9020
9242
|
<dt class="text-zinc-500 dark:text-zinc-400">Author</dt>
|
|
9021
|
-
<dd class="mt-1 text-zinc-950 dark:text-white">${data.data?.author || "Unknown"}</dd>
|
|
9243
|
+
<dd class="mt-1 text-zinc-950 dark:text-white">${chunkMNWKYY5E_cjs.escapeHtml(String(data.data?.author || data.author_name || "Unknown"))}</dd>
|
|
9022
9244
|
</div>
|
|
9023
9245
|
${data.published_at ? `
|
|
9024
9246
|
<div>
|
|
9025
9247
|
<dt class="text-zinc-500 dark:text-zinc-400">Published</dt>
|
|
9026
|
-
<dd class="mt-1 text-zinc-950 dark:text-white">${new Date(data.published_at).toLocaleDateString()}</dd>
|
|
9248
|
+
<dd class="mt-1 text-zinc-950 dark:text-white">${new Date(data.published_at * 1e3).toLocaleDateString()}</dd>
|
|
9027
9249
|
</div>
|
|
9028
9250
|
` : ""}
|
|
9029
9251
|
</dl>
|
|
@@ -9097,33 +9319,44 @@ function renderContentFormPage(data, opts) {
|
|
|
9097
9319
|
</a>
|
|
9098
9320
|
|
|
9099
9321
|
<div class="flex items-center gap-x-3">
|
|
9100
|
-
|
|
9101
|
-
|
|
9102
|
-
|
|
9103
|
-
|
|
9104
|
-
|
|
9105
|
-
|
|
9106
|
-
|
|
9107
|
-
>
|
|
9108
|
-
<
|
|
9109
|
-
|
|
9110
|
-
|
|
9111
|
-
|
|
9112
|
-
|
|
9113
|
-
|
|
9322
|
+
<button
|
|
9323
|
+
type="submit"
|
|
9324
|
+
form="content-form"
|
|
9325
|
+
name="action"
|
|
9326
|
+
value="save"
|
|
9327
|
+
class="inline-flex items-center justify-center gap-x-1.5 rounded-lg bg-zinc-950 dark:bg-white px-3.5 py-2.5 text-sm font-semibold text-white dark:text-zinc-950 hover:bg-zinc-800 dark:hover:bg-zinc-100 transition-colors shadow-sm"
|
|
9328
|
+
>
|
|
9329
|
+
<svg class="h-5 w-5" fill="none" stroke="currentColor" viewBox="0 0 24 24" stroke-width="1.5">
|
|
9330
|
+
<path stroke-linecap="round" stroke-linejoin="round" d="M5 13l4 4L19 7"/>
|
|
9331
|
+
</svg>
|
|
9332
|
+
Save
|
|
9333
|
+
</button>
|
|
9334
|
+
|
|
9335
|
+
<button
|
|
9336
|
+
type="submit"
|
|
9337
|
+
form="content-form"
|
|
9338
|
+
name="action"
|
|
9339
|
+
value="save_and_close"
|
|
9340
|
+
class="inline-flex items-center justify-center gap-x-1.5 rounded-lg bg-white dark:bg-zinc-800 px-3.5 py-2.5 text-sm font-semibold text-zinc-950 dark:text-white ring-1 ring-inset ring-zinc-950/10 dark:ring-white/10 hover:bg-zinc-50 dark:hover:bg-zinc-700 transition-colors shadow-sm"
|
|
9341
|
+
>
|
|
9342
|
+
<svg class="h-5 w-5" fill="none" stroke="currentColor" viewBox="0 0 24 24" stroke-width="1.5">
|
|
9343
|
+
<path stroke-linecap="round" stroke-linejoin="round" d="M6 18L18 6M6 6l12 12"/>
|
|
9344
|
+
</svg>
|
|
9345
|
+
Save & close
|
|
9346
|
+
</button>
|
|
9114
9347
|
|
|
9115
|
-
${data.user?.role !== "viewer" ? `
|
|
9348
|
+
${data.user?.role !== "viewer" && data.versioningEnabled ? `
|
|
9116
9349
|
<button
|
|
9117
9350
|
type="submit"
|
|
9118
9351
|
form="content-form"
|
|
9119
9352
|
name="action"
|
|
9120
9353
|
value="save_and_publish"
|
|
9121
|
-
class="inline-flex items-center justify-center gap-x-1.5 rounded-lg
|
|
9354
|
+
class="inline-flex items-center justify-center gap-x-1.5 rounded-lg bg-lime-600 dark:bg-lime-500 hover:bg-lime-700 dark:hover:bg-lime-600 px-3.5 py-2.5 text-sm font-semibold text-white transition-colors shadow-sm"
|
|
9122
9355
|
>
|
|
9123
9356
|
<svg class="h-5 w-5" fill="none" stroke="currentColor" viewBox="0 0 24 24" stroke-width="1.5">
|
|
9124
9357
|
<path stroke-linecap="round" stroke-linejoin="round" d="M9 12.75L11.25 15 15 9.75M21 12a9 9 0 11-18 0 9 9 0 0118 0z"/>
|
|
9125
9358
|
</svg>
|
|
9126
|
-
|
|
9359
|
+
Publish
|
|
9127
9360
|
</button>
|
|
9128
9361
|
` : ""}
|
|
9129
9362
|
</div>
|
|
@@ -9133,7 +9366,7 @@ function renderContentFormPage(data, opts) {
|
|
|
9133
9366
|
</div>
|
|
9134
9367
|
|
|
9135
9368
|
<!-- Confirmation Dialogs -->
|
|
9136
|
-
${
|
|
9369
|
+
${chunkOUBUS74I_cjs.renderConfirmationDialog({
|
|
9137
9370
|
id: "duplicate-content-confirm",
|
|
9138
9371
|
title: "Duplicate Content",
|
|
9139
9372
|
message: "Create a copy of this content?",
|
|
@@ -9144,7 +9377,7 @@ function renderContentFormPage(data, opts) {
|
|
|
9144
9377
|
onConfirm: "performDuplicateContent()"
|
|
9145
9378
|
})}
|
|
9146
9379
|
|
|
9147
|
-
${
|
|
9380
|
+
${chunkOUBUS74I_cjs.renderConfirmationDialog({
|
|
9148
9381
|
id: "delete-content-confirm",
|
|
9149
9382
|
title: "Delete Content",
|
|
9150
9383
|
message: "Are you sure you want to delete this content? This action cannot be undone.",
|
|
@@ -9155,7 +9388,7 @@ function renderContentFormPage(data, opts) {
|
|
|
9155
9388
|
onConfirm: `performDeleteContent('${data.id}')`
|
|
9156
9389
|
})}
|
|
9157
9390
|
|
|
9158
|
-
${
|
|
9391
|
+
${chunkOUBUS74I_cjs.renderConfirmationDialog({
|
|
9159
9392
|
id: "delete-repeater-item-confirm",
|
|
9160
9393
|
title: "Delete Item",
|
|
9161
9394
|
message: "Are you sure you want to delete this item? This action cannot be undone.",
|
|
@@ -9166,7 +9399,7 @@ function renderContentFormPage(data, opts) {
|
|
|
9166
9399
|
onConfirm: "performRepeaterDelete()"
|
|
9167
9400
|
})}
|
|
9168
9401
|
|
|
9169
|
-
${
|
|
9402
|
+
${chunkOUBUS74I_cjs.renderConfirmationDialog({
|
|
9170
9403
|
id: "delete-block-confirm",
|
|
9171
9404
|
title: "Delete Block",
|
|
9172
9405
|
message: "Are you sure you want to delete this block? This action cannot be undone.",
|
|
@@ -9177,7 +9410,7 @@ function renderContentFormPage(data, opts) {
|
|
|
9177
9410
|
onConfirm: "performRepeaterDelete()"
|
|
9178
9411
|
})}
|
|
9179
9412
|
|
|
9180
|
-
${
|
|
9413
|
+
${chunkOUBUS74I_cjs.getConfirmationDialogScript()}
|
|
9181
9414
|
|
|
9182
9415
|
${data.lexicalEnabled ? getLexicalStyles() : "<!-- Lexical plugin not active -->"}
|
|
9183
9416
|
|
|
@@ -10263,11 +10496,11 @@ function renderContentFormPage(data, opts) {
|
|
|
10263
10496
|
content: pageContent,
|
|
10264
10497
|
version: data.version
|
|
10265
10498
|
};
|
|
10266
|
-
return
|
|
10499
|
+
return chunkMI2YXCK4_cjs.renderAdminLayoutCatalyst(layoutData);
|
|
10267
10500
|
}
|
|
10268
10501
|
|
|
10269
10502
|
// src/templates/pages/admin-content-list.template.ts
|
|
10270
|
-
|
|
10503
|
+
chunkMI2YXCK4_cjs.init_admin_layout_catalyst_template();
|
|
10271
10504
|
function renderContentListPage(data) {
|
|
10272
10505
|
const urlParams = new URLSearchParams();
|
|
10273
10506
|
if (data.modelName && data.modelName !== "all") urlParams.set("model", data.modelName);
|
|
@@ -10701,8 +10934,8 @@ function renderContentListPage(data) {
|
|
|
10701
10934
|
|
|
10702
10935
|
<!-- Content List -->
|
|
10703
10936
|
<div id="content-list">
|
|
10704
|
-
${
|
|
10705
|
-
${
|
|
10937
|
+
${chunkOUBUS74I_cjs.renderTable(tableData)}
|
|
10938
|
+
${chunkOUBUS74I_cjs.renderPagination(paginationData)}
|
|
10706
10939
|
</div>
|
|
10707
10940
|
|
|
10708
10941
|
</div>
|
|
@@ -10912,7 +11145,7 @@ function renderContentListPage(data) {
|
|
|
10912
11145
|
</script>
|
|
10913
11146
|
|
|
10914
11147
|
<!-- Confirmation Dialog for Bulk Actions -->
|
|
10915
|
-
${
|
|
11148
|
+
${chunkOUBUS74I_cjs.renderConfirmationDialog({
|
|
10916
11149
|
id: "bulk-action-confirm",
|
|
10917
11150
|
title: "Confirm Bulk Action",
|
|
10918
11151
|
message: "Are you sure you want to perform this action? This operation will affect multiple items.",
|
|
@@ -10924,7 +11157,7 @@ function renderContentListPage(data) {
|
|
|
10924
11157
|
})}
|
|
10925
11158
|
|
|
10926
11159
|
<!-- Confirmation Dialog Script -->
|
|
10927
|
-
${
|
|
11160
|
+
${chunkOUBUS74I_cjs.getConfirmationDialogScript()}
|
|
10928
11161
|
|
|
10929
11162
|
<!-- Advanced Search Modal -->
|
|
10930
11163
|
<div id="advancedSearchModal" class="hidden fixed inset-0 z-50 overflow-y-auto" aria-labelledby="modal-title" role="dialog" aria-modal="true">
|
|
@@ -11221,7 +11454,7 @@ function renderContentListPage(data) {
|
|
|
11221
11454
|
version: data.version,
|
|
11222
11455
|
content: pageContent
|
|
11223
11456
|
};
|
|
11224
|
-
return
|
|
11457
|
+
return chunkMI2YXCK4_cjs.renderAdminLayoutCatalyst(layoutData);
|
|
11225
11458
|
}
|
|
11226
11459
|
|
|
11227
11460
|
// src/routes/admin-content-field-types.ts
|
|
@@ -11264,9 +11497,9 @@ function parseFieldValue(field, formData, options = {}) {
|
|
|
11264
11497
|
const { skipValidation = false } = options;
|
|
11265
11498
|
const value = formData.get(field.field_name);
|
|
11266
11499
|
const errors = [];
|
|
11267
|
-
const blocksConfig =
|
|
11500
|
+
const blocksConfig = chunkDLTT7QZU_cjs.getBlocksFieldConfig(field.field_options);
|
|
11268
11501
|
if (blocksConfig) {
|
|
11269
|
-
const parsed =
|
|
11502
|
+
const parsed = chunkDLTT7QZU_cjs.parseBlocksValue(value, blocksConfig);
|
|
11270
11503
|
if (!skipValidation && field.is_required && parsed.value.length === 0) {
|
|
11271
11504
|
parsed.errors.push(`${field.field_label} is required`);
|
|
11272
11505
|
}
|
|
@@ -11376,7 +11609,7 @@ function extractFieldData(fields, formData, options = {}) {
|
|
|
11376
11609
|
}
|
|
11377
11610
|
return { data, errors };
|
|
11378
11611
|
}
|
|
11379
|
-
adminContentRoutes.use("*",
|
|
11612
|
+
adminContentRoutes.use("*", chunkE7E3NL3Y_cjs.requireAuth());
|
|
11380
11613
|
async function getCollectionFields(db, collectionId) {
|
|
11381
11614
|
console.log(`[getCollectionFields] Loading fields for collection: ${collectionId}`);
|
|
11382
11615
|
const collectionStmt = db.prepare("SELECT schema, queryable_fields FROM document_types WHERE id = ?");
|
|
@@ -11403,7 +11636,7 @@ async function getCollectionFields(db, collectionId) {
|
|
|
11403
11636
|
};
|
|
11404
11637
|
});
|
|
11405
11638
|
}
|
|
11406
|
-
const codeCollections2 = await
|
|
11639
|
+
const codeCollections2 = await chunkYAURVGUK_cjs.loadCollectionConfigs();
|
|
11407
11640
|
const codeMatch = codeCollections2.find((c) => c.name === collectionId);
|
|
11408
11641
|
if (codeMatch && codeMatch.schema?.properties) {
|
|
11409
11642
|
console.log(`[getCollectionFields] DB doc type has no properties \u2014 using code collection schema`);
|
|
@@ -11435,7 +11668,7 @@ async function getCollectionFields(db, collectionId) {
|
|
|
11435
11668
|
}
|
|
11436
11669
|
}
|
|
11437
11670
|
console.log(`[getCollectionFields] Not in database, checking code collections`);
|
|
11438
|
-
const codeCollections = await
|
|
11671
|
+
const codeCollections = await chunkYAURVGUK_cjs.loadCollectionConfigs();
|
|
11439
11672
|
console.log(`[getCollectionFields] Found ${codeCollections.length} code collections`);
|
|
11440
11673
|
const codeCollection = codeCollections.find((c) => c.name === collectionId);
|
|
11441
11674
|
if (codeCollection && codeCollection.schema) {
|
|
@@ -11489,7 +11722,7 @@ async function getCollection(db, collectionId) {
|
|
|
11489
11722
|
};
|
|
11490
11723
|
}
|
|
11491
11724
|
console.log(`[getCollection] Not in database, checking code collections`);
|
|
11492
|
-
const codeCollections = await
|
|
11725
|
+
const codeCollections = await chunkYAURVGUK_cjs.loadCollectionConfigs();
|
|
11493
11726
|
const codeCollection = codeCollections.find((c) => c.name === collectionId);
|
|
11494
11727
|
if (codeCollection) {
|
|
11495
11728
|
console.log(`[getCollection] Found code collection: ${collectionId}`);
|
|
@@ -11508,7 +11741,7 @@ async function getCollection(db, collectionId) {
|
|
|
11508
11741
|
}
|
|
11509
11742
|
async function getDocBackingType(db, collectionName) {
|
|
11510
11743
|
if (!collectionName) return null;
|
|
11511
|
-
const dt = await new
|
|
11744
|
+
const dt = await new chunkE7E3NL3Y_cjs.DocumentTypeRegistry(db).findById(collectionName);
|
|
11512
11745
|
return dt && dt.isActive ? dt : null;
|
|
11513
11746
|
}
|
|
11514
11747
|
async function getCollectionByName(db, name) {
|
|
@@ -11525,7 +11758,7 @@ async function getCollectionByName(db, name) {
|
|
|
11525
11758
|
};
|
|
11526
11759
|
}
|
|
11527
11760
|
console.log(`[getCollectionByName] Not in database, checking code collections`);
|
|
11528
|
-
const codeCollections = await
|
|
11761
|
+
const codeCollections = await chunkYAURVGUK_cjs.loadCollectionConfigs();
|
|
11529
11762
|
const codeCollection = codeCollections.find((c) => c.name === name);
|
|
11530
11763
|
if (codeCollection) {
|
|
11531
11764
|
console.log(`[getCollectionByName] Found code collection: ${name}`);
|
|
@@ -11541,7 +11774,7 @@ async function getCollectionByName(db, name) {
|
|
|
11541
11774
|
return null;
|
|
11542
11775
|
}
|
|
11543
11776
|
async function loadContentEditorFlags(db) {
|
|
11544
|
-
const flags = { workflowEnabled: await
|
|
11777
|
+
const flags = { workflowEnabled: await chunkE7E3NL3Y_cjs.isPluginActive(db, "workflow") };
|
|
11545
11778
|
const editors = [
|
|
11546
11779
|
["tinymce-plugin", "tinymce"],
|
|
11547
11780
|
["quill-editor", "quill"],
|
|
@@ -11549,10 +11782,10 @@ async function loadContentEditorFlags(db) {
|
|
|
11549
11782
|
["lexical-editor", "lexical"]
|
|
11550
11783
|
];
|
|
11551
11784
|
for (const [plugin, key] of editors) {
|
|
11552
|
-
const enabled = await
|
|
11785
|
+
const enabled = await chunkE7E3NL3Y_cjs.isPluginActive(db, plugin);
|
|
11553
11786
|
flags[`${key}Enabled`] = enabled;
|
|
11554
11787
|
if (enabled) {
|
|
11555
|
-
const ps = new
|
|
11788
|
+
const ps = new chunkYAURVGUK_cjs.PluginService(db);
|
|
11556
11789
|
const p = await ps.getPlugin(plugin);
|
|
11557
11790
|
flags[`${key}Settings`] = p?.settings;
|
|
11558
11791
|
}
|
|
@@ -11560,7 +11793,7 @@ async function loadContentEditorFlags(db) {
|
|
|
11560
11793
|
return flags;
|
|
11561
11794
|
}
|
|
11562
11795
|
function makeDocService(db, docType, tenantId) {
|
|
11563
|
-
return new
|
|
11796
|
+
return new chunkJCBDXEY2_cjs.DocumentsService(db, {
|
|
11564
11797
|
queryableFields: docType.queryableFields ?? [],
|
|
11565
11798
|
typeSchemaVersion: docType.schemaVersion ?? 1,
|
|
11566
11799
|
maxVersionsPerRoot: docType.settings?.maxVersionsPerRoot ?? 50,
|
|
@@ -11588,9 +11821,9 @@ adminContentRoutes.get("/", async (c) => {
|
|
|
11588
11821
|
const offset = (page - 1) * limit;
|
|
11589
11822
|
const collectionsStmt = db.prepare("SELECT id, name, display_name FROM document_types WHERE is_active = 1 ORDER BY display_name");
|
|
11590
11823
|
const { results: collectionsResults } = await collectionsStmt.all();
|
|
11591
|
-
const codeCollections = await
|
|
11824
|
+
const codeCollections = await chunkYAURVGUK_cjs.loadCollectionConfigs();
|
|
11592
11825
|
const codeCollectionMap = new Map(codeCollections.map((c2) => [c2.name, c2]));
|
|
11593
|
-
const docTypeRegistry = new
|
|
11826
|
+
const docTypeRegistry = new chunkE7E3NL3Y_cjs.DocumentTypeRegistry(db);
|
|
11594
11827
|
const docTypes = (await docTypeRegistry.findAll()).filter((dt) => !dt.settings?.internal && !dt.isAuth);
|
|
11595
11828
|
const visibleTypeIds = new Set(docTypes.map((dt) => dt.id));
|
|
11596
11829
|
const allCollections = [
|
|
@@ -11602,7 +11835,7 @@ adminContentRoutes.get("/", async (c) => {
|
|
|
11602
11835
|
...allCollections.map((c2) => ({ name: c2.name, displayName: c2.displayName })),
|
|
11603
11836
|
...docTypes.filter((dt) => !collectionNames.has(dt.id)).map((dt) => ({ name: `doc:${dt.id}`, displayName: dt.displayName }))
|
|
11604
11837
|
];
|
|
11605
|
-
const newContentCollections = await
|
|
11838
|
+
const newContentCollections = await chunkYAURVGUK_cjs.getVisibleCollections(db);
|
|
11606
11839
|
const docBackedCollection = !modelName.startsWith("doc:") && modelName !== "all" ? docTypes.find((dt) => dt.id === modelName) : void 0;
|
|
11607
11840
|
const isDocModel = modelName.startsWith("doc:") || !!docBackedCollection;
|
|
11608
11841
|
if (isDocModel) {
|
|
@@ -11625,6 +11858,14 @@ adminContentRoutes.get("/", async (c) => {
|
|
|
11625
11858
|
docSql += " ORDER BY updated_at DESC LIMIT ? OFFSET ?";
|
|
11626
11859
|
docParams.push(limit, offset);
|
|
11627
11860
|
const { results: docRows } = await db.prepare(docSql).bind(...docParams).all();
|
|
11861
|
+
const docUserIds = [...new Set((docRows ?? []).map((r) => r.created_by).filter(Boolean))];
|
|
11862
|
+
const docAuthorMap = {};
|
|
11863
|
+
for (let i = 0; i < docUserIds.length; i += 99) {
|
|
11864
|
+
const chunk = docUserIds.slice(i, i + 99);
|
|
11865
|
+
const ph = chunk.map(() => "?").join(",");
|
|
11866
|
+
const { results: uRows } = await db.prepare(`SELECT id, email FROM auth_user WHERE id IN (${ph})`).bind(...chunk).all();
|
|
11867
|
+
for (const u of uRows ?? []) docAuthorMap[u.id] = u.email;
|
|
11868
|
+
}
|
|
11628
11869
|
const statusBadgeCss = {
|
|
11629
11870
|
published: "bg-green-50 dark:bg-green-500/10 text-green-700 dark:text-green-400 ring-1 ring-inset ring-green-600/20 dark:ring-green-500/20",
|
|
11630
11871
|
draft: "bg-zinc-50 dark:bg-zinc-500/10 text-zinc-700 dark:text-zinc-400 ring-1 ring-inset ring-zinc-600/20 dark:ring-zinc-500/20"
|
|
@@ -11641,7 +11882,7 @@ adminContentRoutes.get("/", async (c) => {
|
|
|
11641
11882
|
slug: row.slug || "",
|
|
11642
11883
|
modelName: docType?.displayName ?? typeId,
|
|
11643
11884
|
statusBadge: `<span class="inline-flex items-center rounded-md px-2 py-1 text-xs font-medium ${css}">${label}</span>`,
|
|
11644
|
-
authorName: row.created_by || "System",
|
|
11885
|
+
authorName: (row.created_by ? docAuthorMap[row.created_by] ?? row.created_by : null) || "System",
|
|
11645
11886
|
// Document timestamps are stored in SECONDS (documents.ts), unlike legacy content rows which
|
|
11646
11887
|
// store MILLISECONDS — hence the *1000 here (D23).
|
|
11647
11888
|
formattedDate: new Date((row.updated_at ?? 0) * 1e3).toLocaleDateString(),
|
|
@@ -11689,8 +11930,8 @@ adminContentRoutes.get("/", async (c) => {
|
|
|
11689
11930
|
SELECT d.root_id AS id, d.title AS title, d.slug AS slug,
|
|
11690
11931
|
CASE WHEN d.is_published = 1 THEN 'published' ELSE 'draft' END AS status,
|
|
11691
11932
|
d.updated_at * 1000 AS updated_at,
|
|
11692
|
-
dt.display_name AS cdisplay, COALESCE(d.created_by, 'System') AS author_label
|
|
11693
|
-
FROM documents d JOIN document_types dt ON dt.id = d.type_id
|
|
11933
|
+
dt.display_name AS cdisplay, COALESCE(u.email, d.created_by, 'System') AS author_label
|
|
11934
|
+
FROM documents d JOIN document_types dt ON dt.id = d.type_id LEFT JOIN auth_user u ON u.id = d.created_by
|
|
11694
11935
|
WHERE ${docConds.join(" AND ")}
|
|
11695
11936
|
ORDER BY updated_at DESC LIMIT ? OFFSET ?`;
|
|
11696
11937
|
const { results: unionRows } = await db.prepare(unionSql).bind(...docParams, limit, offset).all();
|
|
@@ -11879,9 +12120,9 @@ adminContentRoutes.get("/new", async (c) => {
|
|
|
11879
12120
|
const collectionsStmt = db2.prepare("SELECT id, name, display_name, description FROM document_types WHERE is_active = 1 ORDER BY display_name");
|
|
11880
12121
|
const { results } = await collectionsStmt.all();
|
|
11881
12122
|
const visibleTypeIds = new Set(
|
|
11882
|
-
(await new
|
|
12123
|
+
(await new chunkE7E3NL3Y_cjs.DocumentTypeRegistry(db2).findAll()).filter((dt) => !dt.settings?.internal && !dt.isAuth).map((dt) => dt.id)
|
|
11883
12124
|
);
|
|
11884
|
-
const codeCollections = await
|
|
12125
|
+
const codeCollections = await chunkYAURVGUK_cjs.loadCollectionConfigs();
|
|
11885
12126
|
const dbCollectionNames = new Set((results || []).map((r) => r.name));
|
|
11886
12127
|
const allCollections = [
|
|
11887
12128
|
...codeCollections.filter((c2) => !dbCollectionNames.has(c2.name)).map((c2) => ({
|
|
@@ -11947,32 +12188,32 @@ adminContentRoutes.get("/new", async (c) => {
|
|
|
11947
12188
|
return c.html(renderContentFormPage(formData2));
|
|
11948
12189
|
}
|
|
11949
12190
|
const fields = await getCollectionFields(db, collection.id);
|
|
11950
|
-
const workflowEnabled = await
|
|
11951
|
-
const tinymceEnabled = await
|
|
12191
|
+
const workflowEnabled = await chunkE7E3NL3Y_cjs.isPluginActive(db, "workflow");
|
|
12192
|
+
const tinymceEnabled = await chunkE7E3NL3Y_cjs.isPluginActive(db, "tinymce-plugin");
|
|
11952
12193
|
let tinymceSettings;
|
|
11953
12194
|
if (tinymceEnabled) {
|
|
11954
|
-
const pluginService = new
|
|
12195
|
+
const pluginService = new chunkYAURVGUK_cjs.PluginService(db);
|
|
11955
12196
|
const tinymcePlugin2 = await pluginService.getPlugin("tinymce-plugin");
|
|
11956
12197
|
tinymceSettings = tinymcePlugin2?.settings;
|
|
11957
12198
|
}
|
|
11958
|
-
const quillEnabled = await
|
|
12199
|
+
const quillEnabled = await chunkE7E3NL3Y_cjs.isPluginActive(db, "quill-editor");
|
|
11959
12200
|
let quillSettings;
|
|
11960
12201
|
if (quillEnabled) {
|
|
11961
|
-
const pluginService = new
|
|
12202
|
+
const pluginService = new chunkYAURVGUK_cjs.PluginService(db);
|
|
11962
12203
|
const quillPlugin = await pluginService.getPlugin("quill-editor");
|
|
11963
12204
|
quillSettings = quillPlugin?.settings;
|
|
11964
12205
|
}
|
|
11965
|
-
const mdxeditorEnabled = await
|
|
12206
|
+
const mdxeditorEnabled = await chunkE7E3NL3Y_cjs.isPluginActive(db, "easy-mdx");
|
|
11966
12207
|
let mdxeditorSettings;
|
|
11967
12208
|
if (mdxeditorEnabled) {
|
|
11968
|
-
const pluginService = new
|
|
12209
|
+
const pluginService = new chunkYAURVGUK_cjs.PluginService(db);
|
|
11969
12210
|
const mdxeditorPlugin = await pluginService.getPlugin("easy-mdx");
|
|
11970
12211
|
mdxeditorSettings = mdxeditorPlugin?.settings;
|
|
11971
12212
|
}
|
|
11972
|
-
const lexicalEnabled = await
|
|
12213
|
+
const lexicalEnabled = await chunkE7E3NL3Y_cjs.isPluginActive(db, "lexical-editor");
|
|
11973
12214
|
let lexicalSettings;
|
|
11974
12215
|
if (lexicalEnabled) {
|
|
11975
|
-
const pluginService = new
|
|
12216
|
+
const pluginService = new chunkYAURVGUK_cjs.PluginService(db);
|
|
11976
12217
|
const lexicalPlugin = await pluginService.getPlugin("lexical-editor");
|
|
11977
12218
|
lexicalSettings = lexicalPlugin?.settings;
|
|
11978
12219
|
}
|
|
@@ -12031,6 +12272,13 @@ adminContentRoutes.get("/:id/edit", async (c) => {
|
|
|
12031
12272
|
if (docType && dcoll) {
|
|
12032
12273
|
const fields2 = await getCollectionFields(db, dcoll.id);
|
|
12033
12274
|
const flags = await loadContentEditorFlags(db);
|
|
12275
|
+
let authorName;
|
|
12276
|
+
if (docRow.created_by) {
|
|
12277
|
+
const authorRow = await db.prepare("SELECT name, first_name, last_name, email FROM auth_user WHERE id = ?").bind(docRow.created_by).first();
|
|
12278
|
+
if (authorRow) {
|
|
12279
|
+
authorName = authorRow.name || [authorRow.first_name, authorRow.last_name].filter(Boolean).join(" ") || authorRow.email;
|
|
12280
|
+
}
|
|
12281
|
+
}
|
|
12034
12282
|
const formData2 = {
|
|
12035
12283
|
id: docRow.root_id,
|
|
12036
12284
|
title: docRow.title,
|
|
@@ -12045,6 +12293,7 @@ adminContentRoutes.get("/:id/edit", async (c) => {
|
|
|
12045
12293
|
isEdit: true,
|
|
12046
12294
|
referrerParams,
|
|
12047
12295
|
versioningEnabled: docType?.settings?.versioning === true,
|
|
12296
|
+
author_name: authorName,
|
|
12048
12297
|
user: user ? { name: user.email, email: user.email, role: user.role } : void 0,
|
|
12049
12298
|
version: c.get("appVersion"),
|
|
12050
12299
|
...flags
|
|
@@ -12100,32 +12349,32 @@ adminContentRoutes.get("/:id/edit", async (c) => {
|
|
|
12100
12349
|
};
|
|
12101
12350
|
const fields = await getCollectionFields(db, content.collection_id);
|
|
12102
12351
|
const contentData = content.data ? JSON.parse(content.data) : {};
|
|
12103
|
-
const workflowEnabled = await
|
|
12104
|
-
const tinymceEnabled = await
|
|
12352
|
+
const workflowEnabled = await chunkE7E3NL3Y_cjs.isPluginActive(db, "workflow");
|
|
12353
|
+
const tinymceEnabled = await chunkE7E3NL3Y_cjs.isPluginActive(db, "tinymce-plugin");
|
|
12105
12354
|
let tinymceSettings;
|
|
12106
12355
|
if (tinymceEnabled) {
|
|
12107
|
-
const pluginService = new
|
|
12356
|
+
const pluginService = new chunkYAURVGUK_cjs.PluginService(db);
|
|
12108
12357
|
const tinymcePlugin2 = await pluginService.getPlugin("tinymce-plugin");
|
|
12109
12358
|
tinymceSettings = tinymcePlugin2?.settings;
|
|
12110
12359
|
}
|
|
12111
|
-
const quillEnabled = await
|
|
12360
|
+
const quillEnabled = await chunkE7E3NL3Y_cjs.isPluginActive(db, "quill-editor");
|
|
12112
12361
|
let quillSettings;
|
|
12113
12362
|
if (quillEnabled) {
|
|
12114
|
-
const pluginService = new
|
|
12363
|
+
const pluginService = new chunkYAURVGUK_cjs.PluginService(db);
|
|
12115
12364
|
const quillPlugin = await pluginService.getPlugin("quill-editor");
|
|
12116
12365
|
quillSettings = quillPlugin?.settings;
|
|
12117
12366
|
}
|
|
12118
|
-
const mdxeditorEnabled = await
|
|
12367
|
+
const mdxeditorEnabled = await chunkE7E3NL3Y_cjs.isPluginActive(db, "easy-mdx");
|
|
12119
12368
|
let mdxeditorSettings;
|
|
12120
12369
|
if (mdxeditorEnabled) {
|
|
12121
|
-
const pluginService = new
|
|
12370
|
+
const pluginService = new chunkYAURVGUK_cjs.PluginService(db);
|
|
12122
12371
|
const mdxeditorPlugin = await pluginService.getPlugin("easy-mdx");
|
|
12123
12372
|
mdxeditorSettings = mdxeditorPlugin?.settings;
|
|
12124
12373
|
}
|
|
12125
|
-
const lexicalEnabled = await
|
|
12374
|
+
const lexicalEnabled = await chunkE7E3NL3Y_cjs.isPluginActive(db, "lexical-editor");
|
|
12126
12375
|
let lexicalSettings;
|
|
12127
12376
|
if (lexicalEnabled) {
|
|
12128
|
-
const pluginService = new
|
|
12377
|
+
const pluginService = new chunkYAURVGUK_cjs.PluginService(db);
|
|
12129
12378
|
const lexicalPlugin = await pluginService.getPlugin("lexical-editor");
|
|
12130
12379
|
lexicalSettings = lexicalPlugin?.settings;
|
|
12131
12380
|
}
|
|
@@ -12204,6 +12453,7 @@ adminContentRoutes.post("/", async (c) => {
|
|
|
12204
12453
|
const fields = await getCollectionFields(db, collectionId);
|
|
12205
12454
|
const { data, errors } = extractFieldData(fields, formData);
|
|
12206
12455
|
if (Object.keys(errors).length > 0) {
|
|
12456
|
+
const flags = await loadContentEditorFlags(db);
|
|
12207
12457
|
const formDataWithErrors = {
|
|
12208
12458
|
collection,
|
|
12209
12459
|
fields,
|
|
@@ -12214,7 +12464,8 @@ adminContentRoutes.post("/", async (c) => {
|
|
|
12214
12464
|
name: user.email,
|
|
12215
12465
|
email: user.email,
|
|
12216
12466
|
role: user.role
|
|
12217
|
-
} : void 0
|
|
12467
|
+
} : void 0,
|
|
12468
|
+
...flags
|
|
12218
12469
|
};
|
|
12219
12470
|
if (c.req.header("HX-Request") === "true") {
|
|
12220
12471
|
c.header("HX-Retarget", "#content-form-page");
|
|
@@ -12248,6 +12499,9 @@ adminContentRoutes.post("/", async (c) => {
|
|
|
12248
12499
|
}), user?.userId);
|
|
12249
12500
|
const cache2 = chunk36Z3AKX3_cjs.getCacheService(chunk36Z3AKX3_cjs.CACHE_CONFIGS.content);
|
|
12250
12501
|
await cache2.invalidate(`content:list:${collectionId}:*`);
|
|
12502
|
+
const apiCacheCreate = chunk36Z3AKX3_cjs.getCacheService(chunk36Z3AKX3_cjs.CACHE_CONFIGS.api);
|
|
12503
|
+
await apiCacheCreate.invalidate("api:content-filtered:*");
|
|
12504
|
+
await apiCacheCreate.invalidate(`api:collection-content-filtered:${createDocType.id}:*`);
|
|
12251
12505
|
const redirectUrl2 = `/admin/content/${doc.rootId}/edit?success=Content created successfully!`;
|
|
12252
12506
|
return c.req.header("HX-Request") === "true" ? c.text("", 200, { "HX-Redirect": redirectUrl2 }) : c.redirect(redirectUrl2);
|
|
12253
12507
|
}
|
|
@@ -12366,8 +12620,28 @@ adminContentRoutes.put("/:id", async (c) => {
|
|
|
12366
12620
|
if (status2 === "published") await svc.publish(newDraft.id, user?.userId);
|
|
12367
12621
|
else if (pub) await svc.unpublish(pub.id);
|
|
12368
12622
|
await chunk36Z3AKX3_cjs.getCacheService(chunk36Z3AKX3_cjs.CACHE_CONFIGS.content).invalidate(`content:list:*`);
|
|
12623
|
+
const apiCacheEdit = chunk36Z3AKX3_cjs.getCacheService(chunk36Z3AKX3_cjs.CACHE_CONFIGS.api);
|
|
12624
|
+
await apiCacheEdit.invalidate("api:content-filtered:*");
|
|
12625
|
+
await apiCacheEdit.invalidate(`api:collection-content-filtered:${docRowU.type_id}:*`);
|
|
12626
|
+
const isHTMX2 = c.req.header("HX-Request") === "true";
|
|
12627
|
+
const referrerParams = formData.get("referrer_params");
|
|
12628
|
+
const listUrl = referrerParams ? `/admin/content?${referrerParams}` : `/admin/content?collection=${dcoll.id}`;
|
|
12629
|
+
if (action === "save_and_close") {
|
|
12630
|
+
return isHTMX2 ? c.text("", 200, { "HX-Redirect": listUrl }) : c.redirect(listUrl);
|
|
12631
|
+
}
|
|
12632
|
+
if (isHTMX2) {
|
|
12633
|
+
const label = status2 === "published" ? "Content published successfully!" : "Content saved successfully!";
|
|
12634
|
+
return c.html(html.html`<div id="form-messages">
|
|
12635
|
+
<div class="rounded-lg bg-green-50 dark:bg-green-900/20 p-4 mb-4 flex items-center gap-3 border border-green-200 dark:border-green-800">
|
|
12636
|
+
<svg class="h-5 w-5 text-green-500 shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24" stroke-width="1.5">
|
|
12637
|
+
<path stroke-linecap="round" stroke-linejoin="round" d="M9 12.75L11.25 15 15 9.75M21 12a9 9 0 11-18 0 9 9 0 0118 0z"/>
|
|
12638
|
+
</svg>
|
|
12639
|
+
<span class="text-sm font-medium text-green-800 dark:text-green-200">${label}</span>
|
|
12640
|
+
</div>
|
|
12641
|
+
</div>`);
|
|
12642
|
+
}
|
|
12369
12643
|
const redirectUrl2 = `/admin/content/${id}/edit?success=Content updated successfully!`;
|
|
12370
|
-
return c.
|
|
12644
|
+
return c.redirect(redirectUrl2);
|
|
12371
12645
|
}
|
|
12372
12646
|
}
|
|
12373
12647
|
return c.html(html.html`
|
|
@@ -12395,6 +12669,7 @@ adminContentRoutes.put("/:id", async (c) => {
|
|
|
12395
12669
|
const fields = await getCollectionFields(db, existingContent.collection_id);
|
|
12396
12670
|
const { data, errors } = extractFieldData(fields, formData);
|
|
12397
12671
|
if (Object.keys(errors).length > 0) {
|
|
12672
|
+
const flags = await loadContentEditorFlags(db);
|
|
12398
12673
|
const formDataWithErrors = {
|
|
12399
12674
|
id,
|
|
12400
12675
|
collection,
|
|
@@ -12407,7 +12682,8 @@ adminContentRoutes.put("/:id", async (c) => {
|
|
|
12407
12682
|
name: user.email,
|
|
12408
12683
|
email: user.email,
|
|
12409
12684
|
role: user.role
|
|
12410
|
-
} : void 0
|
|
12685
|
+
} : void 0,
|
|
12686
|
+
...flags
|
|
12411
12687
|
};
|
|
12412
12688
|
if (c.req.header("HX-Request") === "true") {
|
|
12413
12689
|
c.header("HX-Retarget", "#content-form-page");
|
|
@@ -12498,7 +12774,7 @@ adminContentRoutes.put("/:id", async (c) => {
|
|
|
12498
12774
|
`);
|
|
12499
12775
|
}
|
|
12500
12776
|
});
|
|
12501
|
-
adminContentRoutes.post("/preview",
|
|
12777
|
+
adminContentRoutes.post("/preview", chunkE7E3NL3Y_cjs.requireRole(["admin", "editor", "author"]), async (c) => {
|
|
12502
12778
|
try {
|
|
12503
12779
|
const formData = await c.req.formData();
|
|
12504
12780
|
const collectionId = formData.get("collection_id");
|
|
@@ -12759,8 +13035,8 @@ adminContentRoutes.post("/bulk-action", async (c) => {
|
|
|
12759
13035
|
}
|
|
12760
13036
|
await cache.invalidate("content:list:*");
|
|
12761
13037
|
const apiCache = chunk36Z3AKX3_cjs.getCacheService(chunk36Z3AKX3_cjs.CACHE_CONFIGS.api);
|
|
12762
|
-
await apiCache.invalidate("content-filtered:*");
|
|
12763
|
-
await apiCache.invalidate("collection-content-filtered:*");
|
|
13038
|
+
await apiCache.invalidate("api:content-filtered:*");
|
|
13039
|
+
await apiCache.invalidate("api:collection-content-filtered:*");
|
|
12764
13040
|
return c.json({ success: true, count: ids.length });
|
|
12765
13041
|
} catch (error) {
|
|
12766
13042
|
console.error("Bulk action error:", error);
|
|
@@ -12778,6 +13054,9 @@ adminContentRoutes.delete("/:id", async (c) => {
|
|
|
12778
13054
|
const now2 = Math.floor(Date.now() / 1e3);
|
|
12779
13055
|
await db.prepare("UPDATE documents SET deleted_at = ?, updated_at = ? WHERE root_id = ? AND tenant_id = ?").bind(now2, now2, id, tenantId).run();
|
|
12780
13056
|
await chunk36Z3AKX3_cjs.getCacheService(chunk36Z3AKX3_cjs.CACHE_CONFIGS.content).invalidate("content:list:*");
|
|
13057
|
+
const apiCacheDel = chunk36Z3AKX3_cjs.getCacheService(chunk36Z3AKX3_cjs.CACHE_CONFIGS.api);
|
|
13058
|
+
await apiCacheDel.invalidate("api:content-filtered:*");
|
|
13059
|
+
await apiCacheDel.invalidate(`api:collection-content-filtered:${docDel.type_id}:*`);
|
|
12781
13060
|
return c.html(`
|
|
12782
13061
|
<div id="content-list" hx-get="/admin/content?model=${docDel.type_id}" hx-trigger="load" hx-swap="outerHTML">
|
|
12783
13062
|
<div class="flex items-center justify-center p-8"><span class="text-zinc-500">Deleting\u2026</span></div>
|
|
@@ -12817,7 +13096,7 @@ adminContentRoutes.delete("/:id", async (c) => {
|
|
|
12817
13096
|
return c.json({ success: false, error: "Failed to delete content" }, 500);
|
|
12818
13097
|
}
|
|
12819
13098
|
});
|
|
12820
|
-
adminContentRoutes.get("/:id/version/:version/preview",
|
|
13099
|
+
adminContentRoutes.get("/:id/version/:version/preview", chunkE7E3NL3Y_cjs.requireRole(["admin", "editor", "author"]), async (c) => {
|
|
12821
13100
|
try {
|
|
12822
13101
|
const id = c.req.param("id");
|
|
12823
13102
|
const version = parseInt(c.req.param("version") || "0");
|
|
@@ -12913,9 +13192,9 @@ function parseDocFormData(formData, queryableFields = []) {
|
|
|
12913
13192
|
return { title, slug, data };
|
|
12914
13193
|
}
|
|
12915
13194
|
async function getDocService(db, typeId, tenantId) {
|
|
12916
|
-
const registry = new
|
|
13195
|
+
const registry = new chunkE7E3NL3Y_cjs.DocumentTypeRegistry(db);
|
|
12917
13196
|
const docType = await registry.findById(typeId);
|
|
12918
|
-
const svc = new
|
|
13197
|
+
const svc = new chunkJCBDXEY2_cjs.DocumentsService(db, {
|
|
12919
13198
|
queryableFields: docType?.queryableFields ?? [],
|
|
12920
13199
|
typeSchemaVersion: docType?.schemaVersion ?? 1,
|
|
12921
13200
|
maxVersionsPerRoot: docType?.settings?.maxVersionsPerRoot ?? 50,
|
|
@@ -12926,10 +13205,10 @@ async function getDocService(db, typeId, tenantId) {
|
|
|
12926
13205
|
}
|
|
12927
13206
|
adminContentRoutes.get("/documents/:typeId/new", async (c) => {
|
|
12928
13207
|
const { typeId } = c.req.param();
|
|
12929
|
-
const registry = new
|
|
13208
|
+
const registry = new chunkE7E3NL3Y_cjs.DocumentTypeRegistry(c.env.DB);
|
|
12930
13209
|
const docType = await registry.findById(typeId);
|
|
12931
13210
|
if (!docType) return c.html("<p>Unknown document type.</p>", 404);
|
|
12932
|
-
return c.html(
|
|
13211
|
+
return c.html(chunkTT3TQSCZ_cjs.renderDocumentFormPage({ docType, isEdit: false, user: userCtx(c) }));
|
|
12933
13212
|
});
|
|
12934
13213
|
adminContentRoutes.post("/documents/:typeId/new", async (c) => {
|
|
12935
13214
|
const { typeId } = c.req.param();
|
|
@@ -12951,17 +13230,17 @@ adminContentRoutes.post("/documents/:typeId/new", async (c) => {
|
|
|
12951
13230
|
}), user?.userId);
|
|
12952
13231
|
return c.redirect(`/admin/content/documents/${typeId}/${doc.rootId}/edit?message=Created+successfully`);
|
|
12953
13232
|
} catch (err) {
|
|
12954
|
-
const registry = new
|
|
13233
|
+
const registry = new chunkE7E3NL3Y_cjs.DocumentTypeRegistry(c.env.DB);
|
|
12955
13234
|
const docType = await registry.findById(typeId);
|
|
12956
13235
|
if (!docType) return c.html("<p>Unknown document type.</p>", 404);
|
|
12957
|
-
return c.html(
|
|
13236
|
+
return c.html(chunkTT3TQSCZ_cjs.renderDocumentFormPage({ docType, isEdit: false, user: userCtx(c), message: err?.message ?? "Failed to create", messageType: "error" }));
|
|
12958
13237
|
}
|
|
12959
13238
|
});
|
|
12960
13239
|
adminContentRoutes.get("/documents/:typeId/:rootId/edit", async (c) => {
|
|
12961
13240
|
const { typeId, rootId } = c.req.param();
|
|
12962
13241
|
const db = c.env.DB;
|
|
12963
13242
|
const message = c.req.query("message");
|
|
12964
|
-
const registry = new
|
|
13243
|
+
const registry = new chunkE7E3NL3Y_cjs.DocumentTypeRegistry(db);
|
|
12965
13244
|
const docType = await registry.findById(typeId);
|
|
12966
13245
|
if (!docType) return c.html("<p>Unknown document type.</p>", 404);
|
|
12967
13246
|
const tenantId = reqTenant(c);
|
|
@@ -13008,7 +13287,7 @@ adminContentRoutes.get("/documents/:typeId/:rootId/edit", async (c) => {
|
|
|
13008
13287
|
createdAt: draftRow.created_at,
|
|
13009
13288
|
updatedAt: draftRow.updated_at
|
|
13010
13289
|
};
|
|
13011
|
-
return c.html(
|
|
13290
|
+
return c.html(chunkTT3TQSCZ_cjs.renderDocumentFormPage({ docType, doc, publishedDoc, isEdit: true, message, user: userCtx(c), versioningEnabled: docType?.settings?.versioning === true }));
|
|
13012
13291
|
});
|
|
13013
13292
|
adminContentRoutes.post("/documents/:typeId/:rootId", async (c) => {
|
|
13014
13293
|
const { typeId, rootId } = c.req.param();
|
|
@@ -13073,12 +13352,12 @@ adminContentRoutes.post("/documents/:typeId/:documentId/delete", async (c) => {
|
|
|
13073
13352
|
adminContentRoutes.get("/documents/:typeId/:rootId/versions", async (c) => {
|
|
13074
13353
|
const { typeId, rootId } = c.req.param();
|
|
13075
13354
|
const db = c.env.DB;
|
|
13076
|
-
const { renderVersionHistoryFragment } = await import('./admin-documents-form.template-
|
|
13077
|
-
const registry = new
|
|
13355
|
+
const { renderVersionHistoryFragment } = await import('./admin-documents-form.template-UWKGVAMW.cjs');
|
|
13356
|
+
const registry = new chunkE7E3NL3Y_cjs.DocumentTypeRegistry(db);
|
|
13078
13357
|
const docType = await registry.findById(typeId);
|
|
13079
13358
|
if (!docType) return c.html("<div>Unknown type.</div>", 404);
|
|
13080
13359
|
const result = await db.prepare(
|
|
13081
|
-
"SELECT id, version_number, is_current_draft, is_published, status, updated_at, created_by FROM documents WHERE root_id = ? AND tenant_id = ? ORDER BY version_number DESC LIMIT 50"
|
|
13360
|
+
"SELECT d.id, d.version_number, d.is_current_draft, d.is_published, d.status, d.updated_at, COALESCE(u.email, d.created_by) AS created_by FROM documents d LEFT JOIN auth_user u ON u.id = d.created_by WHERE d.root_id = ? AND d.tenant_id = ? ORDER BY d.version_number DESC LIMIT 50"
|
|
13082
13361
|
).bind(rootId, reqTenant(c)).all();
|
|
13083
13362
|
const versions = (result.results ?? []).map((r) => ({
|
|
13084
13363
|
id: r.id,
|
|
@@ -13094,7 +13373,7 @@ adminContentRoutes.get("/documents/:typeId/:rootId/versions", async (c) => {
|
|
|
13094
13373
|
var admin_content_default = adminContentRoutes;
|
|
13095
13374
|
|
|
13096
13375
|
// src/templates/pages/admin-profile.template.ts
|
|
13097
|
-
|
|
13376
|
+
chunkMI2YXCK4_cjs.init_admin_layout_catalyst_template();
|
|
13098
13377
|
function renderAvatarImage(avatarUrl, firstName, lastName) {
|
|
13099
13378
|
return `<div id="avatar-image-container" class="w-24 h-24 rounded-full mx-auto mb-4 overflow-hidden bg-gradient-to-br from-cyan-400 to-purple-400 flex items-center justify-center ring-4 ring-zinc-950/5 dark:ring-white/10">
|
|
13100
13379
|
${avatarUrl ? `<img src="${avatarUrl}" alt="Profile picture" class="w-full h-full object-cover">` : `<span class="text-2xl font-bold text-white">${firstName.charAt(0)}${lastName.charAt(0)}</span>`}
|
|
@@ -13114,8 +13393,8 @@ function renderProfilePage(data) {
|
|
|
13114
13393
|
</div>
|
|
13115
13394
|
|
|
13116
13395
|
<!-- Alert Messages -->
|
|
13117
|
-
${data.error ?
|
|
13118
|
-
${data.success ?
|
|
13396
|
+
${data.error ? chunkOUBUS74I_cjs.renderAlert({ type: "error", message: data.error, dismissible: true }) : ""}
|
|
13397
|
+
${data.success ? chunkOUBUS74I_cjs.renderAlert({ type: "success", message: data.success, dismissible: true }) : ""}
|
|
13119
13398
|
|
|
13120
13399
|
<!-- Profile Form -->
|
|
13121
13400
|
<div class="grid grid-cols-1 lg:grid-cols-3 gap-8">
|
|
@@ -13492,7 +13771,7 @@ function renderProfilePage(data) {
|
|
|
13492
13771
|
version: data.version,
|
|
13493
13772
|
content: pageContent
|
|
13494
13773
|
};
|
|
13495
|
-
return
|
|
13774
|
+
return chunkMI2YXCK4_cjs.renderAdminLayoutCatalyst(layoutData);
|
|
13496
13775
|
}
|
|
13497
13776
|
|
|
13498
13777
|
// src/templates/pages/admin-activity-logs.template.ts
|
|
@@ -13702,7 +13981,7 @@ function renderActivityLogsPage(data) {
|
|
|
13702
13981
|
user: data.user,
|
|
13703
13982
|
content: pageContent
|
|
13704
13983
|
};
|
|
13705
|
-
return
|
|
13984
|
+
return chunkOUBUS74I_cjs.renderAdminLayout(layoutData);
|
|
13706
13985
|
}
|
|
13707
13986
|
function getActionBadgeClass(action) {
|
|
13708
13987
|
if (action.includes("login") || action.includes("logout")) {
|
|
@@ -13722,7 +14001,7 @@ function formatAction(action) {
|
|
|
13722
14001
|
}
|
|
13723
14002
|
|
|
13724
14003
|
// src/templates/pages/admin-user-edit.template.ts
|
|
13725
|
-
|
|
14004
|
+
chunkMI2YXCK4_cjs.init_admin_layout_catalyst_template();
|
|
13726
14005
|
|
|
13727
14006
|
// src/templates/components/confirmation-dialog.template.ts
|
|
13728
14007
|
function renderConfirmationDialog2(options) {
|
|
@@ -13918,8 +14197,8 @@ function renderUserEditPage(data) {
|
|
|
13918
14197
|
|
|
13919
14198
|
<!-- Alert Messages -->
|
|
13920
14199
|
<div id="form-messages" class="mb-6 empty:mb-0">
|
|
13921
|
-
${data.error ?
|
|
13922
|
-
${data.success ?
|
|
14200
|
+
${data.error ? chunkOUBUS74I_cjs.renderAlert({ type: "error", message: data.error, dismissible: true }) : ""}
|
|
14201
|
+
${data.success ? chunkOUBUS74I_cjs.renderAlert({ type: "success", message: data.success, dismissible: true }) : ""}
|
|
13923
14202
|
</div>
|
|
13924
14203
|
|
|
13925
14204
|
<!-- User Edit Form -->
|
|
@@ -14241,11 +14520,11 @@ function renderUserEditPage(data) {
|
|
|
14241
14520
|
user: data.user,
|
|
14242
14521
|
content: pageContent
|
|
14243
14522
|
};
|
|
14244
|
-
return
|
|
14523
|
+
return chunkMI2YXCK4_cjs.renderAdminLayoutCatalyst(layoutData);
|
|
14245
14524
|
}
|
|
14246
14525
|
|
|
14247
14526
|
// src/templates/pages/admin-user-new.template.ts
|
|
14248
|
-
|
|
14527
|
+
chunkMI2YXCK4_cjs.init_admin_layout_catalyst_template();
|
|
14249
14528
|
function renderUserNewPage(data) {
|
|
14250
14529
|
const pageContent = `
|
|
14251
14530
|
<div>
|
|
@@ -14284,8 +14563,8 @@ function renderUserNewPage(data) {
|
|
|
14284
14563
|
|
|
14285
14564
|
<!-- Alert Messages -->
|
|
14286
14565
|
<div id="form-messages">
|
|
14287
|
-
${data.error ?
|
|
14288
|
-
${data.success ?
|
|
14566
|
+
${data.error ? chunkOUBUS74I_cjs.renderAlert({ type: "error", message: data.error, dismissible: true }) : ""}
|
|
14567
|
+
${data.success ? chunkOUBUS74I_cjs.renderAlert({ type: "success", message: data.success, dismissible: true }) : ""}
|
|
14289
14568
|
</div>
|
|
14290
14569
|
|
|
14291
14570
|
<!-- User New Form -->
|
|
@@ -14515,11 +14794,11 @@ function renderUserNewPage(data) {
|
|
|
14515
14794
|
user: data.user,
|
|
14516
14795
|
content: pageContent
|
|
14517
14796
|
};
|
|
14518
|
-
return
|
|
14797
|
+
return chunkMI2YXCK4_cjs.renderAdminLayoutCatalyst(layoutData);
|
|
14519
14798
|
}
|
|
14520
14799
|
|
|
14521
14800
|
// src/templates/pages/admin-users-list.template.ts
|
|
14522
|
-
|
|
14801
|
+
chunkMI2YXCK4_cjs.init_admin_layout_catalyst_template();
|
|
14523
14802
|
function renderUsersListPage(data) {
|
|
14524
14803
|
const columns = [
|
|
14525
14804
|
{
|
|
@@ -14675,8 +14954,8 @@ function renderUsersListPage(data) {
|
|
|
14675
14954
|
</div>
|
|
14676
14955
|
|
|
14677
14956
|
<!-- Alert Messages -->
|
|
14678
|
-
${data.error ?
|
|
14679
|
-
${data.success ?
|
|
14957
|
+
${data.error ? chunkOUBUS74I_cjs.renderAlert({ type: "error", message: data.error, dismissible: true }) : ""}
|
|
14958
|
+
${data.success ? chunkOUBUS74I_cjs.renderAlert({ type: "success", message: data.success, dismissible: true }) : ""}
|
|
14680
14959
|
|
|
14681
14960
|
<!-- Stats -->
|
|
14682
14961
|
<div class="mb-6">
|
|
@@ -14853,10 +15132,10 @@ function renderUsersListPage(data) {
|
|
|
14853
15132
|
</div>
|
|
14854
15133
|
|
|
14855
15134
|
<!-- Users Table -->
|
|
14856
|
-
${
|
|
15135
|
+
${chunkOUBUS74I_cjs.renderTable(tableData)}
|
|
14857
15136
|
|
|
14858
15137
|
<!-- Pagination -->
|
|
14859
|
-
${data.pagination ?
|
|
15138
|
+
${data.pagination ? chunkOUBUS74I_cjs.renderPagination(data.pagination) : ""}
|
|
14860
15139
|
</div>
|
|
14861
15140
|
|
|
14862
15141
|
<script>
|
|
@@ -14927,7 +15206,7 @@ function renderUsersListPage(data) {
|
|
|
14927
15206
|
version: data.version,
|
|
14928
15207
|
content: pageContent
|
|
14929
15208
|
};
|
|
14930
|
-
return
|
|
15209
|
+
return chunkMI2YXCK4_cjs.renderAdminLayoutCatalyst(layoutData);
|
|
14931
15210
|
}
|
|
14932
15211
|
|
|
14933
15212
|
// src/plugins/core-plugins/multi-tenant-plugin/services/tenant-service.ts
|
|
@@ -15007,7 +15286,7 @@ var TenantService = class {
|
|
|
15007
15286
|
SET name = ?, domain = ?, status = ?, notes = ?, updated_at = ?
|
|
15008
15287
|
WHERE slug = ?
|
|
15009
15288
|
`).bind(name, domain, status, notes, now, slug).run();
|
|
15010
|
-
|
|
15289
|
+
chunkYAURVGUK_cjs.invalidateTenantCache();
|
|
15011
15290
|
const updated = await this.getTenantBySlug(slug);
|
|
15012
15291
|
if (!updated) throw new Error("Tenant not found");
|
|
15013
15292
|
return updated;
|
|
@@ -15025,7 +15304,7 @@ var TenantService = class {
|
|
|
15025
15304
|
throw new Error(`Tenant '${slug}' still owns ${docCount} document(s). Delete or migrate its content first.`);
|
|
15026
15305
|
}
|
|
15027
15306
|
await this.db.prepare(`DELETE FROM auth_tenant WHERE slug = ?`).bind(slug).run();
|
|
15028
|
-
|
|
15307
|
+
chunkYAURVGUK_cjs.invalidateTenantCache();
|
|
15029
15308
|
}
|
|
15030
15309
|
// ─── Membership (auth_tenant_member) ───────────────────────────────────────
|
|
15031
15310
|
// Tenant resolution and the admin switcher are gated on membership: an authed user may only
|
|
@@ -15269,7 +15548,7 @@ var TenantService = class {
|
|
|
15269
15548
|
INSERT INTO auth_tenant (id, name, slug, status, domain, notes, metadata, created_at, updated_at)
|
|
15270
15549
|
VALUES (?, ?, ?, 'active', ?, ?, '{}', ?, ?)
|
|
15271
15550
|
`).bind(id, input.name, input.slug, input.domain, input.notes, now, now).run();
|
|
15272
|
-
|
|
15551
|
+
chunkYAURVGUK_cjs.invalidateTenantCache();
|
|
15273
15552
|
const created = await this.getTenantBySlug(input.slug);
|
|
15274
15553
|
if (!created) throw new Error("Failed to create tenant");
|
|
15275
15554
|
return created;
|
|
@@ -15293,14 +15572,14 @@ function mapRowToTenant(row) {
|
|
|
15293
15572
|
|
|
15294
15573
|
// src/routes/admin-users.ts
|
|
15295
15574
|
var userRoutes = new hono.Hono();
|
|
15296
|
-
userRoutes.use("*",
|
|
15297
|
-
userRoutes.use("/users/*",
|
|
15298
|
-
userRoutes.use("/users",
|
|
15299
|
-
userRoutes.use("/invite-user",
|
|
15300
|
-
userRoutes.use("/resend-invitation/*",
|
|
15301
|
-
userRoutes.use("/cancel-invitation/*",
|
|
15302
|
-
userRoutes.use("/activity-logs",
|
|
15303
|
-
userRoutes.use("/activity-logs/*",
|
|
15575
|
+
userRoutes.use("*", chunkE7E3NL3Y_cjs.requireAuth());
|
|
15576
|
+
userRoutes.use("/users/*", chunkE7E3NL3Y_cjs.requireRole(["admin"]));
|
|
15577
|
+
userRoutes.use("/users", chunkE7E3NL3Y_cjs.requireRole(["admin"]));
|
|
15578
|
+
userRoutes.use("/invite-user", chunkE7E3NL3Y_cjs.requireRole(["admin"]));
|
|
15579
|
+
userRoutes.use("/resend-invitation/*", chunkE7E3NL3Y_cjs.requireRole(["admin"]));
|
|
15580
|
+
userRoutes.use("/cancel-invitation/*", chunkE7E3NL3Y_cjs.requireRole(["admin"]));
|
|
15581
|
+
userRoutes.use("/activity-logs", chunkE7E3NL3Y_cjs.requireRole(["admin"]));
|
|
15582
|
+
userRoutes.use("/activity-logs/*", chunkE7E3NL3Y_cjs.requireRole(["admin"]));
|
|
15304
15583
|
userRoutes.get("/", (c) => {
|
|
15305
15584
|
return c.redirect("/admin/dashboard");
|
|
15306
15585
|
});
|
|
@@ -15328,12 +15607,10 @@ var LANGUAGES = [
|
|
|
15328
15607
|
{ value: "ko", label: "Korean" },
|
|
15329
15608
|
{ value: "zh", label: "Chinese" }
|
|
15330
15609
|
];
|
|
15331
|
-
|
|
15332
|
-
|
|
15333
|
-
{ value:
|
|
15334
|
-
|
|
15335
|
-
{ value: "viewer", label: "Viewer" }
|
|
15336
|
-
];
|
|
15610
|
+
async function fetchRoleOptions(db) {
|
|
15611
|
+
const roles = await new chunkJCBDXEY2_cjs.RbacService(db).getRoles();
|
|
15612
|
+
return roles.map((r) => ({ value: r.id, label: r.display_name }));
|
|
15613
|
+
}
|
|
15337
15614
|
userRoutes.get("/profile", async (c) => {
|
|
15338
15615
|
const user = c.get("user");
|
|
15339
15616
|
const db = c.env.DB;
|
|
@@ -15411,7 +15688,7 @@ userRoutes.put("/profile", async (c) => {
|
|
|
15411
15688
|
const language = formData.get("language")?.toString() || "en";
|
|
15412
15689
|
const emailNotifications = formData.get("email_notifications") === "1";
|
|
15413
15690
|
if (!firstName || !lastName || !email) {
|
|
15414
|
-
return c.html(
|
|
15691
|
+
return c.html(chunkTT3TQSCZ_cjs.renderAlert({
|
|
15415
15692
|
type: "error",
|
|
15416
15693
|
message: "First name, last name, and email are required.",
|
|
15417
15694
|
dismissible: true
|
|
@@ -15419,7 +15696,7 @@ userRoutes.put("/profile", async (c) => {
|
|
|
15419
15696
|
}
|
|
15420
15697
|
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
15421
15698
|
if (!emailRegex.test(email)) {
|
|
15422
|
-
return c.html(
|
|
15699
|
+
return c.html(chunkTT3TQSCZ_cjs.renderAlert({
|
|
15423
15700
|
type: "error",
|
|
15424
15701
|
message: "Please enter a valid email address.",
|
|
15425
15702
|
dismissible: true
|
|
@@ -15431,7 +15708,7 @@ userRoutes.put("/profile", async (c) => {
|
|
|
15431
15708
|
`);
|
|
15432
15709
|
const existingUser = await checkStmt.bind(email, user.userId).first();
|
|
15433
15710
|
if (existingUser) {
|
|
15434
|
-
return c.html(
|
|
15711
|
+
return c.html(chunkTT3TQSCZ_cjs.renderAlert({
|
|
15435
15712
|
type: "error",
|
|
15436
15713
|
message: "Email is already taken by another user.",
|
|
15437
15714
|
dismissible: true
|
|
@@ -15463,11 +15740,11 @@ userRoutes.put("/profile", async (c) => {
|
|
|
15463
15740
|
const validation = validateCustomData(sanitized, profileConfig);
|
|
15464
15741
|
if (!validation.valid) {
|
|
15465
15742
|
const errorMessages = Object.values(validation.errors).join(", ");
|
|
15466
|
-
return c.html(
|
|
15743
|
+
return c.html(chunkTT3TQSCZ_cjs.renderAlert({ type: "error", message: errorMessages, dismissible: true }), 400);
|
|
15467
15744
|
}
|
|
15468
15745
|
await saveCustomData(db, user.userId, sanitized);
|
|
15469
15746
|
}
|
|
15470
|
-
await
|
|
15747
|
+
await chunkE7E3NL3Y_cjs.logActivity(
|
|
15471
15748
|
db,
|
|
15472
15749
|
user.userId,
|
|
15473
15750
|
"profile.update",
|
|
@@ -15477,14 +15754,14 @@ userRoutes.put("/profile", async (c) => {
|
|
|
15477
15754
|
c.req.header("x-forwarded-for") || c.req.header("cf-connecting-ip"),
|
|
15478
15755
|
c.req.header("user-agent")
|
|
15479
15756
|
);
|
|
15480
|
-
return c.html(
|
|
15757
|
+
return c.html(chunkTT3TQSCZ_cjs.renderAlert({
|
|
15481
15758
|
type: "success",
|
|
15482
15759
|
message: "Profile updated successfully!",
|
|
15483
15760
|
dismissible: true
|
|
15484
15761
|
}));
|
|
15485
15762
|
} catch (error) {
|
|
15486
15763
|
console.error("Profile update error:", error);
|
|
15487
|
-
return c.html(
|
|
15764
|
+
return c.html(chunkTT3TQSCZ_cjs.renderAlert({
|
|
15488
15765
|
type: "error",
|
|
15489
15766
|
message: "Failed to update profile. Please try again.",
|
|
15490
15767
|
dismissible: true
|
|
@@ -15498,7 +15775,7 @@ userRoutes.post("/profile/avatar", async (c) => {
|
|
|
15498
15775
|
const formData = await c.req.formData();
|
|
15499
15776
|
const avatarFile = formData.get("avatar");
|
|
15500
15777
|
if (!avatarFile || typeof avatarFile === "string" || !avatarFile.name) {
|
|
15501
|
-
return c.html(
|
|
15778
|
+
return c.html(chunkTT3TQSCZ_cjs.renderAlert({
|
|
15502
15779
|
type: "error",
|
|
15503
15780
|
message: "Please select an image file.",
|
|
15504
15781
|
dismissible: true
|
|
@@ -15506,7 +15783,7 @@ userRoutes.post("/profile/avatar", async (c) => {
|
|
|
15506
15783
|
}
|
|
15507
15784
|
const allowedTypes = ["image/jpeg", "image/png", "image/gif", "image/webp"];
|
|
15508
15785
|
if (!allowedTypes.includes(avatarFile.type)) {
|
|
15509
|
-
return c.html(
|
|
15786
|
+
return c.html(chunkTT3TQSCZ_cjs.renderAlert({
|
|
15510
15787
|
type: "error",
|
|
15511
15788
|
message: "Please upload a valid image file (JPEG, PNG, GIF, or WebP).",
|
|
15512
15789
|
dismissible: true
|
|
@@ -15514,7 +15791,7 @@ userRoutes.post("/profile/avatar", async (c) => {
|
|
|
15514
15791
|
}
|
|
15515
15792
|
const maxSize = 5 * 1024 * 1024;
|
|
15516
15793
|
if (avatarFile.size > maxSize) {
|
|
15517
|
-
return c.html(
|
|
15794
|
+
return c.html(chunkTT3TQSCZ_cjs.renderAlert({
|
|
15518
15795
|
type: "error",
|
|
15519
15796
|
message: "Image file must be smaller than 5MB.",
|
|
15520
15797
|
dismissible: true
|
|
@@ -15530,7 +15807,7 @@ userRoutes.post("/profile/avatar", async (c) => {
|
|
|
15530
15807
|
SELECT first_name, last_name FROM auth_user WHERE id = ?
|
|
15531
15808
|
`);
|
|
15532
15809
|
const userData = await userStmt.bind(user.userId).first();
|
|
15533
|
-
await
|
|
15810
|
+
await chunkE7E3NL3Y_cjs.logActivity(
|
|
15534
15811
|
db,
|
|
15535
15812
|
user.userId,
|
|
15536
15813
|
"profile.avatar_update",
|
|
@@ -15540,7 +15817,7 @@ userRoutes.post("/profile/avatar", async (c) => {
|
|
|
15540
15817
|
c.req.header("x-forwarded-for") || c.req.header("cf-connecting-ip"),
|
|
15541
15818
|
c.req.header("user-agent")
|
|
15542
15819
|
);
|
|
15543
|
-
const alertHtml =
|
|
15820
|
+
const alertHtml = chunkTT3TQSCZ_cjs.renderAlert({
|
|
15544
15821
|
type: "success",
|
|
15545
15822
|
message: "Profile picture updated successfully!",
|
|
15546
15823
|
dismissible: true
|
|
@@ -15554,7 +15831,7 @@ userRoutes.post("/profile/avatar", async (c) => {
|
|
|
15554
15831
|
return c.html(alertHtml + avatarImageWithOob);
|
|
15555
15832
|
} catch (error) {
|
|
15556
15833
|
console.error("Avatar upload error:", error);
|
|
15557
|
-
return c.html(
|
|
15834
|
+
return c.html(chunkTT3TQSCZ_cjs.renderAlert({
|
|
15558
15835
|
type: "error",
|
|
15559
15836
|
message: "Failed to upload profile picture. Please try again.",
|
|
15560
15837
|
dismissible: true
|
|
@@ -15570,21 +15847,21 @@ userRoutes.post("/profile/password", async (c) => {
|
|
|
15570
15847
|
const newPassword = formData.get("new_password")?.toString() || "";
|
|
15571
15848
|
const confirmPassword = formData.get("confirm_password")?.toString() || "";
|
|
15572
15849
|
if (!currentPassword || !newPassword || !confirmPassword) {
|
|
15573
|
-
return c.html(
|
|
15850
|
+
return c.html(chunkTT3TQSCZ_cjs.renderAlert({
|
|
15574
15851
|
type: "error",
|
|
15575
15852
|
message: "All password fields are required.",
|
|
15576
15853
|
dismissible: true
|
|
15577
15854
|
}));
|
|
15578
15855
|
}
|
|
15579
15856
|
if (newPassword !== confirmPassword) {
|
|
15580
|
-
return c.html(
|
|
15857
|
+
return c.html(chunkTT3TQSCZ_cjs.renderAlert({
|
|
15581
15858
|
type: "error",
|
|
15582
15859
|
message: "New passwords do not match.",
|
|
15583
15860
|
dismissible: true
|
|
15584
15861
|
}));
|
|
15585
15862
|
}
|
|
15586
15863
|
if (newPassword.length < 8) {
|
|
15587
|
-
return c.html(
|
|
15864
|
+
return c.html(chunkTT3TQSCZ_cjs.renderAlert({
|
|
15588
15865
|
type: "error",
|
|
15589
15866
|
message: "New password must be at least 8 characters long.",
|
|
15590
15867
|
dismissible: true
|
|
@@ -15595,21 +15872,21 @@ userRoutes.post("/profile/password", async (c) => {
|
|
|
15595
15872
|
`);
|
|
15596
15873
|
const userData = await userStmt.bind(user.userId).first();
|
|
15597
15874
|
if (!userData) {
|
|
15598
|
-
return c.html(
|
|
15875
|
+
return c.html(chunkTT3TQSCZ_cjs.renderAlert({
|
|
15599
15876
|
type: "error",
|
|
15600
15877
|
message: "User not found.",
|
|
15601
15878
|
dismissible: true
|
|
15602
15879
|
}));
|
|
15603
15880
|
}
|
|
15604
|
-
const validPassword = await
|
|
15881
|
+
const validPassword = await chunkE7E3NL3Y_cjs.AuthManager.verifyPassword(currentPassword, userData.password_hash);
|
|
15605
15882
|
if (!validPassword) {
|
|
15606
|
-
return c.html(
|
|
15883
|
+
return c.html(chunkTT3TQSCZ_cjs.renderAlert({
|
|
15607
15884
|
type: "error",
|
|
15608
15885
|
message: "Current password is incorrect.",
|
|
15609
15886
|
dismissible: true
|
|
15610
15887
|
}));
|
|
15611
15888
|
}
|
|
15612
|
-
const newPasswordHash = await
|
|
15889
|
+
const newPasswordHash = await chunkE7E3NL3Y_cjs.AuthManager.hashPassword(newPassword);
|
|
15613
15890
|
const historyStmt = db.prepare(`
|
|
15614
15891
|
INSERT INTO auth_password_history (id, user_id, password_hash, created_at)
|
|
15615
15892
|
VALUES (?, ?, ?, ?)
|
|
@@ -15625,7 +15902,7 @@ userRoutes.post("/profile/password", async (c) => {
|
|
|
15625
15902
|
WHERE id = ?
|
|
15626
15903
|
`);
|
|
15627
15904
|
await updateStmt.bind(newPasswordHash, Date.now(), user.userId).run();
|
|
15628
|
-
await
|
|
15905
|
+
await chunkE7E3NL3Y_cjs.logActivity(
|
|
15629
15906
|
db,
|
|
15630
15907
|
user.userId,
|
|
15631
15908
|
"profile.password_change",
|
|
@@ -15635,14 +15912,14 @@ userRoutes.post("/profile/password", async (c) => {
|
|
|
15635
15912
|
c.req.header("x-forwarded-for") || c.req.header("cf-connecting-ip"),
|
|
15636
15913
|
c.req.header("user-agent")
|
|
15637
15914
|
);
|
|
15638
|
-
return c.html(
|
|
15915
|
+
return c.html(chunkTT3TQSCZ_cjs.renderAlert({
|
|
15639
15916
|
type: "success",
|
|
15640
15917
|
message: "Password updated successfully!",
|
|
15641
15918
|
dismissible: true
|
|
15642
15919
|
}));
|
|
15643
15920
|
} catch (error) {
|
|
15644
15921
|
console.error("Password change error:", error);
|
|
15645
|
-
return c.html(
|
|
15922
|
+
return c.html(chunkTT3TQSCZ_cjs.renderAlert({
|
|
15646
15923
|
type: "error",
|
|
15647
15924
|
message: "Failed to update password. Please try again.",
|
|
15648
15925
|
dismissible: true
|
|
@@ -15692,7 +15969,7 @@ userRoutes.get("/users", async (c) => {
|
|
|
15692
15969
|
`);
|
|
15693
15970
|
const countResult = await countStmt.bind(...params).first();
|
|
15694
15971
|
const totalUsers = countResult?.total || 0;
|
|
15695
|
-
await
|
|
15972
|
+
await chunkE7E3NL3Y_cjs.logActivity(
|
|
15696
15973
|
db,
|
|
15697
15974
|
user.userId,
|
|
15698
15975
|
"users.list_view",
|
|
@@ -15763,7 +16040,7 @@ userRoutes.get("/users", async (c) => {
|
|
|
15763
16040
|
if (isApiRequest) {
|
|
15764
16041
|
return c.json({ error: "Failed to load users" }, 500);
|
|
15765
16042
|
}
|
|
15766
|
-
return c.html(
|
|
16043
|
+
return c.html(chunkTT3TQSCZ_cjs.renderAlert({
|
|
15767
16044
|
type: "error",
|
|
15768
16045
|
message: "Failed to load users. Please try again.",
|
|
15769
16046
|
dismissible: true
|
|
@@ -15782,8 +16059,9 @@ userRoutes.get("/users/new", async (c) => {
|
|
|
15782
16059
|
const regFieldNames = profileConfig?.registrationFields ?? [];
|
|
15783
16060
|
const regFields = profileConfig && upRow ? regFieldNames.length > 0 ? profileConfig.fields.filter((f) => regFieldNames.includes(f.name)) : profileConfig.fields : [];
|
|
15784
16061
|
const registrationFieldsHtml = regFields.length > 0 ? renderCustomProfileSection({ fields: regFields }, {}) : void 0;
|
|
16062
|
+
const roles = await fetchRoleOptions(db);
|
|
15785
16063
|
const pageData = {
|
|
15786
|
-
roles
|
|
16064
|
+
roles,
|
|
15787
16065
|
registrationFieldsHtml,
|
|
15788
16066
|
user: {
|
|
15789
16067
|
name: user.email.split("@")[0] || user.email,
|
|
@@ -15794,7 +16072,7 @@ userRoutes.get("/users/new", async (c) => {
|
|
|
15794
16072
|
return c.html(renderUserNewPage(pageData));
|
|
15795
16073
|
} catch (error) {
|
|
15796
16074
|
console.error("User new page error:", error);
|
|
15797
|
-
return c.html(
|
|
16075
|
+
return c.html(chunkTT3TQSCZ_cjs.renderAlert({
|
|
15798
16076
|
type: "error",
|
|
15799
16077
|
message: "Failed to load user creation page. Please try again.",
|
|
15800
16078
|
dismissible: true
|
|
@@ -15811,9 +16089,9 @@ userRoutes.post("/users/new", async (c) => {
|
|
|
15811
16089
|
const email = formData.get("email")?.toString()?.trim().toLowerCase() || "";
|
|
15812
16090
|
const phone = chunkMNWKYY5E_cjs.sanitizeInput(formData.get("phone")?.toString()) || null;
|
|
15813
16091
|
const bio = chunkMNWKYY5E_cjs.sanitizeInput(formData.get("bio")?.toString()) || null;
|
|
15814
|
-
const roleInput = formData.get("role")?.toString() || "
|
|
15815
|
-
const validRoles =
|
|
15816
|
-
const role = validRoles.includes(roleInput) ? roleInput : "
|
|
16092
|
+
const roleInput = formData.get("role")?.toString() || "";
|
|
16093
|
+
const validRoles = (await new chunkJCBDXEY2_cjs.RbacService(db).getRoles()).map((r) => r.id);
|
|
16094
|
+
const role = validRoles.includes(roleInput) ? roleInput : validRoles[0] ?? "admin";
|
|
15817
16095
|
const password = formData.get("password")?.toString() || "";
|
|
15818
16096
|
const confirmPassword = formData.get("confirm_password")?.toString() || "";
|
|
15819
16097
|
const isActive = formData.get("is_active") === "1";
|
|
@@ -15828,12 +16106,12 @@ userRoutes.post("/users/new", async (c) => {
|
|
|
15828
16106
|
const validation = validateCustomData(sanitized, profileConfig);
|
|
15829
16107
|
if (!validation.valid) {
|
|
15830
16108
|
const errorMessages = Object.values(validation.errors).join(", ");
|
|
15831
|
-
return c.html(
|
|
16109
|
+
return c.html(chunkTT3TQSCZ_cjs.renderAlert({ type: "error", message: errorMessages, dismissible: true }), 400);
|
|
15832
16110
|
}
|
|
15833
16111
|
sanitizedRegistrationCustom = sanitized;
|
|
15834
16112
|
}
|
|
15835
16113
|
if (!firstName || !lastName || !email || !password) {
|
|
15836
|
-
return c.html(
|
|
16114
|
+
return c.html(chunkTT3TQSCZ_cjs.renderAlert({
|
|
15837
16115
|
type: "error",
|
|
15838
16116
|
message: "First name, last name, email, and password are required.",
|
|
15839
16117
|
dismissible: true
|
|
@@ -15841,21 +16119,21 @@ userRoutes.post("/users/new", async (c) => {
|
|
|
15841
16119
|
}
|
|
15842
16120
|
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
15843
16121
|
if (!emailRegex.test(email)) {
|
|
15844
|
-
return c.html(
|
|
16122
|
+
return c.html(chunkTT3TQSCZ_cjs.renderAlert({
|
|
15845
16123
|
type: "error",
|
|
15846
16124
|
message: "Please enter a valid email address.",
|
|
15847
16125
|
dismissible: true
|
|
15848
16126
|
}));
|
|
15849
16127
|
}
|
|
15850
16128
|
if (password.length < 8) {
|
|
15851
|
-
return c.html(
|
|
16129
|
+
return c.html(chunkTT3TQSCZ_cjs.renderAlert({
|
|
15852
16130
|
type: "error",
|
|
15853
16131
|
message: "Password must be at least 8 characters long.",
|
|
15854
16132
|
dismissible: true
|
|
15855
16133
|
}));
|
|
15856
16134
|
}
|
|
15857
16135
|
if (password !== confirmPassword) {
|
|
15858
|
-
return c.html(
|
|
16136
|
+
return c.html(chunkTT3TQSCZ_cjs.renderAlert({
|
|
15859
16137
|
type: "error",
|
|
15860
16138
|
message: "Passwords do not match.",
|
|
15861
16139
|
dismissible: true
|
|
@@ -15867,13 +16145,13 @@ userRoutes.post("/users/new", async (c) => {
|
|
|
15867
16145
|
`);
|
|
15868
16146
|
const existingUser = await checkStmt.bind(email).first();
|
|
15869
16147
|
if (existingUser) {
|
|
15870
|
-
return c.html(
|
|
16148
|
+
return c.html(chunkTT3TQSCZ_cjs.renderAlert({
|
|
15871
16149
|
type: "error",
|
|
15872
16150
|
message: "Email is already taken.",
|
|
15873
16151
|
dismissible: true
|
|
15874
16152
|
}));
|
|
15875
16153
|
}
|
|
15876
|
-
const passwordHash = await
|
|
16154
|
+
const passwordHash = await chunkE7E3NL3Y_cjs.AuthManager.hashPassword(password);
|
|
15877
16155
|
const userId = crypto.randomUUID();
|
|
15878
16156
|
const createStmt = db.prepare(`
|
|
15879
16157
|
INSERT INTO auth_user (
|
|
@@ -15898,7 +16176,7 @@ userRoutes.post("/users/new", async (c) => {
|
|
|
15898
16176
|
if (sanitizedRegistrationCustom !== null && Object.keys(sanitizedRegistrationCustom).length > 0) {
|
|
15899
16177
|
await writeProfileData(db, userId, { custom: sanitizedRegistrationCustom }, user.userId);
|
|
15900
16178
|
}
|
|
15901
|
-
await
|
|
16179
|
+
await chunkE7E3NL3Y_cjs.logActivity(
|
|
15902
16180
|
db,
|
|
15903
16181
|
user.userId,
|
|
15904
16182
|
"user!.create",
|
|
@@ -15912,7 +16190,7 @@ userRoutes.post("/users/new", async (c) => {
|
|
|
15912
16190
|
return c.body(null, 200);
|
|
15913
16191
|
} catch (error) {
|
|
15914
16192
|
console.error("User creation error:", error);
|
|
15915
|
-
return c.html(
|
|
16193
|
+
return c.html(chunkTT3TQSCZ_cjs.renderAlert({
|
|
15916
16194
|
type: "error",
|
|
15917
16195
|
message: "Failed to create user!. Please try again.",
|
|
15918
16196
|
dismissible: true
|
|
@@ -15937,7 +16215,7 @@ userRoutes.get("/users/:id", async (c) => {
|
|
|
15937
16215
|
if (!userRecord) {
|
|
15938
16216
|
return c.json({ error: "User not found" }, 404);
|
|
15939
16217
|
}
|
|
15940
|
-
await
|
|
16218
|
+
await chunkE7E3NL3Y_cjs.logActivity(
|
|
15941
16219
|
db,
|
|
15942
16220
|
user.userId,
|
|
15943
16221
|
"user!.view",
|
|
@@ -15982,7 +16260,7 @@ userRoutes.get("/users/:id/edit", async (c) => {
|
|
|
15982
16260
|
`);
|
|
15983
16261
|
const userToEdit = await userStmt.bind(userId).first();
|
|
15984
16262
|
if (!userToEdit) {
|
|
15985
|
-
return c.html(
|
|
16263
|
+
return c.html(chunkTT3TQSCZ_cjs.renderAlert({
|
|
15986
16264
|
type: "error",
|
|
15987
16265
|
message: "User not found",
|
|
15988
16266
|
dismissible: true
|
|
@@ -16035,9 +16313,10 @@ userRoutes.get("/users/:id/edit", async (c) => {
|
|
|
16035
16313
|
}
|
|
16036
16314
|
const queryMessage = c.req.query("message");
|
|
16037
16315
|
const queryType = c.req.query("type") === "error" ? "error" : "success";
|
|
16316
|
+
const roles = await fetchRoleOptions(db);
|
|
16038
16317
|
const pageData = {
|
|
16039
16318
|
userToEdit: editData,
|
|
16040
|
-
roles
|
|
16319
|
+
roles,
|
|
16041
16320
|
hasProfilePlugin: profileConfig !== null && upRow !== null,
|
|
16042
16321
|
customProfileFieldsHtml,
|
|
16043
16322
|
tenantMemberships,
|
|
@@ -16052,7 +16331,7 @@ userRoutes.get("/users/:id/edit", async (c) => {
|
|
|
16052
16331
|
return c.html(renderUserEditPage(pageData));
|
|
16053
16332
|
} catch (error) {
|
|
16054
16333
|
console.error("User edit page error:", error);
|
|
16055
|
-
return c.html(
|
|
16334
|
+
return c.html(chunkTT3TQSCZ_cjs.renderAlert({
|
|
16056
16335
|
type: "error",
|
|
16057
16336
|
message: "Failed to load user. Please try again.",
|
|
16058
16337
|
dismissible: true
|
|
@@ -16069,9 +16348,9 @@ userRoutes.put("/users/:id", async (c) => {
|
|
|
16069
16348
|
const lastName = chunkMNWKYY5E_cjs.sanitizeInput(formData.get("last_name")?.toString());
|
|
16070
16349
|
const email = formData.get("email")?.toString()?.trim().toLowerCase() || "";
|
|
16071
16350
|
const phone = chunkMNWKYY5E_cjs.sanitizeInput(formData.get("phone")?.toString()) || null;
|
|
16072
|
-
const roleInput = formData.get("role")?.toString() || "
|
|
16073
|
-
const validRoles =
|
|
16074
|
-
const role = validRoles.includes(roleInput) ? roleInput : "
|
|
16351
|
+
const roleInput = formData.get("role")?.toString() || "";
|
|
16352
|
+
const validRoles = (await new chunkJCBDXEY2_cjs.RbacService(db).getRoles()).map((r) => r.id);
|
|
16353
|
+
const role = validRoles.includes(roleInput) ? roleInput : validRoles[0] ?? "admin";
|
|
16075
16354
|
const isActive = formData.get("is_active") === "1";
|
|
16076
16355
|
const emailVerified = formData.get("email_verified") === "1";
|
|
16077
16356
|
const newPassword = formData.get("new_password")?.toString() || "";
|
|
@@ -16085,12 +16364,12 @@ userRoutes.put("/users/:id", async (c) => {
|
|
|
16085
16364
|
const validation = validateCustomData(sanitized, profileConfig);
|
|
16086
16365
|
if (!validation.valid) {
|
|
16087
16366
|
const errorMessages = Object.values(validation.errors).join(", ");
|
|
16088
|
-
return c.html(
|
|
16367
|
+
return c.html(chunkTT3TQSCZ_cjs.renderAlert({ type: "error", message: errorMessages, dismissible: true }), 400);
|
|
16089
16368
|
}
|
|
16090
16369
|
sanitizedCustom = sanitized;
|
|
16091
16370
|
}
|
|
16092
16371
|
if (!email) {
|
|
16093
|
-
return c.html(
|
|
16372
|
+
return c.html(chunkTT3TQSCZ_cjs.renderAlert({
|
|
16094
16373
|
type: "error",
|
|
16095
16374
|
message: "Email is required.",
|
|
16096
16375
|
dismissible: true
|
|
@@ -16098,7 +16377,7 @@ userRoutes.put("/users/:id", async (c) => {
|
|
|
16098
16377
|
}
|
|
16099
16378
|
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
16100
16379
|
if (!emailRegex.test(email)) {
|
|
16101
|
-
return c.html(
|
|
16380
|
+
return c.html(chunkTT3TQSCZ_cjs.renderAlert({
|
|
16102
16381
|
type: "error",
|
|
16103
16382
|
message: "Please enter a valid email address.",
|
|
16104
16383
|
dismissible: true
|
|
@@ -16106,14 +16385,14 @@ userRoutes.put("/users/:id", async (c) => {
|
|
|
16106
16385
|
}
|
|
16107
16386
|
if (newPassword) {
|
|
16108
16387
|
if (newPassword.length < 8) {
|
|
16109
|
-
return c.html(
|
|
16388
|
+
return c.html(chunkTT3TQSCZ_cjs.renderAlert({
|
|
16110
16389
|
type: "error",
|
|
16111
16390
|
message: "Password must be at least 8 characters long.",
|
|
16112
16391
|
dismissible: true
|
|
16113
16392
|
}));
|
|
16114
16393
|
}
|
|
16115
16394
|
if (newPassword !== confirmPassword) {
|
|
16116
|
-
return c.html(
|
|
16395
|
+
return c.html(chunkTT3TQSCZ_cjs.renderAlert({
|
|
16117
16396
|
type: "error",
|
|
16118
16397
|
message: "Passwords do not match.",
|
|
16119
16398
|
dismissible: true
|
|
@@ -16126,7 +16405,7 @@ userRoutes.put("/users/:id", async (c) => {
|
|
|
16126
16405
|
`);
|
|
16127
16406
|
const existingUser = await checkStmt.bind(email, userId).first();
|
|
16128
16407
|
if (existingUser) {
|
|
16129
|
-
return c.html(
|
|
16408
|
+
return c.html(chunkTT3TQSCZ_cjs.renderAlert({
|
|
16130
16409
|
type: "error",
|
|
16131
16410
|
message: "Email is already taken by another user.",
|
|
16132
16411
|
dismissible: true
|
|
@@ -16151,7 +16430,7 @@ userRoutes.put("/users/:id", async (c) => {
|
|
|
16151
16430
|
userId
|
|
16152
16431
|
).run();
|
|
16153
16432
|
if (newPassword) {
|
|
16154
|
-
const passwordHash = await
|
|
16433
|
+
const passwordHash = await chunkE7E3NL3Y_cjs.AuthManager.hashPassword(newPassword);
|
|
16155
16434
|
const updatePasswordStmt = db.prepare(`
|
|
16156
16435
|
UPDATE auth_user SET password_hash = ?, updated_at = ? WHERE id = ?
|
|
16157
16436
|
`);
|
|
@@ -16164,7 +16443,7 @@ userRoutes.put("/users/:id", async (c) => {
|
|
|
16164
16443
|
...sanitizedCustom !== null ? { custom: sanitizedCustom } : {}
|
|
16165
16444
|
}, user.userId);
|
|
16166
16445
|
}
|
|
16167
|
-
await
|
|
16446
|
+
await chunkE7E3NL3Y_cjs.logActivity(
|
|
16168
16447
|
db,
|
|
16169
16448
|
user.userId,
|
|
16170
16449
|
"user.update",
|
|
@@ -16174,7 +16453,7 @@ userRoutes.put("/users/:id", async (c) => {
|
|
|
16174
16453
|
c.req.header("x-forwarded-for") || c.req.header("cf-connecting-ip"),
|
|
16175
16454
|
c.req.header("user-agent")
|
|
16176
16455
|
);
|
|
16177
|
-
return c.html(
|
|
16456
|
+
return c.html(chunkTT3TQSCZ_cjs.renderAlert({
|
|
16178
16457
|
type: "success",
|
|
16179
16458
|
message: "User updated successfully!",
|
|
16180
16459
|
dismissible: true,
|
|
@@ -16182,7 +16461,7 @@ userRoutes.put("/users/:id", async (c) => {
|
|
|
16182
16461
|
}));
|
|
16183
16462
|
} catch (error) {
|
|
16184
16463
|
console.error("User update error:", error);
|
|
16185
|
-
return c.html(
|
|
16464
|
+
return c.html(chunkTT3TQSCZ_cjs.renderAlert({
|
|
16186
16465
|
type: "error",
|
|
16187
16466
|
message: "Failed to update user. Please try again.",
|
|
16188
16467
|
dismissible: true
|
|
@@ -16210,7 +16489,7 @@ userRoutes.post("/users/:id/toggle", async (c) => {
|
|
|
16210
16489
|
UPDATE auth_user SET is_active = ?, updated_at = ? WHERE id = ?
|
|
16211
16490
|
`);
|
|
16212
16491
|
await toggleStmt.bind(active ? 1 : 0, Date.now(), userId).run();
|
|
16213
|
-
await
|
|
16492
|
+
await chunkE7E3NL3Y_cjs.logActivity(
|
|
16214
16493
|
db,
|
|
16215
16494
|
user.userId,
|
|
16216
16495
|
active ? "user.activate" : "user.deactivate",
|
|
@@ -16251,7 +16530,7 @@ userRoutes.delete("/users/:id", async (c) => {
|
|
|
16251
16530
|
DELETE FROM auth_user WHERE id = ?
|
|
16252
16531
|
`);
|
|
16253
16532
|
await deleteStmt.bind(userId).run();
|
|
16254
|
-
await
|
|
16533
|
+
await chunkE7E3NL3Y_cjs.logActivity(
|
|
16255
16534
|
db,
|
|
16256
16535
|
user.userId,
|
|
16257
16536
|
"user!.hard_delete",
|
|
@@ -16270,7 +16549,7 @@ userRoutes.delete("/users/:id", async (c) => {
|
|
|
16270
16549
|
UPDATE auth_user SET is_active = 0, updated_at = ? WHERE id = ?
|
|
16271
16550
|
`);
|
|
16272
16551
|
await deleteStmt.bind(Date.now(), userId).run();
|
|
16273
|
-
await
|
|
16552
|
+
await chunkE7E3NL3Y_cjs.logActivity(
|
|
16274
16553
|
db,
|
|
16275
16554
|
user.userId,
|
|
16276
16555
|
"user!.soft_delete",
|
|
@@ -16336,7 +16615,7 @@ userRoutes.post("/invite-user", async (c) => {
|
|
|
16336
16615
|
Date.now(),
|
|
16337
16616
|
Date.now()
|
|
16338
16617
|
).run();
|
|
16339
|
-
await
|
|
16618
|
+
await chunkE7E3NL3Y_cjs.logActivity(
|
|
16340
16619
|
db,
|
|
16341
16620
|
user.userId,
|
|
16342
16621
|
"user!.invite_sent",
|
|
@@ -16393,7 +16672,7 @@ userRoutes.post("/resend-invitation/:id", async (c) => {
|
|
|
16393
16672
|
Date.now(),
|
|
16394
16673
|
userId
|
|
16395
16674
|
).run();
|
|
16396
|
-
await
|
|
16675
|
+
await chunkE7E3NL3Y_cjs.logActivity(
|
|
16397
16676
|
db,
|
|
16398
16677
|
user.userId,
|
|
16399
16678
|
"user!.invitation_resent",
|
|
@@ -16429,7 +16708,7 @@ userRoutes.delete("/cancel-invitation/:id", async (c) => {
|
|
|
16429
16708
|
}
|
|
16430
16709
|
const deleteStmt = db.prepare(`DELETE FROM auth_user WHERE id = ?`);
|
|
16431
16710
|
await deleteStmt.bind(userId).run();
|
|
16432
|
-
await
|
|
16711
|
+
await chunkE7E3NL3Y_cjs.logActivity(
|
|
16433
16712
|
db,
|
|
16434
16713
|
user.userId,
|
|
16435
16714
|
"user!.invitation_cancelled",
|
|
@@ -16678,7 +16957,7 @@ function getFileIcon(mimeType) {
|
|
|
16678
16957
|
}
|
|
16679
16958
|
|
|
16680
16959
|
// src/templates/pages/admin-media-library.template.ts
|
|
16681
|
-
|
|
16960
|
+
chunkMI2YXCK4_cjs.init_admin_layout_catalyst_template();
|
|
16682
16961
|
function renderMediaLibraryPage(data) {
|
|
16683
16962
|
const pageContent = `
|
|
16684
16963
|
<div>
|
|
@@ -17613,7 +17892,7 @@ function renderMediaLibraryPage(data) {
|
|
|
17613
17892
|
version: data.version,
|
|
17614
17893
|
content: pageContent
|
|
17615
17894
|
};
|
|
17616
|
-
return
|
|
17895
|
+
return chunkMI2YXCK4_cjs.renderAdminLayoutCatalyst(layoutData);
|
|
17617
17896
|
}
|
|
17618
17897
|
|
|
17619
17898
|
// src/templates/components/media-file-details.template.ts
|
|
@@ -17810,7 +18089,7 @@ var fileValidationSchema2 = zod.z.object({
|
|
|
17810
18089
|
// 50MB max
|
|
17811
18090
|
});
|
|
17812
18091
|
var adminMediaRoutes = new hono.Hono();
|
|
17813
|
-
adminMediaRoutes.use("*",
|
|
18092
|
+
adminMediaRoutes.use("*", chunkE7E3NL3Y_cjs.requireAuth());
|
|
17814
18093
|
adminMediaRoutes.get("/", async (c) => {
|
|
17815
18094
|
try {
|
|
17816
18095
|
const user = c.get("user");
|
|
@@ -17852,7 +18131,7 @@ adminMediaRoutes.get("/selector", async (c) => {
|
|
|
17852
18131
|
const { searchParams } = new URL(c.req.url);
|
|
17853
18132
|
const search = searchParams.get("search") || "";
|
|
17854
18133
|
const db = c.env.DB;
|
|
17855
|
-
const pluginService = new
|
|
18134
|
+
const pluginService = new chunkYAURVGUK_cjs.PluginService(db);
|
|
17856
18135
|
const mediaPlugin = await pluginService.getPlugin("core-media");
|
|
17857
18136
|
if (!mediaPlugin || mediaPlugin.status !== "active") {
|
|
17858
18137
|
return c.html(html.html`
|
|
@@ -18228,7 +18507,7 @@ adminMediaRoutes.put("/:id", async (c) => {
|
|
|
18228
18507
|
`);
|
|
18229
18508
|
}
|
|
18230
18509
|
});
|
|
18231
|
-
adminMediaRoutes.delete("/cleanup",
|
|
18510
|
+
adminMediaRoutes.delete("/cleanup", chunkE7E3NL3Y_cjs.requireRole("admin"), async (c) => {
|
|
18232
18511
|
try {
|
|
18233
18512
|
const db = c.env.DB;
|
|
18234
18513
|
const allMediaStmt = db.prepare("SELECT id, r2_key, filename FROM media WHERE deleted_at IS NULL");
|
|
@@ -18486,7 +18765,7 @@ function generateMediaItemHTML(file) {
|
|
|
18486
18765
|
}
|
|
18487
18766
|
|
|
18488
18767
|
// src/templates/pages/admin-plugins-list.template.ts
|
|
18489
|
-
|
|
18768
|
+
chunkMI2YXCK4_cjs.init_admin_layout_catalyst_template();
|
|
18490
18769
|
function renderPluginsListPage(data) {
|
|
18491
18770
|
const categories = [
|
|
18492
18771
|
{ value: "content", label: "Content Management" },
|
|
@@ -18658,15 +18937,6 @@ function renderPluginsListPage(data) {
|
|
|
18658
18937
|
</div>
|
|
18659
18938
|
|
|
18660
18939
|
<div class="flex items-center gap-3 w-full sm:w-auto">
|
|
18661
|
-
<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">
|
|
18662
|
-
<option value="name-asc">Name (A-Z)</option>
|
|
18663
|
-
<option value="name-desc">Name (Z-A)</option>
|
|
18664
|
-
<option value="newest">Newest Installed</option>
|
|
18665
|
-
<option value="updated">Recently Updated</option>
|
|
18666
|
-
<option value="popular">Popularity</option>
|
|
18667
|
-
<option value="rating">Highest Rated</option>
|
|
18668
|
-
</select>
|
|
18669
|
-
|
|
18670
18940
|
<button
|
|
18671
18941
|
onclick="location.reload()"
|
|
18672
18942
|
class="inline-flex items-center gap-x-1.5 rounded-md bg-white dark:bg-zinc-900 px-3 py-1.5 h-9 text-sm font-semibold text-zinc-900 dark:text-white shadow-sm ring-1 ring-inset ring-zinc-300 dark:ring-zinc-700 hover:bg-zinc-50 dark:hover:bg-zinc-800"
|
|
@@ -18830,8 +19100,6 @@ function renderPluginsListPage(data) {
|
|
|
18830
19100
|
.forEach(cb => params.append('status', cb.value));
|
|
18831
19101
|
const search = document.getElementById('search-input').value;
|
|
18832
19102
|
if (search) params.set('search', search);
|
|
18833
|
-
const sort = document.getElementById('sort-filter').value;
|
|
18834
|
-
if (sort && sort !== 'name-asc') params.set('sort', sort);
|
|
18835
19103
|
const url = new URL(window.location.href);
|
|
18836
19104
|
url.search = params.toString();
|
|
18837
19105
|
history.replaceState(null, '', url.toString());
|
|
@@ -18849,8 +19117,6 @@ function renderPluginsListPage(data) {
|
|
|
18849
19117
|
});
|
|
18850
19118
|
const search = params.get('search');
|
|
18851
19119
|
if (search) document.getElementById('search-input').value = search;
|
|
18852
|
-
const sort = params.get('sort');
|
|
18853
|
-
if (sort) document.getElementById('sort-filter').value = sort;
|
|
18854
19120
|
if (params.toString()) filterAndSortPlugins();
|
|
18855
19121
|
}
|
|
18856
19122
|
|
|
@@ -18866,7 +19132,6 @@ function renderPluginsListPage(data) {
|
|
|
18866
19132
|
.map(cb => cb.value.toLowerCase());
|
|
18867
19133
|
|
|
18868
19134
|
const searchInput = document.getElementById('search-input').value.toLowerCase();
|
|
18869
|
-
const sortValue = document.getElementById('sort-filter').value;
|
|
18870
19135
|
|
|
18871
19136
|
const pluginsGrid = document.getElementById('plugins-grid');
|
|
18872
19137
|
const pluginCards = Array.from(pluginsGrid.querySelectorAll('.plugin-card'));
|
|
@@ -18890,30 +19155,6 @@ function renderPluginsListPage(data) {
|
|
|
18890
19155
|
return true;
|
|
18891
19156
|
});
|
|
18892
19157
|
|
|
18893
|
-
// Sort
|
|
18894
|
-
visibleCards.sort((a, b) => {
|
|
18895
|
-
const aName = a.getAttribute('data-name') || '';
|
|
18896
|
-
const bName = b.getAttribute('data-name') || '';
|
|
18897
|
-
const aInstalled = parseInt(a.getAttribute('data-installed') || '0');
|
|
18898
|
-
const bInstalled = parseInt(b.getAttribute('data-installed') || '0');
|
|
18899
|
-
const aUpdated = parseInt(a.getAttribute('data-updated') || '0');
|
|
18900
|
-
const bUpdated = parseInt(b.getAttribute('data-updated') || '0');
|
|
18901
|
-
const aDownloads = parseInt(a.getAttribute('data-downloads') || '0');
|
|
18902
|
-
const bDownloads = parseInt(b.getAttribute('data-downloads') || '0');
|
|
18903
|
-
const aRating = parseFloat(a.getAttribute('data-rating') || '0');
|
|
18904
|
-
const bRating = parseFloat(b.getAttribute('data-rating') || '0');
|
|
18905
|
-
|
|
18906
|
-
switch (sortValue) {
|
|
18907
|
-
case 'name-desc': return bName.localeCompare(aName);
|
|
18908
|
-
case 'newest': return bInstalled - aInstalled;
|
|
18909
|
-
case 'updated': return bUpdated - aUpdated;
|
|
18910
|
-
case 'popular': return bDownloads - aDownloads;
|
|
18911
|
-
case 'rating': return bRating - aRating;
|
|
18912
|
-
case 'name-asc':
|
|
18913
|
-
default: return aName.localeCompare(bName);
|
|
18914
|
-
}
|
|
18915
|
-
});
|
|
18916
|
-
|
|
18917
19158
|
// Re-append
|
|
18918
19159
|
pluginCards.forEach(card => card.style.display = 'none'); // Hide all first
|
|
18919
19160
|
|
|
@@ -18969,7 +19210,7 @@ function renderPluginsListPage(data) {
|
|
|
18969
19210
|
version: data.version,
|
|
18970
19211
|
content: pageContent
|
|
18971
19212
|
};
|
|
18972
|
-
return
|
|
19213
|
+
return chunkMI2YXCK4_cjs.renderAdminLayoutCatalyst(layoutData);
|
|
18973
19214
|
}
|
|
18974
19215
|
function renderPluginCard(plugin) {
|
|
18975
19216
|
const statusColors = {
|
|
@@ -19347,8 +19588,9 @@ function escapeHtmlAttr(value) {
|
|
|
19347
19588
|
}
|
|
19348
19589
|
function renderPluginSettingsPage(data) {
|
|
19349
19590
|
const { plugin, activity = [], user, settingsTabData } = data;
|
|
19350
|
-
const pluginDef =
|
|
19351
|
-
const
|
|
19591
|
+
const pluginDef = chunkD6FWEYQE_cjs.getPluginDefinition(plugin.id || plugin.name);
|
|
19592
|
+
const pluginId = plugin.id || plugin.name;
|
|
19593
|
+
const hasUserSettings = pluginDef?.settingsTabContent != null || Object.keys(plugin.settings || {}).some((k) => !k.startsWith("_")) || hasCustomSettingsComponent(pluginId);
|
|
19352
19594
|
const defaultTab = hasUserSettings ? "settings" : "info";
|
|
19353
19595
|
const pageContent = `
|
|
19354
19596
|
<div class="w-full px-4 sm:px-6 lg:px-8 py-6">
|
|
@@ -19513,9 +19755,28 @@ function renderPluginSettingsPage(data) {
|
|
|
19513
19755
|
const form = document.getElementById('settings-form');
|
|
19514
19756
|
const formData = new FormData(form);
|
|
19515
19757
|
const isAuthPlugin = '${plugin.id}' === 'core-auth';
|
|
19758
|
+
const isOAuthPlugin = '${plugin.id}' === 'oauth-providers';
|
|
19516
19759
|
let settings = {};
|
|
19517
19760
|
|
|
19518
|
-
if (
|
|
19761
|
+
if (isOAuthPlugin) {
|
|
19762
|
+
// Build nested provider settings structure
|
|
19763
|
+
const getVal = id => (document.getElementById(id) || {}).value || '';
|
|
19764
|
+
const getChecked = id => !!(document.getElementById(id) || {}).checked;
|
|
19765
|
+
settings = {
|
|
19766
|
+
providers: {
|
|
19767
|
+
github: {
|
|
19768
|
+
clientId: getVal('oauth_github_clientId'),
|
|
19769
|
+
clientSecret: getVal('oauth_github_clientSecret'),
|
|
19770
|
+
enabled: getChecked('oauth_github_enabled'),
|
|
19771
|
+
},
|
|
19772
|
+
google: {
|
|
19773
|
+
clientId: getVal('oauth_google_clientId'),
|
|
19774
|
+
clientSecret: getVal('oauth_google_clientSecret'),
|
|
19775
|
+
enabled: getChecked('oauth_google_enabled'),
|
|
19776
|
+
},
|
|
19777
|
+
}
|
|
19778
|
+
};
|
|
19779
|
+
} else if (isAuthPlugin) {
|
|
19519
19780
|
// Handle nested auth settings structure
|
|
19520
19781
|
settings = {
|
|
19521
19782
|
requiredFields: {},
|
|
@@ -19624,7 +19885,7 @@ function renderPluginSettingsPage(data) {
|
|
|
19624
19885
|
user,
|
|
19625
19886
|
content: pageContent
|
|
19626
19887
|
};
|
|
19627
|
-
return
|
|
19888
|
+
return chunkOUBUS74I_cjs.renderAdminLayout(layoutData);
|
|
19628
19889
|
}
|
|
19629
19890
|
function renderStatusBadge(status) {
|
|
19630
19891
|
const statusColors = {
|
|
@@ -19653,7 +19914,7 @@ function renderSettingsTab(plugin, settingsTabData) {
|
|
|
19653
19914
|
const settings = plugin.settings || {};
|
|
19654
19915
|
const pluginId = plugin.id || plugin.name;
|
|
19655
19916
|
const hasUserKeys = Object.keys(settings).some((k) => !k.startsWith("_"));
|
|
19656
|
-
const pluginDef =
|
|
19917
|
+
const pluginDef = chunkD6FWEYQE_cjs.getPluginDefinition(pluginId);
|
|
19657
19918
|
if (pluginDef?.settingsTabContent) {
|
|
19658
19919
|
return pluginDef.settingsTabContent.render({ plugin, settings, data: settingsTabData });
|
|
19659
19920
|
}
|
|
@@ -20003,7 +20264,8 @@ function formatTimestamp(timestamp) {
|
|
|
20003
20264
|
}
|
|
20004
20265
|
var pluginSettingsComponents = {
|
|
20005
20266
|
"otp-login": renderOTPLoginSettingsContent,
|
|
20006
|
-
"email": renderEmailSettingsContent
|
|
20267
|
+
"email": renderEmailSettingsContent,
|
|
20268
|
+
"oauth-providers": renderOAuthProvidersSettingsContent
|
|
20007
20269
|
};
|
|
20008
20270
|
function renderOTPLoginSettingsContent(plugin, settings) {
|
|
20009
20271
|
const siteName = settings.siteName || "SonicJS";
|
|
@@ -20726,6 +20988,62 @@ defineUserProfile({
|
|
|
20726
20988
|
</div>
|
|
20727
20989
|
`;
|
|
20728
20990
|
}
|
|
20991
|
+
function renderOAuthProvidersSettingsContent(plugin, settings) {
|
|
20992
|
+
const providers = settings.providers || {};
|
|
20993
|
+
const gh = providers.github || {};
|
|
20994
|
+
const gg = providers.google || {};
|
|
20995
|
+
const inputClass = "backdrop-blur-sm bg-white/10 border border-white/20 rounded-lg px-3 py-2 text-white placeholder-gray-300 focus:border-blue-400 focus:outline-none transition-colors w-full";
|
|
20996
|
+
return `
|
|
20997
|
+
<div class="space-y-6">
|
|
20998
|
+
<form id="settings-form">
|
|
20999
|
+
<div class="backdrop-blur-md bg-white/5 rounded-xl border border-white/10 p-6 space-y-6">
|
|
21000
|
+
<h3 class="text-lg font-semibold text-white">GitHub OAuth</h3>
|
|
21001
|
+
<div>
|
|
21002
|
+
<label for="oauth_github_clientId" class="block text-sm font-medium text-gray-300 mb-2">Client ID</label>
|
|
21003
|
+
<input type="text" id="oauth_github_clientId" name="oauth_github_clientId"
|
|
21004
|
+
value="${escapeHtmlAttr(gh.clientId || "")}"
|
|
21005
|
+
placeholder="GitHub OAuth App Client ID" class="${inputClass}" />
|
|
21006
|
+
</div>
|
|
21007
|
+
<div>
|
|
21008
|
+
<label for="oauth_github_clientSecret" class="block text-sm font-medium text-gray-300 mb-2">Client Secret</label>
|
|
21009
|
+
<input type="password" id="oauth_github_clientSecret" name="oauth_github_clientSecret"
|
|
21010
|
+
value="${escapeHtmlAttr(gh.clientSecret || "")}"
|
|
21011
|
+
placeholder="GitHub OAuth App Client Secret" class="${inputClass}" />
|
|
21012
|
+
</div>
|
|
21013
|
+
<div class="flex items-center gap-3">
|
|
21014
|
+
<input type="checkbox" id="oauth_github_enabled" name="oauth_github_enabled"
|
|
21015
|
+
${gh.enabled ? "checked" : ""} class="w-4 h-4 rounded border-white/10" />
|
|
21016
|
+
<label for="oauth_github_enabled" class="text-sm text-gray-300">Enable GitHub login</label>
|
|
21017
|
+
</div>
|
|
21018
|
+
</div>
|
|
21019
|
+
|
|
21020
|
+
<div class="backdrop-blur-md bg-white/5 rounded-xl border border-white/10 p-6 space-y-6 mt-6">
|
|
21021
|
+
<h3 class="text-lg font-semibold text-white">Google OAuth</h3>
|
|
21022
|
+
<div>
|
|
21023
|
+
<label for="oauth_google_clientId" class="block text-sm font-medium text-gray-300 mb-2">Client ID</label>
|
|
21024
|
+
<input type="text" id="oauth_google_clientId" name="oauth_google_clientId"
|
|
21025
|
+
value="${escapeHtmlAttr(gg.clientId || "")}"
|
|
21026
|
+
placeholder="Google OAuth Client ID" class="${inputClass}" />
|
|
21027
|
+
</div>
|
|
21028
|
+
<div>
|
|
21029
|
+
<label for="oauth_google_clientSecret" class="block text-sm font-medium text-gray-300 mb-2">Client Secret</label>
|
|
21030
|
+
<input type="password" id="oauth_google_clientSecret" name="oauth_google_clientSecret"
|
|
21031
|
+
value="${escapeHtmlAttr(gg.clientSecret || "")}"
|
|
21032
|
+
placeholder="Google OAuth Client Secret" class="${inputClass}" />
|
|
21033
|
+
</div>
|
|
21034
|
+
<div class="flex items-center gap-3">
|
|
21035
|
+
<input type="checkbox" id="oauth_google_enabled" name="oauth_google_enabled"
|
|
21036
|
+
${gg.enabled ? "checked" : ""} class="w-4 h-4 rounded border-white/10" />
|
|
21037
|
+
<label for="oauth_google_enabled" class="text-sm text-gray-300">Enable Google login</label>
|
|
21038
|
+
</div>
|
|
21039
|
+
</div>
|
|
21040
|
+
</form>
|
|
21041
|
+
</div>
|
|
21042
|
+
`;
|
|
21043
|
+
}
|
|
21044
|
+
function hasCustomSettingsComponent(pluginId) {
|
|
21045
|
+
return pluginId in pluginSettingsComponents;
|
|
21046
|
+
}
|
|
20729
21047
|
|
|
20730
21048
|
// src/plugins/core-plugins/menu-plugin/services/menu-reconcile.ts
|
|
20731
21049
|
async function upsertPluginRow(db, slug, entry, visible) {
|
|
@@ -20843,8 +21161,8 @@ async function fetchActivePluginIds(db) {
|
|
|
20843
21161
|
}
|
|
20844
21162
|
async function reconcileMenuFromPlugins(db) {
|
|
20845
21163
|
try {
|
|
20846
|
-
const singletonEntries =
|
|
20847
|
-
const manifestEntries = Object.values(
|
|
21164
|
+
const singletonEntries = chunkD6FWEYQE_cjs.getPluginMenu();
|
|
21165
|
+
const manifestEntries = Object.values(chunkYAURVGUK_cjs.PLUGIN_REGISTRY).filter(
|
|
20848
21166
|
(p) => p.adminMenu !== null
|
|
20849
21167
|
);
|
|
20850
21168
|
const byPluginId = /* @__PURE__ */ new Map();
|
|
@@ -20881,8 +21199,8 @@ async function reconcileMenuFromPlugins(db) {
|
|
|
20881
21199
|
|
|
20882
21200
|
// src/routes/admin-plugins.ts
|
|
20883
21201
|
var adminPluginRoutes = new hono.Hono();
|
|
20884
|
-
adminPluginRoutes.use("*",
|
|
20885
|
-
var AVAILABLE_PLUGINS = Object.values(
|
|
21202
|
+
adminPluginRoutes.use("*", chunkE7E3NL3Y_cjs.requireAuth());
|
|
21203
|
+
var AVAILABLE_PLUGINS = Object.values(chunkYAURVGUK_cjs.PLUGIN_REGISTRY).map((p) => ({
|
|
20886
21204
|
id: p.id,
|
|
20887
21205
|
name: p.codeName,
|
|
20888
21206
|
display_name: p.displayName,
|
|
@@ -20902,7 +21220,7 @@ adminPluginRoutes.get("/", async (c) => {
|
|
|
20902
21220
|
if (user?.role !== "admin") {
|
|
20903
21221
|
return c.text("Access denied", 403);
|
|
20904
21222
|
}
|
|
20905
|
-
const pluginService = new
|
|
21223
|
+
const pluginService = new chunkYAURVGUK_cjs.PluginService(db);
|
|
20906
21224
|
let installedPlugins = [];
|
|
20907
21225
|
let stats = { total: 0, active: 0, inactive: 0, errors: 0, uninstalled: 0 };
|
|
20908
21226
|
try {
|
|
@@ -20976,10 +21294,10 @@ adminPluginRoutes.get("/:id", async (c) => {
|
|
|
20976
21294
|
if (user?.role !== "admin") {
|
|
20977
21295
|
return c.redirect("/admin/plugins");
|
|
20978
21296
|
}
|
|
20979
|
-
const pluginService = new
|
|
21297
|
+
const pluginService = new chunkYAURVGUK_cjs.PluginService(db);
|
|
20980
21298
|
let plugin = await pluginService.getPlugin(pluginId);
|
|
20981
21299
|
if (!plugin) {
|
|
20982
|
-
const def =
|
|
21300
|
+
const def = chunkD6FWEYQE_cjs.getPluginDefinition(pluginId);
|
|
20983
21301
|
if (!def) return c.text("Plugin not found", 404);
|
|
20984
21302
|
plugin = await pluginService.ensurePlugin(pluginId, {
|
|
20985
21303
|
displayName: def.displayName ?? pluginId,
|
|
@@ -21050,7 +21368,7 @@ adminPluginRoutes.get("/:id", async (c) => {
|
|
|
21050
21368
|
timestamp: item.timestamp,
|
|
21051
21369
|
user: item.userId || null
|
|
21052
21370
|
}));
|
|
21053
|
-
const pluginDef =
|
|
21371
|
+
const pluginDef = chunkD6FWEYQE_cjs.getPluginDefinition(pluginId);
|
|
21054
21372
|
let settingsTabData = void 0;
|
|
21055
21373
|
if (pluginDef?.settingsTabContent?.loadData) {
|
|
21056
21374
|
try {
|
|
@@ -21080,14 +21398,14 @@ adminPluginRoutes.get("/:id/configure", async (c) => {
|
|
|
21080
21398
|
const user = c.get("user");
|
|
21081
21399
|
const pluginId = c.req.param("id");
|
|
21082
21400
|
if (user?.role !== "admin") return c.redirect("/admin/plugins");
|
|
21083
|
-
const def =
|
|
21401
|
+
const def = chunkD6FWEYQE_cjs.getPluginDefinition(pluginId);
|
|
21084
21402
|
if (!def?.configSchema) return c.text("No schema-driven settings for this plugin", 404);
|
|
21085
21403
|
const db = c.env.DB;
|
|
21086
|
-
const pluginService = new
|
|
21404
|
+
const pluginService = new chunkYAURVGUK_cjs.PluginService(db);
|
|
21087
21405
|
const plugin = await pluginService.getPlugin(pluginId);
|
|
21088
21406
|
const stored = plugin?.settings ?? {};
|
|
21089
|
-
const values =
|
|
21090
|
-
const fieldsHtml =
|
|
21407
|
+
const values = chunkD6FWEYQE_cjs.applySchemaDefaults(def.configSchema, stored);
|
|
21408
|
+
const fieldsHtml = chunkD6FWEYQE_cjs.renderSchemaFields(def.configSchema, values);
|
|
21091
21409
|
const displayName = plugin?.display_name ?? def.displayName ?? def.id;
|
|
21092
21410
|
return c.html(`<!DOCTYPE html>
|
|
21093
21411
|
<html lang="en"><head>
|
|
@@ -21114,12 +21432,12 @@ adminPluginRoutes.post("/:id/configure", async (c) => {
|
|
|
21114
21432
|
const user = c.get("user");
|
|
21115
21433
|
const pluginId = c.req.param("id");
|
|
21116
21434
|
if (user?.role !== "admin") return c.json({ error: "Access denied" }, 403);
|
|
21117
|
-
const def =
|
|
21435
|
+
const def = chunkD6FWEYQE_cjs.getPluginDefinition(pluginId);
|
|
21118
21436
|
if (!def?.configSchema) return c.text("No schema-driven settings for this plugin", 404);
|
|
21119
21437
|
const form = await c.req.formData();
|
|
21120
|
-
const parsed =
|
|
21438
|
+
const parsed = chunkD6FWEYQE_cjs.parseFormDataToSettings(def.configSchema, form);
|
|
21121
21439
|
const db = c.env.DB;
|
|
21122
|
-
const pluginService = new
|
|
21440
|
+
const pluginService = new chunkYAURVGUK_cjs.PluginService(db);
|
|
21123
21441
|
await pluginService.ensurePlugin(pluginId, {
|
|
21124
21442
|
displayName: def.displayName ?? pluginId,
|
|
21125
21443
|
version: def.version,
|
|
@@ -21143,7 +21461,7 @@ adminPluginRoutes.post("/:id/activate", async (c) => {
|
|
|
21143
21461
|
if (user?.role !== "admin") {
|
|
21144
21462
|
return c.json({ error: "Access denied" }, 403);
|
|
21145
21463
|
}
|
|
21146
|
-
const pluginService = new
|
|
21464
|
+
const pluginService = new chunkYAURVGUK_cjs.PluginService(db);
|
|
21147
21465
|
await pluginService.activatePlugin(pluginId);
|
|
21148
21466
|
await reconcileMenuFromPlugins(db);
|
|
21149
21467
|
return c.json({ success: true });
|
|
@@ -21161,7 +21479,7 @@ adminPluginRoutes.post("/:id/deactivate", async (c) => {
|
|
|
21161
21479
|
if (user?.role !== "admin") {
|
|
21162
21480
|
return c.json({ error: "Access denied" }, 403);
|
|
21163
21481
|
}
|
|
21164
|
-
const pluginService = new
|
|
21482
|
+
const pluginService = new chunkYAURVGUK_cjs.PluginService(db);
|
|
21165
21483
|
await pluginService.deactivatePlugin(pluginId);
|
|
21166
21484
|
await reconcileMenuFromPlugins(db);
|
|
21167
21485
|
return c.json({ success: true });
|
|
@@ -21179,8 +21497,8 @@ adminPluginRoutes.post("/install", async (c) => {
|
|
|
21179
21497
|
return c.json({ error: "Access denied" }, 403);
|
|
21180
21498
|
}
|
|
21181
21499
|
const body = await c.req.json();
|
|
21182
|
-
const pluginService = new
|
|
21183
|
-
const registryEntry =
|
|
21500
|
+
const pluginService = new chunkYAURVGUK_cjs.PluginService(db);
|
|
21501
|
+
const registryEntry = chunkYAURVGUK_cjs.findPluginByCodeName(body.name) || chunkYAURVGUK_cjs.PLUGIN_REGISTRY[body.name] || chunkYAURVGUK_cjs.PLUGIN_REGISTRY[body.id];
|
|
21184
21502
|
if (!registryEntry) {
|
|
21185
21503
|
return c.json({ error: "Plugin not found in registry" }, 404);
|
|
21186
21504
|
}
|
|
@@ -21213,7 +21531,7 @@ adminPluginRoutes.post("/:id/uninstall", async (c) => {
|
|
|
21213
21531
|
if (user?.role !== "admin") {
|
|
21214
21532
|
return c.json({ error: "Access denied" }, 403);
|
|
21215
21533
|
}
|
|
21216
|
-
const pluginService = new
|
|
21534
|
+
const pluginService = new chunkYAURVGUK_cjs.PluginService(db);
|
|
21217
21535
|
await pluginService.uninstallPlugin(pluginId);
|
|
21218
21536
|
return c.json({ success: true });
|
|
21219
21537
|
} catch (error) {
|
|
@@ -21231,7 +21549,7 @@ adminPluginRoutes.post("/:id/settings", async (c) => {
|
|
|
21231
21549
|
return c.json({ error: "Access denied" }, 403);
|
|
21232
21550
|
}
|
|
21233
21551
|
const settings = await c.req.json();
|
|
21234
|
-
const pluginService = new
|
|
21552
|
+
const pluginService = new chunkYAURVGUK_cjs.PluginService(db);
|
|
21235
21553
|
const existingPlugin = await pluginService.getPlugin(pluginId);
|
|
21236
21554
|
const existingSettings = existingPlugin?.settings ?? {};
|
|
21237
21555
|
await pluginService.updatePluginSettings(pluginId, { ...existingSettings, ...settings });
|
|
@@ -21266,7 +21584,7 @@ function formatLastUpdated(timestamp) {
|
|
|
21266
21584
|
}
|
|
21267
21585
|
|
|
21268
21586
|
// src/templates/pages/admin-logs-list.template.ts
|
|
21269
|
-
|
|
21587
|
+
chunkMI2YXCK4_cjs.init_admin_layout_catalyst_template();
|
|
21270
21588
|
function renderLogsListPage(data) {
|
|
21271
21589
|
const { logs, pagination, filters, user } = data;
|
|
21272
21590
|
const content = `
|
|
@@ -21577,7 +21895,7 @@ function renderLogsListPage(data) {
|
|
|
21577
21895
|
user,
|
|
21578
21896
|
content
|
|
21579
21897
|
};
|
|
21580
|
-
return
|
|
21898
|
+
return chunkMI2YXCK4_cjs.renderAdminLayoutCatalyst(layoutData);
|
|
21581
21899
|
}
|
|
21582
21900
|
function renderLogDetailsPage(data) {
|
|
21583
21901
|
const { log, user } = data;
|
|
@@ -21789,7 +22107,7 @@ function renderLogDetailsPage(data) {
|
|
|
21789
22107
|
</div>
|
|
21790
22108
|
</div>
|
|
21791
22109
|
`;
|
|
21792
|
-
return
|
|
22110
|
+
return chunkOUBUS74I_cjs.adminLayoutV2({
|
|
21793
22111
|
title: `Log Details - ${log.id}`,
|
|
21794
22112
|
user,
|
|
21795
22113
|
content
|
|
@@ -22032,7 +22350,7 @@ function renderLogConfigPage(data) {
|
|
|
22032
22350
|
|
|
22033
22351
|
<script src="https://unpkg.com/htmx.org@1.9.6"></script>
|
|
22034
22352
|
`;
|
|
22035
|
-
return
|
|
22353
|
+
return chunkOUBUS74I_cjs.adminLayoutV2({
|
|
22036
22354
|
title: "Log Configuration",
|
|
22037
22355
|
user,
|
|
22038
22356
|
content
|
|
@@ -22041,7 +22359,7 @@ function renderLogConfigPage(data) {
|
|
|
22041
22359
|
|
|
22042
22360
|
// src/routes/admin-logs.ts
|
|
22043
22361
|
var adminLogsRoutes = new hono.Hono();
|
|
22044
|
-
adminLogsRoutes.use("*",
|
|
22362
|
+
adminLogsRoutes.use("*", chunkE7E3NL3Y_cjs.requireAuth());
|
|
22045
22363
|
adminLogsRoutes.get("/", async (c) => {
|
|
22046
22364
|
try {
|
|
22047
22365
|
const user = c.get("user");
|
|
@@ -22413,7 +22731,7 @@ adminCheckboxRoutes.get("/", (c) => {
|
|
|
22413
22731
|
role: user.role
|
|
22414
22732
|
} : void 0
|
|
22415
22733
|
};
|
|
22416
|
-
return c.html(
|
|
22734
|
+
return c.html(chunkOUBUS74I_cjs.renderCheckboxPage(pageData));
|
|
22417
22735
|
});
|
|
22418
22736
|
|
|
22419
22737
|
// src/templates/pages/admin-dashboard.template.ts
|
|
@@ -22485,7 +22803,7 @@ function renderDashboardPage(data) {
|
|
|
22485
22803
|
version: data.version,
|
|
22486
22804
|
content: pageContent
|
|
22487
22805
|
};
|
|
22488
|
-
return
|
|
22806
|
+
return chunkOUBUS74I_cjs.renderAdminLayout(layoutData);
|
|
22489
22807
|
}
|
|
22490
22808
|
function renderStatsCards(stats) {
|
|
22491
22809
|
const cards = [
|
|
@@ -23033,9 +23351,9 @@ function renderStorageUsage(databaseSizeBytes, mediaSizeBytes) {
|
|
|
23033
23351
|
}
|
|
23034
23352
|
|
|
23035
23353
|
// src/routes/admin-dashboard.ts
|
|
23036
|
-
var VERSION =
|
|
23354
|
+
var VERSION = chunkBJ6NJL2E_cjs.getCoreVersion();
|
|
23037
23355
|
var router = new hono.Hono();
|
|
23038
|
-
router.use("*",
|
|
23356
|
+
router.use("*", chunkE7E3NL3Y_cjs.requireAuth());
|
|
23039
23357
|
router.get("/", async (c) => {
|
|
23040
23358
|
const user = c.get("user");
|
|
23041
23359
|
try {
|
|
@@ -23225,7 +23543,7 @@ router.get("/system-status", async (c) => {
|
|
|
23225
23543
|
});
|
|
23226
23544
|
|
|
23227
23545
|
// src/templates/pages/admin-collections-list.template.ts
|
|
23228
|
-
|
|
23546
|
+
chunkMI2YXCK4_cjs.init_admin_layout_catalyst_template();
|
|
23229
23547
|
|
|
23230
23548
|
// src/templates/components/table.template.ts
|
|
23231
23549
|
function renderTable2(data) {
|
|
@@ -23707,11 +24025,11 @@ function renderCollectionsListPage(data) {
|
|
|
23707
24025
|
version: data.version,
|
|
23708
24026
|
content: pageContent
|
|
23709
24027
|
};
|
|
23710
|
-
return
|
|
24028
|
+
return chunkMI2YXCK4_cjs.renderAdminLayoutCatalyst(layoutData);
|
|
23711
24029
|
}
|
|
23712
24030
|
|
|
23713
24031
|
// src/templates/pages/admin-collections-form.template.ts
|
|
23714
|
-
|
|
24032
|
+
chunkMI2YXCK4_cjs.init_admin_layout_catalyst_template();
|
|
23715
24033
|
function getFieldTypeBadge(fieldType) {
|
|
23716
24034
|
const typeLabels = {
|
|
23717
24035
|
"text": "Text",
|
|
@@ -23884,8 +24202,8 @@ function renderCollectionFormPage(data) {
|
|
|
23884
24202
|
<!-- Form Content -->
|
|
23885
24203
|
<div class="px-6 py-6">
|
|
23886
24204
|
<div id="form-messages"></div>
|
|
23887
|
-
${data.error ?
|
|
23888
|
-
${data.success ?
|
|
24205
|
+
${data.error ? chunkTT3TQSCZ_cjs.renderAlert({ type: "error", message: data.error, dismissible: true }) : ""}
|
|
24206
|
+
${data.success ? chunkTT3TQSCZ_cjs.renderAlert({ type: "success", message: data.success, dismissible: true }) : ""}
|
|
23889
24207
|
|
|
23890
24208
|
<!-- Form Styling -->
|
|
23891
24209
|
<style>
|
|
@@ -23996,7 +24314,7 @@ function renderCollectionFormPage(data) {
|
|
|
23996
24314
|
}
|
|
23997
24315
|
</style>
|
|
23998
24316
|
|
|
23999
|
-
${
|
|
24317
|
+
${chunkOUBUS74I_cjs.renderForm(formData)}
|
|
24000
24318
|
|
|
24001
24319
|
${isEdit && data.managed ? `
|
|
24002
24320
|
<!-- Read-Only Fields Display for Managed Collections -->
|
|
@@ -24994,13 +25312,13 @@ function renderCollectionFormPage(data) {
|
|
|
24994
25312
|
version: data.version,
|
|
24995
25313
|
content: pageContent
|
|
24996
25314
|
};
|
|
24997
|
-
return
|
|
25315
|
+
return chunkMI2YXCK4_cjs.renderAdminLayoutCatalyst(layoutData);
|
|
24998
25316
|
}
|
|
24999
25317
|
|
|
25000
25318
|
// src/routes/admin-collections.ts
|
|
25001
|
-
|
|
25319
|
+
chunkMI2YXCK4_cjs.init_admin_layout_catalyst_template();
|
|
25002
25320
|
var adminCollectionsRoutes = new hono.Hono();
|
|
25003
|
-
adminCollectionsRoutes.use("*",
|
|
25321
|
+
adminCollectionsRoutes.use("*", chunkE7E3NL3Y_cjs.requireAuth());
|
|
25004
25322
|
adminCollectionsRoutes.get("/", async (c) => {
|
|
25005
25323
|
try {
|
|
25006
25324
|
const user = c.get("user");
|
|
@@ -25017,7 +25335,7 @@ adminCollectionsRoutes.get("/", async (c) => {
|
|
|
25017
25335
|
results = queryResults.results ?? [];
|
|
25018
25336
|
} catch (e) {
|
|
25019
25337
|
}
|
|
25020
|
-
const codeCollections =
|
|
25338
|
+
const codeCollections = chunkYAURVGUK_cjs.getCollectionRegistry().list();
|
|
25021
25339
|
const codeCollectionsMap = new Map(
|
|
25022
25340
|
codeCollections.map((cfg) => {
|
|
25023
25341
|
const fieldCount = cfg.schema?.properties ? Object.keys(cfg.schema.properties).length : 0;
|
|
@@ -25031,7 +25349,7 @@ adminCollectionsRoutes.get("/", async (c) => {
|
|
|
25031
25349
|
field_count: fieldCount,
|
|
25032
25350
|
managed: cfg.managed !== false,
|
|
25033
25351
|
source_type: "code",
|
|
25034
|
-
internal:
|
|
25352
|
+
internal: chunkYAURVGUK_cjs.isCodeCollectionInternal(cfg),
|
|
25035
25353
|
versioning: cfg.versioning === true
|
|
25036
25354
|
}];
|
|
25037
25355
|
})
|
|
@@ -25070,7 +25388,7 @@ adminCollectionsRoutes.get("/", async (c) => {
|
|
|
25070
25388
|
field_count: fieldCount,
|
|
25071
25389
|
managed: false,
|
|
25072
25390
|
source_type: row.source === "code" || row.source === "system" || row.source === "plugin" ? "code" : "user",
|
|
25073
|
-
internal:
|
|
25391
|
+
internal: chunkYAURVGUK_cjs.isDbDocTypeInternal(row.source),
|
|
25074
25392
|
versioning: dbVersioning
|
|
25075
25393
|
};
|
|
25076
25394
|
});
|
|
@@ -25227,11 +25545,11 @@ export const myPlugin = definePlugin({
|
|
|
25227
25545
|
`;
|
|
25228
25546
|
const u = user;
|
|
25229
25547
|
return c.html(
|
|
25230
|
-
|
|
25548
|
+
chunkMI2YXCK4_cjs.renderAdminLayoutCatalyst({
|
|
25231
25549
|
title: "Add a Collection",
|
|
25232
25550
|
pageTitle: "Add a Collection",
|
|
25233
25551
|
currentPath: "/admin/collections",
|
|
25234
|
-
version:
|
|
25552
|
+
version: chunkBJ6NJL2E_cjs.getCoreVersion(),
|
|
25235
25553
|
user: u ? { name: u.email ?? "Admin", email: u.email ?? "", role: u.role ?? "admin" } : void 0,
|
|
25236
25554
|
content
|
|
25237
25555
|
})
|
|
@@ -25248,7 +25566,7 @@ adminCollectionsRoutes.get("/:id", async (c) => {
|
|
|
25248
25566
|
collection = await stmt.bind(id).first();
|
|
25249
25567
|
} catch {
|
|
25250
25568
|
}
|
|
25251
|
-
const registryRecord =
|
|
25569
|
+
const registryRecord = chunkYAURVGUK_cjs.getCollectionRegistry().getById(id) ?? chunkYAURVGUK_cjs.getCollectionRegistry().getByName(id);
|
|
25252
25570
|
if (!collection && !registryRecord) {
|
|
25253
25571
|
const formData2 = {
|
|
25254
25572
|
isEdit: true,
|
|
@@ -25295,9 +25613,9 @@ adminCollectionsRoutes.get("/:id", async (c) => {
|
|
|
25295
25613
|
isCodeDriven = true;
|
|
25296
25614
|
}
|
|
25297
25615
|
const [tinymceActive, quillActive, mdxeditorActive] = await Promise.all([
|
|
25298
|
-
|
|
25299
|
-
|
|
25300
|
-
|
|
25616
|
+
chunkE7E3NL3Y_cjs.isPluginActive(db, "tinymce-plugin"),
|
|
25617
|
+
chunkE7E3NL3Y_cjs.isPluginActive(db, "quill-editor"),
|
|
25618
|
+
chunkE7E3NL3Y_cjs.isPluginActive(db, "easy-mdx")
|
|
25301
25619
|
]);
|
|
25302
25620
|
const displayName = collection?.display_name ?? registryRecord?.displayName ?? id;
|
|
25303
25621
|
const formData = {
|
|
@@ -25317,9 +25635,9 @@ adminCollectionsRoutes.get("/:id", async (c) => {
|
|
|
25317
25635
|
console.error("Error fetching collection:", error);
|
|
25318
25636
|
const user = c.get("user");
|
|
25319
25637
|
const [tinymceActive, quillActive, mdxeditorActive] = await Promise.all([
|
|
25320
|
-
|
|
25321
|
-
|
|
25322
|
-
|
|
25638
|
+
chunkE7E3NL3Y_cjs.isPluginActive(db, "tinymce-plugin"),
|
|
25639
|
+
chunkE7E3NL3Y_cjs.isPluginActive(db, "quill-editor"),
|
|
25640
|
+
chunkE7E3NL3Y_cjs.isPluginActive(db, "easy-mdx")
|
|
25323
25641
|
]);
|
|
25324
25642
|
const formData = {
|
|
25325
25643
|
isEdit: true,
|
|
@@ -25333,7 +25651,7 @@ adminCollectionsRoutes.get("/:id", async (c) => {
|
|
|
25333
25651
|
});
|
|
25334
25652
|
|
|
25335
25653
|
// src/templates/pages/admin-settings.template.ts
|
|
25336
|
-
|
|
25654
|
+
chunkMI2YXCK4_cjs.init_admin_layout_catalyst_template();
|
|
25337
25655
|
function renderSettingsPage(data) {
|
|
25338
25656
|
const activeTab = data.activeTab || "general";
|
|
25339
25657
|
const pageContent = `
|
|
@@ -25723,7 +26041,7 @@ function renderSettingsPage(data) {
|
|
|
25723
26041
|
version: data.version,
|
|
25724
26042
|
content: pageContent
|
|
25725
26043
|
};
|
|
25726
|
-
return
|
|
26044
|
+
return chunkMI2YXCK4_cjs.renderAdminLayoutCatalyst(layoutData);
|
|
25727
26045
|
}
|
|
25728
26046
|
function renderTabButton(tabId, label, iconPath, activeTab) {
|
|
25729
26047
|
const isActive = activeTab === tabId;
|
|
@@ -26268,7 +26586,7 @@ function renderDatabaseToolsSettings(settings) {
|
|
|
26268
26586
|
|
|
26269
26587
|
// src/routes/admin-settings.ts
|
|
26270
26588
|
var adminSettingsRoutes = new hono.Hono();
|
|
26271
|
-
adminSettingsRoutes.use("*",
|
|
26589
|
+
adminSettingsRoutes.use("*", chunkE7E3NL3Y_cjs.requireAuth());
|
|
26272
26590
|
function getMockSettings(user) {
|
|
26273
26591
|
return {
|
|
26274
26592
|
general: {
|
|
@@ -26371,7 +26689,7 @@ adminSettingsRoutes.get("/database-tools", (c) => {
|
|
|
26371
26689
|
adminSettingsRoutes.get("/api/migrations/status", async (c) => {
|
|
26372
26690
|
try {
|
|
26373
26691
|
const db = c.env.DB;
|
|
26374
|
-
const migrationService = new
|
|
26692
|
+
const migrationService = new chunkMOGK3U4A_cjs.MigrationService(db);
|
|
26375
26693
|
const status = await migrationService.getMigrationStatus();
|
|
26376
26694
|
return c.json({
|
|
26377
26695
|
success: true,
|
|
@@ -26411,7 +26729,7 @@ adminSettingsRoutes.post("/api/migrations/run", async (c) => {
|
|
|
26411
26729
|
adminSettingsRoutes.get("/api/migrations/validate", async (c) => {
|
|
26412
26730
|
try {
|
|
26413
26731
|
const db = c.env.DB;
|
|
26414
|
-
const migrationService = new
|
|
26732
|
+
const migrationService = new chunkMOGK3U4A_cjs.MigrationService(db);
|
|
26415
26733
|
const validation = await migrationService.validateSchema();
|
|
26416
26734
|
return c.json({
|
|
26417
26735
|
success: true,
|
|
@@ -26669,7 +26987,7 @@ adminSettingsRoutes.post("/", async (c) => {
|
|
|
26669
26987
|
});
|
|
26670
26988
|
|
|
26671
26989
|
// src/templates/pages/admin-api-reference.template.ts
|
|
26672
|
-
|
|
26990
|
+
chunkMI2YXCK4_cjs.init_admin_layout_catalyst_template();
|
|
26673
26991
|
function renderAuthBadge(auth) {
|
|
26674
26992
|
if (auth === true) {
|
|
26675
26993
|
return `
|
|
@@ -27000,20 +27318,20 @@ function renderAPIReferencePage(data) {
|
|
|
27000
27318
|
version: data.version,
|
|
27001
27319
|
content: pageContent
|
|
27002
27320
|
};
|
|
27003
|
-
return
|
|
27321
|
+
return chunkMI2YXCK4_cjs.renderAdminLayoutCatalyst(layoutData);
|
|
27004
27322
|
}
|
|
27005
27323
|
|
|
27006
27324
|
// src/routes/admin-api-reference.ts
|
|
27007
|
-
var VERSION2 =
|
|
27325
|
+
var VERSION2 = chunkBJ6NJL2E_cjs.getCoreVersion();
|
|
27008
27326
|
var router2 = new hono.Hono();
|
|
27009
|
-
router2.use("*",
|
|
27327
|
+
router2.use("*", chunkE7E3NL3Y_cjs.requireAuth());
|
|
27010
27328
|
router2.get("/", async (c) => {
|
|
27011
27329
|
const user = c.get("user");
|
|
27012
27330
|
try {
|
|
27013
27331
|
const app2 = chunk36Z3AKX3_cjs.getAppInstance();
|
|
27014
27332
|
const baseEndpoints = chunk36Z3AKX3_cjs.buildRouteList(app2);
|
|
27015
27333
|
const collectionRoutes = [];
|
|
27016
|
-
const collections =
|
|
27334
|
+
const collections = chunkYAURVGUK_cjs.getCollectionRegistry().listActive().filter((r) => !r.internal);
|
|
27017
27335
|
const methodOrder = { GET: 0, POST: 1, PUT: 2, PATCH: 3, DELETE: 4 };
|
|
27018
27336
|
for (const col of collections) {
|
|
27019
27337
|
const displayName = col.displayName || col.name;
|
|
@@ -27110,8 +27428,10 @@ exports.createUserProfilesPlugin = createUserProfilesPlugin;
|
|
|
27110
27428
|
exports.defineUserProfile = defineUserProfile;
|
|
27111
27429
|
exports.denyIfNotAllowed = denyIfNotAllowed;
|
|
27112
27430
|
exports.dispatchHookEvent = dispatchHookEvent;
|
|
27431
|
+
exports.effectiveTenantForType = effectiveTenantForType;
|
|
27113
27432
|
exports.getConfirmationDialogScript = getConfirmationDialogScript2;
|
|
27114
27433
|
exports.getCustomData = getCustomData;
|
|
27434
|
+
exports.getDocumentRequestContext = getDocumentRequestContext;
|
|
27115
27435
|
exports.getEmailService = getEmailService;
|
|
27116
27436
|
exports.getUserProfileConfig = getUserProfileConfig;
|
|
27117
27437
|
exports.getVariablesCached = getVariablesCached;
|
|
@@ -27129,7 +27449,8 @@ exports.router2 = router2;
|
|
|
27129
27449
|
exports.setEmailService = setEmailService;
|
|
27130
27450
|
exports.setVariablesCache = setVariablesCache;
|
|
27131
27451
|
exports.test_cleanup_default = test_cleanup_default;
|
|
27452
|
+
exports.updateDocumentSchema = updateDocumentSchema;
|
|
27132
27453
|
exports.userProfilesPlugin = userProfilesPlugin;
|
|
27133
27454
|
exports.userRoutes = userRoutes;
|
|
27134
|
-
//# sourceMappingURL=chunk-
|
|
27135
|
-
//# sourceMappingURL=chunk-
|
|
27455
|
+
//# sourceMappingURL=chunk-6OA77UM7.cjs.map
|
|
27456
|
+
//# sourceMappingURL=chunk-6OA77UM7.cjs.map
|