@sonicjs-cms/core 2.10.0 → 2.11.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.
Files changed (82) hide show
  1. package/dist/{chunk-CJYFSKH7.js → chunk-2MXF4RYZ.js} +3 -3
  2. package/dist/{chunk-CJYFSKH7.js.map → chunk-2MXF4RYZ.js.map} +1 -1
  3. package/dist/{chunk-MNFY6DWY.cjs → chunk-56GUBLJE.cjs} +7 -7
  4. package/dist/{chunk-MNFY6DWY.cjs.map → chunk-56GUBLJE.cjs.map} +1 -1
  5. package/dist/{chunk-IIBRG5S5.cjs → chunk-6BVLPACH.cjs} +408 -2
  6. package/dist/chunk-6BVLPACH.cjs.map +1 -0
  7. package/dist/{chunk-RCA6R6VE.cjs → chunk-ASAEJ4B7.cjs} +315 -162
  8. package/dist/chunk-ASAEJ4B7.cjs.map +1 -0
  9. package/dist/{chunk-IT2TC4ZD.cjs → chunk-B2ASV5RD.cjs} +13 -7
  10. package/dist/chunk-B2ASV5RD.cjs.map +1 -0
  11. package/dist/{chunk-IZWNIUJI.js → chunk-BUU2US2Z.js} +3 -3
  12. package/dist/{chunk-IZWNIUJI.js.map → chunk-BUU2US2Z.js.map} +1 -1
  13. package/dist/{chunk-ZMVWMJ3S.cjs → chunk-DE5YTNCD.cjs} +9 -2
  14. package/dist/chunk-DE5YTNCD.cjs.map +1 -0
  15. package/dist/{chunk-4TTMQQC7.js → chunk-GKRGDJGG.js} +10 -4
  16. package/dist/chunk-GKRGDJGG.js.map +1 -0
  17. package/dist/{chunk-6O3RJV3C.js → chunk-H55AYIRI.js} +9 -2
  18. package/dist/chunk-H55AYIRI.js.map +1 -0
  19. package/dist/{chunk-JTNUM7JE.js → chunk-JTQBNSZX.js} +187 -34
  20. package/dist/chunk-JTQBNSZX.js.map +1 -0
  21. package/dist/{chunk-64APW3DW.cjs → chunk-LFAQUR7P.cjs} +9 -2
  22. package/dist/chunk-LFAQUR7P.cjs.map +1 -0
  23. package/dist/{chunk-27AOVQTR.js → chunk-NMLFKXWW.js} +402 -3
  24. package/dist/chunk-NMLFKXWW.js.map +1 -0
  25. package/dist/{chunk-EKPLKUZT.cjs → chunk-QLPFENZ2.cjs} +3 -3
  26. package/dist/{chunk-EKPLKUZT.cjs.map → chunk-QLPFENZ2.cjs.map} +1 -1
  27. package/dist/{chunk-KYGRJCZM.cjs → chunk-QTFKZBLC.cjs} +3 -2
  28. package/dist/chunk-QTFKZBLC.cjs.map +1 -0
  29. package/dist/{chunk-LOUJRBXV.js → chunk-QXOZI5Q2.js} +3 -2
  30. package/dist/chunk-QXOZI5Q2.js.map +1 -0
  31. package/dist/{chunk-7JMMLHPQ.js → chunk-VJCLJH3X.js} +9 -2
  32. package/dist/chunk-VJCLJH3X.js.map +1 -0
  33. package/dist/index.cjs +751 -152
  34. package/dist/index.cjs.map +1 -1
  35. package/dist/index.d.cts +125 -5
  36. package/dist/index.d.ts +125 -5
  37. package/dist/index.js +582 -15
  38. package/dist/index.js.map +1 -1
  39. package/dist/middleware.cjs +29 -29
  40. package/dist/middleware.js +3 -3
  41. package/dist/migrations-UFVJTPVT.js +4 -0
  42. package/dist/{migrations-N2C2VPJU.js.map → migrations-UFVJTPVT.js.map} +1 -1
  43. package/dist/migrations-VNYOSUNE.cjs +13 -0
  44. package/dist/{migrations-ONIAY6GK.cjs.map → migrations-VNYOSUNE.cjs.map} +1 -1
  45. package/dist/{plugin-0Xogrln-.d.cts → plugin-DDYetMF-.d.cts} +1 -0
  46. package/dist/{plugin-0Xogrln-.d.ts → plugin-DDYetMF-.d.ts} +1 -0
  47. package/dist/{plugin-bootstrap-fpG98Otb.d.cts → plugin-bootstrap-DCXpeQVb.d.cts} +229 -1
  48. package/dist/{plugin-bootstrap-WmpvYM5w.d.ts → plugin-bootstrap-DXBAYaqM.d.ts} +229 -1
  49. package/dist/{plugin-manager-GcIeb226.d.cts → plugin-manager-BoM3Q7o7.d.cts} +1 -1
  50. package/dist/{plugin-manager-Clf2gXwj.d.ts → plugin-manager-Efx9RyDX.d.ts} +1 -1
  51. package/dist/plugins.cjs +10 -10
  52. package/dist/plugins.d.cts +2 -2
  53. package/dist/plugins.d.ts +2 -2
  54. package/dist/plugins.js +2 -2
  55. package/dist/routes.cjs +29 -29
  56. package/dist/routes.js +6 -6
  57. package/dist/services.cjs +60 -32
  58. package/dist/services.d.cts +1 -1
  59. package/dist/services.d.ts +1 -1
  60. package/dist/services.js +3 -3
  61. package/dist/types.cjs +2 -2
  62. package/dist/types.d.cts +1 -1
  63. package/dist/types.d.ts +1 -1
  64. package/dist/types.js +1 -1
  65. package/dist/utils.cjs +11 -11
  66. package/dist/utils.js +1 -1
  67. package/migrations/033_form_content_integration.sql +19 -0
  68. package/package.json +1 -1
  69. package/dist/chunk-27AOVQTR.js.map +0 -1
  70. package/dist/chunk-4TTMQQC7.js.map +0 -1
  71. package/dist/chunk-64APW3DW.cjs.map +0 -1
  72. package/dist/chunk-6O3RJV3C.js.map +0 -1
  73. package/dist/chunk-7JMMLHPQ.js.map +0 -1
  74. package/dist/chunk-IIBRG5S5.cjs.map +0 -1
  75. package/dist/chunk-IT2TC4ZD.cjs.map +0 -1
  76. package/dist/chunk-JTNUM7JE.js.map +0 -1
  77. package/dist/chunk-KYGRJCZM.cjs.map +0 -1
  78. package/dist/chunk-LOUJRBXV.js.map +0 -1
  79. package/dist/chunk-RCA6R6VE.cjs.map +0 -1
  80. package/dist/chunk-ZMVWMJ3S.cjs.map +0 -1
  81. package/dist/migrations-N2C2VPJU.js +0 -4
  82. package/dist/migrations-ONIAY6GK.cjs +0 -13
@@ -1,10 +1,10 @@
1
- import { getCacheService, CACHE_CONFIGS, getLogger, SettingsService, getAppInstance, buildRouteList, CATEGORY_INFO } from './chunk-7JMMLHPQ.js';
2
- import { requireAuth, requireRole, isPluginActive, optionalAuth, rateLimit, AuthManager, logActivity, generateCsrfToken } from './chunk-4TTMQQC7.js';
3
- import { PluginService } from './chunk-27AOVQTR.js';
4
- import { MigrationService } from './chunk-6O3RJV3C.js';
1
+ import { getCacheService, CACHE_CONFIGS, SettingsService, getLogger, getAppInstance, buildRouteList, CATEGORY_INFO } from './chunk-VJCLJH3X.js';
2
+ import { requireAuth, requireRole, isPluginActive, optionalAuth, rateLimit, AuthManager, logActivity, generateCsrfToken } from './chunk-GKRGDJGG.js';
3
+ import { PluginService, createContentFromSubmission } from './chunk-NMLFKXWW.js';
4
+ import { MigrationService } from './chunk-H55AYIRI.js';
5
5
  import { init_admin_layout_catalyst_template, renderDesignPage, renderCheckboxPage, renderTestimonialsList, renderCodeExamplesList, renderAlert, renderTable, renderPagination, renderConfirmationDialog, getConfirmationDialogScript, renderAdminLayoutCatalyst, renderAdminLayout, adminLayoutV2, renderForm } from './chunk-JJS7JZCH.js';
6
6
  import { PluginBuilder, TurnstileService } from './chunk-J5WGMRSU.js';
7
- import { QueryFilterBuilder, getCoreVersion, getBlocksFieldConfig, parseBlocksValue } from './chunk-IZWNIUJI.js';
7
+ import { QueryFilterBuilder, getCoreVersion, getBlocksFieldConfig, parseBlocksValue } from './chunk-BUU2US2Z.js';
8
8
  import { metricsTracker } from './chunk-FICTAGD4.js';
9
9
  import { escapeHtml, sanitizeRichText, sanitizeInput } from './chunk-TQABQWOP.js';
10
10
  import { Hono } from 'hono';
@@ -59,6 +59,69 @@ function normalizePublicContentFilter(filter, userRole) {
59
59
  });
60
60
  return normalizedFilter;
61
61
  }
62
+
63
+ // src/plugins/core-plugins/global-variables-plugin/variable-resolver.ts
64
+ var TOKEN_PATTERN = /\{([a-z0-9_]+)\}/g;
65
+ function resolveVariables(text, variables) {
66
+ if (!text || variables.size === 0) return text;
67
+ return text.replace(TOKEN_PATTERN, (match, key) => {
68
+ const value = variables.get(key);
69
+ return value !== void 0 ? value : match;
70
+ });
71
+ }
72
+ function resolveVariablesInObject(obj, variables) {
73
+ if (!obj || variables.size === 0) return obj;
74
+ if (typeof obj === "string") {
75
+ return resolveVariables(obj, variables);
76
+ }
77
+ if (Array.isArray(obj)) {
78
+ return obj.map((item) => resolveVariablesInObject(item, variables));
79
+ }
80
+ if (typeof obj === "object") {
81
+ const result = {};
82
+ for (const [key, value] of Object.entries(obj)) {
83
+ result[key] = resolveVariablesInObject(value, variables);
84
+ }
85
+ return result;
86
+ }
87
+ return obj;
88
+ }
89
+ var variableCache = null;
90
+ var cacheTimestamp = 0;
91
+ var CACHE_TTL_MS = 3e5;
92
+ function getVariablesCached() {
93
+ const now = Date.now();
94
+ if (variableCache && now - cacheTimestamp < CACHE_TTL_MS) {
95
+ return variableCache;
96
+ }
97
+ return null;
98
+ }
99
+ function setVariablesCache(map) {
100
+ variableCache = map;
101
+ cacheTimestamp = Date.now();
102
+ }
103
+ async function resolveContentVariables(contentData, db) {
104
+ if (!db || !contentData) return contentData;
105
+ try {
106
+ let variables = getVariablesCached();
107
+ if (!variables) {
108
+ const { results } = await db.prepare(
109
+ "SELECT key, value FROM global_variables WHERE is_active = 1"
110
+ ).all();
111
+ variables = /* @__PURE__ */ new Map();
112
+ for (const row of results || []) {
113
+ variables.set(row.key, row.value);
114
+ }
115
+ setVariablesCache(variables);
116
+ }
117
+ if (variables.size === 0) return contentData;
118
+ return resolveVariablesInObject(contentData, variables);
119
+ } catch {
120
+ return contentData;
121
+ }
122
+ }
123
+
124
+ // src/routes/api-content-crud.ts
62
125
  var apiContentCrudRoutes = new Hono();
63
126
  apiContentCrudRoutes.get("/check-slug", async (c) => {
64
127
  try {
@@ -110,6 +173,10 @@ apiContentCrudRoutes.get("/:id", async (c) => {
110
173
  created_at: content.created_at,
111
174
  updated_at: content.updated_at
112
175
  };
176
+ const resolveVars = c.req.query("resolve_variables") !== "false";
177
+ if (resolveVars) {
178
+ transformedContent.data = await resolveContentVariables(transformedContent.data, db);
179
+ }
113
180
  return c.json({ data: transformedContent });
114
181
  } catch (error) {
115
182
  console.error("Error fetching content:", error);
@@ -748,7 +815,7 @@ apiRoutes.get("/collections", async (c) => {
748
815
  }
749
816
  c.header("X-Cache-Status", "MISS");
750
817
  c.header("X-Cache-Source", "database");
751
- const stmt = db.prepare("SELECT * FROM collections WHERE is_active = 1");
818
+ const stmt = db.prepare("SELECT * FROM collections WHERE is_active = 1 AND (source_type IS NULL OR source_type = 'user')");
752
819
  const { results } = await stmt.all();
753
820
  const transformedResults = results.map((row) => ({
754
821
  ...row,
@@ -1777,7 +1844,7 @@ adminApiRoutes.get("/stats", async (c) => {
1777
1844
  const db = c.env.DB;
1778
1845
  let collectionsCount = 0;
1779
1846
  try {
1780
- const collectionsStmt = db.prepare("SELECT COUNT(*) as count FROM collections WHERE is_active = 1");
1847
+ const collectionsStmt = db.prepare("SELECT COUNT(*) as count FROM collections WHERE is_active = 1 AND (source_type IS NULL OR source_type = 'user')");
1781
1848
  const collectionsResult = await collectionsStmt.first();
1782
1849
  collectionsCount = collectionsResult?.count || 0;
1783
1850
  } catch (error) {
@@ -1785,7 +1852,7 @@ adminApiRoutes.get("/stats", async (c) => {
1785
1852
  }
1786
1853
  let contentCount = 0;
1787
1854
  try {
1788
- const contentStmt = db.prepare("SELECT COUNT(*) as count FROM content WHERE deleted_at IS NULL");
1855
+ const contentStmt = db.prepare("SELECT COUNT(*) as count FROM content c JOIN collections col ON c.collection_id = col.id WHERE c.deleted_at IS NULL AND (col.source_type IS NULL OR col.source_type = 'user')");
1789
1856
  const contentResult = await contentStmt.first();
1790
1857
  contentCount = contentResult?.count || 0;
1791
1858
  } catch (error) {
@@ -1927,6 +1994,7 @@ adminApiRoutes.get("/collections", async (c) => {
1927
1994
  SELECT id, name, display_name, description, created_at, updated_at, is_active, managed
1928
1995
  FROM collections
1929
1996
  WHERE ${includeInactive ? "1=1" : "is_active = 1"}
1997
+ AND (source_type IS NULL OR source_type = 'user')
1930
1998
  AND (name LIKE ? OR display_name LIKE ? OR description LIKE ?)
1931
1999
  ORDER BY created_at DESC
1932
2000
  `);
@@ -1937,7 +2005,8 @@ adminApiRoutes.get("/collections", async (c) => {
1937
2005
  stmt = db.prepare(`
1938
2006
  SELECT id, name, display_name, description, created_at, updated_at, is_active, managed
1939
2007
  FROM collections
1940
- ${includeInactive ? "" : "WHERE is_active = 1"}
2008
+ WHERE (source_type IS NULL OR source_type = 'user')
2009
+ ${includeInactive ? "" : "AND is_active = 1"}
1941
2010
  ORDER BY created_at DESC
1942
2011
  `);
1943
2012
  const queryResults = await stmt.all();
@@ -2281,7 +2350,7 @@ adminApiRoutes.delete("/collections/:id", async (c) => {
2281
2350
  });
2282
2351
  adminApiRoutes.get("/migrations/status", async (c) => {
2283
2352
  try {
2284
- const { MigrationService: MigrationService2 } = await import('./migrations-N2C2VPJU.js');
2353
+ const { MigrationService: MigrationService2 } = await import('./migrations-UFVJTPVT.js');
2285
2354
  const db = c.env.DB;
2286
2355
  const migrationService = new MigrationService2(db);
2287
2356
  const status = await migrationService.getMigrationStatus();
@@ -2306,7 +2375,7 @@ adminApiRoutes.post("/migrations/run", async (c) => {
2306
2375
  error: "Unauthorized. Admin access required."
2307
2376
  }, 403);
2308
2377
  }
2309
- const { MigrationService: MigrationService2 } = await import('./migrations-N2C2VPJU.js');
2378
+ const { MigrationService: MigrationService2 } = await import('./migrations-UFVJTPVT.js');
2310
2379
  const db = c.env.DB;
2311
2380
  const migrationService = new MigrationService2(db);
2312
2381
  const result = await migrationService.runPendingMigrations();
@@ -2325,7 +2394,7 @@ adminApiRoutes.post("/migrations/run", async (c) => {
2325
2394
  });
2326
2395
  adminApiRoutes.get("/migrations/validate", async (c) => {
2327
2396
  try {
2328
- const { MigrationService: MigrationService2 } = await import('./migrations-N2C2VPJU.js');
2397
+ const { MigrationService: MigrationService2 } = await import('./migrations-UFVJTPVT.js');
2329
2398
  const db = c.env.DB;
2330
2399
  const migrationService = new MigrationService2(db);
2331
2400
  const validation = await migrationService.validateSchema();
@@ -8137,7 +8206,15 @@ function renderContentFormPage(data) {
8137
8206
  fetch(\`/admin/content/\${contentId}/versions\`)
8138
8207
  .then(response => response.text())
8139
8208
  .then(html => {
8140
- document.getElementById('version-history-content').innerHTML = html;
8209
+ const container = document.getElementById('version-history-content');
8210
+ container.innerHTML = html;
8211
+ // Script tags inserted via innerHTML are not executed by the browser,
8212
+ // so we need to manually create and append them for execution.
8213
+ container.querySelectorAll('script').forEach(oldScript => {
8214
+ const newScript = document.createElement('script');
8215
+ newScript.textContent = oldScript.textContent;
8216
+ oldScript.replaceWith(newScript);
8217
+ });
8141
8218
  })
8142
8219
  .catch(error => {
8143
8220
  console.error('Error loading version history:', error);
@@ -9357,7 +9434,7 @@ adminContentRoutes.get("/", async (c) => {
9357
9434
  const status = url.searchParams.get("status") || "all";
9358
9435
  const search = url.searchParams.get("search") || "";
9359
9436
  const offset = (page - 1) * limit;
9360
- const collectionsStmt = db.prepare("SELECT id, name, display_name FROM collections WHERE is_active = 1 ORDER BY display_name");
9437
+ const collectionsStmt = db.prepare("SELECT id, name, display_name FROM collections WHERE is_active = 1 AND (source_type IS NULL OR source_type = 'user') ORDER BY display_name");
9361
9438
  const { results: collectionsResults } = await collectionsStmt.all();
9362
9439
  const models = (collectionsResults || []).map((row) => ({
9363
9440
  name: row.name,
@@ -9365,6 +9442,7 @@ adminContentRoutes.get("/", async (c) => {
9365
9442
  }));
9366
9443
  const conditions = [];
9367
9444
  const params = [];
9445
+ conditions.push("(col.source_type IS NULL OR col.source_type = 'user')");
9368
9446
  if (status !== "deleted") {
9369
9447
  conditions.push("c.status != 'deleted'");
9370
9448
  }
@@ -9493,7 +9571,7 @@ adminContentRoutes.get("/new", async (c) => {
9493
9571
  const collectionId = url.searchParams.get("collection");
9494
9572
  if (!collectionId) {
9495
9573
  const db2 = c.env.DB;
9496
- const collectionsStmt = db2.prepare("SELECT id, name, display_name, description FROM collections WHERE is_active = 1 ORDER BY display_name");
9574
+ const collectionsStmt = db2.prepare("SELECT id, name, display_name, description FROM collections WHERE is_active = 1 AND (source_type IS NULL OR source_type = 'user') ORDER BY display_name");
9497
9575
  const { results } = await collectionsStmt.all();
9498
9576
  const collections = (results || []).map((row) => ({
9499
9577
  id: row.id,
@@ -11417,6 +11495,36 @@ function renderUserEditPage(data) {
11417
11495
  </div>
11418
11496
  </div>
11419
11497
 
11498
+ <!-- Set Password -->
11499
+ <div class="mb-8">
11500
+ <h3 class="text-base font-semibold text-zinc-950 dark:text-white mb-4">Set Password</h3>
11501
+ <p class="text-sm text-zinc-500 dark:text-zinc-400 mb-4">Leave blank to keep the current password</p>
11502
+ <div class="grid grid-cols-1 md:grid-cols-2 gap-6">
11503
+ <div>
11504
+ <label class="block text-sm font-medium text-zinc-950 dark:text-white mb-2">New Password</label>
11505
+ <input
11506
+ type="password"
11507
+ name="new_password"
11508
+ minlength="8"
11509
+ placeholder="Minimum 8 characters"
11510
+ autocomplete="new-password"
11511
+ 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"
11512
+ />
11513
+ </div>
11514
+ <div>
11515
+ <label class="block text-sm font-medium text-zinc-950 dark:text-white mb-2">Confirm Password</label>
11516
+ <input
11517
+ type="password"
11518
+ name="confirm_password"
11519
+ minlength="8"
11520
+ placeholder="Repeat new password"
11521
+ autocomplete="new-password"
11522
+ 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"
11523
+ />
11524
+ </div>
11525
+ </div>
11526
+ </div>
11527
+
11420
11528
  <!-- Account Status -->
11421
11529
  <div class="mb-8">
11422
11530
  <h3 class="text-base font-semibold text-zinc-950 dark:text-white mb-4">Account Status</h3>
@@ -12738,6 +12846,7 @@ userRoutes.get("/users", async (c) => {
12738
12846
  formattedLastLogin: u.last_login_at ? new Date(u.last_login_at).toLocaleDateString() : void 0,
12739
12847
  formattedCreatedAt: new Date(u.created_at).toLocaleDateString()
12740
12848
  }));
12849
+ const successMessage = c.req.query("success") || void 0;
12741
12850
  const pageData = {
12742
12851
  users,
12743
12852
  currentPage: page,
@@ -12746,6 +12855,7 @@ userRoutes.get("/users", async (c) => {
12746
12855
  searchFilter: search,
12747
12856
  roleFilter,
12748
12857
  statusFilter,
12858
+ success: successMessage,
12749
12859
  pagination: {
12750
12860
  currentPage: page,
12751
12861
  totalPages: Math.ceil(totalUsers / limit),
@@ -12889,7 +12999,8 @@ userRoutes.post("/users/new", async (c) => {
12889
12999
  c.req.header("x-forwarded-for") || c.req.header("cf-connecting-ip"),
12890
13000
  c.req.header("user-agent")
12891
13001
  );
12892
- return c.redirect(`/admin/users/${userId}/edit?success=User created successfully`);
13002
+ c.header("HX-Redirect", "/admin/users?success=User created successfully");
13003
+ return c.body(null, 200);
12893
13004
  } catch (error) {
12894
13005
  console.error("User creation error:", error);
12895
13006
  return c.html(renderAlert2({
@@ -13035,6 +13146,8 @@ userRoutes.put("/users/:id", async (c) => {
13035
13146
  const role = validRoles.includes(roleInput) ? roleInput : "viewer";
13036
13147
  const isActive = formData.get("is_active") === "1";
13037
13148
  const emailVerified = formData.get("email_verified") === "1";
13149
+ const newPassword = formData.get("new_password")?.toString() || "";
13150
+ const confirmPassword = formData.get("confirm_password")?.toString() || "";
13038
13151
  const profileDisplayName = sanitizeInput(formData.get("profile_display_name")?.toString()) || null;
13039
13152
  const profileBio = sanitizeInput(formData.get("profile_bio")?.toString()) || null;
13040
13153
  const profileCompany = sanitizeInput(formData.get("profile_company")?.toString()) || null;
@@ -13058,6 +13171,22 @@ userRoutes.put("/users/:id", async (c) => {
13058
13171
  dismissible: true
13059
13172
  }));
13060
13173
  }
13174
+ if (newPassword) {
13175
+ if (newPassword.length < 8) {
13176
+ return c.html(renderAlert2({
13177
+ type: "error",
13178
+ message: "Password must be at least 8 characters long.",
13179
+ dismissible: true
13180
+ }));
13181
+ }
13182
+ if (newPassword !== confirmPassword) {
13183
+ return c.html(renderAlert2({
13184
+ type: "error",
13185
+ message: "Passwords do not match.",
13186
+ dismissible: true
13187
+ }));
13188
+ }
13189
+ }
13061
13190
  if (profileWebsite) {
13062
13191
  try {
13063
13192
  new URL(profileWebsite);
@@ -13100,6 +13229,13 @@ userRoutes.put("/users/:id", async (c) => {
13100
13229
  Date.now(),
13101
13230
  userId
13102
13231
  ).run();
13232
+ if (newPassword) {
13233
+ const passwordHash = await AuthManager.hashPassword(newPassword);
13234
+ const updatePasswordStmt = db.prepare(`
13235
+ UPDATE users SET password_hash = ?, updated_at = ? WHERE id = ?
13236
+ `);
13237
+ await updatePasswordStmt.bind(passwordHash, Date.now(), userId).run();
13238
+ }
13103
13239
  const hasProfileData = profileDisplayName || profileBio || profileCompany || profileJobTitle || profileWebsite || profileLocation || profileDateOfBirth;
13104
13240
  if (hasProfileData) {
13105
13241
  const now = Date.now();
@@ -13150,7 +13286,7 @@ userRoutes.put("/users/:id", async (c) => {
13150
13286
  "user.update",
13151
13287
  "users",
13152
13288
  userId,
13153
- { fields: ["first_name", "last_name", "username", "email", "phone", "role", "is_active", "email_verified", "profile"] },
13289
+ { fields: ["first_name", "last_name", "username", "email", "phone", "role", "is_active", "email_verified", "profile", ...newPassword ? ["password"] : []] },
13154
13290
  c.req.header("x-forwarded-for") || c.req.header("cf-connecting-ip"),
13155
13291
  c.req.header("user-agent")
13156
13292
  );
@@ -17250,6 +17386,7 @@ function renderOTPLoginSettingsContent(plugin, settings) {
17250
17386
  const maxAttempts = settings.maxAttempts || 3;
17251
17387
  const rateLimitPerHour = settings.rateLimitPerHour || 5;
17252
17388
  const allowNewUserRegistration = settings.allowNewUserRegistration || false;
17389
+ const logoUrl = settings.logoUrl || "";
17253
17390
  return `
17254
17391
  <div class="space-y-6">
17255
17392
  <!-- Test OTP Section -->
@@ -17433,6 +17570,7 @@ function renderOTPLoginSettingsContent(plugin, settings) {
17433
17570
 
17434
17571
  <div class="bg-white rounded-lg overflow-hidden shadow-lg">
17435
17572
  <div style="background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; padding: 30px 20px; text-align: center;">
17573
+ ${logoUrl ? `<img src="${logoUrl}" alt="Logo" style="max-width: 150px; height: auto; margin: 0 auto 16px;">` : ""}
17436
17574
  <h3 style="margin: 0 0 8px 0; font-size: 24px; font-weight: 600;">Your Login Code</h3>
17437
17575
  <p style="margin: 0; opacity: 0.95; font-size: 14px;">Enter this code to sign in to ${siteName}</p>
17438
17576
  </div>
@@ -17957,17 +18095,9 @@ adminPluginRoutes.get("/:id", async (c) => {
17957
18095
  const activity = await pluginService.getPluginActivity(pluginId, 20);
17958
18096
  let enrichedSettings = plugin.settings || {};
17959
18097
  if (pluginId === "otp-login") {
17960
- const generalSettings = await db.prepare(`
17961
- SELECT value FROM settings WHERE key = 'general'
17962
- `).first();
17963
- let siteName = "SonicJS";
17964
- if (generalSettings?.value) {
17965
- try {
17966
- const parsed = JSON.parse(generalSettings.value);
17967
- siteName = parsed.siteName || "SonicJS";
17968
- } catch (e) {
17969
- }
17970
- }
18098
+ const settingsService = new SettingsService(db);
18099
+ const generalSettings = await settingsService.getGeneralSettings();
18100
+ const siteName = generalSettings.siteName || "SonicJS";
17971
18101
  const emailPlugin = await db.prepare(`
17972
18102
  SELECT settings FROM plugins WHERE id = 'email'
17973
18103
  `).first();
@@ -21524,7 +21654,7 @@ router.get("/stats", async (c) => {
21524
21654
  const db = c.env.DB;
21525
21655
  let collectionsCount = 0;
21526
21656
  try {
21527
- const collectionsStmt = db.prepare("SELECT COUNT(*) as count FROM collections WHERE is_active = 1");
21657
+ const collectionsStmt = db.prepare("SELECT COUNT(*) as count FROM collections WHERE is_active = 1 AND (source_type IS NULL OR source_type = 'user')");
21528
21658
  const collectionsResult = await collectionsStmt.first();
21529
21659
  collectionsCount = collectionsResult?.count || 0;
21530
21660
  } catch (error) {
@@ -21532,7 +21662,7 @@ router.get("/stats", async (c) => {
21532
21662
  }
21533
21663
  let contentCount = 0;
21534
21664
  try {
21535
- const contentStmt = db.prepare("SELECT COUNT(*) as count FROM content");
21665
+ const contentStmt = db.prepare("SELECT COUNT(*) as count FROM content c JOIN collections col ON c.collection_id = col.id WHERE (col.source_type IS NULL OR col.source_type = 'user')");
21536
21666
  const contentResult = await contentStmt.first();
21537
21667
  contentCount = contentResult?.count || 0;
21538
21668
  } catch (error) {
@@ -23329,6 +23459,7 @@ adminCollectionsRoutes.get("/", async (c) => {
23329
23459
  SELECT id, name, display_name, description, created_at, managed, schema
23330
23460
  FROM collections
23331
23461
  WHERE is_active = 1
23462
+ AND (source_type IS NULL OR source_type = 'user')
23332
23463
  AND (name LIKE ? OR display_name LIKE ? OR description LIKE ?)
23333
23464
  ORDER BY created_at DESC
23334
23465
  `);
@@ -23336,7 +23467,7 @@ adminCollectionsRoutes.get("/", async (c) => {
23336
23467
  const queryResults = await stmt.bind(searchParam, searchParam, searchParam).all();
23337
23468
  results = queryResults.results;
23338
23469
  } else {
23339
- stmt = db.prepare("SELECT id, name, display_name, description, created_at, managed, schema FROM collections WHERE is_active = 1 ORDER BY created_at DESC");
23470
+ stmt = db.prepare("SELECT id, name, display_name, description, created_at, managed, schema FROM collections WHERE is_active = 1 AND (source_type IS NULL OR source_type = 'user') ORDER BY created_at DESC");
23340
23471
  const queryResults = await stmt.all();
23341
23472
  results = queryResults.results;
23342
23473
  }
@@ -28408,14 +28539,36 @@ publicFormsRoutes.post("/:identifier/submit", async (c) => {
28408
28539
  now
28409
28540
  ).run();
28410
28541
  await db.prepare(`
28411
- UPDATE forms
28542
+ UPDATE forms
28412
28543
  SET submission_count = submission_count + 1,
28413
28544
  updated_at = ?
28414
28545
  WHERE id = ?
28415
28546
  `).bind(now, form.id).run();
28547
+ let contentId = null;
28548
+ try {
28549
+ contentId = await createContentFromSubmission(
28550
+ db,
28551
+ sanitizedData,
28552
+ { id: form.id, name: form.name, display_name: form.display_name },
28553
+ submissionId,
28554
+ {
28555
+ ipAddress: c.req.header("cf-connecting-ip") || null,
28556
+ userAgent: c.req.header("user-agent") || null,
28557
+ userEmail: sanitizedData?.email || null,
28558
+ userId: null
28559
+ // anonymous submission
28560
+ }
28561
+ );
28562
+ if (!contentId) {
28563
+ console.warn("[FormSubmit] Content creation returned null for submission:", submissionId);
28564
+ }
28565
+ } catch (contentError) {
28566
+ console.error("[FormSubmit] Error creating content from submission:", contentError);
28567
+ }
28416
28568
  return c.json({
28417
28569
  success: true,
28418
28570
  submissionId,
28571
+ contentId,
28419
28572
  message: "Form submitted successfully"
28420
28573
  });
28421
28574
  } catch (error) {
@@ -28826,5 +28979,5 @@ var ROUTES_INFO = {
28826
28979
  };
28827
28980
 
28828
28981
  export { ROUTES_INFO, adminCheckboxRoutes, adminCollectionsRoutes, adminDesignRoutes, adminFormsRoutes, adminLogsRoutes, adminMediaRoutes, adminPluginRoutes, adminSettingsRoutes, admin_api_default, admin_code_examples_default, admin_content_default, admin_testimonials_default, api_content_crud_default, api_default, api_media_default, api_system_default, auth_default, getConfirmationDialogScript2 as getConfirmationDialogScript, public_forms_default, renderConfirmationDialog2 as renderConfirmationDialog, router, router2, test_cleanup_default, userRoutes };
28829
- //# sourceMappingURL=chunk-JTNUM7JE.js.map
28830
- //# sourceMappingURL=chunk-JTNUM7JE.js.map
28982
+ //# sourceMappingURL=chunk-JTQBNSZX.js.map
28983
+ //# sourceMappingURL=chunk-JTQBNSZX.js.map