@sonicjs-cms/core 2.7.0 → 2.8.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 (96) hide show
  1. package/dist/{app-DV27cjPy.d.cts → app-CYEm1ytG.d.cts} +1 -0
  2. package/dist/{app-DV27cjPy.d.ts → app-CYEm1ytG.d.ts} +1 -0
  3. package/dist/{chunk-DNHJS6RN.js → chunk-34QIAULP.js} +4 -4
  4. package/dist/{chunk-DNHJS6RN.js.map → chunk-34QIAULP.js.map} +1 -1
  5. package/dist/{chunk-Y3EWJQ4D.js → chunk-3E76TKR5.js} +3 -3
  6. package/dist/{chunk-Y3EWJQ4D.js.map → chunk-3E76TKR5.js.map} +1 -1
  7. package/dist/{chunk-YRFAQ6MI.cjs → chunk-5CENPGR2.cjs} +219 -14
  8. package/dist/chunk-5CENPGR2.cjs.map +1 -0
  9. package/dist/{chunk-MYB5RY7H.cjs → chunk-5HMR2SJW.cjs} +4 -4
  10. package/dist/{chunk-MYB5RY7H.cjs.map → chunk-5HMR2SJW.cjs.map} +1 -1
  11. package/dist/{chunk-YHW27CBV.cjs → chunk-6FHNRRJ3.cjs} +190 -2
  12. package/dist/chunk-6FHNRRJ3.cjs.map +1 -0
  13. package/dist/{chunk-UISZ2MBW.js → chunk-BAWMAS5S.js} +5438 -1443
  14. package/dist/chunk-BAWMAS5S.js.map +1 -0
  15. package/dist/{chunk-F332TENF.js → chunk-CJYFSKH7.js} +4 -190
  16. package/dist/chunk-CJYFSKH7.js.map +1 -0
  17. package/dist/{chunk-3YNNVSMC.js → chunk-G44QUVNM.js} +90 -2
  18. package/dist/chunk-G44QUVNM.js.map +1 -0
  19. package/dist/{chunk-E2BXLXPW.cjs → chunk-GPTMGUFN.cjs} +4 -4
  20. package/dist/{chunk-E2BXLXPW.cjs.map → chunk-GPTMGUFN.cjs.map} +1 -1
  21. package/dist/chunk-H7AMQWVI.js +2466 -0
  22. package/dist/chunk-H7AMQWVI.js.map +1 -0
  23. package/dist/{chunk-CLIH2T74.js → chunk-J5WGMRSU.js} +189 -3
  24. package/dist/chunk-J5WGMRSU.js.map +1 -0
  25. package/dist/{chunk-L2IDZI7F.js → chunk-JDFPB6UW.js} +219 -14
  26. package/dist/chunk-JDFPB6UW.js.map +1 -0
  27. package/dist/{chunk-Y72M3MVX.cjs → chunk-MNFY6DWY.cjs} +13 -200
  28. package/dist/chunk-MNFY6DWY.cjs.map +1 -0
  29. package/dist/chunk-S6K2H2TS.cjs +2470 -0
  30. package/dist/chunk-S6K2H2TS.cjs.map +1 -0
  31. package/dist/{chunk-EHSZ6TAN.cjs → chunk-SHCYIZAN.cjs} +9 -2
  32. package/dist/chunk-SHCYIZAN.cjs.map +1 -0
  33. package/dist/{chunk-GRN3GHUG.js → chunk-VCH6HXVP.js} +9 -2
  34. package/dist/chunk-VCH6HXVP.js.map +1 -0
  35. package/dist/{chunk-7FOAMNTI.cjs → chunk-VNLR35GO.cjs} +90 -2
  36. package/dist/chunk-VNLR35GO.cjs.map +1 -0
  37. package/dist/{chunk-J7F3NPAP.cjs → chunk-YE2MU7CN.cjs} +5192 -1194
  38. package/dist/chunk-YE2MU7CN.cjs.map +1 -0
  39. package/dist/index.cjs +201 -607
  40. package/dist/index.cjs.map +1 -1
  41. package/dist/index.d.cts +3 -3
  42. package/dist/index.d.ts +3 -3
  43. package/dist/index.js +67 -473
  44. package/dist/index.js.map +1 -1
  45. package/dist/middleware.cjs +23 -23
  46. package/dist/middleware.d.cts +1 -1
  47. package/dist/middleware.d.ts +1 -1
  48. package/dist/middleware.js +2 -2
  49. package/dist/migrations-7JGSFOCM.cjs +13 -0
  50. package/dist/{migrations-LEMFV2ND.cjs.map → migrations-7JGSFOCM.cjs.map} +1 -1
  51. package/dist/migrations-YB77VTVF.js +4 -0
  52. package/dist/{migrations-RKQES6XY.js.map → migrations-YB77VTVF.js.map} +1 -1
  53. package/dist/{plugin-bootstrap-CB-xaBfK.d.ts → plugin-bootstrap-C7Mj00Ud.d.ts} +2455 -1
  54. package/dist/{plugin-bootstrap-U-cw9jn3.d.cts → plugin-bootstrap-DKB5f8-E.d.cts} +2455 -1
  55. package/dist/plugins.cjs +14 -14
  56. package/dist/plugins.js +2 -2
  57. package/dist/routes.cjs +39 -27
  58. package/dist/routes.d.cts +126 -53
  59. package/dist/routes.d.ts +126 -53
  60. package/dist/routes.js +7 -7
  61. package/dist/services.cjs +14 -14
  62. package/dist/services.d.cts +1 -1
  63. package/dist/services.d.ts +1 -1
  64. package/dist/services.js +2 -2
  65. package/dist/templates.cjs +25 -17
  66. package/dist/templates.d.cts +21 -1
  67. package/dist/templates.d.ts +21 -1
  68. package/dist/templates.js +2 -2
  69. package/dist/utils.cjs +14 -14
  70. package/dist/utils.js +1 -1
  71. package/migrations/014_fix_plugin_registry.sql +1 -1
  72. package/migrations/020_add_email_plugin.sql +1 -1
  73. package/migrations/026_add_otp_login.sql +1 -1
  74. package/migrations/029_add_forms_system.sql +184 -0
  75. package/migrations/030_add_turnstile_to_forms.sql +14 -0
  76. package/package.json +2 -2
  77. package/dist/chunk-3YNNVSMC.js.map +0 -1
  78. package/dist/chunk-7FOAMNTI.cjs.map +0 -1
  79. package/dist/chunk-AYPF6C4D.cjs +0 -76
  80. package/dist/chunk-AYPF6C4D.cjs.map +0 -1
  81. package/dist/chunk-CLIH2T74.js.map +0 -1
  82. package/dist/chunk-EHSZ6TAN.cjs.map +0 -1
  83. package/dist/chunk-F332TENF.js.map +0 -1
  84. package/dist/chunk-GRN3GHUG.js.map +0 -1
  85. package/dist/chunk-J7F3NPAP.cjs.map +0 -1
  86. package/dist/chunk-L2IDZI7F.js.map +0 -1
  87. package/dist/chunk-UISZ2MBW.js.map +0 -1
  88. package/dist/chunk-V3KVSEG6.js +0 -74
  89. package/dist/chunk-V3KVSEG6.js.map +0 -1
  90. package/dist/chunk-Y72M3MVX.cjs.map +0 -1
  91. package/dist/chunk-YHW27CBV.cjs.map +0 -1
  92. package/dist/chunk-YRFAQ6MI.cjs.map +0 -1
  93. package/dist/migrations-LEMFV2ND.cjs +0 -13
  94. package/dist/migrations-RKQES6XY.js +0 -4
  95. package/migrations/025_rename_mdxeditor_to_easy_mdx.sql +0 -22
  96. /package/migrations/{029_ai_search_plugin.sql → 031_ai_search_plugin.sql} +0 -0
package/dist/index.js CHANGED
@@ -1,25 +1,24 @@
1
- import { renderConfirmationDialog, getConfirmationDialogScript, api_default, api_media_default, api_system_default, admin_api_default, router, adminCollectionsRoutes, adminSettingsRoutes, admin_content_default, adminMediaRoutes, adminPluginRoutes, adminLogsRoutes, userRoutes, auth_default, test_cleanup_default } from './chunk-UISZ2MBW.js';
2
- export { ROUTES_INFO, admin_api_default as adminApiRoutes, adminCheckboxRoutes, admin_code_examples_default as adminCodeExamplesRoutes, adminCollectionsRoutes, admin_content_default as adminContentRoutes, router as adminDashboardRoutes, adminDesignRoutes, adminLogsRoutes, adminMediaRoutes, adminPluginRoutes, adminSettingsRoutes, admin_testimonials_default as adminTestimonialsRoutes, userRoutes as adminUsersRoutes, api_content_crud_default as apiContentCrudRoutes, api_media_default as apiMediaRoutes, api_default as apiRoutes, api_system_default as apiSystemRoutes, auth_default as authRoutes } from './chunk-UISZ2MBW.js';
3
- import { schema_exports } from './chunk-3YNNVSMC.js';
4
- export { Logger, apiTokens, collections, content, contentVersions, getLogger, initLogger, insertCollectionSchema, insertContentSchema, insertLogConfigSchema, insertMediaSchema, insertPluginActivityLogSchema, insertPluginAssetSchema, insertPluginHookSchema, insertPluginRouteSchema, insertPluginSchema, insertSystemLogSchema, insertUserSchema, insertWorkflowHistorySchema, logConfig, media, pluginActivityLog, pluginAssets, pluginHooks, pluginRoutes, plugins, selectCollectionSchema, selectContentSchema, selectLogConfigSchema, selectMediaSchema, selectPluginActivityLogSchema, selectPluginAssetSchema, selectPluginHookSchema, selectPluginRouteSchema, selectPluginSchema, selectSystemLogSchema, selectUserSchema, selectWorkflowHistorySchema, systemLogs, users, workflowHistory } from './chunk-3YNNVSMC.js';
5
- import { requireAuth, AuthManager, metricsMiddleware, bootstrapMiddleware } from './chunk-Y3EWJQ4D.js';
6
- export { AuthManager, PermissionManager, bootstrapMiddleware, cacheHeaders, compressionMiddleware, detailedLoggingMiddleware, getActivePlugins, isPluginActive, logActivity, loggingMiddleware, optionalAuth, performanceLoggingMiddleware, requireActivePlugin, requireActivePlugins, requireAnyPermission, requireAuth, requirePermission, requireRole, securityHeaders, securityLoggingMiddleware } from './chunk-Y3EWJQ4D.js';
1
+ import { renderConfirmationDialog, getConfirmationDialogScript, api_default, api_media_default, api_system_default, admin_api_default, router, adminCollectionsRoutes, adminFormsRoutes, adminSettingsRoutes, public_forms_default, router2, admin_content_default, adminMediaRoutes, adminPluginRoutes, adminLogsRoutes, userRoutes, auth_default, test_cleanup_default } from './chunk-BAWMAS5S.js';
2
+ export { ROUTES_INFO, admin_api_default as adminApiRoutes, adminCheckboxRoutes, admin_code_examples_default as adminCodeExamplesRoutes, adminCollectionsRoutes, admin_content_default as adminContentRoutes, router as adminDashboardRoutes, adminDesignRoutes, adminLogsRoutes, adminMediaRoutes, adminPluginRoutes, adminSettingsRoutes, admin_testimonials_default as adminTestimonialsRoutes, userRoutes as adminUsersRoutes, api_content_crud_default as apiContentCrudRoutes, api_media_default as apiMediaRoutes, api_default as apiRoutes, api_system_default as apiSystemRoutes, auth_default as authRoutes } from './chunk-BAWMAS5S.js';
3
+ import { SettingsService, schema_exports } from './chunk-G44QUVNM.js';
4
+ export { Logger, apiTokens, collections, content, contentVersions, getLogger, initLogger, insertCollectionSchema, insertContentSchema, insertLogConfigSchema, insertMediaSchema, insertPluginActivityLogSchema, insertPluginAssetSchema, insertPluginHookSchema, insertPluginRouteSchema, insertPluginSchema, insertSystemLogSchema, insertUserSchema, insertWorkflowHistorySchema, logConfig, media, pluginActivityLog, pluginAssets, pluginHooks, pluginRoutes, plugins, selectCollectionSchema, selectContentSchema, selectLogConfigSchema, selectMediaSchema, selectPluginActivityLogSchema, selectPluginAssetSchema, selectPluginHookSchema, selectPluginRouteSchema, selectPluginSchema, selectSystemLogSchema, selectUserSchema, selectWorkflowHistorySchema, systemLogs, users, workflowHistory } from './chunk-G44QUVNM.js';
5
+ import { requireAuth, AuthManager, metricsMiddleware, bootstrapMiddleware } from './chunk-3E76TKR5.js';
6
+ export { AuthManager, PermissionManager, bootstrapMiddleware, cacheHeaders, compressionMiddleware, detailedLoggingMiddleware, getActivePlugins, isPluginActive, logActivity, loggingMiddleware, optionalAuth, performanceLoggingMiddleware, requireActivePlugin, requireActivePlugins, requireAnyPermission, requireAuth, requirePermission, requireRole, securityHeaders, securityLoggingMiddleware } from './chunk-3E76TKR5.js';
7
7
  export { PluginBootstrapService, PluginService as PluginServiceClass, cleanupRemovedCollections, fullCollectionSync, getAvailableCollectionNames, getManagedCollections, isCollectionManaged, loadCollectionConfig, loadCollectionConfigs, registerCollections, syncCollection, syncCollections, validateCollectionConfig } from './chunk-YFJJU26H.js';
8
- export { MigrationService } from './chunk-L2IDZI7F.js';
9
- export { renderFilterBar } from './chunk-V3KVSEG6.js';
10
- import { init_admin_layout_catalyst_template, renderAdminLayout, adminLayoutV2, renderAdminLayoutCatalyst } from './chunk-GRN3GHUG.js';
11
- export { getConfirmationDialogScript, renderAlert, renderConfirmationDialog, renderForm, renderFormField, renderPagination, renderTable } from './chunk-GRN3GHUG.js';
12
- export { HookSystemImpl, HookUtils, PluginManager as PluginManagerClass, PluginRegistryImpl, PluginValidator as PluginValidatorClass, ScopedHookSystem as ScopedHookSystemClass } from './chunk-F332TENF.js';
13
- import { PluginBuilder } from './chunk-CLIH2T74.js';
14
- export { PluginBuilder, PluginHelpers } from './chunk-CLIH2T74.js';
15
- import { package_default, getCoreVersion } from './chunk-DNHJS6RN.js';
16
- export { QueryFilterBuilder, SONICJS_VERSION, TemplateRenderer, buildQuery, escapeHtml, getCoreVersion, renderTemplate, sanitizeInput, sanitizeObject, templateRenderer } from './chunk-DNHJS6RN.js';
8
+ export { MigrationService } from './chunk-JDFPB6UW.js';
9
+ export { renderFilterBar } from './chunk-H7AMQWVI.js';
10
+ import { init_admin_layout_catalyst_template, renderAdminLayout, renderAdminLayoutCatalyst } from './chunk-VCH6HXVP.js';
11
+ export { getConfirmationDialogScript, renderAlert, renderConfirmationDialog, renderForm, renderFormField, renderPagination, renderTable } from './chunk-VCH6HXVP.js';
12
+ export { HookSystemImpl, HookUtils, PluginManager as PluginManagerClass, PluginRegistryImpl, PluginValidator as PluginValidatorClass, ScopedHookSystem as ScopedHookSystemClass } from './chunk-CJYFSKH7.js';
13
+ import { PluginBuilder } from './chunk-J5WGMRSU.js';
14
+ export { PluginBuilder, PluginHelpers } from './chunk-J5WGMRSU.js';
15
+ import { package_default, getCoreVersion } from './chunk-34QIAULP.js';
16
+ export { QueryFilterBuilder, SONICJS_VERSION, TemplateRenderer, buildQuery, escapeHtml, getCoreVersion, renderTemplate, sanitizeInput, sanitizeObject, templateRenderer } from './chunk-34QIAULP.js';
17
17
  import './chunk-X7ZAEI5S.js';
18
18
  export { metricsTracker } from './chunk-FICTAGD4.js';
19
19
  export { HOOKS } from './chunk-LOUJRBXV.js';
20
20
  import './chunk-V4OQ3NZ2.js';
21
21
  import { Hono } from 'hono';
22
- import { html } from 'hono/html';
23
22
  import { setCookie } from 'hono/cookie';
24
23
  import { z } from 'zod';
25
24
  import { drizzle } from 'drizzle-orm/d1';
@@ -562,9 +561,9 @@ function formatCellValue(value) {
562
561
 
563
562
  // src/plugins/core-plugins/database-tools-plugin/admin-routes.ts
564
563
  function createDatabaseToolsAdminRoutes() {
565
- const router2 = new Hono();
566
- router2.use("*", requireAuth());
567
- router2.get("/api/stats", async (c) => {
564
+ const router3 = new Hono();
565
+ router3.use("*", requireAuth());
566
+ router3.get("/api/stats", async (c) => {
568
567
  try {
569
568
  const user = c.get("user");
570
569
  if (!user || user.role !== "admin") {
@@ -588,7 +587,7 @@ function createDatabaseToolsAdminRoutes() {
588
587
  }, 500);
589
588
  }
590
589
  });
591
- router2.post("/api/truncate", async (c) => {
590
+ router3.post("/api/truncate", async (c) => {
592
591
  try {
593
592
  const user = c.get("user");
594
593
  if (!user || user.role !== "admin") {
@@ -625,7 +624,7 @@ function createDatabaseToolsAdminRoutes() {
625
624
  }, 500);
626
625
  }
627
626
  });
628
- router2.post("/api/backup", async (c) => {
627
+ router3.post("/api/backup", async (c) => {
629
628
  try {
630
629
  const user = c.get("user");
631
630
  if (!user || user.role !== "admin") {
@@ -652,7 +651,7 @@ function createDatabaseToolsAdminRoutes() {
652
651
  }, 500);
653
652
  }
654
653
  });
655
- router2.get("/api/validate", async (c) => {
654
+ router3.get("/api/validate", async (c) => {
656
655
  try {
657
656
  const user = c.get("user");
658
657
  if (!user || user.role !== "admin") {
@@ -676,7 +675,7 @@ function createDatabaseToolsAdminRoutes() {
676
675
  }, 500);
677
676
  }
678
677
  });
679
- router2.get("/api/tables/:tableName", async (c) => {
678
+ router3.get("/api/tables/:tableName", async (c) => {
680
679
  try {
681
680
  const user = c.get("user");
682
681
  if (!user || user.role !== "admin") {
@@ -705,7 +704,7 @@ function createDatabaseToolsAdminRoutes() {
705
704
  }, 500);
706
705
  }
707
706
  });
708
- router2.get("/tables/:tableName", async (c) => {
707
+ router3.get("/tables/:tableName", async (c) => {
709
708
  try {
710
709
  const user = c.get("user");
711
710
  if (!user || user.role !== "admin") {
@@ -741,7 +740,7 @@ function createDatabaseToolsAdminRoutes() {
741
740
  return c.text(`Error: ${error}`, 500);
742
741
  }
743
742
  });
744
- return router2;
743
+ return router3;
745
744
  }
746
745
 
747
746
  // src/plugins/core-plugins/seed-data-plugin/services/seed-data-service.ts
@@ -1031,7 +1030,7 @@ var SeedDataService = class {
1031
1030
  function createSeedDataAdminRoutes() {
1032
1031
  const routes = new Hono();
1033
1032
  routes.get("/", async (c) => {
1034
- const html3 = `
1033
+ const html = `
1035
1034
  <!DOCTYPE html>
1036
1035
  <html>
1037
1036
  <head>
@@ -1274,7 +1273,7 @@ function createSeedDataAdminRoutes() {
1274
1273
  </body>
1275
1274
  </html>
1276
1275
  `;
1277
- return c.html(html3);
1276
+ return c.html(html);
1278
1277
  });
1279
1278
  routes.post("/generate", async (c) => {
1280
1279
  try {
@@ -1325,253 +1324,6 @@ function createEmailPlugin() {
1325
1324
  compatibility: "^2.0.0"
1326
1325
  });
1327
1326
  const emailRoutes = new Hono();
1328
- emailRoutes.get("/settings", async (c) => {
1329
- const user = c.get("user");
1330
- const db = c.env.DB;
1331
- const plugin2 = await db.prepare(`
1332
- SELECT settings FROM plugins WHERE id = 'email'
1333
- `).first();
1334
- const settings = plugin2?.settings ? JSON.parse(plugin2.settings) : {};
1335
- const contentHTML = await html`
1336
- <div class="p-8">
1337
- <!-- Header -->
1338
- <div class="mb-8">
1339
- <h1 class="text-3xl font-bold text-zinc-950 dark:text-white mb-2">Email Settings</h1>
1340
- <p class="text-zinc-600 dark:text-zinc-400">Configure Resend API for sending transactional emails</p>
1341
- </div>
1342
-
1343
- <!-- Settings Form -->
1344
- <div class="max-w-3xl">
1345
- <!-- Main Settings Card -->
1346
- <div class="rounded-xl bg-white dark:bg-zinc-900 shadow-sm ring-1 ring-zinc-950/5 dark:ring-white/10 p-6 mb-6">
1347
- <h2 class="text-xl font-semibold text-zinc-950 dark:text-white mb-4">Resend Configuration</h2>
1348
-
1349
- <form id="emailSettingsForm" class="space-y-6">
1350
- <!-- API Key -->
1351
- <div>
1352
- <label for="apiKey" class="block text-sm font-medium text-zinc-950 dark:text-white mb-2">
1353
- Resend API Key <span class="text-red-500">*</span>
1354
- </label>
1355
- <input
1356
- type="password"
1357
- id="apiKey"
1358
- name="apiKey"
1359
- value="${settings.apiKey || ""}"
1360
- class="w-full rounded-lg bg-white dark:bg-white/5 px-3 py-2 text-sm text-zinc-950 dark:text-white ring-1 ring-inset ring-zinc-950/10 dark:ring-white/10 placeholder:text-zinc-500 dark:placeholder:text-zinc-400 focus:ring-2 focus:ring-inset focus:ring-indigo-500 dark:focus:ring-indigo-400"
1361
- placeholder="re_..."
1362
- required
1363
- />
1364
- <p class="text-xs text-zinc-500 dark:text-zinc-400 mt-1">
1365
- Get your API key from <a href="https://resend.com/api-keys" target="_blank" class="text-indigo-600 dark:text-indigo-400 hover:underline">resend.com/api-keys</a>
1366
- </p>
1367
- </div>
1368
-
1369
- <!-- From Email -->
1370
- <div>
1371
- <label for="fromEmail" class="block text-sm font-medium text-zinc-950 dark:text-white mb-2">
1372
- From Email <span class="text-red-500">*</span>
1373
- </label>
1374
- <input
1375
- type="email"
1376
- id="fromEmail"
1377
- name="fromEmail"
1378
- value="${settings.fromEmail || ""}"
1379
- class="w-full rounded-lg bg-white dark:bg-white/5 px-3 py-2 text-sm text-zinc-950 dark:text-white ring-1 ring-inset ring-zinc-950/10 dark:ring-white/10 placeholder:text-zinc-500 dark:placeholder:text-zinc-400 focus:ring-2 focus:ring-inset focus:ring-indigo-500 dark:focus:ring-indigo-400"
1380
- placeholder="noreply@yourdomain.com"
1381
- required
1382
- />
1383
- <p class="text-xs text-zinc-500 dark:text-zinc-400 mt-1">
1384
- Must be a verified domain in Resend
1385
- </p>
1386
- </div>
1387
-
1388
- <!-- From Name -->
1389
- <div>
1390
- <label for="fromName" class="block text-sm font-medium text-zinc-950 dark:text-white mb-2">
1391
- From Name <span class="text-red-500">*</span>
1392
- </label>
1393
- <input
1394
- type="text"
1395
- id="fromName"
1396
- name="fromName"
1397
- value="${settings.fromName || ""}"
1398
- class="w-full rounded-lg bg-white dark:bg-white/5 px-3 py-2 text-sm text-zinc-950 dark:text-white ring-1 ring-inset ring-zinc-950/10 dark:ring-white/10 placeholder:text-zinc-500 dark:placeholder:text-zinc-400 focus:ring-2 focus:ring-inset focus:ring-indigo-500 dark:focus:ring-indigo-400"
1399
- placeholder="Your App Name"
1400
- required
1401
- />
1402
- </div>
1403
-
1404
- <!-- Reply To -->
1405
- <div>
1406
- <label for="replyTo" class="block text-sm font-medium text-zinc-950 dark:text-white mb-2">
1407
- Reply-To Email
1408
- </label>
1409
- <input
1410
- type="email"
1411
- id="replyTo"
1412
- name="replyTo"
1413
- value="${settings.replyTo || ""}"
1414
- class="w-full rounded-lg bg-white dark:bg-white/5 px-3 py-2 text-sm text-zinc-950 dark:text-white ring-1 ring-inset ring-zinc-950/10 dark:ring-white/10 placeholder:text-zinc-500 dark:placeholder:text-zinc-400 focus:ring-2 focus:ring-inset focus:ring-indigo-500 dark:focus:ring-indigo-400"
1415
- placeholder="support@yourdomain.com"
1416
- />
1417
- </div>
1418
-
1419
- <!-- Logo URL -->
1420
- <div>
1421
- <label for="logoUrl" class="block text-sm font-medium text-zinc-950 dark:text-white mb-2">
1422
- Logo URL
1423
- </label>
1424
- <input
1425
- type="url"
1426
- id="logoUrl"
1427
- name="logoUrl"
1428
- value="${settings.logoUrl || ""}"
1429
- class="w-full rounded-lg bg-white dark:bg-white/5 px-3 py-2 text-sm text-zinc-950 dark:text-white ring-1 ring-inset ring-zinc-950/10 dark:ring-white/10 placeholder:text-zinc-500 dark:placeholder:text-zinc-400 focus:ring-2 focus:ring-inset focus:ring-indigo-500 dark:focus:ring-indigo-400"
1430
- placeholder="https://yourdomain.com/logo.png"
1431
- />
1432
- <p class="text-xs text-zinc-500 dark:text-zinc-400 mt-1">
1433
- Logo to display in email templates
1434
- </p>
1435
- </div>
1436
-
1437
- <!-- Action Buttons -->
1438
- <div class="flex gap-3 pt-4">
1439
- <button
1440
- type="submit"
1441
- class="inline-flex items-center justify-center rounded-lg bg-zinc-950 dark:bg-white px-3.5 py-2.5 text-sm font-semibold text-white dark:text-zinc-950 hover:bg-zinc-800 dark:hover:bg-zinc-100 transition-colors shadow-sm"
1442
- >
1443
- Save Settings
1444
- </button>
1445
- <button
1446
- type="button"
1447
- id="testEmailBtn"
1448
- class="inline-flex items-center justify-center rounded-lg bg-white dark:bg-zinc-800 px-3.5 py-2.5 text-sm font-semibold text-zinc-950 dark:text-white ring-1 ring-inset ring-zinc-950/10 dark:ring-white/10 hover:bg-zinc-50 dark:hover:bg-zinc-700 transition-colors shadow-sm"
1449
- >
1450
- Send Test Email
1451
- </button>
1452
- <button
1453
- type="button"
1454
- id="resetBtn"
1455
- class="inline-flex items-center justify-center rounded-lg bg-white dark:bg-zinc-800 px-3.5 py-2.5 text-sm font-semibold text-zinc-950 dark:text-white ring-1 ring-inset ring-zinc-950/10 dark:ring-white/10 hover:bg-zinc-50 dark:hover:bg-zinc-700 transition-colors shadow-sm"
1456
- >
1457
- Reset
1458
- </button>
1459
- </div>
1460
- </form>
1461
- </div>
1462
-
1463
- <!-- Status Message -->
1464
- <div id="statusMessage" class="hidden rounded-xl p-4 mb-6"></div>
1465
-
1466
- <!-- Info Card -->
1467
- <div class="rounded-xl bg-indigo-50 dark:bg-indigo-950/30 ring-1 ring-indigo-100 dark:ring-indigo-900/50 p-6">
1468
- <h3 class="font-semibold text-indigo-900 dark:text-indigo-300 mb-3">
1469
- 📧 Email Templates Included
1470
- </h3>
1471
- <ul class="text-sm text-indigo-800 dark:text-indigo-200 space-y-2">
1472
- <li>✓ Registration confirmation</li>
1473
- <li>✓ Email verification</li>
1474
- <li>✓ Password reset</li>
1475
- <li>✓ One-time code (2FA)</li>
1476
- </ul>
1477
- <p class="text-xs text-indigo-700 dark:text-indigo-300 mt-4">
1478
- Templates are code-based and can be customized by editing the plugin files.
1479
- </p>
1480
- </div>
1481
- </div>
1482
- </div>
1483
-
1484
- <script>
1485
- // Form submission handler
1486
- document.getElementById('emailSettingsForm').addEventListener('submit', async (e) => {
1487
- e.preventDefault()
1488
- const formData = new FormData(e.target)
1489
- const data = Object.fromEntries(formData.entries())
1490
-
1491
- const statusEl = document.getElementById('statusMessage')
1492
-
1493
- try {
1494
- const response = await fetch('/admin/plugins/email/settings', {
1495
- method: 'POST',
1496
- headers: { 'Content-Type': 'application/json' },
1497
- body: JSON.stringify(data)
1498
- })
1499
-
1500
- if (response.ok) {
1501
- statusEl.className = 'rounded-xl bg-green-50 dark:bg-green-950/30 ring-1 ring-green-100 dark:ring-green-900/50 p-4 mb-6 text-green-900 dark:text-green-200'
1502
- statusEl.innerHTML = '✅ Settings saved successfully!'
1503
- statusEl.classList.remove('hidden')
1504
- setTimeout(() => statusEl.classList.add('hidden'), 3000)
1505
- } else {
1506
- throw new Error('Failed to save settings')
1507
- }
1508
- } catch (error) {
1509
- statusEl.className = 'rounded-xl bg-red-50 dark:bg-red-950/30 ring-1 ring-red-100 dark:ring-red-900/50 p-4 mb-6 text-red-900 dark:text-red-200'
1510
- statusEl.innerHTML = '❌ Failed to save settings. Please try again.'
1511
- statusEl.classList.remove('hidden')
1512
- }
1513
- })
1514
-
1515
- // Test email handler
1516
- document.getElementById('testEmailBtn').addEventListener('click', async () => {
1517
- // Prompt for destination email
1518
- const toEmail = prompt('Enter destination email address for test:')
1519
- if (!toEmail) return
1520
-
1521
- // Basic email validation
1522
- if (!toEmail.match(/^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/)) {
1523
- alert('Please enter a valid email address')
1524
- return
1525
- }
1526
-
1527
- const statusEl = document.getElementById('statusMessage')
1528
-
1529
- statusEl.className = 'rounded-xl bg-indigo-50 dark:bg-indigo-950/30 ring-1 ring-indigo-100 dark:ring-indigo-900/50 p-4 mb-6 text-indigo-900 dark:text-indigo-200'
1530
- statusEl.innerHTML = \`📧 Sending test email to \${toEmail}...\`
1531
- statusEl.classList.remove('hidden')
1532
-
1533
- try {
1534
- const response = await fetch('/admin/plugins/email/test', {
1535
- method: 'POST',
1536
- headers: { 'Content-Type': 'application/json' },
1537
- body: JSON.stringify({ toEmail })
1538
- })
1539
-
1540
- const data = await response.json()
1541
-
1542
- if (response.ok) {
1543
- statusEl.className = 'rounded-xl bg-green-50 dark:bg-green-950/30 ring-1 ring-green-100 dark:ring-green-900/50 p-4 mb-6 text-green-900 dark:text-green-200'
1544
- statusEl.innerHTML = \`✅ \${data.message || 'Test email sent! Check your inbox.'}\`
1545
- } else {
1546
- statusEl.className = 'rounded-xl bg-red-50 dark:bg-red-950/30 ring-1 ring-red-100 dark:ring-red-900/50 p-4 mb-6 text-red-900 dark:text-red-200'
1547
- statusEl.innerHTML = \`❌ \${data.error || 'Failed to send test email. Check your settings.'}\`
1548
- }
1549
- } catch (error) {
1550
- statusEl.className = 'rounded-xl bg-red-50 dark:bg-red-950/30 ring-1 ring-red-100 dark:ring-red-900/50 p-4 mb-6 text-red-900 dark:text-red-200'
1551
- statusEl.innerHTML = '❌ Network error. Please try again.'
1552
- }
1553
- })
1554
-
1555
- // Reset button handler
1556
- document.getElementById('resetBtn').addEventListener('click', () => {
1557
- document.getElementById('emailSettingsForm').reset()
1558
- })
1559
- </script>
1560
- `;
1561
- const templateUser = user ? {
1562
- name: user.name ?? user.email ?? "Admin",
1563
- email: user.email ?? "admin@sonicjs.com",
1564
- role: user.role ?? "admin"
1565
- } : void 0;
1566
- return c.html(
1567
- renderAdminLayout({
1568
- title: "Email Settings",
1569
- content: contentHTML,
1570
- user: templateUser,
1571
- currentPath: "/admin/plugins/email/settings"
1572
- })
1573
- );
1574
- });
1575
1327
  emailRoutes.post("/settings", async (c) => {
1576
1328
  try {
1577
1329
  const body = await c.req.json();
@@ -1667,7 +1419,7 @@ function createEmailPlugin() {
1667
1419
  requiresAuth: true,
1668
1420
  priority: 80
1669
1421
  });
1670
- builder.addMenuItem("Email", "/admin/plugins/email/settings", {
1422
+ builder.addMenuItem("Email", "/admin/plugins/email", {
1671
1423
  icon: "envelope",
1672
1424
  order: 80,
1673
1425
  permissions: ["email:manage"]
@@ -1984,8 +1736,7 @@ var DEFAULT_SETTINGS = {
1984
1736
  codeExpiryMinutes: 10,
1985
1737
  maxAttempts: 3,
1986
1738
  rateLimitPerHour: 5,
1987
- allowNewUserRegistration: false,
1988
- appName: "SonicJS"
1739
+ allowNewUserRegistration: false
1989
1740
  };
1990
1741
  function createOTPLoginPlugin() {
1991
1742
  const builder = PluginBuilder.create({
@@ -2016,7 +1767,21 @@ function createOTPLoginPlugin() {
2016
1767
  const normalizedEmail = email.toLowerCase();
2017
1768
  const db = c.env.DB;
2018
1769
  const otpService = new OTPService(db);
2019
- const settings = { ...DEFAULT_SETTINGS };
1770
+ let settings = { ...DEFAULT_SETTINGS };
1771
+ const pluginRow = await db.prepare(`
1772
+ SELECT settings FROM plugins WHERE id = 'otp-login'
1773
+ `).first();
1774
+ if (pluginRow?.settings) {
1775
+ try {
1776
+ const savedSettings = JSON.parse(pluginRow.settings);
1777
+ settings = { ...DEFAULT_SETTINGS, ...savedSettings };
1778
+ } catch (e) {
1779
+ console.warn("Failed to parse OTP plugin settings, using defaults");
1780
+ }
1781
+ }
1782
+ const settingsService = new SettingsService(db);
1783
+ const generalSettings = await settingsService.getGeneralSettings();
1784
+ const siteName = generalSettings.siteName;
2020
1785
  const canRequest = await otpService.checkRateLimit(normalizedEmail, settings);
2021
1786
  if (!canRequest) {
2022
1787
  return c.json({
@@ -2060,7 +1825,7 @@ function createOTPLoginPlugin() {
2060
1825
  email: normalizedEmail,
2061
1826
  ipAddress,
2062
1827
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
2063
- appName: settings.appName
1828
+ appName: siteName
2064
1829
  });
2065
1830
  const emailPlugin2 = await db.prepare(`
2066
1831
  SELECT settings FROM plugins WHERE id = 'email'
@@ -2077,7 +1842,7 @@ function createOTPLoginPlugin() {
2077
1842
  body: JSON.stringify({
2078
1843
  from: `${emailSettings.fromName} <${emailSettings.fromEmail}>`,
2079
1844
  to: [normalizedEmail],
2080
- subject: `Your login code for ${settings.appName}`,
1845
+ subject: `Your login code for ${siteName}`,
2081
1846
  html: emailContent.html,
2082
1847
  text: emailContent.text,
2083
1848
  reply_to: emailSettings.replyTo || emailSettings.fromEmail
@@ -2128,7 +1893,18 @@ function createOTPLoginPlugin() {
2128
1893
  const normalizedEmail = email.toLowerCase();
2129
1894
  const db = c.env.DB;
2130
1895
  const otpService = new OTPService(db);
2131
- const settings = { ...DEFAULT_SETTINGS };
1896
+ let settings = { ...DEFAULT_SETTINGS };
1897
+ const pluginRow = await db.prepare(`
1898
+ SELECT settings FROM plugins WHERE id = 'otp-login'
1899
+ `).first();
1900
+ if (pluginRow?.settings) {
1901
+ try {
1902
+ const savedSettings = JSON.parse(pluginRow.settings);
1903
+ settings = { ...DEFAULT_SETTINGS, ...savedSettings };
1904
+ } catch (e) {
1905
+ console.warn("Failed to parse OTP plugin settings, using defaults");
1906
+ }
1907
+ }
2132
1908
  const verification = await otpService.verifyCode(normalizedEmail, code, settings);
2133
1909
  if (!verification.valid) {
2134
1910
  await otpService.incrementAttempts(normalizedEmail, code);
@@ -2207,193 +1983,7 @@ function createOTPLoginPlugin() {
2207
1983
  requiresAuth: false,
2208
1984
  priority: 100
2209
1985
  });
2210
- const adminRoutes2 = new Hono();
2211
- adminRoutes2.get("/settings", async (c) => {
2212
- const user = c.get("user");
2213
- const contentHTML = await html`
2214
- <div class="p-8">
2215
- <div class="mb-8">
2216
- <h1 class="text-3xl font-bold mb-2">OTP Login Settings</h1>
2217
- <p class="text-zinc-600 dark:text-zinc-400">Configure passwordless authentication via email codes</p>
2218
- </div>
2219
-
2220
- <div class="max-w-3xl">
2221
- <div class="backdrop-blur-md bg-black/20 border border-white/10 shadow-xl rounded-xl p-6 mb-6">
2222
- <h2 class="text-xl font-semibold mb-4">Code Settings</h2>
2223
-
2224
- <form id="otpSettingsForm" class="space-y-6">
2225
- <div>
2226
- <label for="codeLength" class="block text-sm font-medium mb-2">
2227
- Code Length
2228
- </label>
2229
- <input
2230
- type="number"
2231
- id="codeLength"
2232
- name="codeLength"
2233
- min="4"
2234
- max="8"
2235
- value="6"
2236
- class="w-full px-4 py-2 rounded-lg bg-white/5 border border-white/10 focus:border-blue-500 focus:outline-none"
2237
- />
2238
- <p class="text-xs text-zinc-500 mt-1">Number of digits in OTP code (4-8)</p>
2239
- </div>
2240
-
2241
- <div>
2242
- <label for="codeExpiryMinutes" class="block text-sm font-medium mb-2">
2243
- Code Expiry (minutes)
2244
- </label>
2245
- <input
2246
- type="number"
2247
- id="codeExpiryMinutes"
2248
- name="codeExpiryMinutes"
2249
- min="5"
2250
- max="60"
2251
- value="10"
2252
- class="w-full px-4 py-2 rounded-lg bg-white/5 border border-white/10 focus:border-blue-500 focus:outline-none"
2253
- />
2254
- <p class="text-xs text-zinc-500 mt-1">How long codes remain valid (5-60 minutes)</p>
2255
- </div>
2256
-
2257
- <div>
2258
- <label for="maxAttempts" class="block text-sm font-medium mb-2">
2259
- Maximum Attempts
2260
- </label>
2261
- <input
2262
- type="number"
2263
- id="maxAttempts"
2264
- name="maxAttempts"
2265
- min="3"
2266
- max="10"
2267
- value="3"
2268
- class="w-full px-4 py-2 rounded-lg bg-white/5 border border-white/10 focus:border-blue-500 focus:outline-none"
2269
- />
2270
- <p class="text-xs text-zinc-500 mt-1">Max verification attempts before invalidation</p>
2271
- </div>
2272
-
2273
- <div>
2274
- <label for="rateLimitPerHour" class="block text-sm font-medium mb-2">
2275
- Rate Limit (per hour)
2276
- </label>
2277
- <input
2278
- type="number"
2279
- id="rateLimitPerHour"
2280
- name="rateLimitPerHour"
2281
- min="3"
2282
- max="20"
2283
- value="5"
2284
- class="w-full px-4 py-2 rounded-lg bg-white/5 border border-white/10 focus:border-blue-500 focus:outline-none"
2285
- />
2286
- <p class="text-xs text-zinc-500 mt-1">Max code requests per email per hour</p>
2287
- </div>
2288
-
2289
- <div class="flex items-center">
2290
- <input
2291
- type="checkbox"
2292
- id="allowNewUserRegistration"
2293
- name="allowNewUserRegistration"
2294
- class="w-4 h-4 rounded border-white/10"
2295
- />
2296
- <label for="allowNewUserRegistration" class="ml-2 text-sm">
2297
- Allow new user registration via OTP
2298
- </label>
2299
- </div>
2300
-
2301
- <div class="flex gap-3 pt-4">
2302
- <button
2303
- type="submit"
2304
- class="px-6 py-2 bg-gradient-to-r from-blue-500 to-purple-600 text-white rounded-lg font-medium hover:from-blue-600 hover:to-purple-700 transition-all"
2305
- >
2306
- Save Settings
2307
- </button>
2308
- <button
2309
- type="button"
2310
- id="testOTPBtn"
2311
- class="px-6 py-2 bg-white/10 hover:bg-white/20 text-white rounded-lg font-medium transition-all"
2312
- >
2313
- Send Test Code
2314
- </button>
2315
- </div>
2316
- </form>
2317
- </div>
2318
-
2319
- <div id="statusMessage" class="hidden backdrop-blur-md bg-black/20 border border-white/10 rounded-xl p-4 mb-6"></div>
2320
-
2321
- <div class="backdrop-blur-md bg-blue-500/10 border border-blue-500/20 rounded-xl p-6">
2322
- <h3 class="font-semibold text-blue-400 mb-3">
2323
- 🔢 Features
2324
- </h3>
2325
- <ul class="text-sm text-blue-200 space-y-2">
2326
- <li>✓ Passwordless authentication</li>
2327
- <li>✓ Secure random code generation</li>
2328
- <li>✓ Rate limiting protection</li>
2329
- <li>✓ Brute force prevention</li>
2330
- <li>✓ Mobile-friendly UX</li>
2331
- </ul>
2332
- </div>
2333
- </div>
2334
- </div>
2335
-
2336
- <script>
2337
- document.getElementById('otpSettingsForm').addEventListener('submit', async (e) => {
2338
- e.preventDefault()
2339
- const statusEl = document.getElementById('statusMessage')
2340
- statusEl.className = 'backdrop-blur-md bg-green-500/20 border border-green-500/30 rounded-xl p-4 mb-6'
2341
- statusEl.innerHTML = '✅ Settings saved successfully!'
2342
- statusEl.classList.remove('hidden')
2343
- setTimeout(() => statusEl.classList.add('hidden'), 3000)
2344
- })
2345
-
2346
- document.getElementById('testOTPBtn').addEventListener('click', async () => {
2347
- const email = prompt('Enter email address for test:')
2348
- if (!email) return
2349
-
2350
- const statusEl = document.getElementById('statusMessage')
2351
- statusEl.className = 'backdrop-blur-md bg-blue-500/20 border border-blue-500/30 rounded-xl p-4 mb-6'
2352
- statusEl.innerHTML = '📧 Sending test code...'
2353
- statusEl.classList.remove('hidden')
2354
-
2355
- try {
2356
- const response = await fetch('/auth/otp/request', {
2357
- method: 'POST',
2358
- headers: { 'Content-Type': 'application/json' },
2359
- body: JSON.stringify({ email })
2360
- })
2361
-
2362
- const data = await response.json()
2363
-
2364
- if (response.ok) {
2365
- statusEl.className = 'backdrop-blur-md bg-green-500/20 border border-green-500/30 rounded-xl p-4 mb-6'
2366
- statusEl.innerHTML = '✅ Test code sent!' + (data.dev_code ? \` Code: <strong>\${data.dev_code}</strong>\` : '')
2367
- } else {
2368
- throw new Error(data.error || 'Failed')
2369
- }
2370
- } catch (error) {
2371
- statusEl.className = 'backdrop-blur-md bg-red-500/20 border border-red-500/30 rounded-xl p-4 mb-6'
2372
- statusEl.innerHTML = '❌ Failed to send test code'
2373
- }
2374
- })
2375
- </script>
2376
- `;
2377
- const templateUser = user ? {
2378
- name: user.name ?? user.email ?? "Admin",
2379
- email: user.email ?? "admin@sonicjs.com",
2380
- role: user.role ?? "admin"
2381
- } : void 0;
2382
- return c.html(
2383
- adminLayoutV2({
2384
- title: "OTP Login Settings",
2385
- content: contentHTML,
2386
- user: templateUser,
2387
- currentPath: "/admin/plugins/otp-login/settings"
2388
- })
2389
- );
2390
- });
2391
- builder.addRoute("/admin/plugins/otp-login", adminRoutes2, {
2392
- description: "OTP login admin interface",
2393
- requiresAuth: true,
2394
- priority: 85
2395
- });
2396
- builder.addMenuItem("OTP Login", "/admin/plugins/otp-login/settings", {
1986
+ builder.addMenuItem("OTP Login", "/admin/plugins/otp-login", {
2397
1987
  icon: "key",
2398
1988
  order: 85,
2399
1989
  permissions: ["otp:manage"]
@@ -6418,7 +6008,11 @@ function createSonicJSApp(config = {}) {
6418
6008
  app2.route("/admin/api", admin_api_default);
6419
6009
  app2.route("/admin/dashboard", router);
6420
6010
  app2.route("/admin/collections", adminCollectionsRoutes);
6011
+ app2.route("/admin/forms", adminFormsRoutes);
6421
6012
  app2.route("/admin/settings", adminSettingsRoutes);
6013
+ app2.route("/forms", public_forms_default);
6014
+ app2.route("/api/forms", public_forms_default);
6015
+ app2.route("/admin/api-reference", router2);
6422
6016
  app2.route("/admin/database-tools", createDatabaseToolsAdminRoutes());
6423
6017
  app2.route("/admin/seed-data", createSeedDataAdminRoutes());
6424
6018
  app2.route("/admin/content", admin_content_default);
@@ -6429,6 +6023,11 @@ function createSonicJSApp(config = {}) {
6429
6023
  }
6430
6024
  }
6431
6025
  app2.route("/admin/cache", cache_default.getRoutes());
6026
+ if (otpLoginPlugin.routes && otpLoginPlugin.routes.length > 0) {
6027
+ for (const route of otpLoginPlugin.routes) {
6028
+ app2.route(route.path, route.handler);
6029
+ }
6030
+ }
6432
6031
  app2.route("/admin/plugins", adminPluginRoutes);
6433
6032
  app2.route("/admin/logs", adminLogsRoutes);
6434
6033
  app2.route("/admin", userRoutes);
@@ -6439,11 +6038,6 @@ function createSonicJSApp(config = {}) {
6439
6038
  app2.route(route.path, route.handler);
6440
6039
  }
6441
6040
  }
6442
- if (otpLoginPlugin.routes && otpLoginPlugin.routes.length > 0) {
6443
- for (const route of otpLoginPlugin.routes) {
6444
- app2.route(route.path, route.handler);
6445
- }
6446
- }
6447
6041
  const magicLinkPlugin = createMagicLinkAuthPlugin();
6448
6042
  if (magicLinkPlugin.routes && magicLinkPlugin.routes.length > 0) {
6449
6043
  for (const route of magicLinkPlugin.routes) {