@sonicjs-cms/core 2.0.4 → 2.0.5
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-LEG4KNFP.cjs → chunk-3JMOWGUU.cjs} +20 -2
- package/dist/chunk-3JMOWGUU.cjs.map +1 -0
- package/dist/{chunk-LH4Z7QID.js → chunk-6FR25MPC.js} +111 -3
- package/dist/chunk-6FR25MPC.js.map +1 -0
- package/dist/{chunk-3NVJ6W27.cjs → chunk-DOR2IU73.cjs} +111 -2
- package/dist/chunk-DOR2IU73.cjs.map +1 -0
- package/dist/{chunk-M6FPVS7E.js → chunk-G5KY3WJV.js} +16 -29
- package/dist/chunk-G5KY3WJV.js.map +1 -0
- package/dist/{chunk-CDBVZEWR.js → chunk-HSRPDEQQ.js} +20 -2
- package/dist/chunk-HSRPDEQQ.js.map +1 -0
- package/dist/{chunk-4BJGEGX5.cjs → chunk-IM5SDXOE.cjs} +19 -32
- package/dist/chunk-IM5SDXOE.cjs.map +1 -0
- package/dist/{chunk-CQ2VMJQO.js → chunk-LGC3TNCY.js} +252 -84
- package/dist/chunk-LGC3TNCY.js.map +1 -0
- package/dist/{chunk-RZW752PE.cjs → chunk-NPWWR6RI.cjs} +359 -191
- package/dist/chunk-NPWWR6RI.cjs.map +1 -0
- package/dist/{chunk-BRPONFW6.cjs → chunk-TRSHFTF6.cjs} +3 -3
- package/dist/{chunk-BRPONFW6.cjs.map → chunk-TRSHFTF6.cjs.map} +1 -1
- package/dist/{chunk-WKGONLHK.js → chunk-VSLEA22M.js} +3 -3
- package/dist/{chunk-WKGONLHK.js.map → chunk-VSLEA22M.js.map} +1 -1
- package/dist/index.cjs +876 -127
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +759 -9
- package/dist/index.js.map +1 -1
- package/dist/middleware.cjs +23 -23
- package/dist/middleware.js +2 -2
- package/dist/routes.cjs +25 -25
- package/dist/routes.js +5 -5
- package/dist/services.cjs +25 -21
- package/dist/services.js +2 -2
- package/dist/utils.cjs +11 -11
- package/dist/utils.js +1 -1
- package/migrations/006_plugin_system.sql +2 -2
- package/migrations/011_config_managed_collections.sql +1 -0
- package/migrations/018_settings_table.sql +23 -0
- package/package.json +1 -1
- package/dist/chunk-3NVJ6W27.cjs.map +0 -1
- package/dist/chunk-4BJGEGX5.cjs.map +0 -1
- package/dist/chunk-CDBVZEWR.js.map +0 -1
- package/dist/chunk-CQ2VMJQO.js.map +0 -1
- package/dist/chunk-LEG4KNFP.cjs.map +0 -1
- package/dist/chunk-LH4Z7QID.js.map +0 -1
- package/dist/chunk-M6FPVS7E.js.map +0 -1
- package/dist/chunk-RZW752PE.cjs.map +0 -1
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
4
|
-
var
|
|
5
|
-
var
|
|
3
|
+
var chunkDOR2IU73_cjs = require('./chunk-DOR2IU73.cjs');
|
|
4
|
+
var chunkIM5SDXOE_cjs = require('./chunk-IM5SDXOE.cjs');
|
|
5
|
+
var chunk3JMOWGUU_cjs = require('./chunk-3JMOWGUU.cjs');
|
|
6
6
|
var chunk3SPQ3J4N_cjs = require('./chunk-3SPQ3J4N.cjs');
|
|
7
|
-
var
|
|
7
|
+
var chunkTRSHFTF6_cjs = require('./chunk-TRSHFTF6.cjs');
|
|
8
8
|
var chunkRCQ2HIQD_cjs = require('./chunk-RCQ2HIQD.cjs');
|
|
9
9
|
var hono = require('hono');
|
|
10
10
|
var cors = require('hono/cors');
|
|
@@ -43,7 +43,7 @@ apiContentCrudRoutes.get("/:id", async (c) => {
|
|
|
43
43
|
}, 500);
|
|
44
44
|
}
|
|
45
45
|
});
|
|
46
|
-
apiContentCrudRoutes.post("/",
|
|
46
|
+
apiContentCrudRoutes.post("/", chunkIM5SDXOE_cjs.requireAuth(), async (c) => {
|
|
47
47
|
try {
|
|
48
48
|
const db = c.env.DB;
|
|
49
49
|
const user = c.get("user");
|
|
@@ -80,11 +80,11 @@ apiContentCrudRoutes.post("/", chunk4BJGEGX5_cjs.requireAuth(), async (c) => {
|
|
|
80
80
|
title,
|
|
81
81
|
JSON.stringify(data || {}),
|
|
82
82
|
status || "draft",
|
|
83
|
-
user?.userId || "
|
|
83
|
+
user?.userId || "system",
|
|
84
84
|
now,
|
|
85
85
|
now
|
|
86
86
|
).run();
|
|
87
|
-
const cache =
|
|
87
|
+
const cache = chunkDOR2IU73_cjs.getCacheService(chunkDOR2IU73_cjs.CACHE_CONFIGS.api);
|
|
88
88
|
await cache.invalidate(`content:list:${collectionId}:*`);
|
|
89
89
|
await cache.invalidate("content-filtered:*");
|
|
90
90
|
const getStmt = db.prepare("SELECT * FROM content WHERE id = ?");
|
|
@@ -109,7 +109,7 @@ apiContentCrudRoutes.post("/", chunk4BJGEGX5_cjs.requireAuth(), async (c) => {
|
|
|
109
109
|
}, 500);
|
|
110
110
|
}
|
|
111
111
|
});
|
|
112
|
-
apiContentCrudRoutes.put("/:id",
|
|
112
|
+
apiContentCrudRoutes.put("/:id", chunkIM5SDXOE_cjs.requireAuth(), async (c) => {
|
|
113
113
|
try {
|
|
114
114
|
const id = c.req.param("id");
|
|
115
115
|
const db = c.env.DB;
|
|
@@ -147,7 +147,7 @@ apiContentCrudRoutes.put("/:id", chunk4BJGEGX5_cjs.requireAuth(), async (c) => {
|
|
|
147
147
|
WHERE id = ?
|
|
148
148
|
`);
|
|
149
149
|
await updateStmt.bind(...params).run();
|
|
150
|
-
const cache =
|
|
150
|
+
const cache = chunkDOR2IU73_cjs.getCacheService(chunkDOR2IU73_cjs.CACHE_CONFIGS.api);
|
|
151
151
|
await cache.delete(cache.generateKey("content", id));
|
|
152
152
|
await cache.invalidate(`content:list:${existing.collection_id}:*`);
|
|
153
153
|
await cache.invalidate("content-filtered:*");
|
|
@@ -173,7 +173,7 @@ apiContentCrudRoutes.put("/:id", chunk4BJGEGX5_cjs.requireAuth(), async (c) => {
|
|
|
173
173
|
}, 500);
|
|
174
174
|
}
|
|
175
175
|
});
|
|
176
|
-
apiContentCrudRoutes.delete("/:id",
|
|
176
|
+
apiContentCrudRoutes.delete("/:id", chunkIM5SDXOE_cjs.requireAuth(), async (c) => {
|
|
177
177
|
try {
|
|
178
178
|
const id = c.req.param("id");
|
|
179
179
|
const db = c.env.DB;
|
|
@@ -184,7 +184,7 @@ apiContentCrudRoutes.delete("/:id", chunk4BJGEGX5_cjs.requireAuth(), async (c) =
|
|
|
184
184
|
}
|
|
185
185
|
const deleteStmt = db.prepare("DELETE FROM content WHERE id = ?");
|
|
186
186
|
await deleteStmt.bind(id).run();
|
|
187
|
-
const cache =
|
|
187
|
+
const cache = chunkDOR2IU73_cjs.getCacheService(chunkDOR2IU73_cjs.CACHE_CONFIGS.api);
|
|
188
188
|
await cache.delete(cache.generateKey("content", id));
|
|
189
189
|
await cache.invalidate(`content:list:${existing.collection_id}:*`);
|
|
190
190
|
await cache.invalidate("content-filtered:*");
|
|
@@ -209,7 +209,7 @@ apiRoutes.use("*", async (c, next) => {
|
|
|
209
209
|
c.header("X-Response-Time", `${totalTime}ms`);
|
|
210
210
|
});
|
|
211
211
|
apiRoutes.use("*", async (c, next) => {
|
|
212
|
-
const cacheEnabled = await
|
|
212
|
+
const cacheEnabled = await chunkIM5SDXOE_cjs.isPluginActive(c.env.DB, "core-cache");
|
|
213
213
|
c.set("cacheEnabled", cacheEnabled);
|
|
214
214
|
await next();
|
|
215
215
|
});
|
|
@@ -257,7 +257,7 @@ apiRoutes.get("/collections", async (c) => {
|
|
|
257
257
|
try {
|
|
258
258
|
const db = c.env.DB;
|
|
259
259
|
const cacheEnabled = c.get("cacheEnabled");
|
|
260
|
-
const cache =
|
|
260
|
+
const cache = chunkDOR2IU73_cjs.getCacheService(chunkDOR2IU73_cjs.CACHE_CONFIGS.api);
|
|
261
261
|
const cacheKey = cache.generateKey("collections", "all");
|
|
262
262
|
if (cacheEnabled) {
|
|
263
263
|
const cacheResult = await cache.getWithSource(cacheKey);
|
|
@@ -334,12 +334,12 @@ apiRoutes.get("/content", async (c) => {
|
|
|
334
334
|
});
|
|
335
335
|
}
|
|
336
336
|
}
|
|
337
|
-
const filter =
|
|
337
|
+
const filter = chunkTRSHFTF6_cjs.QueryFilterBuilder.parseFromQuery(queryParams);
|
|
338
338
|
if (!filter.limit) {
|
|
339
339
|
filter.limit = 50;
|
|
340
340
|
}
|
|
341
341
|
filter.limit = Math.min(filter.limit, 1e3);
|
|
342
|
-
const builder = new
|
|
342
|
+
const builder = new chunkTRSHFTF6_cjs.QueryFilterBuilder();
|
|
343
343
|
const queryResult = builder.build("content", filter);
|
|
344
344
|
if (queryResult.errors.length > 0) {
|
|
345
345
|
return c.json({
|
|
@@ -348,7 +348,7 @@ apiRoutes.get("/content", async (c) => {
|
|
|
348
348
|
}, 400);
|
|
349
349
|
}
|
|
350
350
|
const cacheEnabled = c.get("cacheEnabled");
|
|
351
|
-
const cache =
|
|
351
|
+
const cache = chunkDOR2IU73_cjs.getCacheService(chunkDOR2IU73_cjs.CACHE_CONFIGS.api);
|
|
352
352
|
const cacheKey = cache.generateKey("content-filtered", JSON.stringify({ filter, query: queryResult.sql }));
|
|
353
353
|
if (cacheEnabled) {
|
|
354
354
|
const cacheResult = await cache.getWithSource(cacheKey);
|
|
@@ -426,7 +426,7 @@ apiRoutes.get("/collections/:collection/content", async (c) => {
|
|
|
426
426
|
if (!collectionResult) {
|
|
427
427
|
return c.json({ error: "Collection not found" }, 404);
|
|
428
428
|
}
|
|
429
|
-
const filter =
|
|
429
|
+
const filter = chunkTRSHFTF6_cjs.QueryFilterBuilder.parseFromQuery(queryParams);
|
|
430
430
|
if (!filter.where) {
|
|
431
431
|
filter.where = { and: [] };
|
|
432
432
|
}
|
|
@@ -442,7 +442,7 @@ apiRoutes.get("/collections/:collection/content", async (c) => {
|
|
|
442
442
|
filter.limit = 50;
|
|
443
443
|
}
|
|
444
444
|
filter.limit = Math.min(filter.limit, 1e3);
|
|
445
|
-
const builder = new
|
|
445
|
+
const builder = new chunkTRSHFTF6_cjs.QueryFilterBuilder();
|
|
446
446
|
const queryResult = builder.build("content", filter);
|
|
447
447
|
if (queryResult.errors.length > 0) {
|
|
448
448
|
return c.json({
|
|
@@ -451,7 +451,7 @@ apiRoutes.get("/collections/:collection/content", async (c) => {
|
|
|
451
451
|
}, 400);
|
|
452
452
|
}
|
|
453
453
|
const cacheEnabled = c.get("cacheEnabled");
|
|
454
|
-
const cache =
|
|
454
|
+
const cache = chunkDOR2IU73_cjs.getCacheService(chunkDOR2IU73_cjs.CACHE_CONFIGS.api);
|
|
455
455
|
const cacheKey = cache.generateKey("collection-content-filtered", `${collection}:${JSON.stringify({ filter, query: queryResult.sql })}`);
|
|
456
456
|
if (cacheEnabled) {
|
|
457
457
|
const cacheResult = await cache.getWithSource(cacheKey);
|
|
@@ -567,7 +567,7 @@ var fileValidationSchema = zod.z.object({
|
|
|
567
567
|
// 50MB max
|
|
568
568
|
});
|
|
569
569
|
var apiMediaRoutes = new hono.Hono();
|
|
570
|
-
apiMediaRoutes.use("*",
|
|
570
|
+
apiMediaRoutes.use("*", chunkIM5SDXOE_cjs.requireAuth());
|
|
571
571
|
apiMediaRoutes.post("/upload", async (c) => {
|
|
572
572
|
try {
|
|
573
573
|
const user = c.get("user");
|
|
@@ -673,6 +673,7 @@ apiMediaRoutes.post("/upload", async (c) => {
|
|
|
673
673
|
size: mediaRecord.size,
|
|
674
674
|
width: mediaRecord.width,
|
|
675
675
|
height: mediaRecord.height,
|
|
676
|
+
r2_key: mediaRecord.r2_key,
|
|
676
677
|
publicUrl: mediaRecord.public_url,
|
|
677
678
|
thumbnailUrl: mediaRecord.thumbnail_url,
|
|
678
679
|
uploadedAt: new Date(mediaRecord.uploaded_at * 1e3).toISOString()
|
|
@@ -799,6 +800,7 @@ apiMediaRoutes.post("/upload-multiple", async (c) => {
|
|
|
799
800
|
size: mediaRecord.size,
|
|
800
801
|
width: mediaRecord.width,
|
|
801
802
|
height: mediaRecord.height,
|
|
803
|
+
r2_key: mediaRecord.r2_key,
|
|
802
804
|
publicUrl: mediaRecord.public_url,
|
|
803
805
|
thumbnailUrl: mediaRecord.thumbnail_url,
|
|
804
806
|
uploadedAt: new Date(mediaRecord.uploaded_at * 1e3).toISOString()
|
|
@@ -1309,8 +1311,8 @@ apiSystemRoutes.get("/env", (c) => {
|
|
|
1309
1311
|
});
|
|
1310
1312
|
var api_system_default = apiSystemRoutes;
|
|
1311
1313
|
var adminApiRoutes = new hono.Hono();
|
|
1312
|
-
adminApiRoutes.use("*",
|
|
1313
|
-
adminApiRoutes.use("*",
|
|
1314
|
+
adminApiRoutes.use("*", chunkIM5SDXOE_cjs.requireAuth());
|
|
1315
|
+
adminApiRoutes.use("*", chunkIM5SDXOE_cjs.requireRole(["admin", "editor"]));
|
|
1314
1316
|
adminApiRoutes.get("/stats", async (c) => {
|
|
1315
1317
|
try {
|
|
1316
1318
|
const db = c.env.DB;
|
|
@@ -1442,8 +1444,12 @@ adminApiRoutes.get("/activity", async (c) => {
|
|
|
1442
1444
|
});
|
|
1443
1445
|
var createCollectionSchema = zod.z.object({
|
|
1444
1446
|
name: zod.z.string().min(1).max(255).regex(/^[a-z0-9_]+$/, "Must contain only lowercase letters, numbers, and underscores"),
|
|
1445
|
-
|
|
1447
|
+
displayName: zod.z.string().min(1).max(255).optional(),
|
|
1448
|
+
display_name: zod.z.string().min(1).max(255).optional(),
|
|
1446
1449
|
description: zod.z.string().optional()
|
|
1450
|
+
}).refine((data) => data.displayName || data.display_name, {
|
|
1451
|
+
message: "Either displayName or display_name is required",
|
|
1452
|
+
path: ["displayName"]
|
|
1447
1453
|
});
|
|
1448
1454
|
var updateCollectionSchema = zod.z.object({
|
|
1449
1455
|
display_name: zod.z.string().min(1).max(255).optional(),
|
|
@@ -1530,15 +1536,16 @@ adminApiRoutes.get("/collections/:id", async (c) => {
|
|
|
1530
1536
|
updated_at: Number(row.updated_at)
|
|
1531
1537
|
}));
|
|
1532
1538
|
return c.json({
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1539
|
+
id: collection.id,
|
|
1540
|
+
name: collection.name,
|
|
1541
|
+
display_name: collection.display_name,
|
|
1542
|
+
description: collection.description,
|
|
1543
|
+
is_active: collection.is_active === 1,
|
|
1544
|
+
managed: collection.managed === 1,
|
|
1545
|
+
schema: collection.schema ? JSON.parse(collection.schema) : null,
|
|
1546
|
+
created_at: Number(collection.created_at),
|
|
1547
|
+
updated_at: Number(collection.updated_at),
|
|
1548
|
+
fields
|
|
1542
1549
|
});
|
|
1543
1550
|
} catch (error) {
|
|
1544
1551
|
console.error("Error fetching collection:", error);
|
|
@@ -1547,7 +1554,16 @@ adminApiRoutes.get("/collections/:id", async (c) => {
|
|
|
1547
1554
|
});
|
|
1548
1555
|
adminApiRoutes.post("/collections", async (c) => {
|
|
1549
1556
|
try {
|
|
1550
|
-
const
|
|
1557
|
+
const contentType = c.req.header("Content-Type");
|
|
1558
|
+
if (!contentType || !contentType.includes("application/json")) {
|
|
1559
|
+
return c.json({ error: "Content-Type must be application/json" }, 400);
|
|
1560
|
+
}
|
|
1561
|
+
let body;
|
|
1562
|
+
try {
|
|
1563
|
+
body = await c.req.json();
|
|
1564
|
+
} catch (e) {
|
|
1565
|
+
return c.json({ error: "Invalid JSON in request body" }, 400);
|
|
1566
|
+
}
|
|
1551
1567
|
const validation = createCollectionSchema.safeParse(body);
|
|
1552
1568
|
if (!validation.success) {
|
|
1553
1569
|
return c.json({ error: "Validation failed", details: validation.error.errors }, 400);
|
|
@@ -1555,6 +1571,7 @@ adminApiRoutes.post("/collections", async (c) => {
|
|
|
1555
1571
|
const validatedData = validation.data;
|
|
1556
1572
|
const db = c.env.DB;
|
|
1557
1573
|
const user = c.get("user");
|
|
1574
|
+
const displayName = validatedData.displayName || validatedData.display_name || "";
|
|
1558
1575
|
const existingStmt = db.prepare("SELECT id FROM collections WHERE name = ?");
|
|
1559
1576
|
const existing = await existingStmt.bind(validatedData.name).first();
|
|
1560
1577
|
if (existing) {
|
|
@@ -1591,7 +1608,7 @@ adminApiRoutes.post("/collections", async (c) => {
|
|
|
1591
1608
|
await insertStmt.bind(
|
|
1592
1609
|
collectionId,
|
|
1593
1610
|
validatedData.name,
|
|
1594
|
-
|
|
1611
|
+
displayName,
|
|
1595
1612
|
validatedData.description || null,
|
|
1596
1613
|
JSON.stringify(basicSchema),
|
|
1597
1614
|
1,
|
|
@@ -1606,13 +1623,11 @@ adminApiRoutes.post("/collections", async (c) => {
|
|
|
1606
1623
|
console.error("Error clearing cache:", e);
|
|
1607
1624
|
}
|
|
1608
1625
|
return c.json({
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
created_at: now
|
|
1615
|
-
}
|
|
1626
|
+
id: collectionId,
|
|
1627
|
+
name: validatedData.name,
|
|
1628
|
+
displayName,
|
|
1629
|
+
description: validatedData.description,
|
|
1630
|
+
created_at: now
|
|
1616
1631
|
}, 201);
|
|
1617
1632
|
} catch (error) {
|
|
1618
1633
|
console.error("Error creating collection:", error);
|
|
@@ -1676,6 +1691,11 @@ adminApiRoutes.delete("/collections/:id", async (c) => {
|
|
|
1676
1691
|
try {
|
|
1677
1692
|
const id = c.req.param("id");
|
|
1678
1693
|
const db = c.env.DB;
|
|
1694
|
+
const collectionStmt = db.prepare("SELECT name FROM collections WHERE id = ?");
|
|
1695
|
+
const collection = await collectionStmt.bind(id).first();
|
|
1696
|
+
if (!collection) {
|
|
1697
|
+
return c.json({ error: "Collection not found" }, 404);
|
|
1698
|
+
}
|
|
1679
1699
|
const contentStmt = db.prepare("SELECT COUNT(*) as count FROM content WHERE collection_id = ?");
|
|
1680
1700
|
const contentResult = await contentStmt.bind(id).first();
|
|
1681
1701
|
if (contentResult && contentResult.count > 0) {
|
|
@@ -1683,17 +1703,13 @@ adminApiRoutes.delete("/collections/:id", async (c) => {
|
|
|
1683
1703
|
error: `Cannot delete collection: it contains ${contentResult.count} content item(s). Delete all content first.`
|
|
1684
1704
|
}, 400);
|
|
1685
1705
|
}
|
|
1686
|
-
const collectionStmt = db.prepare("SELECT name FROM collections WHERE id = ?");
|
|
1687
|
-
const collection = await collectionStmt.bind(id).first();
|
|
1688
1706
|
const deleteFieldsStmt = db.prepare("DELETE FROM content_fields WHERE collection_id = ?");
|
|
1689
1707
|
await deleteFieldsStmt.bind(id).run();
|
|
1690
1708
|
const deleteStmt = db.prepare("DELETE FROM collections WHERE id = ?");
|
|
1691
1709
|
await deleteStmt.bind(id).run();
|
|
1692
1710
|
try {
|
|
1693
1711
|
await c.env.CACHE_KV.delete("cache:collections:all");
|
|
1694
|
-
|
|
1695
|
-
await c.env.CACHE_KV.delete(`cache:collection:${collection.name}`);
|
|
1696
|
-
}
|
|
1712
|
+
await c.env.CACHE_KV.delete(`cache:collection:${collection.name}`);
|
|
1697
1713
|
} catch (e) {
|
|
1698
1714
|
console.error("Error clearing cache:", e);
|
|
1699
1715
|
}
|
|
@@ -2126,7 +2142,7 @@ authRoutes.post(
|
|
|
2126
2142
|
if (existingUser) {
|
|
2127
2143
|
return c.json({ error: "User with this email or username already exists" }, 400);
|
|
2128
2144
|
}
|
|
2129
|
-
const passwordHash = await
|
|
2145
|
+
const passwordHash = await chunkIM5SDXOE_cjs.AuthManager.hashPassword(password);
|
|
2130
2146
|
const userId = crypto.randomUUID();
|
|
2131
2147
|
const now = /* @__PURE__ */ new Date();
|
|
2132
2148
|
await db.prepare(`
|
|
@@ -2146,7 +2162,7 @@ authRoutes.post(
|
|
|
2146
2162
|
now.getTime(),
|
|
2147
2163
|
now.getTime()
|
|
2148
2164
|
).run();
|
|
2149
|
-
const token = await
|
|
2165
|
+
const token = await chunkIM5SDXOE_cjs.AuthManager.generateToken(userId, normalizedEmail, "viewer");
|
|
2150
2166
|
cookie.setCookie(c, "auth_token", token, {
|
|
2151
2167
|
httpOnly: true,
|
|
2152
2168
|
secure: true,
|
|
@@ -2181,7 +2197,7 @@ authRoutes.post("/login", async (c) => {
|
|
|
2181
2197
|
const { email, password } = validation.data;
|
|
2182
2198
|
const db = c.env.DB;
|
|
2183
2199
|
const normalizedEmail = email.toLowerCase();
|
|
2184
|
-
const cache =
|
|
2200
|
+
const cache = chunkDOR2IU73_cjs.getCacheService(chunkDOR2IU73_cjs.CACHE_CONFIGS.user);
|
|
2185
2201
|
let user = await cache.get(cache.generateKey("user", `email:${normalizedEmail}`));
|
|
2186
2202
|
if (!user) {
|
|
2187
2203
|
user = await db.prepare("SELECT * FROM users WHERE email = ? AND is_active = 1").bind(normalizedEmail).first();
|
|
@@ -2193,11 +2209,11 @@ authRoutes.post("/login", async (c) => {
|
|
|
2193
2209
|
if (!user) {
|
|
2194
2210
|
return c.json({ error: "Invalid email or password" }, 401);
|
|
2195
2211
|
}
|
|
2196
|
-
const isValidPassword = await
|
|
2212
|
+
const isValidPassword = await chunkIM5SDXOE_cjs.AuthManager.verifyPassword(password, user.password_hash);
|
|
2197
2213
|
if (!isValidPassword) {
|
|
2198
2214
|
return c.json({ error: "Invalid email or password" }, 401);
|
|
2199
2215
|
}
|
|
2200
|
-
const token = await
|
|
2216
|
+
const token = await chunkIM5SDXOE_cjs.AuthManager.generateToken(user.id, user.email, user.role);
|
|
2201
2217
|
cookie.setCookie(c, "auth_token", token, {
|
|
2202
2218
|
httpOnly: true,
|
|
2203
2219
|
secure: true,
|
|
@@ -2246,7 +2262,7 @@ authRoutes.get("/logout", (c) => {
|
|
|
2246
2262
|
});
|
|
2247
2263
|
return c.redirect("/auth/login?message=You have been logged out successfully");
|
|
2248
2264
|
});
|
|
2249
|
-
authRoutes.get("/me",
|
|
2265
|
+
authRoutes.get("/me", chunkIM5SDXOE_cjs.requireAuth(), async (c) => {
|
|
2250
2266
|
try {
|
|
2251
2267
|
const user = c.get("user");
|
|
2252
2268
|
if (!user) {
|
|
@@ -2263,13 +2279,13 @@ authRoutes.get("/me", chunk4BJGEGX5_cjs.requireAuth(), async (c) => {
|
|
|
2263
2279
|
return c.json({ error: "Failed to get user" }, 500);
|
|
2264
2280
|
}
|
|
2265
2281
|
});
|
|
2266
|
-
authRoutes.post("/refresh",
|
|
2282
|
+
authRoutes.post("/refresh", chunkIM5SDXOE_cjs.requireAuth(), async (c) => {
|
|
2267
2283
|
try {
|
|
2268
2284
|
const user = c.get("user");
|
|
2269
2285
|
if (!user) {
|
|
2270
2286
|
return c.json({ error: "Not authenticated" }, 401);
|
|
2271
2287
|
}
|
|
2272
|
-
const token = await
|
|
2288
|
+
const token = await chunkIM5SDXOE_cjs.AuthManager.generateToken(user.userId, user.email, user.role);
|
|
2273
2289
|
cookie.setCookie(c, "auth_token", token, {
|
|
2274
2290
|
httpOnly: true,
|
|
2275
2291
|
secure: true,
|
|
@@ -2319,7 +2335,7 @@ authRoutes.post("/register/form", async (c) => {
|
|
|
2319
2335
|
</div>
|
|
2320
2336
|
`);
|
|
2321
2337
|
}
|
|
2322
|
-
const passwordHash = await
|
|
2338
|
+
const passwordHash = await chunkIM5SDXOE_cjs.AuthManager.hashPassword(password);
|
|
2323
2339
|
const userId = crypto.randomUUID();
|
|
2324
2340
|
const now = /* @__PURE__ */ new Date();
|
|
2325
2341
|
await db.prepare(`
|
|
@@ -2339,7 +2355,7 @@ authRoutes.post("/register/form", async (c) => {
|
|
|
2339
2355
|
now.getTime(),
|
|
2340
2356
|
now.getTime()
|
|
2341
2357
|
).run();
|
|
2342
|
-
const token = await
|
|
2358
|
+
const token = await chunkIM5SDXOE_cjs.AuthManager.generateToken(userId, normalizedEmail, "admin");
|
|
2343
2359
|
cookie.setCookie(c, "auth_token", token, {
|
|
2344
2360
|
httpOnly: true,
|
|
2345
2361
|
secure: false,
|
|
@@ -2390,7 +2406,7 @@ authRoutes.post("/login/form", async (c) => {
|
|
|
2390
2406
|
</div>
|
|
2391
2407
|
`);
|
|
2392
2408
|
}
|
|
2393
|
-
const isValidPassword = await
|
|
2409
|
+
const isValidPassword = await chunkIM5SDXOE_cjs.AuthManager.verifyPassword(password, user.password_hash);
|
|
2394
2410
|
if (!isValidPassword) {
|
|
2395
2411
|
return c.html(html.html`
|
|
2396
2412
|
<div class="bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded">
|
|
@@ -2398,7 +2414,7 @@ authRoutes.post("/login/form", async (c) => {
|
|
|
2398
2414
|
</div>
|
|
2399
2415
|
`);
|
|
2400
2416
|
}
|
|
2401
|
-
const token = await
|
|
2417
|
+
const token = await chunkIM5SDXOE_cjs.AuthManager.generateToken(user.id, user.email, user.role);
|
|
2402
2418
|
cookie.setCookie(c, "auth_token", token, {
|
|
2403
2419
|
httpOnly: true,
|
|
2404
2420
|
secure: false,
|
|
@@ -2467,7 +2483,7 @@ authRoutes.post("/seed-admin", async (c) => {
|
|
|
2467
2483
|
}
|
|
2468
2484
|
});
|
|
2469
2485
|
}
|
|
2470
|
-
const passwordHash = await
|
|
2486
|
+
const passwordHash = await chunkIM5SDXOE_cjs.AuthManager.hashPassword("admin123");
|
|
2471
2487
|
const userId = "admin-user-id";
|
|
2472
2488
|
const now = Date.now();
|
|
2473
2489
|
const adminEmail = "admin@sonicjs.com".toLowerCase();
|
|
@@ -2687,7 +2703,7 @@ authRoutes.post("/accept-invitation", async (c) => {
|
|
|
2687
2703
|
if (existingUsername) {
|
|
2688
2704
|
return c.json({ error: "Username is already taken" }, 400);
|
|
2689
2705
|
}
|
|
2690
|
-
const passwordHash = await
|
|
2706
|
+
const passwordHash = await chunkIM5SDXOE_cjs.AuthManager.hashPassword(password);
|
|
2691
2707
|
const updateStmt = db.prepare(`
|
|
2692
2708
|
UPDATE users SET
|
|
2693
2709
|
username = ?,
|
|
@@ -2706,7 +2722,7 @@ authRoutes.post("/accept-invitation", async (c) => {
|
|
|
2706
2722
|
Date.now(),
|
|
2707
2723
|
invitedUser.id
|
|
2708
2724
|
).run();
|
|
2709
|
-
const authToken = await
|
|
2725
|
+
const authToken = await chunkIM5SDXOE_cjs.AuthManager.generateToken(invitedUser.id, invitedUser.email, invitedUser.role);
|
|
2710
2726
|
cookie.setCookie(c, "auth_token", authToken, {
|
|
2711
2727
|
httpOnly: true,
|
|
2712
2728
|
secure: true,
|
|
@@ -2936,7 +2952,7 @@ authRoutes.post("/reset-password", async (c) => {
|
|
|
2936
2952
|
if (Date.now() > user.password_reset_expires) {
|
|
2937
2953
|
return c.json({ error: "Reset token has expired" }, 400);
|
|
2938
2954
|
}
|
|
2939
|
-
const newPasswordHash = await
|
|
2955
|
+
const newPasswordHash = await chunkIM5SDXOE_cjs.AuthManager.hashPassword(password);
|
|
2940
2956
|
try {
|
|
2941
2957
|
const historyStmt = db.prepare(`
|
|
2942
2958
|
INSERT INTO password_history (id, user_id, password_hash, created_at)
|
|
@@ -4741,9 +4757,9 @@ var isPluginActive2 = () => false;
|
|
|
4741
4757
|
|
|
4742
4758
|
// src/routes/admin-content.ts
|
|
4743
4759
|
var adminContentRoutes = new hono.Hono();
|
|
4744
|
-
adminContentRoutes.use("*",
|
|
4760
|
+
adminContentRoutes.use("*", chunkIM5SDXOE_cjs.requireAuth());
|
|
4745
4761
|
async function getCollectionFields(db, collectionId) {
|
|
4746
|
-
const cache =
|
|
4762
|
+
const cache = chunkDOR2IU73_cjs.getCacheService(chunkDOR2IU73_cjs.CACHE_CONFIGS.collection);
|
|
4747
4763
|
return cache.getOrSet(
|
|
4748
4764
|
cache.generateKey("fields", collectionId),
|
|
4749
4765
|
async () => {
|
|
@@ -4767,7 +4783,7 @@ async function getCollectionFields(db, collectionId) {
|
|
|
4767
4783
|
);
|
|
4768
4784
|
}
|
|
4769
4785
|
async function getCollection(db, collectionId) {
|
|
4770
|
-
const cache =
|
|
4786
|
+
const cache = chunkDOR2IU73_cjs.getCacheService(chunkDOR2IU73_cjs.CACHE_CONFIGS.collection);
|
|
4771
4787
|
return cache.getOrSet(
|
|
4772
4788
|
cache.generateKey("collection", collectionId),
|
|
4773
4789
|
async () => {
|
|
@@ -5023,7 +5039,7 @@ adminContentRoutes.get("/:id/edit", async (c) => {
|
|
|
5023
5039
|
const db = c.env.DB;
|
|
5024
5040
|
const url = new URL(c.req.url);
|
|
5025
5041
|
const referrerParams = url.searchParams.get("ref") || "";
|
|
5026
|
-
const cache =
|
|
5042
|
+
const cache = chunkDOR2IU73_cjs.getCacheService(chunkDOR2IU73_cjs.CACHE_CONFIGS.content);
|
|
5027
5043
|
const content = await cache.getOrSet(
|
|
5028
5044
|
cache.generateKey("content", id),
|
|
5029
5045
|
async () => {
|
|
@@ -5192,11 +5208,11 @@ adminContentRoutes.post("/", async (c) => {
|
|
|
5192
5208
|
const now = Date.now();
|
|
5193
5209
|
const insertStmt = db.prepare(`
|
|
5194
5210
|
INSERT INTO content (
|
|
5195
|
-
id, collection_id, slug, title, data, status,
|
|
5211
|
+
id, collection_id, slug, title, data, status,
|
|
5196
5212
|
scheduled_publish_at, scheduled_unpublish_at,
|
|
5197
|
-
meta_title, meta_description, author_id, created_at, updated_at
|
|
5213
|
+
meta_title, meta_description, author_id, created_by, created_at, updated_at
|
|
5198
5214
|
)
|
|
5199
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
5215
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
5200
5216
|
`);
|
|
5201
5217
|
await insertStmt.bind(
|
|
5202
5218
|
contentId,
|
|
@@ -5210,10 +5226,11 @@ adminContentRoutes.post("/", async (c) => {
|
|
|
5210
5226
|
data.meta_title || null,
|
|
5211
5227
|
data.meta_description || null,
|
|
5212
5228
|
user?.userId || "unknown",
|
|
5229
|
+
user?.userId || "unknown",
|
|
5213
5230
|
now,
|
|
5214
5231
|
now
|
|
5215
5232
|
).run();
|
|
5216
|
-
const cache =
|
|
5233
|
+
const cache = chunkDOR2IU73_cjs.getCacheService(chunkDOR2IU73_cjs.CACHE_CONFIGS.content);
|
|
5217
5234
|
await cache.invalidate(`content:list:${collectionId}:*`);
|
|
5218
5235
|
const versionStmt = db.prepare(`
|
|
5219
5236
|
INSERT INTO content_versions (id, content_id, version, data, author_id, created_at)
|
|
@@ -5361,7 +5378,7 @@ adminContentRoutes.put("/:id", async (c) => {
|
|
|
5361
5378
|
now,
|
|
5362
5379
|
id
|
|
5363
5380
|
).run();
|
|
5364
|
-
const cache =
|
|
5381
|
+
const cache = chunkDOR2IU73_cjs.getCacheService(chunkDOR2IU73_cjs.CACHE_CONFIGS.content);
|
|
5365
5382
|
await cache.delete(cache.generateKey("content", id));
|
|
5366
5383
|
await cache.invalidate(`content:list:${existingContent.collection_id}:*`);
|
|
5367
5384
|
const existingData = JSON.parse(existingContent.data || "{}");
|
|
@@ -5511,10 +5528,10 @@ adminContentRoutes.post("/duplicate", async (c) => {
|
|
|
5511
5528
|
originalData.title = `${originalData.title || "Untitled"} (Copy)`;
|
|
5512
5529
|
const insertStmt = db.prepare(`
|
|
5513
5530
|
INSERT INTO content (
|
|
5514
|
-
id, collection_id, slug, title, data, status,
|
|
5515
|
-
author_id, created_at, updated_at
|
|
5531
|
+
id, collection_id, slug, title, data, status,
|
|
5532
|
+
author_id, created_by, created_at, updated_at
|
|
5516
5533
|
)
|
|
5517
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
5534
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
5518
5535
|
`);
|
|
5519
5536
|
await insertStmt.bind(
|
|
5520
5537
|
newId,
|
|
@@ -5525,6 +5542,7 @@ adminContentRoutes.post("/duplicate", async (c) => {
|
|
|
5525
5542
|
"draft",
|
|
5526
5543
|
// Always start as draft
|
|
5527
5544
|
user?.userId || "unknown",
|
|
5545
|
+
user?.userId || "unknown",
|
|
5528
5546
|
now,
|
|
5529
5547
|
now
|
|
5530
5548
|
).run();
|
|
@@ -5654,7 +5672,7 @@ adminContentRoutes.post("/bulk-action", async (c) => {
|
|
|
5654
5672
|
} else {
|
|
5655
5673
|
return c.json({ success: false, error: "Invalid action" });
|
|
5656
5674
|
}
|
|
5657
|
-
const cache =
|
|
5675
|
+
const cache = chunkDOR2IU73_cjs.getCacheService(chunkDOR2IU73_cjs.CACHE_CONFIGS.content);
|
|
5658
5676
|
for (const contentId of ids) {
|
|
5659
5677
|
await cache.delete(cache.generateKey("content", contentId));
|
|
5660
5678
|
}
|
|
@@ -5682,7 +5700,7 @@ adminContentRoutes.delete("/:id", async (c) => {
|
|
|
5682
5700
|
WHERE id = ?
|
|
5683
5701
|
`);
|
|
5684
5702
|
await deleteStmt.bind(now, id).run();
|
|
5685
|
-
const cache =
|
|
5703
|
+
const cache = chunkDOR2IU73_cjs.getCacheService(chunkDOR2IU73_cjs.CACHE_CONFIGS.content);
|
|
5686
5704
|
await cache.delete(cache.generateKey("content", id));
|
|
5687
5705
|
await cache.invalidate("content:list:*");
|
|
5688
5706
|
return c.html(`
|
|
@@ -5875,6 +5893,11 @@ var admin_content_default = adminContentRoutes;
|
|
|
5875
5893
|
|
|
5876
5894
|
// src/templates/pages/admin-profile.template.ts
|
|
5877
5895
|
chunk3SPQ3J4N_cjs.init_admin_layout_catalyst_template();
|
|
5896
|
+
function renderAvatarImage(avatarUrl, firstName, lastName) {
|
|
5897
|
+
return `<div id="avatar-image-container" class="w-24 h-24 rounded-full mx-auto mb-4 overflow-hidden bg-gradient-to-br from-cyan-400 to-purple-400 flex items-center justify-center ring-4 ring-zinc-950/5 dark:ring-white/10">
|
|
5898
|
+
${avatarUrl ? `<img src="${avatarUrl}" alt="Profile picture" class="w-full h-full object-cover">` : `<span class="text-2xl font-bold text-white">${firstName.charAt(0)}${lastName.charAt(0)}</span>`}
|
|
5899
|
+
</div>`;
|
|
5900
|
+
}
|
|
5878
5901
|
function renderProfilePage(data) {
|
|
5879
5902
|
const pageContent = `
|
|
5880
5903
|
<div class="space-y-8">
|
|
@@ -6073,9 +6096,7 @@ function renderProfilePage(data) {
|
|
|
6073
6096
|
<h3 class="text-base font-semibold text-zinc-950 dark:text-white mb-4">Profile Picture</h3>
|
|
6074
6097
|
|
|
6075
6098
|
<div class="text-center">
|
|
6076
|
-
|
|
6077
|
-
${data.profile.avatar_url ? `<img src="${data.profile.avatar_url}" alt="Profile picture" class="w-full h-full object-cover">` : `<span class="text-2xl font-bold text-white">${data.profile.first_name.charAt(0)}${data.profile.last_name.charAt(0)}</span>`}
|
|
6078
|
-
</div>
|
|
6099
|
+
${renderAvatarImage(data.profile.avatar_url, data.profile.first_name, data.profile.last_name)}
|
|
6079
6100
|
|
|
6080
6101
|
<form id="avatar-form" hx-post="/admin/profile/avatar" hx-target="#avatar-messages" hx-encoding="multipart/form-data">
|
|
6081
6102
|
<input
|
|
@@ -6723,7 +6744,7 @@ function renderUserEditPage(data) {
|
|
|
6723
6744
|
<input
|
|
6724
6745
|
type="text"
|
|
6725
6746
|
name="first_name"
|
|
6726
|
-
value="${
|
|
6747
|
+
value="${chunkTRSHFTF6_cjs.escapeHtml(data.userToEdit.firstName || "")}"
|
|
6727
6748
|
required
|
|
6728
6749
|
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"
|
|
6729
6750
|
/>
|
|
@@ -6734,7 +6755,7 @@ function renderUserEditPage(data) {
|
|
|
6734
6755
|
<input
|
|
6735
6756
|
type="text"
|
|
6736
6757
|
name="last_name"
|
|
6737
|
-
value="${
|
|
6758
|
+
value="${chunkTRSHFTF6_cjs.escapeHtml(data.userToEdit.lastName || "")}"
|
|
6738
6759
|
required
|
|
6739
6760
|
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"
|
|
6740
6761
|
/>
|
|
@@ -6745,7 +6766,7 @@ function renderUserEditPage(data) {
|
|
|
6745
6766
|
<input
|
|
6746
6767
|
type="text"
|
|
6747
6768
|
name="username"
|
|
6748
|
-
value="${
|
|
6769
|
+
value="${chunkTRSHFTF6_cjs.escapeHtml(data.userToEdit.username || "")}"
|
|
6749
6770
|
required
|
|
6750
6771
|
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"
|
|
6751
6772
|
/>
|
|
@@ -6756,7 +6777,7 @@ function renderUserEditPage(data) {
|
|
|
6756
6777
|
<input
|
|
6757
6778
|
type="email"
|
|
6758
6779
|
name="email"
|
|
6759
|
-
value="${
|
|
6780
|
+
value="${chunkTRSHFTF6_cjs.escapeHtml(data.userToEdit.email || "")}"
|
|
6760
6781
|
required
|
|
6761
6782
|
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"
|
|
6762
6783
|
/>
|
|
@@ -6767,7 +6788,7 @@ function renderUserEditPage(data) {
|
|
|
6767
6788
|
<input
|
|
6768
6789
|
type="tel"
|
|
6769
6790
|
name="phone"
|
|
6770
|
-
value="${
|
|
6791
|
+
value="${chunkTRSHFTF6_cjs.escapeHtml(data.userToEdit.phone || "")}"
|
|
6771
6792
|
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"
|
|
6772
6793
|
/>
|
|
6773
6794
|
</div>
|
|
@@ -6781,7 +6802,7 @@ function renderUserEditPage(data) {
|
|
|
6781
6802
|
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"
|
|
6782
6803
|
>
|
|
6783
6804
|
${data.roles.map((role) => `
|
|
6784
|
-
<option value="${
|
|
6805
|
+
<option value="${chunkTRSHFTF6_cjs.escapeHtml(role.value)}" ${data.userToEdit.role === role.value ? "selected" : ""}>${chunkTRSHFTF6_cjs.escapeHtml(role.label)}</option>
|
|
6785
6806
|
`).join("")}
|
|
6786
6807
|
</select>
|
|
6787
6808
|
<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">
|
|
@@ -6797,7 +6818,7 @@ function renderUserEditPage(data) {
|
|
|
6797
6818
|
name="bio"
|
|
6798
6819
|
rows="3"
|
|
6799
6820
|
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"
|
|
6800
|
-
>${
|
|
6821
|
+
>${chunkTRSHFTF6_cjs.escapeHtml(data.userToEdit.bio || "")}</textarea>
|
|
6801
6822
|
</div>
|
|
6802
6823
|
</div>
|
|
6803
6824
|
|
|
@@ -7697,7 +7718,7 @@ function renderUsersListPage(data) {
|
|
|
7697
7718
|
|
|
7698
7719
|
// src/routes/admin-users.ts
|
|
7699
7720
|
var userRoutes = new hono.Hono();
|
|
7700
|
-
userRoutes.use("*",
|
|
7721
|
+
userRoutes.use("*", chunkIM5SDXOE_cjs.requireAuth());
|
|
7701
7722
|
userRoutes.get("/", (c) => {
|
|
7702
7723
|
return c.redirect("/admin/dashboard");
|
|
7703
7724
|
});
|
|
@@ -7796,12 +7817,12 @@ userRoutes.put("/profile", async (c) => {
|
|
|
7796
7817
|
const db = c.env.DB;
|
|
7797
7818
|
try {
|
|
7798
7819
|
const formData = await c.req.formData();
|
|
7799
|
-
const firstName =
|
|
7800
|
-
const lastName =
|
|
7801
|
-
const username =
|
|
7820
|
+
const firstName = chunkTRSHFTF6_cjs.sanitizeInput(formData.get("first_name")?.toString());
|
|
7821
|
+
const lastName = chunkTRSHFTF6_cjs.sanitizeInput(formData.get("last_name")?.toString());
|
|
7822
|
+
const username = chunkTRSHFTF6_cjs.sanitizeInput(formData.get("username")?.toString());
|
|
7802
7823
|
const email = formData.get("email")?.toString()?.trim().toLowerCase() || "";
|
|
7803
|
-
const phone =
|
|
7804
|
-
const bio =
|
|
7824
|
+
const phone = chunkTRSHFTF6_cjs.sanitizeInput(formData.get("phone")?.toString()) || null;
|
|
7825
|
+
const bio = chunkTRSHFTF6_cjs.sanitizeInput(formData.get("bio")?.toString()) || null;
|
|
7805
7826
|
const timezone = formData.get("timezone")?.toString() || "UTC";
|
|
7806
7827
|
const language = formData.get("language")?.toString() || "en";
|
|
7807
7828
|
const emailNotifications = formData.get("email_notifications") === "1";
|
|
@@ -7852,7 +7873,7 @@ userRoutes.put("/profile", async (c) => {
|
|
|
7852
7873
|
Date.now(),
|
|
7853
7874
|
user.userId
|
|
7854
7875
|
).run();
|
|
7855
|
-
await
|
|
7876
|
+
await chunkIM5SDXOE_cjs.logActivity(
|
|
7856
7877
|
db,
|
|
7857
7878
|
user.userId,
|
|
7858
7879
|
"profile.update",
|
|
@@ -7911,7 +7932,11 @@ userRoutes.post("/profile/avatar", async (c) => {
|
|
|
7911
7932
|
WHERE id = ?
|
|
7912
7933
|
`);
|
|
7913
7934
|
await updateStmt.bind(avatarUrl, Date.now(), user.userId).run();
|
|
7914
|
-
|
|
7935
|
+
const userStmt = db.prepare(`
|
|
7936
|
+
SELECT first_name, last_name FROM users WHERE id = ?
|
|
7937
|
+
`);
|
|
7938
|
+
const userData = await userStmt.bind(user.userId).first();
|
|
7939
|
+
await chunkIM5SDXOE_cjs.logActivity(
|
|
7915
7940
|
db,
|
|
7916
7941
|
user.userId,
|
|
7917
7942
|
"profile.avatar_update",
|
|
@@ -7921,11 +7946,18 @@ userRoutes.post("/profile/avatar", async (c) => {
|
|
|
7921
7946
|
c.req.header("x-forwarded-for") || c.req.header("cf-connecting-ip"),
|
|
7922
7947
|
c.req.header("user-agent")
|
|
7923
7948
|
);
|
|
7924
|
-
|
|
7949
|
+
const alertHtml = renderAlert2({
|
|
7925
7950
|
type: "success",
|
|
7926
7951
|
message: "Profile picture updated successfully!",
|
|
7927
7952
|
dismissible: true
|
|
7928
|
-
})
|
|
7953
|
+
});
|
|
7954
|
+
const avatarUrlWithCache = `${avatarUrl}?t=${Date.now()}`;
|
|
7955
|
+
const avatarImageHtml = renderAvatarImage(avatarUrlWithCache, userData.first_name, userData.last_name);
|
|
7956
|
+
const avatarImageWithOob = avatarImageHtml.replace(
|
|
7957
|
+
'id="avatar-image-container"',
|
|
7958
|
+
'id="avatar-image-container" hx-swap-oob="true"'
|
|
7959
|
+
);
|
|
7960
|
+
return c.html(alertHtml + avatarImageWithOob);
|
|
7929
7961
|
} catch (error) {
|
|
7930
7962
|
console.error("Avatar upload error:", error);
|
|
7931
7963
|
return c.html(renderAlert2({
|
|
@@ -7975,7 +8007,7 @@ userRoutes.post("/profile/password", async (c) => {
|
|
|
7975
8007
|
dismissible: true
|
|
7976
8008
|
}));
|
|
7977
8009
|
}
|
|
7978
|
-
const validPassword = await
|
|
8010
|
+
const validPassword = await chunkIM5SDXOE_cjs.AuthManager.verifyPassword(currentPassword, userData.password_hash);
|
|
7979
8011
|
if (!validPassword) {
|
|
7980
8012
|
return c.html(renderAlert2({
|
|
7981
8013
|
type: "error",
|
|
@@ -7983,7 +8015,7 @@ userRoutes.post("/profile/password", async (c) => {
|
|
|
7983
8015
|
dismissible: true
|
|
7984
8016
|
}));
|
|
7985
8017
|
}
|
|
7986
|
-
const newPasswordHash = await
|
|
8018
|
+
const newPasswordHash = await chunkIM5SDXOE_cjs.AuthManager.hashPassword(newPassword);
|
|
7987
8019
|
const historyStmt = db.prepare(`
|
|
7988
8020
|
INSERT INTO password_history (id, user_id, password_hash, created_at)
|
|
7989
8021
|
VALUES (?, ?, ?, ?)
|
|
@@ -7999,7 +8031,7 @@ userRoutes.post("/profile/password", async (c) => {
|
|
|
7999
8031
|
WHERE id = ?
|
|
8000
8032
|
`);
|
|
8001
8033
|
await updateStmt.bind(newPasswordHash, Date.now(), user.userId).run();
|
|
8002
|
-
await
|
|
8034
|
+
await chunkIM5SDXOE_cjs.logActivity(
|
|
8003
8035
|
db,
|
|
8004
8036
|
user.userId,
|
|
8005
8037
|
"profile.password_change",
|
|
@@ -8066,7 +8098,7 @@ userRoutes.get("/users", async (c) => {
|
|
|
8066
8098
|
`);
|
|
8067
8099
|
const countResult = await countStmt.bind(...params).first();
|
|
8068
8100
|
const totalUsers = countResult?.total || 0;
|
|
8069
|
-
await
|
|
8101
|
+
await chunkIM5SDXOE_cjs.logActivity(
|
|
8070
8102
|
db,
|
|
8071
8103
|
user.userId,
|
|
8072
8104
|
"users.list_view",
|
|
@@ -8168,12 +8200,12 @@ userRoutes.post("/users/new", async (c) => {
|
|
|
8168
8200
|
const user = c.get("user");
|
|
8169
8201
|
try {
|
|
8170
8202
|
const formData = await c.req.formData();
|
|
8171
|
-
const firstName =
|
|
8172
|
-
const lastName =
|
|
8173
|
-
const username =
|
|
8203
|
+
const firstName = chunkTRSHFTF6_cjs.sanitizeInput(formData.get("first_name")?.toString());
|
|
8204
|
+
const lastName = chunkTRSHFTF6_cjs.sanitizeInput(formData.get("last_name")?.toString());
|
|
8205
|
+
const username = chunkTRSHFTF6_cjs.sanitizeInput(formData.get("username")?.toString());
|
|
8174
8206
|
const email = formData.get("email")?.toString()?.trim().toLowerCase() || "";
|
|
8175
|
-
const phone =
|
|
8176
|
-
const bio =
|
|
8207
|
+
const phone = chunkTRSHFTF6_cjs.sanitizeInput(formData.get("phone")?.toString()) || null;
|
|
8208
|
+
const bio = chunkTRSHFTF6_cjs.sanitizeInput(formData.get("bio")?.toString()) || null;
|
|
8177
8209
|
const role = formData.get("role")?.toString() || "viewer";
|
|
8178
8210
|
const password = formData.get("password")?.toString() || "";
|
|
8179
8211
|
const confirmPassword = formData.get("confirm_password")?.toString() || "";
|
|
@@ -8220,7 +8252,7 @@ userRoutes.post("/users/new", async (c) => {
|
|
|
8220
8252
|
dismissible: true
|
|
8221
8253
|
}));
|
|
8222
8254
|
}
|
|
8223
|
-
const passwordHash = await
|
|
8255
|
+
const passwordHash = await chunkIM5SDXOE_cjs.AuthManager.hashPassword(password);
|
|
8224
8256
|
const userId = globalThis.crypto.randomUUID();
|
|
8225
8257
|
const createStmt = db.prepare(`
|
|
8226
8258
|
INSERT INTO users (
|
|
@@ -8243,7 +8275,7 @@ userRoutes.post("/users/new", async (c) => {
|
|
|
8243
8275
|
Date.now(),
|
|
8244
8276
|
Date.now()
|
|
8245
8277
|
).run();
|
|
8246
|
-
await
|
|
8278
|
+
await chunkIM5SDXOE_cjs.logActivity(
|
|
8247
8279
|
db,
|
|
8248
8280
|
user.userId,
|
|
8249
8281
|
"user!.create",
|
|
@@ -8281,7 +8313,7 @@ userRoutes.get("/users/:id", async (c) => {
|
|
|
8281
8313
|
if (!userRecord) {
|
|
8282
8314
|
return c.json({ error: "User not found" }, 404);
|
|
8283
8315
|
}
|
|
8284
|
-
await
|
|
8316
|
+
await chunkIM5SDXOE_cjs.logActivity(
|
|
8285
8317
|
db,
|
|
8286
8318
|
user.userId,
|
|
8287
8319
|
"user!.view",
|
|
@@ -8374,12 +8406,12 @@ userRoutes.put("/users/:id", async (c) => {
|
|
|
8374
8406
|
const userId = c.req.param("id");
|
|
8375
8407
|
try {
|
|
8376
8408
|
const formData = await c.req.formData();
|
|
8377
|
-
const firstName =
|
|
8378
|
-
const lastName =
|
|
8379
|
-
const username =
|
|
8409
|
+
const firstName = chunkTRSHFTF6_cjs.sanitizeInput(formData.get("first_name")?.toString());
|
|
8410
|
+
const lastName = chunkTRSHFTF6_cjs.sanitizeInput(formData.get("last_name")?.toString());
|
|
8411
|
+
const username = chunkTRSHFTF6_cjs.sanitizeInput(formData.get("username")?.toString());
|
|
8380
8412
|
const email = formData.get("email")?.toString()?.trim().toLowerCase() || "";
|
|
8381
|
-
const phone =
|
|
8382
|
-
const bio =
|
|
8413
|
+
const phone = chunkTRSHFTF6_cjs.sanitizeInput(formData.get("phone")?.toString()) || null;
|
|
8414
|
+
const bio = chunkTRSHFTF6_cjs.sanitizeInput(formData.get("bio")?.toString()) || null;
|
|
8383
8415
|
const role = formData.get("role")?.toString() || "viewer";
|
|
8384
8416
|
const isActive = formData.get("is_active") === "1";
|
|
8385
8417
|
const emailVerified = formData.get("email_verified") === "1";
|
|
@@ -8430,7 +8462,7 @@ userRoutes.put("/users/:id", async (c) => {
|
|
|
8430
8462
|
Date.now(),
|
|
8431
8463
|
userId
|
|
8432
8464
|
).run();
|
|
8433
|
-
await
|
|
8465
|
+
await chunkIM5SDXOE_cjs.logActivity(
|
|
8434
8466
|
db,
|
|
8435
8467
|
user.userId,
|
|
8436
8468
|
"user!.update",
|
|
@@ -8476,7 +8508,7 @@ userRoutes.delete("/users/:id", async (c) => {
|
|
|
8476
8508
|
DELETE FROM users WHERE id = ?
|
|
8477
8509
|
`);
|
|
8478
8510
|
await deleteStmt.bind(userId).run();
|
|
8479
|
-
await
|
|
8511
|
+
await chunkIM5SDXOE_cjs.logActivity(
|
|
8480
8512
|
db,
|
|
8481
8513
|
user.userId,
|
|
8482
8514
|
"user!.hard_delete",
|
|
@@ -8495,7 +8527,7 @@ userRoutes.delete("/users/:id", async (c) => {
|
|
|
8495
8527
|
UPDATE users SET is_active = 0, updated_at = ? WHERE id = ?
|
|
8496
8528
|
`);
|
|
8497
8529
|
await deleteStmt.bind(Date.now(), userId).run();
|
|
8498
|
-
await
|
|
8530
|
+
await chunkIM5SDXOE_cjs.logActivity(
|
|
8499
8531
|
db,
|
|
8500
8532
|
user.userId,
|
|
8501
8533
|
"user!.soft_delete",
|
|
@@ -8522,8 +8554,8 @@ userRoutes.post("/invite-user", async (c) => {
|
|
|
8522
8554
|
const formData = await c.req.formData();
|
|
8523
8555
|
const email = formData.get("email")?.toString()?.trim().toLowerCase() || "";
|
|
8524
8556
|
const role = formData.get("role")?.toString()?.trim() || "viewer";
|
|
8525
|
-
const firstName =
|
|
8526
|
-
const lastName =
|
|
8557
|
+
const firstName = chunkTRSHFTF6_cjs.sanitizeInput(formData.get("first_name")?.toString());
|
|
8558
|
+
const lastName = chunkTRSHFTF6_cjs.sanitizeInput(formData.get("last_name")?.toString());
|
|
8527
8559
|
if (!email || !firstName || !lastName) {
|
|
8528
8560
|
return c.json({ error: "Email, first name, and last name are required" }, 400);
|
|
8529
8561
|
}
|
|
@@ -8562,7 +8594,7 @@ userRoutes.post("/invite-user", async (c) => {
|
|
|
8562
8594
|
Date.now(),
|
|
8563
8595
|
Date.now()
|
|
8564
8596
|
).run();
|
|
8565
|
-
await
|
|
8597
|
+
await chunkIM5SDXOE_cjs.logActivity(
|
|
8566
8598
|
db,
|
|
8567
8599
|
user.userId,
|
|
8568
8600
|
"user!.invite_sent",
|
|
@@ -8619,7 +8651,7 @@ userRoutes.post("/resend-invitation/:id", async (c) => {
|
|
|
8619
8651
|
Date.now(),
|
|
8620
8652
|
userId
|
|
8621
8653
|
).run();
|
|
8622
|
-
await
|
|
8654
|
+
await chunkIM5SDXOE_cjs.logActivity(
|
|
8623
8655
|
db,
|
|
8624
8656
|
user.userId,
|
|
8625
8657
|
"user!.invitation_resent",
|
|
@@ -8655,7 +8687,7 @@ userRoutes.delete("/cancel-invitation/:id", async (c) => {
|
|
|
8655
8687
|
}
|
|
8656
8688
|
const deleteStmt = db.prepare(`DELETE FROM users WHERE id = ?`);
|
|
8657
8689
|
await deleteStmt.bind(userId).run();
|
|
8658
|
-
await
|
|
8690
|
+
await chunkIM5SDXOE_cjs.logActivity(
|
|
8659
8691
|
db,
|
|
8660
8692
|
user.userId,
|
|
8661
8693
|
"user!.invitation_cancelled",
|
|
@@ -8738,7 +8770,7 @@ userRoutes.get("/activity-logs", async (c) => {
|
|
|
8738
8770
|
...log,
|
|
8739
8771
|
details: log.details ? JSON.parse(log.details) : null
|
|
8740
8772
|
}));
|
|
8741
|
-
await
|
|
8773
|
+
await chunkIM5SDXOE_cjs.logActivity(
|
|
8742
8774
|
db,
|
|
8743
8775
|
user.userId,
|
|
8744
8776
|
"activity.logs_viewed",
|
|
@@ -8845,7 +8877,7 @@ userRoutes.get("/activity-logs/export", async (c) => {
|
|
|
8845
8877
|
csvRows.push(row.join(","));
|
|
8846
8878
|
}
|
|
8847
8879
|
const csvContent = csvRows.join("\n");
|
|
8848
|
-
await
|
|
8880
|
+
await chunkIM5SDXOE_cjs.logActivity(
|
|
8849
8881
|
db,
|
|
8850
8882
|
user.userId,
|
|
8851
8883
|
"activity.logs_exported",
|
|
@@ -9157,8 +9189,10 @@ function renderMediaLibraryPage(data) {
|
|
|
9157
9189
|
</button>
|
|
9158
9190
|
<button
|
|
9159
9191
|
class="w-full text-left px-3 py-2 text-sm text-zinc-700 dark:text-zinc-300 hover:text-zinc-950 dark:hover:text-white hover:bg-zinc-50 dark:hover:bg-zinc-800/50 rounded-lg transition-colors"
|
|
9160
|
-
hx-delete="/media/cleanup"
|
|
9192
|
+
hx-delete="/admin/media/cleanup"
|
|
9161
9193
|
hx-confirm="Delete unused files?"
|
|
9194
|
+
hx-target="body"
|
|
9195
|
+
hx-swap="beforeend"
|
|
9162
9196
|
>
|
|
9163
9197
|
Cleanup Unused
|
|
9164
9198
|
</button>
|
|
@@ -10182,7 +10216,7 @@ var fileValidationSchema2 = zod.z.object({
|
|
|
10182
10216
|
// 50MB max
|
|
10183
10217
|
});
|
|
10184
10218
|
var adminMediaRoutes = new hono.Hono();
|
|
10185
|
-
adminMediaRoutes.use("*",
|
|
10219
|
+
adminMediaRoutes.use("*", chunkIM5SDXOE_cjs.requireAuth());
|
|
10186
10220
|
adminMediaRoutes.get("/", async (c) => {
|
|
10187
10221
|
try {
|
|
10188
10222
|
const user = c.get("user");
|
|
@@ -10761,6 +10795,87 @@ adminMediaRoutes.put("/:id", async (c) => {
|
|
|
10761
10795
|
`);
|
|
10762
10796
|
}
|
|
10763
10797
|
});
|
|
10798
|
+
adminMediaRoutes.delete("/cleanup", chunkIM5SDXOE_cjs.requireRole("admin"), async (c) => {
|
|
10799
|
+
try {
|
|
10800
|
+
const db = c.env.DB;
|
|
10801
|
+
const allMediaStmt = db.prepare("SELECT id, r2_key, filename FROM media WHERE deleted_at IS NULL");
|
|
10802
|
+
const { results: allMedia } = await allMediaStmt.all();
|
|
10803
|
+
const contentStmt = db.prepare("SELECT data FROM content");
|
|
10804
|
+
const { results: contentRecords } = await contentStmt.all();
|
|
10805
|
+
const referencedUrls = /* @__PURE__ */ new Set();
|
|
10806
|
+
for (const record of contentRecords) {
|
|
10807
|
+
if (record.data) {
|
|
10808
|
+
const dataStr = typeof record.data === "string" ? record.data : JSON.stringify(record.data);
|
|
10809
|
+
const urlMatches = dataStr.matchAll(/\/files\/([^\s"',]+)/g);
|
|
10810
|
+
for (const match of urlMatches) {
|
|
10811
|
+
referencedUrls.add(match[1]);
|
|
10812
|
+
}
|
|
10813
|
+
}
|
|
10814
|
+
}
|
|
10815
|
+
const unusedFiles = allMedia.filter((file) => !referencedUrls.has(file.r2_key));
|
|
10816
|
+
if (unusedFiles.length === 0) {
|
|
10817
|
+
return c.html(html.html`
|
|
10818
|
+
<div class="bg-blue-100 border border-blue-400 text-blue-700 px-4 py-3 rounded">
|
|
10819
|
+
No unused media files found. All files are referenced in content.
|
|
10820
|
+
</div>
|
|
10821
|
+
<script>
|
|
10822
|
+
setTimeout(() => {
|
|
10823
|
+
window.location.href = '/admin/media?t=' + Date.now();
|
|
10824
|
+
}, 2000);
|
|
10825
|
+
</script>
|
|
10826
|
+
`);
|
|
10827
|
+
}
|
|
10828
|
+
let deletedCount = 0;
|
|
10829
|
+
const errors = [];
|
|
10830
|
+
for (const file of unusedFiles) {
|
|
10831
|
+
try {
|
|
10832
|
+
await c.env.MEDIA_BUCKET.delete(file.r2_key);
|
|
10833
|
+
const deleteStmt = db.prepare("UPDATE media SET deleted_at = ? WHERE id = ?");
|
|
10834
|
+
await deleteStmt.bind(Math.floor(Date.now() / 1e3), file.id).run();
|
|
10835
|
+
deletedCount++;
|
|
10836
|
+
} catch (error) {
|
|
10837
|
+
console.error(`Failed to delete ${file.filename}:`, error);
|
|
10838
|
+
errors.push({
|
|
10839
|
+
filename: file.filename,
|
|
10840
|
+
error: error instanceof Error ? error.message : "Unknown error"
|
|
10841
|
+
});
|
|
10842
|
+
}
|
|
10843
|
+
}
|
|
10844
|
+
return c.html(html.html`
|
|
10845
|
+
<div class="bg-green-100 border border-green-400 text-green-700 px-4 py-3 rounded mb-4">
|
|
10846
|
+
Successfully cleaned up ${deletedCount} unused media file${deletedCount !== 1 ? "s" : ""}.
|
|
10847
|
+
${errors.length > 0 ? html.html`
|
|
10848
|
+
<br><span class="text-sm">Failed to delete ${errors.length} file${errors.length !== 1 ? "s" : ""}.</span>
|
|
10849
|
+
` : ""}
|
|
10850
|
+
</div>
|
|
10851
|
+
|
|
10852
|
+
${errors.length > 0 ? html.html`
|
|
10853
|
+
<div class="bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded">
|
|
10854
|
+
<p class="font-medium">Cleanup errors:</p>
|
|
10855
|
+
<ul class="list-disc list-inside mt-2 text-sm">
|
|
10856
|
+
${errors.map((error) => html.html`
|
|
10857
|
+
<li>${error.filename}: ${error.error}</li>
|
|
10858
|
+
`)}
|
|
10859
|
+
</ul>
|
|
10860
|
+
</div>
|
|
10861
|
+
` : ""}
|
|
10862
|
+
|
|
10863
|
+
<script>
|
|
10864
|
+
// Refresh media library after cleanup
|
|
10865
|
+
setTimeout(() => {
|
|
10866
|
+
window.location.href = '/admin/media?t=' + Date.now();
|
|
10867
|
+
}, 2500);
|
|
10868
|
+
</script>
|
|
10869
|
+
`);
|
|
10870
|
+
} catch (error) {
|
|
10871
|
+
console.error("Cleanup error:", error);
|
|
10872
|
+
return c.html(html.html`
|
|
10873
|
+
<div class="bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded">
|
|
10874
|
+
Cleanup failed: ${error instanceof Error ? error.message : "Unknown error"}
|
|
10875
|
+
</div>
|
|
10876
|
+
`);
|
|
10877
|
+
}
|
|
10878
|
+
});
|
|
10764
10879
|
adminMediaRoutes.delete("/:id", async (c) => {
|
|
10765
10880
|
try {
|
|
10766
10881
|
const user = c.get("user");
|
|
@@ -12216,7 +12331,7 @@ function formatTimestamp(timestamp) {
|
|
|
12216
12331
|
|
|
12217
12332
|
// src/routes/admin-plugins.ts
|
|
12218
12333
|
var adminPluginRoutes = new hono.Hono();
|
|
12219
|
-
adminPluginRoutes.use("*",
|
|
12334
|
+
adminPluginRoutes.use("*", chunkIM5SDXOE_cjs.requireAuth());
|
|
12220
12335
|
adminPluginRoutes.get("/", async (c) => {
|
|
12221
12336
|
try {
|
|
12222
12337
|
const user = c.get("user");
|
|
@@ -12224,7 +12339,7 @@ adminPluginRoutes.get("/", async (c) => {
|
|
|
12224
12339
|
if (user?.role !== "admin") {
|
|
12225
12340
|
return c.text("Access denied", 403);
|
|
12226
12341
|
}
|
|
12227
|
-
const pluginService = new
|
|
12342
|
+
const pluginService = new chunk3JMOWGUU_cjs.PluginService(db);
|
|
12228
12343
|
let plugins = [];
|
|
12229
12344
|
let stats = { total: 0, active: 0, inactive: 0, errors: 0 };
|
|
12230
12345
|
try {
|
|
@@ -12274,7 +12389,7 @@ adminPluginRoutes.get("/:id", async (c) => {
|
|
|
12274
12389
|
if (user?.role !== "admin") {
|
|
12275
12390
|
return c.redirect("/admin/plugins");
|
|
12276
12391
|
}
|
|
12277
|
-
const pluginService = new
|
|
12392
|
+
const pluginService = new chunk3JMOWGUU_cjs.PluginService(db);
|
|
12278
12393
|
const plugin = await pluginService.getPlugin(pluginId);
|
|
12279
12394
|
if (!plugin) {
|
|
12280
12395
|
return c.text("Plugin not found", 404);
|
|
@@ -12328,7 +12443,7 @@ adminPluginRoutes.post("/:id/activate", async (c) => {
|
|
|
12328
12443
|
if (user?.role !== "admin") {
|
|
12329
12444
|
return c.json({ error: "Access denied" }, 403);
|
|
12330
12445
|
}
|
|
12331
|
-
const pluginService = new
|
|
12446
|
+
const pluginService = new chunk3JMOWGUU_cjs.PluginService(db);
|
|
12332
12447
|
await pluginService.activatePlugin(pluginId);
|
|
12333
12448
|
return c.json({ success: true });
|
|
12334
12449
|
} catch (error) {
|
|
@@ -12345,7 +12460,7 @@ adminPluginRoutes.post("/:id/deactivate", async (c) => {
|
|
|
12345
12460
|
if (user?.role !== "admin") {
|
|
12346
12461
|
return c.json({ error: "Access denied" }, 403);
|
|
12347
12462
|
}
|
|
12348
|
-
const pluginService = new
|
|
12463
|
+
const pluginService = new chunk3JMOWGUU_cjs.PluginService(db);
|
|
12349
12464
|
await pluginService.deactivatePlugin(pluginId);
|
|
12350
12465
|
return c.json({ success: true });
|
|
12351
12466
|
} catch (error) {
|
|
@@ -12362,7 +12477,7 @@ adminPluginRoutes.post("/install", async (c) => {
|
|
|
12362
12477
|
return c.json({ error: "Access denied" }, 403);
|
|
12363
12478
|
}
|
|
12364
12479
|
const body = await c.req.json();
|
|
12365
|
-
const pluginService = new
|
|
12480
|
+
const pluginService = new chunk3JMOWGUU_cjs.PluginService(db);
|
|
12366
12481
|
if (body.name === "faq-plugin") {
|
|
12367
12482
|
const faqPlugin = await pluginService.installPlugin({
|
|
12368
12483
|
id: "third-party-faq",
|
|
@@ -12512,7 +12627,7 @@ adminPluginRoutes.post("/:id/uninstall", async (c) => {
|
|
|
12512
12627
|
if (user?.role !== "admin") {
|
|
12513
12628
|
return c.json({ error: "Access denied" }, 403);
|
|
12514
12629
|
}
|
|
12515
|
-
const pluginService = new
|
|
12630
|
+
const pluginService = new chunk3JMOWGUU_cjs.PluginService(db);
|
|
12516
12631
|
await pluginService.uninstallPlugin(pluginId);
|
|
12517
12632
|
return c.json({ success: true });
|
|
12518
12633
|
} catch (error) {
|
|
@@ -12530,7 +12645,7 @@ adminPluginRoutes.post("/:id/settings", async (c) => {
|
|
|
12530
12645
|
return c.json({ error: "Access denied" }, 403);
|
|
12531
12646
|
}
|
|
12532
12647
|
const settings = await c.req.json();
|
|
12533
|
-
const pluginService = new
|
|
12648
|
+
const pluginService = new chunk3JMOWGUU_cjs.PluginService(db);
|
|
12534
12649
|
await pluginService.updatePluginSettings(pluginId, settings);
|
|
12535
12650
|
return c.json({ success: true });
|
|
12536
12651
|
} catch (error) {
|
|
@@ -13326,11 +13441,11 @@ function renderLogConfigPage(data) {
|
|
|
13326
13441
|
|
|
13327
13442
|
// src/routes/admin-logs.ts
|
|
13328
13443
|
var adminLogsRoutes = new hono.Hono();
|
|
13329
|
-
adminLogsRoutes.use("*",
|
|
13444
|
+
adminLogsRoutes.use("*", chunkIM5SDXOE_cjs.requireAuth());
|
|
13330
13445
|
adminLogsRoutes.get("/", async (c) => {
|
|
13331
13446
|
try {
|
|
13332
13447
|
const user = c.get("user");
|
|
13333
|
-
const logger =
|
|
13448
|
+
const logger = chunkDOR2IU73_cjs.getLogger(c.env.DB);
|
|
13334
13449
|
const query = c.req.query();
|
|
13335
13450
|
const page = parseInt(query.page || "1");
|
|
13336
13451
|
const limit = parseInt(query.limit || "50");
|
|
@@ -13410,7 +13525,7 @@ adminLogsRoutes.get("/:id", async (c) => {
|
|
|
13410
13525
|
try {
|
|
13411
13526
|
const id = c.req.param("id");
|
|
13412
13527
|
const user = c.get("user");
|
|
13413
|
-
const logger =
|
|
13528
|
+
const logger = chunkDOR2IU73_cjs.getLogger(c.env.DB);
|
|
13414
13529
|
const { logs } = await logger.getLogs({
|
|
13415
13530
|
limit: 1,
|
|
13416
13531
|
offset: 0,
|
|
@@ -13447,7 +13562,7 @@ adminLogsRoutes.get("/:id", async (c) => {
|
|
|
13447
13562
|
adminLogsRoutes.get("/config", async (c) => {
|
|
13448
13563
|
try {
|
|
13449
13564
|
const user = c.get("user");
|
|
13450
|
-
const logger =
|
|
13565
|
+
const logger = chunkDOR2IU73_cjs.getLogger(c.env.DB);
|
|
13451
13566
|
const configs = await logger.getAllConfigs();
|
|
13452
13567
|
const pageData = {
|
|
13453
13568
|
configs,
|
|
@@ -13471,7 +13586,7 @@ adminLogsRoutes.post("/config/:category", async (c) => {
|
|
|
13471
13586
|
const level = formData.get("level");
|
|
13472
13587
|
const retention = parseInt(formData.get("retention"));
|
|
13473
13588
|
const maxSize = parseInt(formData.get("max_size"));
|
|
13474
|
-
const logger =
|
|
13589
|
+
const logger = chunkDOR2IU73_cjs.getLogger(c.env.DB);
|
|
13475
13590
|
await logger.updateConfig(category, {
|
|
13476
13591
|
enabled,
|
|
13477
13592
|
level,
|
|
@@ -13500,7 +13615,7 @@ adminLogsRoutes.get("/export", async (c) => {
|
|
|
13500
13615
|
const category = query.category;
|
|
13501
13616
|
const startDate = query.start_date;
|
|
13502
13617
|
const endDate = query.end_date;
|
|
13503
|
-
const logger =
|
|
13618
|
+
const logger = chunkDOR2IU73_cjs.getLogger(c.env.DB);
|
|
13504
13619
|
const filter = {
|
|
13505
13620
|
limit: 1e4,
|
|
13506
13621
|
// Export up to 10k logs
|
|
@@ -13581,7 +13696,7 @@ adminLogsRoutes.post("/cleanup", async (c) => {
|
|
|
13581
13696
|
error: "Unauthorized. Admin access required."
|
|
13582
13697
|
}, 403);
|
|
13583
13698
|
}
|
|
13584
|
-
const logger =
|
|
13699
|
+
const logger = chunkDOR2IU73_cjs.getLogger(c.env.DB);
|
|
13585
13700
|
await logger.cleanupByRetention();
|
|
13586
13701
|
return c.html(html.html`
|
|
13587
13702
|
<div class="bg-green-100 border border-green-400 text-green-700 px-4 py-3 rounded">
|
|
@@ -13603,7 +13718,7 @@ adminLogsRoutes.post("/search", async (c) => {
|
|
|
13603
13718
|
const search = formData.get("search");
|
|
13604
13719
|
const level = formData.get("level");
|
|
13605
13720
|
const category = formData.get("category");
|
|
13606
|
-
const logger =
|
|
13721
|
+
const logger = chunkDOR2IU73_cjs.getLogger(c.env.DB);
|
|
13607
13722
|
const filter = {
|
|
13608
13723
|
limit: 20,
|
|
13609
13724
|
offset: 0,
|
|
@@ -16259,9 +16374,9 @@ function renderStorageUsage(databaseSizeBytes, mediaSizeBytes) {
|
|
|
16259
16374
|
}
|
|
16260
16375
|
|
|
16261
16376
|
// src/routes/admin-dashboard.ts
|
|
16262
|
-
var VERSION =
|
|
16377
|
+
var VERSION = chunkTRSHFTF6_cjs.getCoreVersion();
|
|
16263
16378
|
var router = new hono.Hono();
|
|
16264
|
-
router.use("*",
|
|
16379
|
+
router.use("*", chunkIM5SDXOE_cjs.requireAuth());
|
|
16265
16380
|
router.get("/", async (c) => {
|
|
16266
16381
|
const user = c.get("user");
|
|
16267
16382
|
try {
|
|
@@ -16324,14 +16439,14 @@ router.get("/stats", async (c) => {
|
|
|
16324
16439
|
} catch (error) {
|
|
16325
16440
|
console.error("Error fetching users count:", error);
|
|
16326
16441
|
}
|
|
16327
|
-
const
|
|
16442
|
+
const html8 = renderStatsCards({
|
|
16328
16443
|
collections: collectionsCount,
|
|
16329
16444
|
contentItems: contentCount,
|
|
16330
16445
|
mediaFiles: mediaCount,
|
|
16331
16446
|
users: usersCount,
|
|
16332
16447
|
mediaSize
|
|
16333
16448
|
});
|
|
16334
|
-
return c.html(
|
|
16449
|
+
return c.html(html8);
|
|
16335
16450
|
} catch (error) {
|
|
16336
16451
|
console.error("Error fetching stats:", error);
|
|
16337
16452
|
return c.html('<div class="text-red-500">Failed to load statistics</div>');
|
|
@@ -16355,8 +16470,8 @@ router.get("/storage", async (c) => {
|
|
|
16355
16470
|
} catch (error) {
|
|
16356
16471
|
console.error("Error fetching media size:", error);
|
|
16357
16472
|
}
|
|
16358
|
-
const
|
|
16359
|
-
return c.html(
|
|
16473
|
+
const html8 = renderStorageUsage(databaseSize, mediaSize);
|
|
16474
|
+
return c.html(html8);
|
|
16360
16475
|
} catch (error) {
|
|
16361
16476
|
console.error("Error fetching storage usage:", error);
|
|
16362
16477
|
return c.html('<div class="text-red-500">Failed to load storage information</div>');
|
|
@@ -16405,12 +16520,12 @@ router.get("/recent-activity", async (c) => {
|
|
|
16405
16520
|
user: userName
|
|
16406
16521
|
};
|
|
16407
16522
|
});
|
|
16408
|
-
const
|
|
16409
|
-
return c.html(
|
|
16523
|
+
const html8 = renderRecentActivity(activities);
|
|
16524
|
+
return c.html(html8);
|
|
16410
16525
|
} catch (error) {
|
|
16411
16526
|
console.error("Error fetching recent activity:", error);
|
|
16412
|
-
const
|
|
16413
|
-
return c.html(
|
|
16527
|
+
const html8 = renderRecentActivity([]);
|
|
16528
|
+
return c.html(html8);
|
|
16414
16529
|
}
|
|
16415
16530
|
});
|
|
16416
16531
|
router.get("/api/metrics", async (c) => {
|
|
@@ -16423,7 +16538,7 @@ router.get("/api/metrics", async (c) => {
|
|
|
16423
16538
|
});
|
|
16424
16539
|
router.get("/system-status", async (c) => {
|
|
16425
16540
|
try {
|
|
16426
|
-
const
|
|
16541
|
+
const html8 = `
|
|
16427
16542
|
<div class="grid grid-cols-1 sm:grid-cols-2 gap-4">
|
|
16428
16543
|
<div class="relative group">
|
|
16429
16544
|
<div class="absolute inset-0 bg-gradient-to-br from-blue-500/20 to-cyan-500/20 dark:from-blue-500/10 dark:to-cyan-500/10 rounded-xl opacity-0 group-hover:opacity-100 transition-opacity duration-300"></div>
|
|
@@ -16478,7 +16593,7 @@ router.get("/system-status", async (c) => {
|
|
|
16478
16593
|
</div>
|
|
16479
16594
|
</div>
|
|
16480
16595
|
`;
|
|
16481
|
-
return c.html(
|
|
16596
|
+
return c.html(html8);
|
|
16482
16597
|
} catch (error) {
|
|
16483
16598
|
console.error("Error fetching system status:", error);
|
|
16484
16599
|
return c.html('<div class="text-red-500">Failed to load system status</div>');
|
|
@@ -17742,7 +17857,7 @@ function renderCollectionFormPage(data) {
|
|
|
17742
17857
|
|
|
17743
17858
|
// src/routes/admin-collections.ts
|
|
17744
17859
|
var adminCollectionsRoutes = new hono.Hono();
|
|
17745
|
-
adminCollectionsRoutes.use("*",
|
|
17860
|
+
adminCollectionsRoutes.use("*", chunkIM5SDXOE_cjs.requireAuth());
|
|
17746
17861
|
adminCollectionsRoutes.get("/", async (c) => {
|
|
17747
17862
|
try {
|
|
17748
17863
|
const user = c.get("user");
|
|
@@ -18234,31 +18349,52 @@ function renderSettingsPage(data) {
|
|
|
18234
18349
|
// Initialize tab-specific features on page load
|
|
18235
18350
|
const currentTab = '${activeTab}';
|
|
18236
18351
|
|
|
18237
|
-
function saveAllSettings() {
|
|
18352
|
+
async function saveAllSettings() {
|
|
18238
18353
|
// Collect all form data
|
|
18239
18354
|
const formData = new FormData();
|
|
18240
|
-
|
|
18241
|
-
// Get all form inputs
|
|
18242
|
-
document.querySelectorAll('input, select, textarea').forEach(input => {
|
|
18355
|
+
|
|
18356
|
+
// Get all form inputs in the settings content area
|
|
18357
|
+
document.querySelectorAll('#settings-content input, #settings-content select, #settings-content textarea').forEach(input => {
|
|
18243
18358
|
if (input.type === 'checkbox') {
|
|
18244
|
-
formData.append(input.name, input.checked);
|
|
18359
|
+
formData.append(input.name, input.checked ? 'true' : 'false');
|
|
18245
18360
|
} else if (input.name) {
|
|
18246
18361
|
formData.append(input.name, input.value);
|
|
18247
18362
|
}
|
|
18248
18363
|
});
|
|
18249
|
-
|
|
18364
|
+
|
|
18250
18365
|
// Show loading state
|
|
18251
18366
|
const saveBtn = document.querySelector('button[onclick="saveAllSettings()"]');
|
|
18252
18367
|
const originalText = saveBtn.innerHTML;
|
|
18253
|
-
saveBtn.innerHTML = 'Saving...';
|
|
18368
|
+
saveBtn.innerHTML = '<svg class="animate-spin -ml-0.5 mr-1.5 h-5 w-5 inline" fill="none" stroke="currentColor" viewBox="0 0 24 24"><circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle><path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z"></path></svg>Saving...';
|
|
18254
18369
|
saveBtn.disabled = true;
|
|
18255
|
-
|
|
18256
|
-
|
|
18257
|
-
|
|
18370
|
+
|
|
18371
|
+
try {
|
|
18372
|
+
// Determine which endpoint to call based on current tab
|
|
18373
|
+
let endpoint = '/admin/settings/general';
|
|
18374
|
+
if (currentTab === 'general') {
|
|
18375
|
+
endpoint = '/admin/settings/general';
|
|
18376
|
+
}
|
|
18377
|
+
// Add more endpoints for other tabs when implemented
|
|
18378
|
+
|
|
18379
|
+
const response = await fetch(endpoint, {
|
|
18380
|
+
method: 'POST',
|
|
18381
|
+
body: formData
|
|
18382
|
+
});
|
|
18383
|
+
|
|
18384
|
+
const result = await response.json();
|
|
18385
|
+
|
|
18386
|
+
if (result.success) {
|
|
18387
|
+
showNotification(result.message || 'Settings saved successfully!', 'success');
|
|
18388
|
+
} else {
|
|
18389
|
+
showNotification(result.error || 'Failed to save settings', 'error');
|
|
18390
|
+
}
|
|
18391
|
+
} catch (error) {
|
|
18392
|
+
console.error('Error saving settings:', error);
|
|
18393
|
+
showNotification('Failed to save settings. Please try again.', 'error');
|
|
18394
|
+
} finally {
|
|
18258
18395
|
saveBtn.innerHTML = originalText;
|
|
18259
18396
|
saveBtn.disabled = false;
|
|
18260
|
-
|
|
18261
|
-
}, 1000);
|
|
18397
|
+
}
|
|
18262
18398
|
}
|
|
18263
18399
|
|
|
18264
18400
|
function resetSettings() {
|
|
@@ -19601,7 +19737,7 @@ function renderDatabaseToolsSettings(settings) {
|
|
|
19601
19737
|
|
|
19602
19738
|
// src/routes/admin-settings.ts
|
|
19603
19739
|
var adminSettingsRoutes = new hono.Hono();
|
|
19604
|
-
adminSettingsRoutes.use("*",
|
|
19740
|
+
adminSettingsRoutes.use("*", chunkIM5SDXOE_cjs.requireAuth());
|
|
19605
19741
|
function getMockSettings(user) {
|
|
19606
19742
|
return {
|
|
19607
19743
|
general: {
|
|
@@ -19663,15 +19799,20 @@ function getMockSettings(user) {
|
|
|
19663
19799
|
adminSettingsRoutes.get("/", (c) => {
|
|
19664
19800
|
return c.redirect("/admin/settings/general");
|
|
19665
19801
|
});
|
|
19666
|
-
adminSettingsRoutes.get("/general", (c) => {
|
|
19802
|
+
adminSettingsRoutes.get("/general", async (c) => {
|
|
19667
19803
|
const user = c.get("user");
|
|
19804
|
+
const db = c.env.DB;
|
|
19805
|
+
const settingsService = new chunkDOR2IU73_cjs.SettingsService(db);
|
|
19806
|
+
const generalSettings = await settingsService.getGeneralSettings(user?.email);
|
|
19807
|
+
const mockSettings = getMockSettings(user);
|
|
19808
|
+
mockSettings.general = generalSettings;
|
|
19668
19809
|
const pageData = {
|
|
19669
19810
|
user: user ? {
|
|
19670
19811
|
name: user.email,
|
|
19671
19812
|
email: user.email,
|
|
19672
19813
|
role: user.role
|
|
19673
19814
|
} : void 0,
|
|
19674
|
-
settings:
|
|
19815
|
+
settings: mockSettings,
|
|
19675
19816
|
activeTab: "general",
|
|
19676
19817
|
version: c.get("appVersion")
|
|
19677
19818
|
};
|
|
@@ -19764,7 +19905,7 @@ adminSettingsRoutes.get("/database-tools", (c) => {
|
|
|
19764
19905
|
adminSettingsRoutes.get("/api/migrations/status", async (c) => {
|
|
19765
19906
|
try {
|
|
19766
19907
|
const db = c.env.DB;
|
|
19767
|
-
const migrationService = new
|
|
19908
|
+
const migrationService = new chunk3JMOWGUU_cjs.MigrationService(db);
|
|
19768
19909
|
const status = await migrationService.getMigrationStatus();
|
|
19769
19910
|
return c.json({
|
|
19770
19911
|
success: true,
|
|
@@ -19788,7 +19929,7 @@ adminSettingsRoutes.post("/api/migrations/run", async (c) => {
|
|
|
19788
19929
|
}, 403);
|
|
19789
19930
|
}
|
|
19790
19931
|
const db = c.env.DB;
|
|
19791
|
-
const migrationService = new
|
|
19932
|
+
const migrationService = new chunk3JMOWGUU_cjs.MigrationService(db);
|
|
19792
19933
|
const result = await migrationService.runPendingMigrations();
|
|
19793
19934
|
return c.json({
|
|
19794
19935
|
success: result.success,
|
|
@@ -19806,7 +19947,7 @@ adminSettingsRoutes.post("/api/migrations/run", async (c) => {
|
|
|
19806
19947
|
adminSettingsRoutes.get("/api/migrations/validate", async (c) => {
|
|
19807
19948
|
try {
|
|
19808
19949
|
const db = c.env.DB;
|
|
19809
|
-
const migrationService = new
|
|
19950
|
+
const migrationService = new chunk3JMOWGUU_cjs.MigrationService(db);
|
|
19810
19951
|
const validation = await migrationService.validateSchema();
|
|
19811
19952
|
return c.json({
|
|
19812
19953
|
success: true,
|
|
@@ -19952,28 +20093,55 @@ adminSettingsRoutes.post("/api/database-tools/truncate", async (c) => {
|
|
|
19952
20093
|
}, 500);
|
|
19953
20094
|
}
|
|
19954
20095
|
});
|
|
19955
|
-
adminSettingsRoutes.post("/", async (c) => {
|
|
20096
|
+
adminSettingsRoutes.post("/general", async (c) => {
|
|
19956
20097
|
try {
|
|
20098
|
+
const user = c.get("user");
|
|
20099
|
+
if (!user || user.role !== "admin") {
|
|
20100
|
+
return c.json({
|
|
20101
|
+
success: false,
|
|
20102
|
+
error: "Unauthorized. Admin access required."
|
|
20103
|
+
}, 403);
|
|
20104
|
+
}
|
|
19957
20105
|
const formData = await c.req.formData();
|
|
19958
|
-
|
|
19959
|
-
|
|
19960
|
-
|
|
19961
|
-
|
|
19962
|
-
|
|
19963
|
-
|
|
19964
|
-
|
|
19965
|
-
|
|
19966
|
-
|
|
19967
|
-
|
|
20106
|
+
const db = c.env.DB;
|
|
20107
|
+
const settingsService = new chunkDOR2IU73_cjs.SettingsService(db);
|
|
20108
|
+
const settings = {
|
|
20109
|
+
siteName: formData.get("siteName"),
|
|
20110
|
+
siteDescription: formData.get("siteDescription"),
|
|
20111
|
+
adminEmail: formData.get("adminEmail"),
|
|
20112
|
+
timezone: formData.get("timezone"),
|
|
20113
|
+
language: formData.get("language"),
|
|
20114
|
+
maintenanceMode: formData.get("maintenanceMode") === "true"
|
|
20115
|
+
};
|
|
20116
|
+
if (!settings.siteName || !settings.siteDescription) {
|
|
20117
|
+
return c.json({
|
|
20118
|
+
success: false,
|
|
20119
|
+
error: "Site name and description are required"
|
|
20120
|
+
}, 400);
|
|
20121
|
+
}
|
|
20122
|
+
const success = await settingsService.saveGeneralSettings(settings);
|
|
20123
|
+
if (success) {
|
|
20124
|
+
return c.json({
|
|
20125
|
+
success: true,
|
|
20126
|
+
message: "General settings saved successfully!"
|
|
20127
|
+
});
|
|
20128
|
+
} else {
|
|
20129
|
+
return c.json({
|
|
20130
|
+
success: false,
|
|
20131
|
+
error: "Failed to save settings"
|
|
20132
|
+
}, 500);
|
|
20133
|
+
}
|
|
19968
20134
|
} catch (error) {
|
|
19969
|
-
console.error("Error saving settings:", error);
|
|
19970
|
-
return c.
|
|
19971
|
-
|
|
19972
|
-
|
|
19973
|
-
|
|
19974
|
-
`);
|
|
20135
|
+
console.error("Error saving general settings:", error);
|
|
20136
|
+
return c.json({
|
|
20137
|
+
success: false,
|
|
20138
|
+
error: "Failed to save settings. Please try again."
|
|
20139
|
+
}, 500);
|
|
19975
20140
|
}
|
|
19976
20141
|
});
|
|
20142
|
+
adminSettingsRoutes.post("/", async (c) => {
|
|
20143
|
+
return c.redirect("/admin/settings/general");
|
|
20144
|
+
});
|
|
19977
20145
|
|
|
19978
20146
|
// src/routes/index.ts
|
|
19979
20147
|
var ROUTES_INFO = {
|
|
@@ -20023,5 +20191,5 @@ exports.api_system_default = api_system_default;
|
|
|
20023
20191
|
exports.auth_default = auth_default;
|
|
20024
20192
|
exports.router = router;
|
|
20025
20193
|
exports.userRoutes = userRoutes;
|
|
20026
|
-
//# sourceMappingURL=chunk-
|
|
20027
|
-
//# sourceMappingURL=chunk-
|
|
20194
|
+
//# sourceMappingURL=chunk-NPWWR6RI.cjs.map
|
|
20195
|
+
//# sourceMappingURL=chunk-NPWWR6RI.cjs.map
|