@sonicjs-cms/core 2.3.17 → 2.5.0
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/dist/{chunk-CPXAVWCU.js → chunk-3YUHXWSG.js} +278 -3
- package/dist/chunk-3YUHXWSG.js.map +1 -0
- package/dist/chunk-AI2JJIJX.cjs +211 -0
- package/dist/chunk-AI2JJIJX.cjs.map +1 -0
- package/dist/{chunk-TMQOLXLY.js → chunk-BHNDALCA.js} +56 -4
- package/dist/chunk-BHNDALCA.js.map +1 -0
- package/dist/{chunk-IEWLOVP3.cjs → chunk-I4V3VZWF.cjs} +46 -2
- package/dist/chunk-I4V3VZWF.cjs.map +1 -0
- package/dist/{chunk-DTLB6UIH.cjs → chunk-LWG2MWDA.cjs} +280 -2
- package/dist/chunk-LWG2MWDA.cjs.map +1 -0
- package/dist/{chunk-QBWD6FKH.js → chunk-OJZ45OJD.js} +559 -281
- package/dist/chunk-OJZ45OJD.js.map +1 -0
- package/dist/chunk-QDBNW7KQ.js +209 -0
- package/dist/chunk-QDBNW7KQ.js.map +1 -0
- package/dist/{chunk-VYL6RIV6.js → chunk-TJTWRO4G.js} +5 -5
- package/dist/chunk-TJTWRO4G.js.map +1 -0
- package/dist/{chunk-74DP754U.cjs → chunk-UAQL2VWX.cjs} +644 -366
- package/dist/chunk-UAQL2VWX.cjs.map +1 -0
- package/dist/{chunk-B6YJRVFQ.js → chunk-VEL7QRYI.js} +46 -2
- package/dist/chunk-VEL7QRYI.js.map +1 -0
- package/dist/{chunk-YHJB26RJ.cjs → chunk-YYV3XQOQ.cjs} +6 -6
- package/dist/chunk-YYV3XQOQ.cjs.map +1 -0
- package/dist/{chunk-2XCJ3HT5.cjs → chunk-ZWV3EBZ7.cjs} +58 -3
- package/dist/chunk-ZWV3EBZ7.cjs.map +1 -0
- package/dist/{collection-config-FLlGtsh9.d.cts → collection-config-B6gMPunn.d.cts} +9 -1
- package/dist/{collection-config-FLlGtsh9.d.ts → collection-config-B6gMPunn.d.ts} +9 -1
- package/dist/index.cjs +114 -85
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +4 -4
- package/dist/index.d.ts +4 -4
- package/dist/index.js +37 -8
- package/dist/index.js.map +1 -1
- package/dist/middleware.cjs +23 -23
- package/dist/middleware.js +2 -2
- package/dist/migrations-NIEUFG44.cjs +13 -0
- package/dist/{migrations-EOV7NJZ7.cjs.map → migrations-NIEUFG44.cjs.map} +1 -1
- package/dist/migrations-TGZKJKV4.js +4 -0
- package/dist/{migrations-6HKPNPTK.js.map → migrations-TGZKJKV4.js.map} +1 -1
- package/dist/{plugin-bootstrap-C0E3jdz-.d.cts → plugin-bootstrap-SHsdjE6X.d.cts} +1 -1
- package/dist/{plugin-bootstrap-CDh0JHtW.d.ts → plugin-bootstrap-dYhD9fQR.d.ts} +1 -1
- package/dist/plugin-manager-Baa6xXqB.d.ts +328 -0
- package/dist/plugin-manager-vBal9Zip.d.cts +328 -0
- package/dist/plugins.cjs +20 -7
- package/dist/plugins.d.cts +53 -310
- package/dist/plugins.d.ts +53 -310
- package/dist/plugins.js +2 -1
- package/dist/routes.cjs +25 -24
- package/dist/routes.js +5 -4
- package/dist/services.cjs +2 -2
- package/dist/services.d.cts +2 -2
- package/dist/services.d.ts +2 -2
- package/dist/services.js +1 -1
- package/dist/types.d.cts +1 -1
- package/dist/types.d.ts +1 -1
- package/dist/utils.cjs +23 -11
- package/dist/utils.d.cts +38 -1
- package/dist/utils.d.ts +38 -1
- package/dist/utils.js +1 -1
- package/migrations/027_fix_slug_field_type.sql +18 -0
- package/migrations/028_fix_slug_field_type_in_schemas.sql +30 -0
- package/package.json +2 -1
- package/dist/chunk-2XCJ3HT5.cjs.map +0 -1
- package/dist/chunk-74DP754U.cjs.map +0 -1
- package/dist/chunk-B6YJRVFQ.js.map +0 -1
- package/dist/chunk-CPXAVWCU.js.map +0 -1
- package/dist/chunk-DTLB6UIH.cjs.map +0 -1
- package/dist/chunk-IEWLOVP3.cjs.map +0 -1
- package/dist/chunk-QBWD6FKH.js.map +0 -1
- package/dist/chunk-TMQOLXLY.js.map +0 -1
- package/dist/chunk-VYL6RIV6.js.map +0 -1
- package/dist/chunk-YHJB26RJ.cjs.map +0 -1
- package/dist/migrations-6HKPNPTK.js +0 -4
- package/dist/migrations-EOV7NJZ7.cjs +0 -13
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var chunk7FOAMNTI_cjs = require('./chunk-7FOAMNTI.cjs');
|
|
4
|
-
var
|
|
4
|
+
var chunkYYV3XQOQ_cjs = require('./chunk-YYV3XQOQ.cjs');
|
|
5
5
|
var chunkILZ3DP4I_cjs = require('./chunk-ILZ3DP4I.cjs');
|
|
6
|
-
var
|
|
6
|
+
var chunkI4V3VZWF_cjs = require('./chunk-I4V3VZWF.cjs');
|
|
7
7
|
var chunkAZLU3ROK_cjs = require('./chunk-AZLU3ROK.cjs');
|
|
8
|
-
var
|
|
8
|
+
var chunkAI2JJIJX_cjs = require('./chunk-AI2JJIJX.cjs');
|
|
9
|
+
var chunkZWV3EBZ7_cjs = require('./chunk-ZWV3EBZ7.cjs');
|
|
9
10
|
var chunkRCQ2HIQD_cjs = require('./chunk-RCQ2HIQD.cjs');
|
|
10
11
|
var hono = require('hono');
|
|
11
12
|
var cors = require('hono/cors');
|
|
@@ -16,6 +17,37 @@ var html = require('hono/html');
|
|
|
16
17
|
// src/schemas/index.ts
|
|
17
18
|
var schemaDefinitions = [];
|
|
18
19
|
var apiContentCrudRoutes = new hono.Hono();
|
|
20
|
+
apiContentCrudRoutes.get("/check-slug", async (c) => {
|
|
21
|
+
try {
|
|
22
|
+
const db = c.env.DB;
|
|
23
|
+
const collectionId = c.req.query("collectionId");
|
|
24
|
+
const slug = c.req.query("slug");
|
|
25
|
+
const excludeId = c.req.query("excludeId");
|
|
26
|
+
if (!collectionId || !slug) {
|
|
27
|
+
return c.json({ error: "collectionId and slug are required" }, 400);
|
|
28
|
+
}
|
|
29
|
+
let query = "SELECT id FROM content WHERE collection_id = ? AND slug = ?";
|
|
30
|
+
const params = [collectionId, slug];
|
|
31
|
+
if (excludeId) {
|
|
32
|
+
query += " AND id != ?";
|
|
33
|
+
params.push(excludeId);
|
|
34
|
+
}
|
|
35
|
+
const existing = await db.prepare(query).bind(...params).first();
|
|
36
|
+
if (existing) {
|
|
37
|
+
return c.json({
|
|
38
|
+
available: false,
|
|
39
|
+
message: "This URL slug is already in use in this collection"
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
return c.json({ available: true });
|
|
43
|
+
} catch (error) {
|
|
44
|
+
console.error("Error checking slug:", error);
|
|
45
|
+
return c.json({
|
|
46
|
+
error: "Failed to check slug availability",
|
|
47
|
+
details: error instanceof Error ? error.message : String(error)
|
|
48
|
+
}, 500);
|
|
49
|
+
}
|
|
50
|
+
});
|
|
19
51
|
apiContentCrudRoutes.get("/:id", async (c) => {
|
|
20
52
|
try {
|
|
21
53
|
const id = c.req.param("id");
|
|
@@ -44,7 +76,7 @@ apiContentCrudRoutes.get("/:id", async (c) => {
|
|
|
44
76
|
}, 500);
|
|
45
77
|
}
|
|
46
78
|
});
|
|
47
|
-
apiContentCrudRoutes.post("/",
|
|
79
|
+
apiContentCrudRoutes.post("/", chunkYYV3XQOQ_cjs.requireAuth(), async (c) => {
|
|
48
80
|
try {
|
|
49
81
|
const db = c.env.DB;
|
|
50
82
|
const user = c.get("user");
|
|
@@ -110,7 +142,7 @@ apiContentCrudRoutes.post("/", chunkYHJB26RJ_cjs.requireAuth(), async (c) => {
|
|
|
110
142
|
}, 500);
|
|
111
143
|
}
|
|
112
144
|
});
|
|
113
|
-
apiContentCrudRoutes.put("/:id",
|
|
145
|
+
apiContentCrudRoutes.put("/:id", chunkYYV3XQOQ_cjs.requireAuth(), async (c) => {
|
|
114
146
|
try {
|
|
115
147
|
const id = c.req.param("id");
|
|
116
148
|
const db = c.env.DB;
|
|
@@ -174,7 +206,7 @@ apiContentCrudRoutes.put("/:id", chunkYHJB26RJ_cjs.requireAuth(), async (c) => {
|
|
|
174
206
|
}, 500);
|
|
175
207
|
}
|
|
176
208
|
});
|
|
177
|
-
apiContentCrudRoutes.delete("/:id",
|
|
209
|
+
apiContentCrudRoutes.delete("/:id", chunkYYV3XQOQ_cjs.requireAuth(), async (c) => {
|
|
178
210
|
try {
|
|
179
211
|
const id = c.req.param("id");
|
|
180
212
|
const db = c.env.DB;
|
|
@@ -210,7 +242,7 @@ apiRoutes.use("*", async (c, next) => {
|
|
|
210
242
|
c.header("X-Response-Time", `${totalTime}ms`);
|
|
211
243
|
});
|
|
212
244
|
apiRoutes.use("*", async (c, next) => {
|
|
213
|
-
const cacheEnabled = await
|
|
245
|
+
const cacheEnabled = await chunkYYV3XQOQ_cjs.isPluginActive(c.env.DB, "core-cache");
|
|
214
246
|
c.set("cacheEnabled", cacheEnabled);
|
|
215
247
|
await next();
|
|
216
248
|
});
|
|
@@ -335,12 +367,12 @@ apiRoutes.get("/content", async (c) => {
|
|
|
335
367
|
});
|
|
336
368
|
}
|
|
337
369
|
}
|
|
338
|
-
const filter =
|
|
370
|
+
const filter = chunkZWV3EBZ7_cjs.QueryFilterBuilder.parseFromQuery(queryParams);
|
|
339
371
|
if (!filter.limit) {
|
|
340
372
|
filter.limit = 50;
|
|
341
373
|
}
|
|
342
374
|
filter.limit = Math.min(filter.limit, 1e3);
|
|
343
|
-
const builder3 = new
|
|
375
|
+
const builder3 = new chunkZWV3EBZ7_cjs.QueryFilterBuilder();
|
|
344
376
|
const queryResult = builder3.build("content", filter);
|
|
345
377
|
if (queryResult.errors.length > 0) {
|
|
346
378
|
return c.json({
|
|
@@ -427,7 +459,7 @@ apiRoutes.get("/collections/:collection/content", async (c) => {
|
|
|
427
459
|
if (!collectionResult) {
|
|
428
460
|
return c.json({ error: "Collection not found" }, 404);
|
|
429
461
|
}
|
|
430
|
-
const filter =
|
|
462
|
+
const filter = chunkZWV3EBZ7_cjs.QueryFilterBuilder.parseFromQuery(queryParams);
|
|
431
463
|
if (!filter.where) {
|
|
432
464
|
filter.where = { and: [] };
|
|
433
465
|
}
|
|
@@ -443,7 +475,7 @@ apiRoutes.get("/collections/:collection/content", async (c) => {
|
|
|
443
475
|
filter.limit = 50;
|
|
444
476
|
}
|
|
445
477
|
filter.limit = Math.min(filter.limit, 1e3);
|
|
446
|
-
const builder3 = new
|
|
478
|
+
const builder3 = new chunkZWV3EBZ7_cjs.QueryFilterBuilder();
|
|
447
479
|
const queryResult = builder3.build("content", filter);
|
|
448
480
|
if (queryResult.errors.length > 0) {
|
|
449
481
|
return c.json({
|
|
@@ -568,7 +600,7 @@ var fileValidationSchema = zod.z.object({
|
|
|
568
600
|
// 50MB max
|
|
569
601
|
});
|
|
570
602
|
var apiMediaRoutes = new hono.Hono();
|
|
571
|
-
apiMediaRoutes.use("*",
|
|
603
|
+
apiMediaRoutes.use("*", chunkYYV3XQOQ_cjs.requireAuth());
|
|
572
604
|
apiMediaRoutes.post("/upload", async (c) => {
|
|
573
605
|
try {
|
|
574
606
|
const user = c.get("user");
|
|
@@ -1312,8 +1344,8 @@ apiSystemRoutes.get("/env", (c) => {
|
|
|
1312
1344
|
});
|
|
1313
1345
|
var api_system_default = apiSystemRoutes;
|
|
1314
1346
|
var adminApiRoutes = new hono.Hono();
|
|
1315
|
-
adminApiRoutes.use("*",
|
|
1316
|
-
adminApiRoutes.use("*",
|
|
1347
|
+
adminApiRoutes.use("*", chunkYYV3XQOQ_cjs.requireAuth());
|
|
1348
|
+
adminApiRoutes.use("*", chunkYYV3XQOQ_cjs.requireRole(["admin", "editor"]));
|
|
1317
1349
|
adminApiRoutes.get("/stats", async (c) => {
|
|
1318
1350
|
try {
|
|
1319
1351
|
const db = c.env.DB;
|
|
@@ -1722,7 +1754,7 @@ adminApiRoutes.delete("/collections/:id", async (c) => {
|
|
|
1722
1754
|
});
|
|
1723
1755
|
adminApiRoutes.get("/migrations/status", async (c) => {
|
|
1724
1756
|
try {
|
|
1725
|
-
const { MigrationService: MigrationService2 } = await import('./migrations-
|
|
1757
|
+
const { MigrationService: MigrationService2 } = await import('./migrations-NIEUFG44.cjs');
|
|
1726
1758
|
const db = c.env.DB;
|
|
1727
1759
|
const migrationService = new MigrationService2(db);
|
|
1728
1760
|
const status = await migrationService.getMigrationStatus();
|
|
@@ -1747,7 +1779,7 @@ adminApiRoutes.post("/migrations/run", async (c) => {
|
|
|
1747
1779
|
error: "Unauthorized. Admin access required."
|
|
1748
1780
|
}, 403);
|
|
1749
1781
|
}
|
|
1750
|
-
const { MigrationService: MigrationService2 } = await import('./migrations-
|
|
1782
|
+
const { MigrationService: MigrationService2 } = await import('./migrations-NIEUFG44.cjs');
|
|
1751
1783
|
const db = c.env.DB;
|
|
1752
1784
|
const migrationService = new MigrationService2(db);
|
|
1753
1785
|
const result = await migrationService.runPendingMigrations();
|
|
@@ -1766,7 +1798,7 @@ adminApiRoutes.post("/migrations/run", async (c) => {
|
|
|
1766
1798
|
});
|
|
1767
1799
|
adminApiRoutes.get("/migrations/validate", async (c) => {
|
|
1768
1800
|
try {
|
|
1769
|
-
const { MigrationService: MigrationService2 } = await import('./migrations-
|
|
1801
|
+
const { MigrationService: MigrationService2 } = await import('./migrations-NIEUFG44.cjs');
|
|
1770
1802
|
const db = c.env.DB;
|
|
1771
1803
|
const migrationService = new MigrationService2(db);
|
|
1772
1804
|
const validation = await migrationService.validateSchema();
|
|
@@ -1993,18 +2025,40 @@ function renderRegisterPage(data) {
|
|
|
1993
2025
|
<div class="flex min-h-full flex-col justify-center py-12 sm:px-6 lg:px-8">
|
|
1994
2026
|
<!-- Logo Section -->
|
|
1995
2027
|
<div class="sm:mx-auto sm:w-full sm:max-w-md text-center">
|
|
1996
|
-
<div class="mx-auto
|
|
1997
|
-
<svg class="
|
|
1998
|
-
<path
|
|
2028
|
+
<div class="mx-auto w-64 mb-8">
|
|
2029
|
+
<svg class="w-full h-auto" viewBox="380 1300 2250 400" aria-hidden="true">
|
|
2030
|
+
<path fill="#F1F2F2" d="M476.851,1404.673h168.536c4.714,0,8.695-1.618,11.944-4.866c3.241-3.241,4.866-7.222,4.866-11.943 c0-2.357-0.443-4.569-1.327-6.636c-0.885-2.06-2.067-3.829-3.539-5.308c-1.479-1.472-3.249-2.654-5.308-3.538 c-2.067-0.885-4.279-1.327-6.635-1.327H476.851c-20.057,0-37.158,7.154-51.313,21.454c-14.155,14.308-21.233,31.483-21.233,51.534 c0,20.058,7.078,37.234,21.233,51.534c14.155,14.308,31.255,21.454,51.313,21.454h112.357c10.907,0,20.196,3.837,27.868,11.502 c7.666,7.672,11.502,16.885,11.502,27.646c0,10.769-3.836,19.982-11.502,27.647c-7.672,7.673-16.961,11.502-27.868,11.502H421.115 c-4.721,0-8.702,1.624-11.944,4.865c-3.248,3.249-4.866,7.23-4.866,11.944c0,3.248,0.733,6.123,2.212,8.626 c1.472,2.509,3.462,4.499,5.971,5.972c2.502,1.472,5.378,2.212,8.626,2.212h168.094c20.052,0,37.227-7.078,51.534-21.234 c14.3-14.155,21.454-31.331,21.454-51.534c0-20.196-7.154-37.379-21.454-51.534c-14.308-14.156-31.483-21.234-51.534-21.234 H476.851c-10.616,0-19.76-3.905-27.426-11.721c-7.672-7.811-11.501-17.101-11.501-27.87c0-10.761,3.829-19.975,11.501-27.647 C457.091,1408.508,466.235,1404.673,476.851,1404.673z"></path>
|
|
2031
|
+
<path fill="#F1F2F2" d="M974.78,1398.211c-5.016,6.574-10.034,13.146-15.048,19.721c-1.828,2.398-3.657,4.796-5.487,7.194 c1.994,1.719,3.958,3.51,5.873,5.424c18.724,18.731,28.089,41.216,28.089,67.459c0,26.251-9.366,48.658-28.089,67.237 c-18.731,18.579-41.215,27.868-67.459,27.868c-9.848,0-19.156-1.308-27.923-3.923l-4.185,3.354 c-8.587,6.885-17.154,13.796-25.725,20.702c17.52,8.967,36.86,13.487,58.054,13.487c35.533,0,65.91-12.608,91.124-37.821 c25.214-25.215,37.821-55.584,37.821-91.125c0-35.534-12.607-65.911-37.821-91.126 C981.004,1403.663,977.926,1400.854,974.78,1398.211z"></path>
|
|
2032
|
+
<path fill="#F1F2F2" d="M1364.644,1439.619c-4.72,0-8.702,1.624-11.943,4.865c-3.249,3.249-4.866,7.23-4.866,11.944v138.014 l-167.651-211.003c-0.297-0.586-0.74-1.03-1.327-1.326c-4.721-4.714-10.249-7.742-16.588-9.069 c-6.346-1.326-12.608-0.732-18.801,1.77c-6.192,2.509-11.059,6.49-14.598,11.944c-3.539,5.46-5.308,11.577-5.308,18.357v208.348 c0,4.721,1.618,8.703,4.866,11.944c3.241,3.241,7.222,4.865,11.943,4.865c2.945,0,5.751-0.738,8.405-2.211 c2.654-1.472,4.713-3.463,6.193-5.971c1.473-2.503,2.212-5.378,2.212-8.627v-205.251l166.325,209.675 c2.06,2.654,4.423,4.865,7.078,6.635c5.308,3.829,11.349,5.75,18.137,5.75c5.308,0,10.464-1.182,15.482-3.538 c3.539-1.769,6.56-4.127,9.069-7.078c2.502-2.945,4.491-6.338,5.971-10.175c1.473-3.829,2.212-7.664,2.212-11.501v-141.552 c0-4.714-1.624-8.695-4.865-11.944C1373.339,1441.243,1369.359,1439.619,1364.644,1439.619z"></path>
|
|
2033
|
+
<path fill="#F1F2F2" d="M1508.406,1432.983c-2.654-1.472-5.46-2.212-8.404-2.212c-4.721,0-8.703,1.7-11.944,5.087 c-3.249,3.395-4.865,7.3-4.865,11.723v163.228c0,4.721,1.616,8.702,4.865,11.943c3.241,3.249,7.223,4.866,11.944,4.866 c2.944,0,5.751-0.732,8.404-2.212c2.655-1.472,4.714-3.539,6.193-6.194c1.473-2.654,2.213-5.453,2.213-8.404V1447.58 c0-2.945-0.74-5.75-2.213-8.405C1513.12,1436.522,1511.06,1434.462,1508.406,1432.983z"></path>
|
|
2034
|
+
<path fill="#F1F2F2" d="M1499.78,1367.957c-4.575,0-8.481,1.625-11.722,4.866c-3.249,3.249-4.865,7.23-4.865,11.943 c0,2.951,0.732,5.75,2.212,8.405c1.472,2.654,3.463,4.721,5.971,6.193c2.503,1.479,5.378,2.212,8.627,2.212 c4.423,0,8.328-1.618,11.721-4.865c3.387-3.243,5.088-7.224,5.088-11.944c0-4.713-1.701-8.694-5.088-11.943 C1508.33,1369.582,1504.349,1367.957,1499.78,1367.957z"></path>
|
|
2035
|
+
<path fill="#F1F2F2" d="M1859.627,1369.727H1747.27c-35.388,0-65.69,12.607-90.904,37.821 c-25.213,25.215-37.82,55.591-37.82,91.125c0,35.54,12.607,65.911,37.82,91.125c25.215,25.215,55.516,37.821,90.904,37.821h56.178 c4.714,0,8.695-1.618,11.944-4.866c3.241-3.241,4.865-7.222,4.865-11.943c0-4.714-1.624-8.695-4.865-11.943 c-3.249-3.243-7.23-4.866-11.944-4.866h-56.178c-26.251,0-48.659-9.359-67.237-28.09c-18.579-18.723-27.868-41.207-27.868-67.459 c0-26.243,9.29-48.659,27.868-67.237c18.579-18.579,40.987-27.868,67.237-27.868h112.357c4.714,0,8.696-1.693,11.944-5.087 c3.241-3.387,4.865-7.368,4.865-11.943c0-4.569-1.624-8.475-4.865-11.723C1868.322,1371.351,1864.341,1369.727,1859.627,1369.727z "></path>
|
|
2036
|
+
<path fill="#06b6d4" d="M2219.256,1371.054h-112.357c-4.423,0-8.336,1.624-11.723,4.865c-3.393,3.249-5.087,7.23-5.087,11.944 c0,4.721,1.694,8.702,5.087,11.943c3.387,3.249,7.3,4.866,11.723,4.866h95.547v95.105c0,26.251-9.365,48.659-28.088,67.237 c-18.731,18.579-41.215,27.868-67.459,27.868c-26.251,0-48.659-9.289-67.237-27.868c-18.579-18.579-27.868-40.987-27.868-67.237 c0-4.713-1.701-8.771-5.088-12.165c-3.393-3.387-7.374-5.087-11.943-5.087c-4.575,0-8.481,1.7-11.722,5.087 c-3.249,3.393-4.865,7.451-4.865,12.165c0,35.388,12.607,65.69,37.82,90.904c25.215,25.213,55.584,37.82,91.126,37.82 c35.532,0,65.91-12.607,91.125-37.82c25.214-25.215,37.82-55.516,37.82-90.904v-111.915c0-4.714-1.624-8.695-4.865-11.944 C2227.951,1372.678,2223.971,1371.054,2219.256,1371.054z"></path>
|
|
2037
|
+
<path fill="#06b6d4" d="M2574.24,1502.875c-14.306-14.156-31.483-21.234-51.533-21.234H2410.35 c-10.617,0-19.762-3.829-27.426-11.501c-7.672-7.664-11.501-16.954-11.501-27.868c0-10.907,3.829-20.196,11.501-27.868 c7.664-7.664,16.809-11.501,27.426-11.501h112.357c4.714,0,8.695-1.617,11.944-4.866c3.241-3.241,4.865-7.222,4.865-11.943 c0-4.714-1.624-8.695-4.865-11.944c-3.249-3.241-7.23-4.865-11.944-4.865H2410.35c-20.058,0-37.158,7.154-51.313,21.454 c-14.156,14.308-21.232,31.483-21.232,51.534c0,20.058,7.077,37.234,21.232,51.534c14.156,14.308,31.255,21.454,51.313,21.454 h112.357c7.078,0,13.637,1.77,19.684,5.308c6.042,3.539,10.838,8.336,14.377,14.377c3.538,6.047,5.307,12.607,5.307,19.685 c0,10.616-3.835,19.76-11.501,27.425c-7.672,7.673-16.961,11.502-27.868,11.502h-168.094c-4.721,0-8.703,1.7-11.944,5.087 c-3.249,3.393-4.865,7.374-4.865,11.943c0,4.576,1.616,8.481,4.865,11.723c3.241,3.249,7.223,4.866,11.944,4.866h168.094 c20.051,0,37.227-7.078,51.533-21.234c14.302-14.155,21.454-31.331,21.454-51.534 C2595.695,1534.213,2588.542,1517.03,2574.24,1502.875z"></path>
|
|
2038
|
+
<path fill="#06b6d4" d="M854.024,1585.195l20.001-16.028c16.616-13.507,33.04-27.265,50.086-40.251 c1.13-0.861,2.9-1.686,2.003-3.516c-0.843-1.716-2.481-2.302-4.484-2.123c-8.514,0.765-17.016-0.538-25.537-0.353 c-1.124,0.024-2.768,0.221-3.163-1.25c-0.371-1.369,1.088-2.063,1.919-2.894c6.26-6.242,12.574-12.43,18.816-18.691 c9.303-9.327,18.565-18.714,27.851-28.066c1.848-1.859,3.701-3.713,5.549-5.572c2.655-2.661,5.309-5.315,7.958-7.982 c0.574-0.579,1.259-1.141,1.246-1.94c-0.004-0.257-0.078-0.538-0.254-0.853c-0.556-0.981-1.441-1.1-2.469-0.957 c-0.658,0.096-1.315,0.185-1.973,0.275c-3.844,0.538-7.689,1.076-11.533,1.608c-3.641,0.505-7.281,1.02-10.922,1.529 c-4.162,0.582-8.324,1.158-12.486,1.748c-1.142,0.161-2.409,1.662-3.354,0.508c-0.419-0.508-0.431-1.028-0.251-1.531 c0.269-0.741,0.957-1.441,1.387-2.021c3.414-4.58,6.882-9.124,10.356-13.662c1.74-2.272,3.48-4.544,5.214-6.822 c4.682-6.141,9.369-12.281,14.051-18.422c0.09-0.119,0.181-0.237,0.271-0.355c6.848-8.98,13.7-17.958,20.553-26.936 c0.488-0.64,0.977-1.28,1.465-1.92c2.159-2.828,4.315-5.658,6.476-8.486c4.197-5.501,8.454-10.954,12.67-16.442 c0.263-0.347,0.538-0.718,0.717-1.106c0.269-0.586,0.299-1.196-0.335-1.776c-0.825-0.753-1.8-0.15-2.595,0.419 c-0.67,0.472-1.333,0.957-1.955,1.489c-2.206,1.889-4.401,3.797-6.595,5.698c-3.958,3.438-7.922,6.876-11.976,10.194 c-2.443,2.003-4.865,4.028-7.301,6.038c-18.689-10.581-39.53-15.906-62.549-15.906c-35.54,0-65.911,12.607-91.125,37.82 c-25.214,25.215-37.821,55.592-37.821,91.126c0,35.54,12.607,65.91,37.821,91.125c4.146,4.146,8.445,7.916,12.87,11.381 c-9.015,11.14-18.036,22.277-27.034,33.429c-1.208,1.489-3.755,3.151-2.745,4.891c0.078,0.144,0.173,0.281,0.305,0.425 c1.321,1.429,3.492-1.303,4.933-2.457c6.673-5.333,13.333-10.685,19.982-16.042c3.707-2.984,7.417-5.965,11.124-8.952 c1.474-1.188,2.951-2.373,4.425-3.561c6.41-5.164,12.816-10.333,19.238-15.481L854.024,1585.195z M797.552,1498.009 c0-26.243,9.29-48.728,27.868-67.459c18.579-18.723,40.987-28.089,67.238-28.089c12.273,0,23.712,2.075,34.34,6.171 c-3.37,2.905-6.734,5.816-10.069,8.762c-6.075,5.351-12.365,10.469-18.667,15.564c-4.179,3.378-8.371,6.744-12.514,10.164 c-7.54,6.23-15.037,12.52-22.529,18.804c-7.091,5.955-14.182,11.904-21.19,17.949c-1.136,0.974-3.055,1.907-2.135,3.94 c0.831,1.836,2.774,1.417,4.341,1.578l12.145-0.599l14.151-0.698c1.031-0.102,2.192-0.257,2.89,0.632 c0.034,0.044,0.073,0.078,0.106,0.127c1.017,1.561-0.67,2.105-1.387,2.942c-6.308,7.318-12.616,14.637-18.978,21.907 c-8.161,9.339-16.353,18.649-24.544,27.958c-2.146,2.433-4.275,4.879-6.422,7.312c-1.034,1.172-2.129,2.272-1.238,3.922 c0.933,1.728,2.685,1.752,4.323,1.602c4.134-0.367,8.263-0.489,12.396-0.492c0.242,0,0.485-0.005,0.728-0.004 c2.711,0.009,5.422,0.068,8.134,0.145c2.582,0.074,5.166,0.165,7.752,0.249c0.275,1.62-0.879,2.356-1.62,3.259 c-1.333,1.626-2.667,3.247-4,4.867c-4.315,5.252-8.62,10.514-12.928,15.772c-3.562-2.725-7.007-5.733-10.324-9.051 C806.842,1546.667,797.552,1524.26,797.552,1498.009z"></path>
|
|
1999
2039
|
</svg>
|
|
2000
2040
|
</div>
|
|
2001
|
-
<
|
|
2002
|
-
|
|
2041
|
+
<h2 class="mt-6 text-xl font-medium text-white">${data.isSetup ? "Welcome to SonicJS" : "Create Account"}</h2>
|
|
2042
|
+
${data.isSetup ? `<p class="mt-2 text-sm text-zinc-400">Create your admin account to get started.</p>` : `<p class="mt-2 text-sm text-zinc-400">Create your account and get started</p>`}
|
|
2003
2043
|
</div>
|
|
2004
2044
|
|
|
2005
2045
|
<!-- Form Container -->
|
|
2006
2046
|
<div class="mt-8 sm:mx-auto sm:w-full sm:max-w-md">
|
|
2007
2047
|
<div class="bg-zinc-900 shadow-sm ring-1 ring-white/10 rounded-xl px-6 py-8 sm:px-10">
|
|
2048
|
+
<!-- Setup Banner -->
|
|
2049
|
+
${data.isSetup ? `
|
|
2050
|
+
<div class="mb-6 rounded-lg bg-blue-500/10 p-4 ring-1 ring-blue-500/20">
|
|
2051
|
+
<div class="flex items-start gap-x-3">
|
|
2052
|
+
<svg class="h-5 w-5 text-blue-400 shrink-0 mt-0.5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
2053
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"/>
|
|
2054
|
+
</svg>
|
|
2055
|
+
<div class="flex-1">
|
|
2056
|
+
<p class="text-sm font-medium text-blue-300">First-time Setup</p>
|
|
2057
|
+
<p class="text-sm text-blue-400/80 mt-1">This account will be the administrator with full access to manage your SonicJS installation.</p>
|
|
2058
|
+
</div>
|
|
2059
|
+
</div>
|
|
2060
|
+
</div>
|
|
2061
|
+
` : ""}
|
|
2008
2062
|
<!-- Alerts -->
|
|
2009
2063
|
${data.error ? `<div class="mb-6">${chunkAZLU3ROK_cjs.renderAlert({ type: "error", message: data.error })}</div>` : ""}
|
|
2010
2064
|
|
|
@@ -2119,6 +2173,7 @@ function renderRegisterPage(data) {
|
|
|
2119
2173
|
</html>
|
|
2120
2174
|
`;
|
|
2121
2175
|
}
|
|
2176
|
+
var adminExistsCache = null;
|
|
2122
2177
|
async function isRegistrationEnabled(db) {
|
|
2123
2178
|
try {
|
|
2124
2179
|
const plugin = await db.prepare("SELECT settings FROM plugins WHERE id = ?").bind("core-auth").first();
|
|
@@ -2140,6 +2195,21 @@ async function isFirstUserRegistration(db) {
|
|
|
2140
2195
|
return false;
|
|
2141
2196
|
}
|
|
2142
2197
|
}
|
|
2198
|
+
async function checkAdminUserExists(db) {
|
|
2199
|
+
if (adminExistsCache !== null) {
|
|
2200
|
+
return adminExistsCache;
|
|
2201
|
+
}
|
|
2202
|
+
try {
|
|
2203
|
+
const result = await db.prepare("SELECT id FROM users WHERE role = ?").bind("admin").first();
|
|
2204
|
+
adminExistsCache = !!result;
|
|
2205
|
+
return adminExistsCache;
|
|
2206
|
+
} catch {
|
|
2207
|
+
return false;
|
|
2208
|
+
}
|
|
2209
|
+
}
|
|
2210
|
+
function setAdminExists() {
|
|
2211
|
+
adminExistsCache = true;
|
|
2212
|
+
}
|
|
2143
2213
|
var baseRegistrationSchema = zod.z.object({
|
|
2144
2214
|
email: zod.z.string().email("Valid email is required"),
|
|
2145
2215
|
password: zod.z.string().min(8, "Password must be at least 8 characters"),
|
|
@@ -2201,8 +2271,11 @@ authRoutes.get("/register", async (c) => {
|
|
|
2201
2271
|
}
|
|
2202
2272
|
}
|
|
2203
2273
|
const error = c.req.query("error");
|
|
2274
|
+
const isSetup = c.req.query("setup") === "true";
|
|
2204
2275
|
const pageData = {
|
|
2205
|
-
error: error || void 0
|
|
2276
|
+
error: error || void 0,
|
|
2277
|
+
isSetup: isSetup && isFirstUser
|
|
2278
|
+
// Only show setup message if truly first user
|
|
2206
2279
|
};
|
|
2207
2280
|
return c.html(renderRegisterPage(pageData));
|
|
2208
2281
|
});
|
|
@@ -2248,7 +2321,7 @@ authRoutes.post(
|
|
|
2248
2321
|
if (existingUser) {
|
|
2249
2322
|
return c.json({ error: "User with this email or username already exists" }, 400);
|
|
2250
2323
|
}
|
|
2251
|
-
const passwordHash = await
|
|
2324
|
+
const passwordHash = await chunkYYV3XQOQ_cjs.AuthManager.hashPassword(password);
|
|
2252
2325
|
const userId = crypto.randomUUID();
|
|
2253
2326
|
const now = /* @__PURE__ */ new Date();
|
|
2254
2327
|
await db.prepare(`
|
|
@@ -2268,7 +2341,7 @@ authRoutes.post(
|
|
|
2268
2341
|
now.getTime(),
|
|
2269
2342
|
now.getTime()
|
|
2270
2343
|
).run();
|
|
2271
|
-
const token = await
|
|
2344
|
+
const token = await chunkYYV3XQOQ_cjs.AuthManager.generateToken(userId, normalizedEmail, "viewer");
|
|
2272
2345
|
cookie.setCookie(c, "auth_token", token, {
|
|
2273
2346
|
httpOnly: true,
|
|
2274
2347
|
secure: true,
|
|
@@ -2321,11 +2394,11 @@ authRoutes.post("/login", async (c) => {
|
|
|
2321
2394
|
if (!user) {
|
|
2322
2395
|
return c.json({ error: "Invalid email or password" }, 401);
|
|
2323
2396
|
}
|
|
2324
|
-
const isValidPassword = await
|
|
2397
|
+
const isValidPassword = await chunkYYV3XQOQ_cjs.AuthManager.verifyPassword(password, user.password_hash);
|
|
2325
2398
|
if (!isValidPassword) {
|
|
2326
2399
|
return c.json({ error: "Invalid email or password" }, 401);
|
|
2327
2400
|
}
|
|
2328
|
-
const token = await
|
|
2401
|
+
const token = await chunkYYV3XQOQ_cjs.AuthManager.generateToken(user.id, user.email, user.role);
|
|
2329
2402
|
cookie.setCookie(c, "auth_token", token, {
|
|
2330
2403
|
httpOnly: true,
|
|
2331
2404
|
secure: true,
|
|
@@ -2374,7 +2447,7 @@ authRoutes.get("/logout", (c) => {
|
|
|
2374
2447
|
});
|
|
2375
2448
|
return c.redirect("/auth/login?message=You have been logged out successfully");
|
|
2376
2449
|
});
|
|
2377
|
-
authRoutes.get("/me",
|
|
2450
|
+
authRoutes.get("/me", chunkYYV3XQOQ_cjs.requireAuth(), async (c) => {
|
|
2378
2451
|
try {
|
|
2379
2452
|
const user = c.get("user");
|
|
2380
2453
|
if (!user) {
|
|
@@ -2391,13 +2464,13 @@ authRoutes.get("/me", chunkYHJB26RJ_cjs.requireAuth(), async (c) => {
|
|
|
2391
2464
|
return c.json({ error: "Failed to get user" }, 500);
|
|
2392
2465
|
}
|
|
2393
2466
|
});
|
|
2394
|
-
authRoutes.post("/refresh",
|
|
2467
|
+
authRoutes.post("/refresh", chunkYYV3XQOQ_cjs.requireAuth(), async (c) => {
|
|
2395
2468
|
try {
|
|
2396
2469
|
const user = c.get("user");
|
|
2397
2470
|
if (!user) {
|
|
2398
2471
|
return c.json({ error: "Not authenticated" }, 401);
|
|
2399
2472
|
}
|
|
2400
|
-
const token = await
|
|
2473
|
+
const token = await chunkYYV3XQOQ_cjs.AuthManager.generateToken(user.userId, user.email, user.role);
|
|
2401
2474
|
cookie.setCookie(c, "auth_token", token, {
|
|
2402
2475
|
httpOnly: true,
|
|
2403
2476
|
secure: true,
|
|
@@ -2457,7 +2530,7 @@ authRoutes.post("/register/form", async (c) => {
|
|
|
2457
2530
|
</div>
|
|
2458
2531
|
`);
|
|
2459
2532
|
}
|
|
2460
|
-
const passwordHash = await
|
|
2533
|
+
const passwordHash = await chunkYYV3XQOQ_cjs.AuthManager.hashPassword(password);
|
|
2461
2534
|
const role = isFirstUser ? "admin" : "viewer";
|
|
2462
2535
|
const userId = crypto.randomUUID();
|
|
2463
2536
|
const now = /* @__PURE__ */ new Date();
|
|
@@ -2477,7 +2550,10 @@ authRoutes.post("/register/form", async (c) => {
|
|
|
2477
2550
|
now.getTime(),
|
|
2478
2551
|
now.getTime()
|
|
2479
2552
|
).run();
|
|
2480
|
-
|
|
2553
|
+
if (isFirstUser) {
|
|
2554
|
+
setAdminExists();
|
|
2555
|
+
}
|
|
2556
|
+
const token = await chunkYYV3XQOQ_cjs.AuthManager.generateToken(userId, normalizedEmail, role);
|
|
2481
2557
|
cookie.setCookie(c, "auth_token", token, {
|
|
2482
2558
|
httpOnly: true,
|
|
2483
2559
|
secure: false,
|
|
@@ -2529,7 +2605,7 @@ authRoutes.post("/login/form", async (c) => {
|
|
|
2529
2605
|
</div>
|
|
2530
2606
|
`);
|
|
2531
2607
|
}
|
|
2532
|
-
const isValidPassword = await
|
|
2608
|
+
const isValidPassword = await chunkYYV3XQOQ_cjs.AuthManager.verifyPassword(password, user.password_hash);
|
|
2533
2609
|
if (!isValidPassword) {
|
|
2534
2610
|
return c.html(html.html`
|
|
2535
2611
|
<div class="bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded">
|
|
@@ -2537,7 +2613,7 @@ authRoutes.post("/login/form", async (c) => {
|
|
|
2537
2613
|
</div>
|
|
2538
2614
|
`);
|
|
2539
2615
|
}
|
|
2540
|
-
const token = await
|
|
2616
|
+
const token = await chunkYYV3XQOQ_cjs.AuthManager.generateToken(user.id, user.email, user.role);
|
|
2541
2617
|
cookie.setCookie(c, "auth_token", token, {
|
|
2542
2618
|
httpOnly: true,
|
|
2543
2619
|
secure: false,
|
|
@@ -2596,8 +2672,9 @@ authRoutes.post("/seed-admin", async (c) => {
|
|
|
2596
2672
|
`).run();
|
|
2597
2673
|
const existingAdmin = await db.prepare("SELECT id FROM users WHERE email = ? OR username = ?").bind("admin@sonicjs.com", "admin").first();
|
|
2598
2674
|
if (existingAdmin) {
|
|
2599
|
-
const passwordHash2 = await
|
|
2675
|
+
const passwordHash2 = await chunkYYV3XQOQ_cjs.AuthManager.hashPassword("sonicjs!");
|
|
2600
2676
|
await db.prepare("UPDATE users SET password_hash = ?, updated_at = ? WHERE id = ?").bind(passwordHash2, Date.now(), existingAdmin.id).run();
|
|
2677
|
+
setAdminExists();
|
|
2601
2678
|
return c.json({
|
|
2602
2679
|
message: "Admin user already exists (password updated)",
|
|
2603
2680
|
user: {
|
|
@@ -2608,7 +2685,7 @@ authRoutes.post("/seed-admin", async (c) => {
|
|
|
2608
2685
|
}
|
|
2609
2686
|
});
|
|
2610
2687
|
}
|
|
2611
|
-
const passwordHash = await
|
|
2688
|
+
const passwordHash = await chunkYYV3XQOQ_cjs.AuthManager.hashPassword("sonicjs!");
|
|
2612
2689
|
const userId = "admin-user-id";
|
|
2613
2690
|
const now = Date.now();
|
|
2614
2691
|
const adminEmail = "admin@sonicjs.com".toLowerCase();
|
|
@@ -2628,6 +2705,7 @@ authRoutes.post("/seed-admin", async (c) => {
|
|
|
2628
2705
|
now,
|
|
2629
2706
|
now
|
|
2630
2707
|
).run();
|
|
2708
|
+
setAdminExists();
|
|
2631
2709
|
return c.json({
|
|
2632
2710
|
message: "Admin user created successfully",
|
|
2633
2711
|
user: {
|
|
@@ -2828,7 +2906,7 @@ authRoutes.post("/accept-invitation", async (c) => {
|
|
|
2828
2906
|
if (existingUsername) {
|
|
2829
2907
|
return c.json({ error: "Username is already taken" }, 400);
|
|
2830
2908
|
}
|
|
2831
|
-
const passwordHash = await
|
|
2909
|
+
const passwordHash = await chunkYYV3XQOQ_cjs.AuthManager.hashPassword(password);
|
|
2832
2910
|
const updateStmt = db.prepare(`
|
|
2833
2911
|
UPDATE users SET
|
|
2834
2912
|
username = ?,
|
|
@@ -2847,7 +2925,7 @@ authRoutes.post("/accept-invitation", async (c) => {
|
|
|
2847
2925
|
Date.now(),
|
|
2848
2926
|
invitedUser.id
|
|
2849
2927
|
).run();
|
|
2850
|
-
const authToken = await
|
|
2928
|
+
const authToken = await chunkYYV3XQOQ_cjs.AuthManager.generateToken(invitedUser.id, invitedUser.email, invitedUser.role);
|
|
2851
2929
|
cookie.setCookie(c, "auth_token", authToken, {
|
|
2852
2930
|
httpOnly: true,
|
|
2853
2931
|
secure: true,
|
|
@@ -3077,7 +3155,7 @@ authRoutes.post("/reset-password", async (c) => {
|
|
|
3077
3155
|
if (Date.now() > user.password_reset_expires) {
|
|
3078
3156
|
return c.json({ error: "Reset token has expired" }, 400);
|
|
3079
3157
|
}
|
|
3080
|
-
const newPasswordHash = await
|
|
3158
|
+
const newPasswordHash = await chunkYYV3XQOQ_cjs.AuthManager.hashPassword(password);
|
|
3081
3159
|
try {
|
|
3082
3160
|
const historyStmt = db.prepare(`
|
|
3083
3161
|
INSERT INTO password_history (id, user_id, password_hash, created_at)
|
|
@@ -3339,7 +3417,7 @@ chunkAZLU3ROK_cjs.init_admin_layout_catalyst_template();
|
|
|
3339
3417
|
|
|
3340
3418
|
// src/templates/components/dynamic-field.template.ts
|
|
3341
3419
|
function renderDynamicField(field, options = {}) {
|
|
3342
|
-
const { value = "", errors = [], disabled = false, className = "", pluginStatuses = {} } = options;
|
|
3420
|
+
const { value = "", errors = [], disabled = false, className = "", pluginStatuses = {}, collectionId = "", contentId = "" } = options;
|
|
3343
3421
|
const opts = field.field_options || {};
|
|
3344
3422
|
const required = field.is_required ? "required" : "";
|
|
3345
3423
|
const baseClasses = `w-full rounded-lg px-3 py-2 text-sm text-zinc-950 dark:text-white bg-white dark:bg-zinc-800 shadow-sm ring-1 ring-inset ring-zinc-950/10 dark:ring-white/10 placeholder:text-zinc-400 dark:placeholder:text-zinc-500 focus:outline-none focus:ring-2 focus:ring-zinc-950 dark:focus:ring-white transition-shadow ${className}`;
|
|
@@ -3592,67 +3670,171 @@ function renderDynamicField(field, options = {}) {
|
|
|
3592
3670
|
`;
|
|
3593
3671
|
break;
|
|
3594
3672
|
case "slug":
|
|
3595
|
-
|
|
3596
|
-
|
|
3597
|
-
|
|
3673
|
+
const slugPattern = opts.pattern || "^[a-z0-9-]+$";
|
|
3674
|
+
const collectionIdValue = collectionId || opts.collectionId || "";
|
|
3675
|
+
const contentIdValue = contentId || opts.contentId || "";
|
|
3676
|
+
const isEditMode = !!value;
|
|
3598
3677
|
fieldHTML = `
|
|
3599
|
-
<
|
|
3600
|
-
|
|
3601
|
-
|
|
3602
|
-
|
|
3603
|
-
|
|
3604
|
-
|
|
3605
|
-
|
|
3606
|
-
|
|
3607
|
-
|
|
3608
|
-
|
|
3609
|
-
|
|
3610
|
-
|
|
3611
|
-
|
|
3678
|
+
<div class="slug-field-container">
|
|
3679
|
+
<input
|
|
3680
|
+
type="text"
|
|
3681
|
+
id="${fieldId}"
|
|
3682
|
+
name="${fieldName}"
|
|
3683
|
+
value="${escapeHtml2(value)}"
|
|
3684
|
+
placeholder="${opts.placeholder || "url-friendly-slug"}"
|
|
3685
|
+
maxlength="${opts.maxLength || 100}"
|
|
3686
|
+
data-pattern="${slugPattern}"
|
|
3687
|
+
data-collection-id="${collectionIdValue}"
|
|
3688
|
+
data-content-id="${contentIdValue}"
|
|
3689
|
+
data-is-edit-mode="${isEditMode}"
|
|
3690
|
+
class="${baseClasses} ${errorClasses}"
|
|
3691
|
+
${required}
|
|
3692
|
+
${disabled ? "disabled" : ""}
|
|
3693
|
+
>
|
|
3694
|
+
<div id="${fieldId}-status" class="slug-status mt-1 text-sm min-h-[20px]"></div>
|
|
3695
|
+
<button
|
|
3696
|
+
type="button"
|
|
3697
|
+
class="regenerate-slug-btn mt-2 text-sm text-cyan-600 dark:text-cyan-400 hover:text-cyan-700 dark:hover:text-cyan-300 flex items-center gap-1 transition-colors"
|
|
3698
|
+
onclick="window.regenerateSlugFromTitle_${fieldId.replace(/-/g, "_")}()"
|
|
3699
|
+
>
|
|
3700
|
+
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
|
3701
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15"></path>
|
|
3702
|
+
</svg>
|
|
3703
|
+
Regenerate from title
|
|
3704
|
+
</button>
|
|
3705
|
+
<p class="text-xs text-zinc-500 dark:text-zinc-400 mt-1">Use lowercase letters, numbers, and hyphens only</p>
|
|
3706
|
+
</div>
|
|
3707
|
+
|
|
3612
3708
|
<script>
|
|
3613
3709
|
(function() {
|
|
3614
|
-
const
|
|
3710
|
+
const slugField = document.getElementById('${fieldId}');
|
|
3711
|
+
const statusDiv = document.getElementById('${fieldId}-status');
|
|
3712
|
+
const isEditMode = slugField.dataset.isEditMode === 'true';
|
|
3615
3713
|
const pattern = new RegExp('${slugPattern}');
|
|
3616
|
-
|
|
3617
|
-
|
|
3618
|
-
|
|
3619
|
-
|
|
3620
|
-
|
|
3621
|
-
|
|
3622
|
-
|
|
3623
|
-
|
|
3624
|
-
|
|
3625
|
-
|
|
3626
|
-
|
|
3627
|
-
|
|
3628
|
-
})();
|
|
3629
|
-
|
|
3630
|
-
function generateSlugFromTitle(slugFieldId) {
|
|
3631
|
-
const titleField = document.querySelector('input[name="title"]');
|
|
3632
|
-
const slugField = document.getElementById(slugFieldId);
|
|
3633
|
-
if (titleField && slugField) {
|
|
3634
|
-
const slug = titleField.value
|
|
3714
|
+
const collectionId = slugField.dataset.collectionId;
|
|
3715
|
+
const contentId = slugField.dataset.contentId;
|
|
3716
|
+
|
|
3717
|
+
let checkTimeout;
|
|
3718
|
+
let lastCheckedSlug = '';
|
|
3719
|
+
let manuallyEdited = false;
|
|
3720
|
+
|
|
3721
|
+
// Shared slug generation function
|
|
3722
|
+
function generateSlug(text) {
|
|
3723
|
+
if (!text) return '';
|
|
3724
|
+
|
|
3725
|
+
return text
|
|
3635
3726
|
.toLowerCase()
|
|
3727
|
+
.normalize('NFD')
|
|
3728
|
+
.replace(/[\\u0300-\\u036f]/g, '')
|
|
3636
3729
|
.replace(/[^a-z0-9\\s_-]/g, '')
|
|
3637
3730
|
.replace(/\\s+/g, '-')
|
|
3638
3731
|
.replace(/[-_]+/g, '-')
|
|
3639
|
-
.replace(/^[-_]
|
|
3640
|
-
|
|
3732
|
+
.replace(/^[-_]+|[-_]+$/g, '')
|
|
3733
|
+
.substring(0, 100);
|
|
3641
3734
|
}
|
|
3642
|
-
|
|
3643
|
-
|
|
3644
|
-
|
|
3645
|
-
|
|
3646
|
-
|
|
3647
|
-
|
|
3648
|
-
|
|
3649
|
-
|
|
3650
|
-
|
|
3651
|
-
|
|
3735
|
+
|
|
3736
|
+
// Check if slug is available
|
|
3737
|
+
async function checkSlugAvailability(slug) {
|
|
3738
|
+
if (!slug || !collectionId) return;
|
|
3739
|
+
|
|
3740
|
+
// Don't check if it's the same as last time
|
|
3741
|
+
if (slug === lastCheckedSlug) return;
|
|
3742
|
+
lastCheckedSlug = slug;
|
|
3743
|
+
|
|
3744
|
+
try {
|
|
3745
|
+
// Show checking status
|
|
3746
|
+
statusDiv.innerHTML = '<span class="text-gray-400">\u23F3 Checking availability...</span>';
|
|
3747
|
+
|
|
3748
|
+
// Build URL
|
|
3749
|
+
let url = \`/api/content/check-slug?collectionId=\${encodeURIComponent(collectionId)}&slug=\${encodeURIComponent(slug)}\`;
|
|
3750
|
+
if (contentId) {
|
|
3751
|
+
url += \`&excludeId=\${encodeURIComponent(contentId)}\`;
|
|
3652
3752
|
}
|
|
3653
|
-
|
|
3753
|
+
|
|
3754
|
+
const response = await fetch(url);
|
|
3755
|
+
const data = await response.json();
|
|
3756
|
+
|
|
3757
|
+
if (data.available) {
|
|
3758
|
+
statusDiv.innerHTML = '<span class="text-green-500 dark:text-green-400">\u2713 Available</span>';
|
|
3759
|
+
slugField.setCustomValidity('');
|
|
3760
|
+
} else {
|
|
3761
|
+
statusDiv.innerHTML = \`<span class="text-red-500 dark:text-red-400">\u2717 \${data.message || 'Already in use'}</span>\`;
|
|
3762
|
+
slugField.setCustomValidity(data.message || 'This slug is already in use');
|
|
3763
|
+
}
|
|
3764
|
+
} catch (error) {
|
|
3765
|
+
console.error('Error checking slug:', error);
|
|
3766
|
+
statusDiv.innerHTML = '<span class="text-yellow-500 dark:text-yellow-400">\u26A0 Could not verify</span>';
|
|
3767
|
+
}
|
|
3654
3768
|
}
|
|
3655
|
-
|
|
3769
|
+
|
|
3770
|
+
// Format validation and duplicate checking
|
|
3771
|
+
slugField.addEventListener('input', function() {
|
|
3772
|
+
const value = this.value;
|
|
3773
|
+
|
|
3774
|
+
// Mark as manually edited if user types directly
|
|
3775
|
+
if (document.activeElement === this) {
|
|
3776
|
+
manuallyEdited = true;
|
|
3777
|
+
}
|
|
3778
|
+
|
|
3779
|
+
// Clear status if empty
|
|
3780
|
+
if (!value) {
|
|
3781
|
+
statusDiv.innerHTML = '';
|
|
3782
|
+
this.setCustomValidity('');
|
|
3783
|
+
return;
|
|
3784
|
+
}
|
|
3785
|
+
|
|
3786
|
+
// Pattern validation
|
|
3787
|
+
if (!pattern.test(value)) {
|
|
3788
|
+
this.setCustomValidity('Please use only lowercase letters, numbers, and hyphens.');
|
|
3789
|
+
statusDiv.innerHTML = '<span class="text-red-500 dark:text-red-400">\u2717 Invalid format</span>';
|
|
3790
|
+
return;
|
|
3791
|
+
}
|
|
3792
|
+
|
|
3793
|
+
// Debounce the availability check
|
|
3794
|
+
clearTimeout(checkTimeout);
|
|
3795
|
+
checkTimeout = setTimeout(() => {
|
|
3796
|
+
checkSlugAvailability(value);
|
|
3797
|
+
}, 500); // Wait 500ms after user stops typing
|
|
3798
|
+
});
|
|
3799
|
+
|
|
3800
|
+
// Initial check if field has value
|
|
3801
|
+
if (slugField.value) {
|
|
3802
|
+
checkSlugAvailability(slugField.value);
|
|
3803
|
+
}
|
|
3804
|
+
|
|
3805
|
+
// Auto-generate only in create mode
|
|
3806
|
+
// Wait for all fields to be rendered before attaching listeners
|
|
3807
|
+
if (!isEditMode) {
|
|
3808
|
+
// Use setTimeout to ensure all fields in the form are rendered
|
|
3809
|
+
setTimeout(() => {
|
|
3810
|
+
const titleField = document.querySelector('input[name="title"]');
|
|
3811
|
+
if (titleField) {
|
|
3812
|
+
titleField.addEventListener('input', function() {
|
|
3813
|
+
if (!manuallyEdited) {
|
|
3814
|
+
const slug = generateSlug(this.value);
|
|
3815
|
+
slugField.value = slug;
|
|
3816
|
+
|
|
3817
|
+
// Trigger validation and duplicate check
|
|
3818
|
+
slugField.dispatchEvent(new Event('input', { bubbles: true }));
|
|
3819
|
+
}
|
|
3820
|
+
});
|
|
3821
|
+
}
|
|
3822
|
+
}, 0);
|
|
3823
|
+
}
|
|
3824
|
+
|
|
3825
|
+
// Global function for regenerate button
|
|
3826
|
+
window.regenerateSlugFromTitle_${fieldId.replace(/-/g, "_")} = function() {
|
|
3827
|
+
const titleField = document.querySelector('input[name="title"]');
|
|
3828
|
+
if (titleField && slugField) {
|
|
3829
|
+
const slug = generateSlug(titleField.value);
|
|
3830
|
+
slugField.value = slug;
|
|
3831
|
+
manuallyEdited = false;
|
|
3832
|
+
|
|
3833
|
+
// Trigger validation and duplicate check
|
|
3834
|
+
slugField.dispatchEvent(new Event('input', { bubbles: true }));
|
|
3835
|
+
}
|
|
3836
|
+
};
|
|
3837
|
+
})();
|
|
3656
3838
|
</script>
|
|
3657
3839
|
`;
|
|
3658
3840
|
break;
|
|
@@ -3785,210 +3967,9 @@ function escapeHtml2(text) {
|
|
|
3785
3967
|
"'": "'"
|
|
3786
3968
|
})[char] || char);
|
|
3787
3969
|
}
|
|
3788
|
-
var PluginBuilder = class _PluginBuilder {
|
|
3789
|
-
plugin;
|
|
3790
|
-
constructor(options) {
|
|
3791
|
-
this.plugin = {
|
|
3792
|
-
name: options.name,
|
|
3793
|
-
version: options.version,
|
|
3794
|
-
description: options.description,
|
|
3795
|
-
author: options.author,
|
|
3796
|
-
dependencies: options.dependencies,
|
|
3797
|
-
routes: [],
|
|
3798
|
-
middleware: [],
|
|
3799
|
-
models: [],
|
|
3800
|
-
services: [],
|
|
3801
|
-
adminPages: [],
|
|
3802
|
-
adminComponents: [],
|
|
3803
|
-
menuItems: [],
|
|
3804
|
-
hooks: []
|
|
3805
|
-
};
|
|
3806
|
-
}
|
|
3807
|
-
/**
|
|
3808
|
-
* Create a new plugin builder
|
|
3809
|
-
*/
|
|
3810
|
-
static create(options) {
|
|
3811
|
-
return new _PluginBuilder(options);
|
|
3812
|
-
}
|
|
3813
|
-
/**
|
|
3814
|
-
* Add metadata to the plugin
|
|
3815
|
-
*/
|
|
3816
|
-
metadata(metadata) {
|
|
3817
|
-
Object.assign(this.plugin, metadata);
|
|
3818
|
-
return this;
|
|
3819
|
-
}
|
|
3820
|
-
/**
|
|
3821
|
-
* Add routes to plugin
|
|
3822
|
-
*/
|
|
3823
|
-
addRoutes(routes) {
|
|
3824
|
-
this.plugin.routes = [...this.plugin.routes || [], ...routes];
|
|
3825
|
-
return this;
|
|
3826
|
-
}
|
|
3827
|
-
/**
|
|
3828
|
-
* Add a single route to plugin
|
|
3829
|
-
*/
|
|
3830
|
-
addRoute(path, handler, options) {
|
|
3831
|
-
const route = {
|
|
3832
|
-
path,
|
|
3833
|
-
handler,
|
|
3834
|
-
...options
|
|
3835
|
-
};
|
|
3836
|
-
this.plugin.routes = [...this.plugin.routes || [], route];
|
|
3837
|
-
return this;
|
|
3838
|
-
}
|
|
3839
|
-
/**
|
|
3840
|
-
* Add middleware to plugin
|
|
3841
|
-
*/
|
|
3842
|
-
addMiddleware(middleware) {
|
|
3843
|
-
this.plugin.middleware = [...this.plugin.middleware || [], ...middleware];
|
|
3844
|
-
return this;
|
|
3845
|
-
}
|
|
3846
|
-
/**
|
|
3847
|
-
* Add a single middleware to plugin
|
|
3848
|
-
*/
|
|
3849
|
-
addSingleMiddleware(name, handler, options) {
|
|
3850
|
-
const middleware = {
|
|
3851
|
-
name,
|
|
3852
|
-
handler,
|
|
3853
|
-
...options
|
|
3854
|
-
};
|
|
3855
|
-
this.plugin.middleware = [...this.plugin.middleware || [], middleware];
|
|
3856
|
-
return this;
|
|
3857
|
-
}
|
|
3858
|
-
/**
|
|
3859
|
-
* Add models to plugin
|
|
3860
|
-
*/
|
|
3861
|
-
addModels(models) {
|
|
3862
|
-
this.plugin.models = [...this.plugin.models || [], ...models];
|
|
3863
|
-
return this;
|
|
3864
|
-
}
|
|
3865
|
-
/**
|
|
3866
|
-
* Add a single model to plugin
|
|
3867
|
-
*/
|
|
3868
|
-
addModel(name, options) {
|
|
3869
|
-
const model = {
|
|
3870
|
-
name,
|
|
3871
|
-
...options
|
|
3872
|
-
};
|
|
3873
|
-
this.plugin.models = [...this.plugin.models || [], model];
|
|
3874
|
-
return this;
|
|
3875
|
-
}
|
|
3876
|
-
/**
|
|
3877
|
-
* Add services to plugin
|
|
3878
|
-
*/
|
|
3879
|
-
addServices(services) {
|
|
3880
|
-
this.plugin.services = [...this.plugin.services || [], ...services];
|
|
3881
|
-
return this;
|
|
3882
|
-
}
|
|
3883
|
-
/**
|
|
3884
|
-
* Add a single service to plugin
|
|
3885
|
-
*/
|
|
3886
|
-
addService(name, implementation, options) {
|
|
3887
|
-
const service = {
|
|
3888
|
-
name,
|
|
3889
|
-
implementation,
|
|
3890
|
-
...options
|
|
3891
|
-
};
|
|
3892
|
-
this.plugin.services = [...this.plugin.services || [], service];
|
|
3893
|
-
return this;
|
|
3894
|
-
}
|
|
3895
|
-
/**
|
|
3896
|
-
* Add admin pages to plugin
|
|
3897
|
-
*/
|
|
3898
|
-
addAdminPages(pages) {
|
|
3899
|
-
this.plugin.adminPages = [...this.plugin.adminPages || [], ...pages];
|
|
3900
|
-
return this;
|
|
3901
|
-
}
|
|
3902
|
-
/**
|
|
3903
|
-
* Add a single admin page to plugin
|
|
3904
|
-
*/
|
|
3905
|
-
addAdminPage(path, title, component, options) {
|
|
3906
|
-
const page = {
|
|
3907
|
-
path,
|
|
3908
|
-
title,
|
|
3909
|
-
component,
|
|
3910
|
-
...options
|
|
3911
|
-
};
|
|
3912
|
-
this.plugin.adminPages = [...this.plugin.adminPages || [], page];
|
|
3913
|
-
return this;
|
|
3914
|
-
}
|
|
3915
|
-
/**
|
|
3916
|
-
* Add admin components to plugin
|
|
3917
|
-
*/
|
|
3918
|
-
addComponents(components) {
|
|
3919
|
-
this.plugin.adminComponents = [...this.plugin.adminComponents || [], ...components];
|
|
3920
|
-
return this;
|
|
3921
|
-
}
|
|
3922
|
-
/**
|
|
3923
|
-
* Add a single admin component to plugin
|
|
3924
|
-
*/
|
|
3925
|
-
addComponent(name, template, options) {
|
|
3926
|
-
const component = {
|
|
3927
|
-
name,
|
|
3928
|
-
template,
|
|
3929
|
-
...options
|
|
3930
|
-
};
|
|
3931
|
-
this.plugin.adminComponents = [...this.plugin.adminComponents || [], component];
|
|
3932
|
-
return this;
|
|
3933
|
-
}
|
|
3934
|
-
/**
|
|
3935
|
-
* Add menu items to plugin
|
|
3936
|
-
*/
|
|
3937
|
-
addMenuItems(items) {
|
|
3938
|
-
this.plugin.menuItems = [...this.plugin.menuItems || [], ...items];
|
|
3939
|
-
return this;
|
|
3940
|
-
}
|
|
3941
|
-
/**
|
|
3942
|
-
* Add a single menu item to plugin
|
|
3943
|
-
*/
|
|
3944
|
-
addMenuItem(label, path, options) {
|
|
3945
|
-
const menuItem = {
|
|
3946
|
-
label,
|
|
3947
|
-
path,
|
|
3948
|
-
...options
|
|
3949
|
-
};
|
|
3950
|
-
this.plugin.menuItems = [...this.plugin.menuItems || [], menuItem];
|
|
3951
|
-
return this;
|
|
3952
|
-
}
|
|
3953
|
-
/**
|
|
3954
|
-
* Add hooks to plugin
|
|
3955
|
-
*/
|
|
3956
|
-
addHooks(hooks) {
|
|
3957
|
-
this.plugin.hooks = [...this.plugin.hooks || [], ...hooks];
|
|
3958
|
-
return this;
|
|
3959
|
-
}
|
|
3960
|
-
/**
|
|
3961
|
-
* Add a single hook to plugin
|
|
3962
|
-
*/
|
|
3963
|
-
addHook(name, handler, options) {
|
|
3964
|
-
const hook = {
|
|
3965
|
-
name,
|
|
3966
|
-
handler,
|
|
3967
|
-
...options
|
|
3968
|
-
};
|
|
3969
|
-
this.plugin.hooks = [...this.plugin.hooks || [], hook];
|
|
3970
|
-
return this;
|
|
3971
|
-
}
|
|
3972
|
-
/**
|
|
3973
|
-
* Add lifecycle hooks
|
|
3974
|
-
*/
|
|
3975
|
-
lifecycle(hooks) {
|
|
3976
|
-
Object.assign(this.plugin, hooks);
|
|
3977
|
-
return this;
|
|
3978
|
-
}
|
|
3979
|
-
/**
|
|
3980
|
-
* Build the plugin
|
|
3981
|
-
*/
|
|
3982
|
-
build() {
|
|
3983
|
-
if (!this.plugin.name || !this.plugin.version) {
|
|
3984
|
-
throw new Error("Plugin name and version are required");
|
|
3985
|
-
}
|
|
3986
|
-
return this.plugin;
|
|
3987
|
-
}
|
|
3988
|
-
};
|
|
3989
3970
|
|
|
3990
3971
|
// src/plugins/available/tinymce-plugin/index.ts
|
|
3991
|
-
var builder = PluginBuilder.create({
|
|
3972
|
+
var builder = chunkAI2JJIJX_cjs.PluginBuilder.create({
|
|
3992
3973
|
name: "tinymce-plugin",
|
|
3993
3974
|
version: "1.0.0",
|
|
3994
3975
|
description: "Powerful WYSIWYG rich text editor for content creation"
|
|
@@ -4271,7 +4252,7 @@ function getQuillCDN(version = "2.0.2") {
|
|
|
4271
4252
|
`;
|
|
4272
4253
|
}
|
|
4273
4254
|
function createQuillEditorPlugin() {
|
|
4274
|
-
const builder3 = PluginBuilder.create({
|
|
4255
|
+
const builder3 = chunkAI2JJIJX_cjs.PluginBuilder.create({
|
|
4275
4256
|
name: "quill-editor",
|
|
4276
4257
|
version: "1.0.0",
|
|
4277
4258
|
description: "Quill rich text editor integration for SonicJS"
|
|
@@ -4297,7 +4278,7 @@ function createQuillEditorPlugin() {
|
|
|
4297
4278
|
createQuillEditorPlugin();
|
|
4298
4279
|
|
|
4299
4280
|
// src/plugins/available/easy-mdx/index.ts
|
|
4300
|
-
var builder2 = PluginBuilder.create({
|
|
4281
|
+
var builder2 = chunkAI2JJIJX_cjs.PluginBuilder.create({
|
|
4301
4282
|
name: "easy-mdx",
|
|
4302
4283
|
version: "1.0.0",
|
|
4303
4284
|
description: "Lightweight markdown editor with live preview"
|
|
@@ -4529,17 +4510,24 @@ function renderContentFormPage(data) {
|
|
|
4529
4510
|
const coreFieldsHTML = coreFields.sort((a, b) => a.field_order - b.field_order).map((field) => renderDynamicField(field, {
|
|
4530
4511
|
value: getFieldValue(field.field_name),
|
|
4531
4512
|
errors: data.validationErrors?.[field.field_name] || [],
|
|
4532
|
-
pluginStatuses
|
|
4513
|
+
pluginStatuses,
|
|
4514
|
+
collectionId: data.collection.id,
|
|
4515
|
+
contentId: data.id
|
|
4516
|
+
// Pass content ID when editing
|
|
4533
4517
|
}));
|
|
4534
4518
|
const contentFieldsHTML = contentFields.sort((a, b) => a.field_order - b.field_order).map((field) => renderDynamicField(field, {
|
|
4535
4519
|
value: getFieldValue(field.field_name),
|
|
4536
4520
|
errors: data.validationErrors?.[field.field_name] || [],
|
|
4537
|
-
pluginStatuses
|
|
4521
|
+
pluginStatuses,
|
|
4522
|
+
collectionId: data.collection.id,
|
|
4523
|
+
contentId: data.id
|
|
4538
4524
|
}));
|
|
4539
4525
|
const metaFieldsHTML = metaFields.sort((a, b) => a.field_order - b.field_order).map((field) => renderDynamicField(field, {
|
|
4540
4526
|
value: getFieldValue(field.field_name),
|
|
4541
4527
|
errors: data.validationErrors?.[field.field_name] || [],
|
|
4542
|
-
pluginStatuses
|
|
4528
|
+
pluginStatuses,
|
|
4529
|
+
collectionId: data.collection.id,
|
|
4530
|
+
contentId: data.id
|
|
4543
4531
|
}));
|
|
4544
4532
|
const pageContent = `
|
|
4545
4533
|
<div class="space-y-6">
|
|
@@ -5979,7 +5967,7 @@ async function isPluginActive2(db, pluginId) {
|
|
|
5979
5967
|
|
|
5980
5968
|
// src/routes/admin-content.ts
|
|
5981
5969
|
var adminContentRoutes = new hono.Hono();
|
|
5982
|
-
adminContentRoutes.use("*",
|
|
5970
|
+
adminContentRoutes.use("*", chunkYYV3XQOQ_cjs.requireAuth());
|
|
5983
5971
|
async function getCollectionFields(db, collectionId) {
|
|
5984
5972
|
const cache = chunk7FOAMNTI_cjs.getCacheService(chunk7FOAMNTI_cjs.CACHE_CONFIGS.collection);
|
|
5985
5973
|
return cache.getOrSet(
|
|
@@ -6456,6 +6444,18 @@ adminContentRoutes.post("/", async (c) => {
|
|
|
6456
6444
|
const errors = {};
|
|
6457
6445
|
for (const field of fields) {
|
|
6458
6446
|
const value = formData.get(field.field_name);
|
|
6447
|
+
const blocksConfig = chunkZWV3EBZ7_cjs.getBlocksFieldConfig(field.field_options);
|
|
6448
|
+
if (blocksConfig) {
|
|
6449
|
+
const parsed = chunkZWV3EBZ7_cjs.parseBlocksValue(value, blocksConfig);
|
|
6450
|
+
if (field.is_required && parsed.value.length === 0) {
|
|
6451
|
+
parsed.errors.push(`${field.field_label} is required`);
|
|
6452
|
+
}
|
|
6453
|
+
if (parsed.errors.length > 0) {
|
|
6454
|
+
errors[field.field_name] = parsed.errors;
|
|
6455
|
+
}
|
|
6456
|
+
data[field.field_name] = parsed.value;
|
|
6457
|
+
continue;
|
|
6458
|
+
}
|
|
6459
6459
|
if (field.is_required && (!value || value.toString().trim() === "")) {
|
|
6460
6460
|
errors[field.field_name] = [`${field.field_label} is required`];
|
|
6461
6461
|
continue;
|
|
@@ -6478,6 +6478,67 @@ adminContentRoutes.post("/", async (c) => {
|
|
|
6478
6478
|
data[field.field_name] = value;
|
|
6479
6479
|
}
|
|
6480
6480
|
break;
|
|
6481
|
+
case "array": {
|
|
6482
|
+
if (!value || value.toString().trim() === "") {
|
|
6483
|
+
data[field.field_name] = [];
|
|
6484
|
+
if (field.is_required) {
|
|
6485
|
+
errors[field.field_name] = [`${field.field_label} is required`];
|
|
6486
|
+
}
|
|
6487
|
+
break;
|
|
6488
|
+
}
|
|
6489
|
+
try {
|
|
6490
|
+
const parsed = JSON.parse(value.toString());
|
|
6491
|
+
if (!Array.isArray(parsed)) {
|
|
6492
|
+
errors[field.field_name] = [`${field.field_label} must be a JSON array`];
|
|
6493
|
+
} else {
|
|
6494
|
+
if (field.is_required && parsed.length === 0) {
|
|
6495
|
+
errors[field.field_name] = [`${field.field_label} is required`];
|
|
6496
|
+
}
|
|
6497
|
+
data[field.field_name] = parsed;
|
|
6498
|
+
}
|
|
6499
|
+
} catch {
|
|
6500
|
+
errors[field.field_name] = [`${field.field_label} must be valid JSON`];
|
|
6501
|
+
}
|
|
6502
|
+
break;
|
|
6503
|
+
}
|
|
6504
|
+
case "object": {
|
|
6505
|
+
if (!value || value.toString().trim() === "") {
|
|
6506
|
+
data[field.field_name] = {};
|
|
6507
|
+
if (field.is_required) {
|
|
6508
|
+
errors[field.field_name] = [`${field.field_label} is required`];
|
|
6509
|
+
}
|
|
6510
|
+
break;
|
|
6511
|
+
}
|
|
6512
|
+
try {
|
|
6513
|
+
const parsed = JSON.parse(value.toString());
|
|
6514
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
6515
|
+
errors[field.field_name] = [`${field.field_label} must be a JSON object`];
|
|
6516
|
+
} else {
|
|
6517
|
+
if (field.is_required && Object.keys(parsed).length === 0) {
|
|
6518
|
+
errors[field.field_name] = [`${field.field_label} is required`];
|
|
6519
|
+
}
|
|
6520
|
+
data[field.field_name] = parsed;
|
|
6521
|
+
}
|
|
6522
|
+
} catch {
|
|
6523
|
+
errors[field.field_name] = [`${field.field_label} must be valid JSON`];
|
|
6524
|
+
}
|
|
6525
|
+
break;
|
|
6526
|
+
}
|
|
6527
|
+
case "json": {
|
|
6528
|
+
if (!value || value.toString().trim() === "") {
|
|
6529
|
+
data[field.field_name] = null;
|
|
6530
|
+
if (field.is_required) {
|
|
6531
|
+
errors[field.field_name] = [`${field.field_label} is required`];
|
|
6532
|
+
}
|
|
6533
|
+
break;
|
|
6534
|
+
}
|
|
6535
|
+
try {
|
|
6536
|
+
data[field.field_name] = JSON.parse(value.toString());
|
|
6537
|
+
} catch {
|
|
6538
|
+
errors[field.field_name] = [`${field.field_label} must be valid JSON`];
|
|
6539
|
+
}
|
|
6540
|
+
break;
|
|
6541
|
+
}
|
|
6481
6542
|
default:
|
|
6482
6543
|
data[field.field_name] = value;
|
|
6483
6544
|
}
|
|
@@ -6602,6 +6663,18 @@ adminContentRoutes.put("/:id", async (c) => {
|
|
|
6602
6663
|
const errors = {};
|
|
6603
6664
|
for (const field of fields) {
|
|
6604
6665
|
const value = formData.get(field.field_name);
|
|
6666
|
+
const blocksConfig = chunkZWV3EBZ7_cjs.getBlocksFieldConfig(field.field_options);
|
|
6667
|
+
if (blocksConfig) {
|
|
6668
|
+
const parsed = chunkZWV3EBZ7_cjs.parseBlocksValue(value, blocksConfig);
|
|
6669
|
+
if (field.is_required && parsed.value.length === 0) {
|
|
6670
|
+
parsed.errors.push(`${field.field_label} is required`);
|
|
6671
|
+
}
|
|
6672
|
+
if (parsed.errors.length > 0) {
|
|
6673
|
+
errors[field.field_name] = parsed.errors;
|
|
6674
|
+
}
|
|
6675
|
+
data[field.field_name] = parsed.value;
|
|
6676
|
+
continue;
|
|
6677
|
+
}
|
|
6605
6678
|
if (field.is_required && (!value || value.toString().trim() === "")) {
|
|
6606
6679
|
errors[field.field_name] = [`${field.field_label} is required`];
|
|
6607
6680
|
continue;
|
|
@@ -6624,6 +6697,67 @@ adminContentRoutes.put("/:id", async (c) => {
|
|
|
6624
6697
|
data[field.field_name] = value;
|
|
6625
6698
|
}
|
|
6626
6699
|
break;
|
|
6700
|
+
case "array": {
|
|
6701
|
+
if (!value || value.toString().trim() === "") {
|
|
6702
|
+
data[field.field_name] = [];
|
|
6703
|
+
if (field.is_required) {
|
|
6704
|
+
errors[field.field_name] = [`${field.field_label} is required`];
|
|
6705
|
+
}
|
|
6706
|
+
break;
|
|
6707
|
+
}
|
|
6708
|
+
try {
|
|
6709
|
+
const parsed = JSON.parse(value.toString());
|
|
6710
|
+
if (!Array.isArray(parsed)) {
|
|
6711
|
+
errors[field.field_name] = [`${field.field_label} must be a JSON array`];
|
|
6712
|
+
} else {
|
|
6713
|
+
if (field.is_required && parsed.length === 0) {
|
|
6714
|
+
errors[field.field_name] = [`${field.field_label} is required`];
|
|
6715
|
+
}
|
|
6716
|
+
data[field.field_name] = parsed;
|
|
6717
|
+
}
|
|
6718
|
+
} catch {
|
|
6719
|
+
errors[field.field_name] = [`${field.field_label} must be valid JSON`];
|
|
6720
|
+
}
|
|
6721
|
+
break;
|
|
6722
|
+
}
|
|
6723
|
+
case "object": {
|
|
6724
|
+
if (!value || value.toString().trim() === "") {
|
|
6725
|
+
data[field.field_name] = {};
|
|
6726
|
+
if (field.is_required) {
|
|
6727
|
+
errors[field.field_name] = [`${field.field_label} is required`];
|
|
6728
|
+
}
|
|
6729
|
+
break;
|
|
6730
|
+
}
|
|
6731
|
+
try {
|
|
6732
|
+
const parsed = JSON.parse(value.toString());
|
|
6733
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
6734
|
+
errors[field.field_name] = [`${field.field_label} must be a JSON object`];
|
|
6735
|
+
} else {
|
|
6736
|
+
if (field.is_required && Object.keys(parsed).length === 0) {
|
|
6737
|
+
errors[field.field_name] = [`${field.field_label} is required`];
|
|
6738
|
+
}
|
|
6739
|
+
data[field.field_name] = parsed;
|
|
6740
|
+
}
|
|
6741
|
+
} catch {
|
|
6742
|
+
errors[field.field_name] = [`${field.field_label} must be valid JSON`];
|
|
6743
|
+
}
|
|
6744
|
+
break;
|
|
6745
|
+
}
|
|
6746
|
+
case "json": {
|
|
6747
|
+
if (!value || value.toString().trim() === "") {
|
|
6748
|
+
data[field.field_name] = null;
|
|
6749
|
+
if (field.is_required) {
|
|
6750
|
+
errors[field.field_name] = [`${field.field_label} is required`];
|
|
6751
|
+
}
|
|
6752
|
+
break;
|
|
6753
|
+
}
|
|
6754
|
+
try {
|
|
6755
|
+
data[field.field_name] = JSON.parse(value.toString());
|
|
6756
|
+
} catch {
|
|
6757
|
+
errors[field.field_name] = [`${field.field_label} must be valid JSON`];
|
|
6758
|
+
}
|
|
6759
|
+
break;
|
|
6760
|
+
}
|
|
6627
6761
|
default:
|
|
6628
6762
|
data[field.field_name] = value;
|
|
6629
6763
|
}
|
|
@@ -6743,6 +6877,12 @@ adminContentRoutes.post("/preview", async (c) => {
|
|
|
6743
6877
|
const data = {};
|
|
6744
6878
|
for (const field of fields) {
|
|
6745
6879
|
const value = formData.get(field.field_name);
|
|
6880
|
+
const blocksConfig = chunkZWV3EBZ7_cjs.getBlocksFieldConfig(field.field_options);
|
|
6881
|
+
if (blocksConfig) {
|
|
6882
|
+
const parsed = chunkZWV3EBZ7_cjs.parseBlocksValue(value, blocksConfig);
|
|
6883
|
+
data[field.field_name] = parsed.value;
|
|
6884
|
+
continue;
|
|
6885
|
+
}
|
|
6746
6886
|
switch (field.field_type) {
|
|
6747
6887
|
case "number":
|
|
6748
6888
|
data[field.field_name] = value ? Number(value) : null;
|
|
@@ -8040,7 +8180,7 @@ function renderUserEditPage(data) {
|
|
|
8040
8180
|
<input
|
|
8041
8181
|
type="text"
|
|
8042
8182
|
name="first_name"
|
|
8043
|
-
value="${
|
|
8183
|
+
value="${chunkZWV3EBZ7_cjs.escapeHtml(data.userToEdit.firstName || "")}"
|
|
8044
8184
|
required
|
|
8045
8185
|
class="w-full rounded-lg bg-white dark:bg-zinc-800 px-3 py-2 text-sm text-zinc-950 dark:text-white shadow-sm ring-1 ring-inset ring-zinc-950/10 dark:ring-white/10 placeholder:text-zinc-400 dark:placeholder:text-zinc-500 focus:outline-none focus:ring-2 focus:ring-zinc-950 dark:focus:ring-white transition-shadow"
|
|
8046
8186
|
/>
|
|
@@ -8051,7 +8191,7 @@ function renderUserEditPage(data) {
|
|
|
8051
8191
|
<input
|
|
8052
8192
|
type="text"
|
|
8053
8193
|
name="last_name"
|
|
8054
|
-
value="${
|
|
8194
|
+
value="${chunkZWV3EBZ7_cjs.escapeHtml(data.userToEdit.lastName || "")}"
|
|
8055
8195
|
required
|
|
8056
8196
|
class="w-full rounded-lg bg-white dark:bg-zinc-800 px-3 py-2 text-sm text-zinc-950 dark:text-white shadow-sm ring-1 ring-inset ring-zinc-950/10 dark:ring-white/10 placeholder:text-zinc-400 dark:placeholder:text-zinc-500 focus:outline-none focus:ring-2 focus:ring-zinc-950 dark:focus:ring-white transition-shadow"
|
|
8057
8197
|
/>
|
|
@@ -8062,7 +8202,7 @@ function renderUserEditPage(data) {
|
|
|
8062
8202
|
<input
|
|
8063
8203
|
type="text"
|
|
8064
8204
|
name="username"
|
|
8065
|
-
value="${
|
|
8205
|
+
value="${chunkZWV3EBZ7_cjs.escapeHtml(data.userToEdit.username || "")}"
|
|
8066
8206
|
required
|
|
8067
8207
|
class="w-full rounded-lg bg-white dark:bg-zinc-800 px-3 py-2 text-sm text-zinc-950 dark:text-white shadow-sm ring-1 ring-inset ring-zinc-950/10 dark:ring-white/10 placeholder:text-zinc-400 dark:placeholder:text-zinc-500 focus:outline-none focus:ring-2 focus:ring-zinc-950 dark:focus:ring-white transition-shadow"
|
|
8068
8208
|
/>
|
|
@@ -8073,7 +8213,7 @@ function renderUserEditPage(data) {
|
|
|
8073
8213
|
<input
|
|
8074
8214
|
type="email"
|
|
8075
8215
|
name="email"
|
|
8076
|
-
value="${
|
|
8216
|
+
value="${chunkZWV3EBZ7_cjs.escapeHtml(data.userToEdit.email || "")}"
|
|
8077
8217
|
required
|
|
8078
8218
|
class="w-full rounded-lg bg-white dark:bg-zinc-800 px-3 py-2 text-sm text-zinc-950 dark:text-white shadow-sm ring-1 ring-inset ring-zinc-950/10 dark:ring-white/10 placeholder:text-zinc-400 dark:placeholder:text-zinc-500 focus:outline-none focus:ring-2 focus:ring-zinc-950 dark:focus:ring-white transition-shadow"
|
|
8079
8219
|
/>
|
|
@@ -8084,7 +8224,7 @@ function renderUserEditPage(data) {
|
|
|
8084
8224
|
<input
|
|
8085
8225
|
type="tel"
|
|
8086
8226
|
name="phone"
|
|
8087
|
-
value="${
|
|
8227
|
+
value="${chunkZWV3EBZ7_cjs.escapeHtml(data.userToEdit.phone || "")}"
|
|
8088
8228
|
class="w-full rounded-lg bg-white dark:bg-zinc-800 px-3 py-2 text-sm text-zinc-950 dark:text-white shadow-sm ring-1 ring-inset ring-zinc-950/10 dark:ring-white/10 placeholder:text-zinc-400 dark:placeholder:text-zinc-500 focus:outline-none focus:ring-2 focus:ring-zinc-950 dark:focus:ring-white transition-shadow"
|
|
8089
8229
|
/>
|
|
8090
8230
|
</div>
|
|
@@ -8098,7 +8238,7 @@ function renderUserEditPage(data) {
|
|
|
8098
8238
|
class="col-start-1 row-start-1 w-full appearance-none rounded-md bg-white/5 dark:bg-white/5 py-1.5 pl-3 pr-8 text-base text-zinc-950 dark:text-white outline outline-1 -outline-offset-1 outline-zinc-500/30 dark:outline-zinc-400/30 *:bg-white dark:*:bg-zinc-800 focus-visible:outline focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-zinc-500 dark:focus-visible:outline-zinc-400 sm:text-sm/6"
|
|
8099
8239
|
>
|
|
8100
8240
|
${data.roles.map((role) => `
|
|
8101
|
-
<option value="${
|
|
8241
|
+
<option value="${chunkZWV3EBZ7_cjs.escapeHtml(role.value)}" ${data.userToEdit.role === role.value ? "selected" : ""}>${chunkZWV3EBZ7_cjs.escapeHtml(role.label)}</option>
|
|
8102
8242
|
`).join("")}
|
|
8103
8243
|
</select>
|
|
8104
8244
|
<svg viewBox="0 0 16 16" fill="currentColor" data-slot="icon" aria-hidden="true" class="pointer-events-none col-start-1 row-start-1 mr-2 size-5 self-center justify-self-end text-zinc-600 dark:text-zinc-400 sm:size-4">
|
|
@@ -8114,7 +8254,7 @@ function renderUserEditPage(data) {
|
|
|
8114
8254
|
name="bio"
|
|
8115
8255
|
rows="3"
|
|
8116
8256
|
class="w-full rounded-lg bg-white dark:bg-zinc-800 px-3 py-2 text-sm text-zinc-950 dark:text-white shadow-sm ring-1 ring-inset ring-zinc-950/10 dark:ring-white/10 placeholder:text-zinc-400 dark:placeholder:text-zinc-500 focus:outline-none focus:ring-2 focus:ring-zinc-950 dark:focus:ring-white transition-shadow"
|
|
8117
|
-
>${
|
|
8257
|
+
>${chunkZWV3EBZ7_cjs.escapeHtml(data.userToEdit.bio || "")}</textarea>
|
|
8118
8258
|
</div>
|
|
8119
8259
|
</div>
|
|
8120
8260
|
|
|
@@ -9014,7 +9154,7 @@ function renderUsersListPage(data) {
|
|
|
9014
9154
|
|
|
9015
9155
|
// src/routes/admin-users.ts
|
|
9016
9156
|
var userRoutes = new hono.Hono();
|
|
9017
|
-
userRoutes.use("*",
|
|
9157
|
+
userRoutes.use("*", chunkYYV3XQOQ_cjs.requireAuth());
|
|
9018
9158
|
userRoutes.get("/", (c) => {
|
|
9019
9159
|
return c.redirect("/admin/dashboard");
|
|
9020
9160
|
});
|
|
@@ -9113,12 +9253,12 @@ userRoutes.put("/profile", async (c) => {
|
|
|
9113
9253
|
const db = c.env.DB;
|
|
9114
9254
|
try {
|
|
9115
9255
|
const formData = await c.req.formData();
|
|
9116
|
-
const firstName =
|
|
9117
|
-
const lastName =
|
|
9118
|
-
const username =
|
|
9256
|
+
const firstName = chunkZWV3EBZ7_cjs.sanitizeInput(formData.get("first_name")?.toString());
|
|
9257
|
+
const lastName = chunkZWV3EBZ7_cjs.sanitizeInput(formData.get("last_name")?.toString());
|
|
9258
|
+
const username = chunkZWV3EBZ7_cjs.sanitizeInput(formData.get("username")?.toString());
|
|
9119
9259
|
const email = formData.get("email")?.toString()?.trim().toLowerCase() || "";
|
|
9120
|
-
const phone =
|
|
9121
|
-
const bio =
|
|
9260
|
+
const phone = chunkZWV3EBZ7_cjs.sanitizeInput(formData.get("phone")?.toString()) || null;
|
|
9261
|
+
const bio = chunkZWV3EBZ7_cjs.sanitizeInput(formData.get("bio")?.toString()) || null;
|
|
9122
9262
|
const timezone = formData.get("timezone")?.toString() || "UTC";
|
|
9123
9263
|
const language = formData.get("language")?.toString() || "en";
|
|
9124
9264
|
const emailNotifications = formData.get("email_notifications") === "1";
|
|
@@ -9169,7 +9309,7 @@ userRoutes.put("/profile", async (c) => {
|
|
|
9169
9309
|
Date.now(),
|
|
9170
9310
|
user.userId
|
|
9171
9311
|
).run();
|
|
9172
|
-
await
|
|
9312
|
+
await chunkYYV3XQOQ_cjs.logActivity(
|
|
9173
9313
|
db,
|
|
9174
9314
|
user.userId,
|
|
9175
9315
|
"profile.update",
|
|
@@ -9232,7 +9372,7 @@ userRoutes.post("/profile/avatar", async (c) => {
|
|
|
9232
9372
|
SELECT first_name, last_name FROM users WHERE id = ?
|
|
9233
9373
|
`);
|
|
9234
9374
|
const userData = await userStmt.bind(user.userId).first();
|
|
9235
|
-
await
|
|
9375
|
+
await chunkYYV3XQOQ_cjs.logActivity(
|
|
9236
9376
|
db,
|
|
9237
9377
|
user.userId,
|
|
9238
9378
|
"profile.avatar_update",
|
|
@@ -9303,7 +9443,7 @@ userRoutes.post("/profile/password", async (c) => {
|
|
|
9303
9443
|
dismissible: true
|
|
9304
9444
|
}));
|
|
9305
9445
|
}
|
|
9306
|
-
const validPassword = await
|
|
9446
|
+
const validPassword = await chunkYYV3XQOQ_cjs.AuthManager.verifyPassword(currentPassword, userData.password_hash);
|
|
9307
9447
|
if (!validPassword) {
|
|
9308
9448
|
return c.html(renderAlert2({
|
|
9309
9449
|
type: "error",
|
|
@@ -9311,7 +9451,7 @@ userRoutes.post("/profile/password", async (c) => {
|
|
|
9311
9451
|
dismissible: true
|
|
9312
9452
|
}));
|
|
9313
9453
|
}
|
|
9314
|
-
const newPasswordHash = await
|
|
9454
|
+
const newPasswordHash = await chunkYYV3XQOQ_cjs.AuthManager.hashPassword(newPassword);
|
|
9315
9455
|
const historyStmt = db.prepare(`
|
|
9316
9456
|
INSERT INTO password_history (id, user_id, password_hash, created_at)
|
|
9317
9457
|
VALUES (?, ?, ?, ?)
|
|
@@ -9327,7 +9467,7 @@ userRoutes.post("/profile/password", async (c) => {
|
|
|
9327
9467
|
WHERE id = ?
|
|
9328
9468
|
`);
|
|
9329
9469
|
await updateStmt.bind(newPasswordHash, Date.now(), user.userId).run();
|
|
9330
|
-
await
|
|
9470
|
+
await chunkYYV3XQOQ_cjs.logActivity(
|
|
9331
9471
|
db,
|
|
9332
9472
|
user.userId,
|
|
9333
9473
|
"profile.password_change",
|
|
@@ -9394,7 +9534,7 @@ userRoutes.get("/users", async (c) => {
|
|
|
9394
9534
|
`);
|
|
9395
9535
|
const countResult = await countStmt.bind(...params).first();
|
|
9396
9536
|
const totalUsers = countResult?.total || 0;
|
|
9397
|
-
await
|
|
9537
|
+
await chunkYYV3XQOQ_cjs.logActivity(
|
|
9398
9538
|
db,
|
|
9399
9539
|
user.userId,
|
|
9400
9540
|
"users.list_view",
|
|
@@ -9496,12 +9636,12 @@ userRoutes.post("/users/new", async (c) => {
|
|
|
9496
9636
|
const user = c.get("user");
|
|
9497
9637
|
try {
|
|
9498
9638
|
const formData = await c.req.formData();
|
|
9499
|
-
const firstName =
|
|
9500
|
-
const lastName =
|
|
9501
|
-
const username =
|
|
9639
|
+
const firstName = chunkZWV3EBZ7_cjs.sanitizeInput(formData.get("first_name")?.toString());
|
|
9640
|
+
const lastName = chunkZWV3EBZ7_cjs.sanitizeInput(formData.get("last_name")?.toString());
|
|
9641
|
+
const username = chunkZWV3EBZ7_cjs.sanitizeInput(formData.get("username")?.toString());
|
|
9502
9642
|
const email = formData.get("email")?.toString()?.trim().toLowerCase() || "";
|
|
9503
|
-
const phone =
|
|
9504
|
-
const bio =
|
|
9643
|
+
const phone = chunkZWV3EBZ7_cjs.sanitizeInput(formData.get("phone")?.toString()) || null;
|
|
9644
|
+
const bio = chunkZWV3EBZ7_cjs.sanitizeInput(formData.get("bio")?.toString()) || null;
|
|
9505
9645
|
const role = formData.get("role")?.toString() || "viewer";
|
|
9506
9646
|
const password = formData.get("password")?.toString() || "";
|
|
9507
9647
|
const confirmPassword = formData.get("confirm_password")?.toString() || "";
|
|
@@ -9548,7 +9688,7 @@ userRoutes.post("/users/new", async (c) => {
|
|
|
9548
9688
|
dismissible: true
|
|
9549
9689
|
}));
|
|
9550
9690
|
}
|
|
9551
|
-
const passwordHash = await
|
|
9691
|
+
const passwordHash = await chunkYYV3XQOQ_cjs.AuthManager.hashPassword(password);
|
|
9552
9692
|
const userId = crypto.randomUUID();
|
|
9553
9693
|
const createStmt = db.prepare(`
|
|
9554
9694
|
INSERT INTO users (
|
|
@@ -9571,7 +9711,7 @@ userRoutes.post("/users/new", async (c) => {
|
|
|
9571
9711
|
Date.now(),
|
|
9572
9712
|
Date.now()
|
|
9573
9713
|
).run();
|
|
9574
|
-
await
|
|
9714
|
+
await chunkYYV3XQOQ_cjs.logActivity(
|
|
9575
9715
|
db,
|
|
9576
9716
|
user.userId,
|
|
9577
9717
|
"user!.create",
|
|
@@ -9609,7 +9749,7 @@ userRoutes.get("/users/:id", async (c) => {
|
|
|
9609
9749
|
if (!userRecord) {
|
|
9610
9750
|
return c.json({ error: "User not found" }, 404);
|
|
9611
9751
|
}
|
|
9612
|
-
await
|
|
9752
|
+
await chunkYYV3XQOQ_cjs.logActivity(
|
|
9613
9753
|
db,
|
|
9614
9754
|
user.userId,
|
|
9615
9755
|
"user!.view",
|
|
@@ -9702,12 +9842,12 @@ userRoutes.put("/users/:id", async (c) => {
|
|
|
9702
9842
|
const userId = c.req.param("id");
|
|
9703
9843
|
try {
|
|
9704
9844
|
const formData = await c.req.formData();
|
|
9705
|
-
const firstName =
|
|
9706
|
-
const lastName =
|
|
9707
|
-
const username =
|
|
9845
|
+
const firstName = chunkZWV3EBZ7_cjs.sanitizeInput(formData.get("first_name")?.toString());
|
|
9846
|
+
const lastName = chunkZWV3EBZ7_cjs.sanitizeInput(formData.get("last_name")?.toString());
|
|
9847
|
+
const username = chunkZWV3EBZ7_cjs.sanitizeInput(formData.get("username")?.toString());
|
|
9708
9848
|
const email = formData.get("email")?.toString()?.trim().toLowerCase() || "";
|
|
9709
|
-
const phone =
|
|
9710
|
-
const bio =
|
|
9849
|
+
const phone = chunkZWV3EBZ7_cjs.sanitizeInput(formData.get("phone")?.toString()) || null;
|
|
9850
|
+
const bio = chunkZWV3EBZ7_cjs.sanitizeInput(formData.get("bio")?.toString()) || null;
|
|
9711
9851
|
const role = formData.get("role")?.toString() || "viewer";
|
|
9712
9852
|
const isActive = formData.get("is_active") === "1";
|
|
9713
9853
|
const emailVerified = formData.get("email_verified") === "1";
|
|
@@ -9758,7 +9898,7 @@ userRoutes.put("/users/:id", async (c) => {
|
|
|
9758
9898
|
Date.now(),
|
|
9759
9899
|
userId
|
|
9760
9900
|
).run();
|
|
9761
|
-
await
|
|
9901
|
+
await chunkYYV3XQOQ_cjs.logActivity(
|
|
9762
9902
|
db,
|
|
9763
9903
|
user.userId,
|
|
9764
9904
|
"user!.update",
|
|
@@ -9803,7 +9943,7 @@ userRoutes.post("/users/:id/toggle", async (c) => {
|
|
|
9803
9943
|
UPDATE users SET is_active = ?, updated_at = ? WHERE id = ?
|
|
9804
9944
|
`);
|
|
9805
9945
|
await toggleStmt.bind(active ? 1 : 0, Date.now(), userId).run();
|
|
9806
|
-
await
|
|
9946
|
+
await chunkYYV3XQOQ_cjs.logActivity(
|
|
9807
9947
|
db,
|
|
9808
9948
|
user.userId,
|
|
9809
9949
|
active ? "user.activate" : "user.deactivate",
|
|
@@ -9844,7 +9984,7 @@ userRoutes.delete("/users/:id", async (c) => {
|
|
|
9844
9984
|
DELETE FROM users WHERE id = ?
|
|
9845
9985
|
`);
|
|
9846
9986
|
await deleteStmt.bind(userId).run();
|
|
9847
|
-
await
|
|
9987
|
+
await chunkYYV3XQOQ_cjs.logActivity(
|
|
9848
9988
|
db,
|
|
9849
9989
|
user.userId,
|
|
9850
9990
|
"user!.hard_delete",
|
|
@@ -9863,7 +10003,7 @@ userRoutes.delete("/users/:id", async (c) => {
|
|
|
9863
10003
|
UPDATE users SET is_active = 0, updated_at = ? WHERE id = ?
|
|
9864
10004
|
`);
|
|
9865
10005
|
await deleteStmt.bind(Date.now(), userId).run();
|
|
9866
|
-
await
|
|
10006
|
+
await chunkYYV3XQOQ_cjs.logActivity(
|
|
9867
10007
|
db,
|
|
9868
10008
|
user.userId,
|
|
9869
10009
|
"user!.soft_delete",
|
|
@@ -9890,8 +10030,8 @@ userRoutes.post("/invite-user", async (c) => {
|
|
|
9890
10030
|
const formData = await c.req.formData();
|
|
9891
10031
|
const email = formData.get("email")?.toString()?.trim().toLowerCase() || "";
|
|
9892
10032
|
const role = formData.get("role")?.toString()?.trim() || "viewer";
|
|
9893
|
-
const firstName =
|
|
9894
|
-
const lastName =
|
|
10033
|
+
const firstName = chunkZWV3EBZ7_cjs.sanitizeInput(formData.get("first_name")?.toString());
|
|
10034
|
+
const lastName = chunkZWV3EBZ7_cjs.sanitizeInput(formData.get("last_name")?.toString());
|
|
9895
10035
|
if (!email || !firstName || !lastName) {
|
|
9896
10036
|
return c.json({ error: "Email, first name, and last name are required" }, 400);
|
|
9897
10037
|
}
|
|
@@ -9929,7 +10069,7 @@ userRoutes.post("/invite-user", async (c) => {
|
|
|
9929
10069
|
Date.now(),
|
|
9930
10070
|
Date.now()
|
|
9931
10071
|
).run();
|
|
9932
|
-
await
|
|
10072
|
+
await chunkYYV3XQOQ_cjs.logActivity(
|
|
9933
10073
|
db,
|
|
9934
10074
|
user.userId,
|
|
9935
10075
|
"user!.invite_sent",
|
|
@@ -9986,7 +10126,7 @@ userRoutes.post("/resend-invitation/:id", async (c) => {
|
|
|
9986
10126
|
Date.now(),
|
|
9987
10127
|
userId
|
|
9988
10128
|
).run();
|
|
9989
|
-
await
|
|
10129
|
+
await chunkYYV3XQOQ_cjs.logActivity(
|
|
9990
10130
|
db,
|
|
9991
10131
|
user.userId,
|
|
9992
10132
|
"user!.invitation_resent",
|
|
@@ -10022,7 +10162,7 @@ userRoutes.delete("/cancel-invitation/:id", async (c) => {
|
|
|
10022
10162
|
}
|
|
10023
10163
|
const deleteStmt = db.prepare(`DELETE FROM users WHERE id = ?`);
|
|
10024
10164
|
await deleteStmt.bind(userId).run();
|
|
10025
|
-
await
|
|
10165
|
+
await chunkYYV3XQOQ_cjs.logActivity(
|
|
10026
10166
|
db,
|
|
10027
10167
|
user.userId,
|
|
10028
10168
|
"user!.invitation_cancelled",
|
|
@@ -10105,7 +10245,7 @@ userRoutes.get("/activity-logs", async (c) => {
|
|
|
10105
10245
|
...log,
|
|
10106
10246
|
details: log.details ? JSON.parse(log.details) : null
|
|
10107
10247
|
}));
|
|
10108
|
-
await
|
|
10248
|
+
await chunkYYV3XQOQ_cjs.logActivity(
|
|
10109
10249
|
db,
|
|
10110
10250
|
user.userId,
|
|
10111
10251
|
"activity.logs_viewed",
|
|
@@ -10212,7 +10352,7 @@ userRoutes.get("/activity-logs/export", async (c) => {
|
|
|
10212
10352
|
csvRows.push(row.join(","));
|
|
10213
10353
|
}
|
|
10214
10354
|
const csvContent = csvRows.join("\n");
|
|
10215
|
-
await
|
|
10355
|
+
await chunkYYV3XQOQ_cjs.logActivity(
|
|
10216
10356
|
db,
|
|
10217
10357
|
user.userId,
|
|
10218
10358
|
"activity.logs_exported",
|
|
@@ -11551,7 +11691,7 @@ var fileValidationSchema2 = zod.z.object({
|
|
|
11551
11691
|
// 50MB max
|
|
11552
11692
|
});
|
|
11553
11693
|
var adminMediaRoutes = new hono.Hono();
|
|
11554
|
-
adminMediaRoutes.use("*",
|
|
11694
|
+
adminMediaRoutes.use("*", chunkYYV3XQOQ_cjs.requireAuth());
|
|
11555
11695
|
adminMediaRoutes.get("/", async (c) => {
|
|
11556
11696
|
try {
|
|
11557
11697
|
const user = c.get("user");
|
|
@@ -12137,7 +12277,7 @@ adminMediaRoutes.put("/:id", async (c) => {
|
|
|
12137
12277
|
`);
|
|
12138
12278
|
}
|
|
12139
12279
|
});
|
|
12140
|
-
adminMediaRoutes.delete("/cleanup",
|
|
12280
|
+
adminMediaRoutes.delete("/cleanup", chunkYYV3XQOQ_cjs.requireRole("admin"), async (c) => {
|
|
12141
12281
|
try {
|
|
12142
12282
|
const db = c.env.DB;
|
|
12143
12283
|
const allMediaStmt = db.prepare("SELECT id, r2_key, filename FROM media WHERE deleted_at IS NULL");
|
|
@@ -13271,6 +13411,9 @@ function renderAuthSettingsForm(settings) {
|
|
|
13271
13411
|
}
|
|
13272
13412
|
|
|
13273
13413
|
// src/templates/pages/admin-plugin-settings.template.ts
|
|
13414
|
+
function escapeHtmlAttr(value) {
|
|
13415
|
+
return value.replace(/&/g, "&").replace(/"/g, """).replace(/'/g, "'").replace(/</g, "<").replace(/>/g, ">");
|
|
13416
|
+
}
|
|
13274
13417
|
function renderPluginSettingsPage(data) {
|
|
13275
13418
|
const { plugin, activity = [], user } = data;
|
|
13276
13419
|
const pageContent = `
|
|
@@ -13548,6 +13691,7 @@ function renderSettingsTab(plugin) {
|
|
|
13548
13691
|
const settings = plugin.settings || {};
|
|
13549
13692
|
const isSeedDataPlugin = plugin.id === "seed-data" || plugin.name === "seed-data";
|
|
13550
13693
|
const isAuthPlugin = plugin.id === "core-auth" || plugin.name === "core-auth";
|
|
13694
|
+
const isTurnstilePlugin = plugin.id === "turnstile" || plugin.name === "turnstile";
|
|
13551
13695
|
return `
|
|
13552
13696
|
${isSeedDataPlugin ? `
|
|
13553
13697
|
<div class="backdrop-blur-md bg-black/20 rounded-xl border border-white/10 shadow-xl p-6 mb-6">
|
|
@@ -13574,12 +13718,15 @@ function renderSettingsTab(plugin) {
|
|
|
13574
13718
|
${isAuthPlugin ? `
|
|
13575
13719
|
<h2 class="text-xl font-semibold text-white mb-4">Authentication Settings</h2>
|
|
13576
13720
|
<p class="text-gray-400 mb-6">Configure user registration fields and validation rules.</p>
|
|
13721
|
+
` : isTurnstilePlugin ? `
|
|
13722
|
+
<h2 class="text-xl font-semibold text-white mb-4">Cloudflare Turnstile Settings</h2>
|
|
13723
|
+
<p class="text-gray-400 mb-6">Configure CAPTCHA-free bot protection for your forms.</p>
|
|
13577
13724
|
` : `
|
|
13578
13725
|
<h2 class="text-xl font-semibold text-white mb-4">Plugin Settings</h2>
|
|
13579
13726
|
`}
|
|
13580
13727
|
|
|
13581
13728
|
<form id="settings-form" class="space-y-6">
|
|
13582
|
-
${isAuthPlugin && Object.keys(settings).length > 0 ? renderAuthSettingsForm(settings) : Object.keys(settings).length > 0 ? renderSettingsFields(settings) : renderNoSettings(plugin)}
|
|
13729
|
+
${isAuthPlugin && Object.keys(settings).length > 0 ? renderAuthSettingsForm(settings) : isTurnstilePlugin && Object.keys(settings).length > 0 ? renderTurnstileSettingsForm(settings) : Object.keys(settings).length > 0 ? renderSettingsFields(settings) : renderNoSettings(plugin)}
|
|
13583
13730
|
|
|
13584
13731
|
${Object.keys(settings).length > 0 ? `
|
|
13585
13732
|
<div class="flex items-center justify-end pt-6 border-t border-white/10">
|
|
@@ -13643,6 +13790,80 @@ function renderSettingsFields(settings) {
|
|
|
13643
13790
|
}
|
|
13644
13791
|
}).join("");
|
|
13645
13792
|
}
|
|
13793
|
+
function renderTurnstileSettingsForm(settings) {
|
|
13794
|
+
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";
|
|
13795
|
+
const selectClass = "backdrop-blur-sm bg-zinc-800 border border-white/20 rounded-lg px-3 py-2 text-white focus:border-blue-400 focus:outline-none transition-colors w-full [&>option]:bg-zinc-800 [&>option]:text-white";
|
|
13796
|
+
return `
|
|
13797
|
+
<!-- Enable Toggle -->
|
|
13798
|
+
<div class="flex items-center justify-between">
|
|
13799
|
+
<div>
|
|
13800
|
+
<label for="setting_enabled" class="text-sm font-medium text-gray-300">Enable Turnstile</label>
|
|
13801
|
+
<p class="text-xs text-gray-400">Enable or disable Turnstile verification globally</p>
|
|
13802
|
+
</div>
|
|
13803
|
+
<label class="relative inline-flex items-center cursor-pointer">
|
|
13804
|
+
<input type="checkbox" name="setting_enabled" id="setting_enabled" ${settings.enabled ? "checked" : ""} class="sr-only peer">
|
|
13805
|
+
<div class="w-11 h-6 bg-gray-600 peer-focus:outline-none peer-focus:ring-4 peer-focus:ring-blue-800 rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-blue-600"></div>
|
|
13806
|
+
</label>
|
|
13807
|
+
</div>
|
|
13808
|
+
|
|
13809
|
+
<!-- Site Key -->
|
|
13810
|
+
<div>
|
|
13811
|
+
<label for="setting_siteKey" class="block text-sm font-medium text-gray-300 mb-2">Site Key</label>
|
|
13812
|
+
<input type="text" name="setting_siteKey" id="setting_siteKey" value="${escapeHtmlAttr(settings.siteKey || "")}" placeholder="0x4AAAAAAAA..." class="${inputClass}">
|
|
13813
|
+
<p class="text-xs text-gray-400 mt-1">Your Cloudflare Turnstile site key (public)</p>
|
|
13814
|
+
</div>
|
|
13815
|
+
|
|
13816
|
+
<!-- Secret Key -->
|
|
13817
|
+
<div>
|
|
13818
|
+
<label for="setting_secretKey" class="block text-sm font-medium text-gray-300 mb-2">Secret Key</label>
|
|
13819
|
+
<input type="password" name="setting_secretKey" id="setting_secretKey" value="${escapeHtmlAttr(settings.secretKey || "")}" placeholder="0x4AAAAAAAA..." class="${inputClass}">
|
|
13820
|
+
<p class="text-xs text-gray-400 mt-1">Your Cloudflare Turnstile secret key (private)</p>
|
|
13821
|
+
</div>
|
|
13822
|
+
|
|
13823
|
+
<!-- Theme -->
|
|
13824
|
+
<div>
|
|
13825
|
+
<label for="setting_theme" class="block text-sm font-medium text-gray-300 mb-2">Widget Theme</label>
|
|
13826
|
+
<select name="setting_theme" id="setting_theme" class="${selectClass}" style="color: white; background-color: rgb(39, 39, 42);">
|
|
13827
|
+
<option value="auto" ${settings.theme === "auto" ? "selected" : ""} style="background-color: rgb(39, 39, 42); color: white;">Auto (matches page theme)</option>
|
|
13828
|
+
<option value="light" ${settings.theme === "light" ? "selected" : ""} style="background-color: rgb(39, 39, 42); color: white;">Light</option>
|
|
13829
|
+
<option value="dark" ${settings.theme === "dark" ? "selected" : ""} style="background-color: rgb(39, 39, 42); color: white;">Dark</option>
|
|
13830
|
+
</select>
|
|
13831
|
+
<p class="text-xs text-gray-400 mt-1">Visual appearance of the Turnstile widget</p>
|
|
13832
|
+
</div>
|
|
13833
|
+
|
|
13834
|
+
<!-- Size -->
|
|
13835
|
+
<div>
|
|
13836
|
+
<label for="setting_size" class="block text-sm font-medium text-gray-300 mb-2">Widget Size</label>
|
|
13837
|
+
<select name="setting_size" id="setting_size" class="${selectClass}" style="color: white; background-color: rgb(39, 39, 42);">
|
|
13838
|
+
<option value="normal" ${settings.size === "normal" ? "selected" : ""} style="background-color: rgb(39, 39, 42); color: white;">Normal (300x65px)</option>
|
|
13839
|
+
<option value="compact" ${settings.size === "compact" ? "selected" : ""} style="background-color: rgb(39, 39, 42); color: white;">Compact (130x120px)</option>
|
|
13840
|
+
</select>
|
|
13841
|
+
<p class="text-xs text-gray-400 mt-1">Size of the Turnstile challenge widget</p>
|
|
13842
|
+
</div>
|
|
13843
|
+
|
|
13844
|
+
<!-- Widget Mode -->
|
|
13845
|
+
<div>
|
|
13846
|
+
<label for="setting_mode" class="block text-sm font-medium text-gray-300 mb-2">Widget Mode</label>
|
|
13847
|
+
<select name="setting_mode" id="setting_mode" class="${selectClass}" style="color: white; background-color: rgb(39, 39, 42);">
|
|
13848
|
+
<option value="managed" ${!settings.mode || settings.mode === "managed" ? "selected" : ""} style="background-color: rgb(39, 39, 42); color: white;">Managed (Recommended) - Adaptive challenge</option>
|
|
13849
|
+
<option value="non-interactive" ${settings.mode === "non-interactive" ? "selected" : ""} style="background-color: rgb(39, 39, 42); color: white;">Non-Interactive - Always visible, minimal friction</option>
|
|
13850
|
+
<option value="invisible" ${settings.mode === "invisible" ? "selected" : ""} style="background-color: rgb(39, 39, 42); color: white;">Invisible - No visible widget</option>
|
|
13851
|
+
</select>
|
|
13852
|
+
<p class="text-xs text-gray-400 mt-1"><strong>Managed:</strong> Shows challenge only when needed. <strong>Non-Interactive:</strong> Always shows but doesn't require interaction. <strong>Invisible:</strong> Runs in background without UI.</p>
|
|
13853
|
+
</div>
|
|
13854
|
+
|
|
13855
|
+
<!-- Appearance (Pre-clearance) -->
|
|
13856
|
+
<div>
|
|
13857
|
+
<label for="setting_appearance" class="block text-sm font-medium text-gray-300 mb-2">Pre-clearance / Appearance</label>
|
|
13858
|
+
<select name="setting_appearance" id="setting_appearance" class="${selectClass}" style="color: white; background-color: rgb(39, 39, 42);">
|
|
13859
|
+
<option value="always" ${!settings.appearance || settings.appearance === "always" ? "selected" : ""} style="background-color: rgb(39, 39, 42); color: white;">Always - Pre-clearance enabled (verifies immediately)</option>
|
|
13860
|
+
<option value="execute" ${settings.appearance === "execute" ? "selected" : ""} style="background-color: rgb(39, 39, 42); color: white;">Execute - Challenge on form submit</option>
|
|
13861
|
+
<option value="interaction-only" ${settings.appearance === "interaction-only" ? "selected" : ""} style="background-color: rgb(39, 39, 42); color: white;">Interaction Only - Only after user interaction</option>
|
|
13862
|
+
</select>
|
|
13863
|
+
<p class="text-xs text-gray-400 mt-1">Controls when Turnstile verification occurs. <strong>Always:</strong> Verifies immediately (pre-clearance). <strong>Execute:</strong> Verifies on form submit. <strong>Interaction Only:</strong> Only after user interaction.</p>
|
|
13864
|
+
</div>
|
|
13865
|
+
`;
|
|
13866
|
+
}
|
|
13646
13867
|
function renderNoSettings(plugin) {
|
|
13647
13868
|
if (plugin.id === "seed-data" || plugin.name === "seed-data") {
|
|
13648
13869
|
return `
|
|
@@ -13782,7 +14003,7 @@ function formatTimestamp(timestamp) {
|
|
|
13782
14003
|
|
|
13783
14004
|
// src/routes/admin-plugins.ts
|
|
13784
14005
|
var adminPluginRoutes = new hono.Hono();
|
|
13785
|
-
adminPluginRoutes.use("*",
|
|
14006
|
+
adminPluginRoutes.use("*", chunkYYV3XQOQ_cjs.requireAuth());
|
|
13786
14007
|
var AVAILABLE_PLUGINS = [
|
|
13787
14008
|
{
|
|
13788
14009
|
id: "third-party-faq",
|
|
@@ -13874,6 +14095,19 @@ var AVAILABLE_PLUGINS = [
|
|
|
13874
14095
|
permissions: [],
|
|
13875
14096
|
dependencies: [],
|
|
13876
14097
|
is_core: false
|
|
14098
|
+
},
|
|
14099
|
+
{
|
|
14100
|
+
id: "turnstile",
|
|
14101
|
+
name: "turnstile-plugin",
|
|
14102
|
+
display_name: "Cloudflare Turnstile",
|
|
14103
|
+
description: "CAPTCHA-free bot protection for forms using Cloudflare Turnstile. Provides seamless spam prevention with configurable modes, themes, and pre-clearance options.",
|
|
14104
|
+
version: "1.0.0",
|
|
14105
|
+
author: "SonicJS Team",
|
|
14106
|
+
category: "security",
|
|
14107
|
+
icon: "\u{1F6E1}\uFE0F",
|
|
14108
|
+
permissions: [],
|
|
14109
|
+
dependencies: [],
|
|
14110
|
+
is_core: true
|
|
13877
14111
|
}
|
|
13878
14112
|
];
|
|
13879
14113
|
adminPluginRoutes.get("/", async (c) => {
|
|
@@ -14244,6 +14478,33 @@ adminPluginRoutes.post("/install", async (c) => {
|
|
|
14244
14478
|
});
|
|
14245
14479
|
return c.json({ success: true, plugin: easyMdxPlugin2 });
|
|
14246
14480
|
}
|
|
14481
|
+
if (body.name === "turnstile-plugin") {
|
|
14482
|
+
const turnstilePlugin = await pluginService.installPlugin({
|
|
14483
|
+
id: "turnstile",
|
|
14484
|
+
name: "turnstile-plugin",
|
|
14485
|
+
display_name: "Cloudflare Turnstile",
|
|
14486
|
+
description: "CAPTCHA-free bot protection for forms using Cloudflare Turnstile. Provides seamless spam prevention with configurable modes, themes, and pre-clearance options.",
|
|
14487
|
+
version: "1.0.0",
|
|
14488
|
+
author: "SonicJS Team",
|
|
14489
|
+
category: "security",
|
|
14490
|
+
icon: "\u{1F6E1}\uFE0F",
|
|
14491
|
+
permissions: [],
|
|
14492
|
+
dependencies: [],
|
|
14493
|
+
is_core: true,
|
|
14494
|
+
settings: {
|
|
14495
|
+
siteKey: "",
|
|
14496
|
+
secretKey: "",
|
|
14497
|
+
theme: "auto",
|
|
14498
|
+
size: "normal",
|
|
14499
|
+
mode: "managed",
|
|
14500
|
+
appearance: "always",
|
|
14501
|
+
preClearanceEnabled: false,
|
|
14502
|
+
preClearanceLevel: "managed",
|
|
14503
|
+
enabled: false
|
|
14504
|
+
}
|
|
14505
|
+
});
|
|
14506
|
+
return c.json({ success: true, plugin: turnstilePlugin });
|
|
14507
|
+
}
|
|
14247
14508
|
return c.json({ error: "Plugin not found in registry" }, 404);
|
|
14248
14509
|
} catch (error) {
|
|
14249
14510
|
console.error("Error installing plugin:", error);
|
|
@@ -15073,7 +15334,7 @@ function renderLogConfigPage(data) {
|
|
|
15073
15334
|
|
|
15074
15335
|
// src/routes/admin-logs.ts
|
|
15075
15336
|
var adminLogsRoutes = new hono.Hono();
|
|
15076
|
-
adminLogsRoutes.use("*",
|
|
15337
|
+
adminLogsRoutes.use("*", chunkYYV3XQOQ_cjs.requireAuth());
|
|
15077
15338
|
adminLogsRoutes.get("/", async (c) => {
|
|
15078
15339
|
try {
|
|
15079
15340
|
const user = c.get("user");
|
|
@@ -17401,9 +17662,9 @@ function renderStorageUsage(databaseSizeBytes, mediaSizeBytes) {
|
|
|
17401
17662
|
}
|
|
17402
17663
|
|
|
17403
17664
|
// src/routes/admin-dashboard.ts
|
|
17404
|
-
var VERSION =
|
|
17665
|
+
var VERSION = chunkZWV3EBZ7_cjs.getCoreVersion();
|
|
17405
17666
|
var router = new hono.Hono();
|
|
17406
|
-
router.use("*",
|
|
17667
|
+
router.use("*", chunkYYV3XQOQ_cjs.requireAuth());
|
|
17407
17668
|
router.get("/", async (c) => {
|
|
17408
17669
|
const user = c.get("user");
|
|
17409
17670
|
try {
|
|
@@ -19161,7 +19422,7 @@ function renderCollectionFormPage(data) {
|
|
|
19161
19422
|
|
|
19162
19423
|
// src/routes/admin-collections.ts
|
|
19163
19424
|
var adminCollectionsRoutes = new hono.Hono();
|
|
19164
|
-
adminCollectionsRoutes.use("*",
|
|
19425
|
+
adminCollectionsRoutes.use("*", chunkYYV3XQOQ_cjs.requireAuth());
|
|
19165
19426
|
adminCollectionsRoutes.get("/", async (c) => {
|
|
19166
19427
|
try {
|
|
19167
19428
|
const user = c.get("user");
|
|
@@ -19417,16 +19678,30 @@ adminCollectionsRoutes.get("/:id", async (c) => {
|
|
|
19417
19678
|
const schema = typeof collection.schema === "string" ? JSON.parse(collection.schema) : collection.schema;
|
|
19418
19679
|
if (schema && schema.properties) {
|
|
19419
19680
|
let fieldOrder = 0;
|
|
19420
|
-
fields = Object.entries(schema.properties).map(([fieldName, fieldConfig]) =>
|
|
19421
|
-
|
|
19422
|
-
|
|
19423
|
-
|
|
19424
|
-
|
|
19425
|
-
|
|
19426
|
-
|
|
19427
|
-
|
|
19428
|
-
|
|
19429
|
-
|
|
19681
|
+
fields = Object.entries(schema.properties).map(([fieldName, fieldConfig]) => {
|
|
19682
|
+
let fieldType = fieldConfig.type || "string";
|
|
19683
|
+
if (fieldConfig.enum) {
|
|
19684
|
+
fieldType = "select";
|
|
19685
|
+
} else if (fieldConfig.format === "richtext") {
|
|
19686
|
+
fieldType = "richtext";
|
|
19687
|
+
} else if (fieldConfig.format === "media") {
|
|
19688
|
+
fieldType = "media";
|
|
19689
|
+
} else if (fieldConfig.format === "date-time") {
|
|
19690
|
+
fieldType = "date";
|
|
19691
|
+
} else if (fieldConfig.type === "slug" || fieldConfig.format === "slug") {
|
|
19692
|
+
fieldType = "slug";
|
|
19693
|
+
}
|
|
19694
|
+
return {
|
|
19695
|
+
id: `schema-${fieldName}`,
|
|
19696
|
+
field_name: fieldName,
|
|
19697
|
+
field_type: fieldType,
|
|
19698
|
+
field_label: fieldConfig.title || fieldName,
|
|
19699
|
+
field_options: fieldConfig,
|
|
19700
|
+
field_order: fieldOrder++,
|
|
19701
|
+
is_required: fieldConfig.required === true || schema.required && schema.required.includes(fieldName),
|
|
19702
|
+
is_searchable: fieldConfig.searchable === true || false
|
|
19703
|
+
};
|
|
19704
|
+
});
|
|
19430
19705
|
}
|
|
19431
19706
|
} catch (e) {
|
|
19432
19707
|
console.error("Error parsing collection schema:", e);
|
|
@@ -19641,6 +19916,9 @@ adminCollectionsRoutes.post("/:id/fields", async (c) => {
|
|
|
19641
19916
|
fieldConfig.enum = parsedOptions.options || [];
|
|
19642
19917
|
} else if (fieldType === "media") {
|
|
19643
19918
|
fieldConfig.format = "media";
|
|
19919
|
+
} else if (fieldType === "slug") {
|
|
19920
|
+
fieldConfig.type = "slug";
|
|
19921
|
+
fieldConfig.format = "slug";
|
|
19644
19922
|
} else if (fieldType === "quill") {
|
|
19645
19923
|
fieldConfig.type = "quill";
|
|
19646
19924
|
} else if (fieldType === "mdxeditor") {
|
|
@@ -21324,7 +21602,7 @@ function renderDatabaseToolsSettings(settings) {
|
|
|
21324
21602
|
|
|
21325
21603
|
// src/routes/admin-settings.ts
|
|
21326
21604
|
var adminSettingsRoutes = new hono.Hono();
|
|
21327
|
-
adminSettingsRoutes.use("*",
|
|
21605
|
+
adminSettingsRoutes.use("*", chunkYYV3XQOQ_cjs.requireAuth());
|
|
21328
21606
|
function getMockSettings(user) {
|
|
21329
21607
|
return {
|
|
21330
21608
|
general: {
|
|
@@ -21492,7 +21770,7 @@ adminSettingsRoutes.get("/database-tools", (c) => {
|
|
|
21492
21770
|
adminSettingsRoutes.get("/api/migrations/status", async (c) => {
|
|
21493
21771
|
try {
|
|
21494
21772
|
const db = c.env.DB;
|
|
21495
|
-
const migrationService = new
|
|
21773
|
+
const migrationService = new chunkI4V3VZWF_cjs.MigrationService(db);
|
|
21496
21774
|
const status = await migrationService.getMigrationStatus();
|
|
21497
21775
|
return c.json({
|
|
21498
21776
|
success: true,
|
|
@@ -21516,7 +21794,7 @@ adminSettingsRoutes.post("/api/migrations/run", async (c) => {
|
|
|
21516
21794
|
}, 403);
|
|
21517
21795
|
}
|
|
21518
21796
|
const db = c.env.DB;
|
|
21519
|
-
const migrationService = new
|
|
21797
|
+
const migrationService = new chunkI4V3VZWF_cjs.MigrationService(db);
|
|
21520
21798
|
const result = await migrationService.runPendingMigrations();
|
|
21521
21799
|
return c.json({
|
|
21522
21800
|
success: result.success,
|
|
@@ -21534,7 +21812,7 @@ adminSettingsRoutes.post("/api/migrations/run", async (c) => {
|
|
|
21534
21812
|
adminSettingsRoutes.get("/api/migrations/validate", async (c) => {
|
|
21535
21813
|
try {
|
|
21536
21814
|
const db = c.env.DB;
|
|
21537
|
-
const migrationService = new
|
|
21815
|
+
const migrationService = new chunkI4V3VZWF_cjs.MigrationService(db);
|
|
21538
21816
|
const validation = await migrationService.validateSchema();
|
|
21539
21817
|
return c.json({
|
|
21540
21818
|
success: true,
|
|
@@ -21758,7 +22036,6 @@ var ROUTES_INFO = {
|
|
|
21758
22036
|
reference: "https://github.com/sonicjs/sonicjs"
|
|
21759
22037
|
};
|
|
21760
22038
|
|
|
21761
|
-
exports.PluginBuilder = PluginBuilder;
|
|
21762
22039
|
exports.ROUTES_INFO = ROUTES_INFO;
|
|
21763
22040
|
exports.adminCheckboxRoutes = adminCheckboxRoutes;
|
|
21764
22041
|
exports.adminCollectionsRoutes = adminCollectionsRoutes;
|
|
@@ -21776,8 +22053,9 @@ exports.api_default = api_default;
|
|
|
21776
22053
|
exports.api_media_default = api_media_default;
|
|
21777
22054
|
exports.api_system_default = api_system_default;
|
|
21778
22055
|
exports.auth_default = auth_default;
|
|
22056
|
+
exports.checkAdminUserExists = checkAdminUserExists;
|
|
21779
22057
|
exports.router = router;
|
|
21780
22058
|
exports.test_cleanup_default = test_cleanup_default;
|
|
21781
22059
|
exports.userRoutes = userRoutes;
|
|
21782
|
-
//# sourceMappingURL=chunk-
|
|
21783
|
-
//# sourceMappingURL=chunk-
|
|
22060
|
+
//# sourceMappingURL=chunk-UAQL2VWX.cjs.map
|
|
22061
|
+
//# sourceMappingURL=chunk-UAQL2VWX.cjs.map
|