@sonicjs-cms/core 3.0.0-beta.2 → 3.0.0-beta.20

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 (170) hide show
  1. package/README.md +48 -49
  2. package/dist/admin-documents-form.template-DDSH6ROU.js +6 -0
  3. package/dist/{admin-documents-form.template-NLSI6Z42.js.map → admin-documents-form.template-DDSH6ROU.js.map} +1 -1
  4. package/dist/admin-documents-form.template-LSZKGA5J.cjs +19 -0
  5. package/dist/{admin-layout-catalyst.template-WHJGSWWD.js.map → admin-documents-form.template-LSZKGA5J.cjs.map} +1 -1
  6. package/dist/{filter-bar.template-DlVYMk-T.d.ts → admin-layout-catalyst.template-DrwDUfsE.d.cts} +25 -1
  7. package/dist/{filter-bar.template-DlVYMk-T.d.cts → admin-layout-catalyst.template-DrwDUfsE.d.ts} +25 -1
  8. package/dist/admin-layout-catalyst.template-KDHKVLXR.cjs +21 -0
  9. package/dist/{admin-layout-catalyst.template-ZK5HD545.cjs.map → admin-layout-catalyst.template-KDHKVLXR.cjs.map} +1 -1
  10. package/dist/admin-layout-catalyst.template-YQ4EMF2J.js +7 -0
  11. package/dist/{admin-documents-form.template-KN7JF66Q.cjs.map → admin-layout-catalyst.template-YQ4EMF2J.js.map} +1 -1
  12. package/dist/{app-Bo0X1OWX.d.ts → app-01M0dIwt.d.ts} +1 -1
  13. package/dist/{app-Do66yCcV.d.cts → app-aj39TGHB.d.cts} +1 -1
  14. package/dist/{chunk-ZEZ245PW.js → chunk-2XAQTPAE.js} +4 -236
  15. package/dist/chunk-2XAQTPAE.js.map +1 -0
  16. package/dist/{chunk-BDDABDAB.cjs → chunk-36Z3AKX3.cjs} +3 -239
  17. package/dist/chunk-36Z3AKX3.cjs.map +1 -0
  18. package/dist/{chunk-VXE42MYF.cjs → chunk-3E7IROND.cjs} +695 -428
  19. package/dist/chunk-3E7IROND.cjs.map +1 -0
  20. package/dist/{chunk-BLMTL57B.js → chunk-3TMTYJAJ.js} +26 -4
  21. package/dist/chunk-3TMTYJAJ.js.map +1 -0
  22. package/dist/{chunk-AAWNRBRB.cjs → chunk-4SHNHNRP.cjs} +95 -20
  23. package/dist/chunk-4SHNHNRP.cjs.map +1 -0
  24. package/dist/{chunk-QAYFOER6.cjs → chunk-5ARIHAGN.cjs} +285 -3
  25. package/dist/chunk-5ARIHAGN.cjs.map +1 -0
  26. package/dist/{chunk-XW56B23A.cjs → chunk-5RSB5SEK.cjs} +4 -4
  27. package/dist/{chunk-XW56B23A.cjs.map → chunk-5RSB5SEK.cjs.map} +1 -1
  28. package/dist/{chunk-VD2EA3WT.js → chunk-5UCMLBRQ.js} +328 -62
  29. package/dist/chunk-5UCMLBRQ.js.map +1 -0
  30. package/dist/{chunk-3TB6AT6X.js → chunk-5V62WT6M.js} +35 -4
  31. package/dist/chunk-5V62WT6M.js.map +1 -0
  32. package/dist/{chunk-LRZIAW7U.cjs → chunk-AQJEMVAY.cjs} +3 -3
  33. package/dist/chunk-AQJEMVAY.cjs.map +1 -0
  34. package/dist/{chunk-WULONYGB.cjs → chunk-CRGUD4KC.cjs} +9 -9
  35. package/dist/{chunk-WULONYGB.cjs.map → chunk-CRGUD4KC.cjs.map} +1 -1
  36. package/dist/{chunk-NLJVSER2.js → chunk-DSXEVMOM.js} +3 -2
  37. package/dist/chunk-DSXEVMOM.js.map +1 -0
  38. package/dist/{chunk-H2AXVCLS.cjs → chunk-DTGCXWWM.cjs} +141 -74
  39. package/dist/chunk-DTGCXWWM.cjs.map +1 -0
  40. package/dist/{chunk-NUKJ54GA.cjs → chunk-GMMCCIQO.cjs} +6 -6
  41. package/dist/{chunk-NUKJ54GA.cjs.map → chunk-GMMCCIQO.cjs.map} +1 -1
  42. package/dist/{chunk-6OUHGKFD.js → chunk-GMZ5TGYP.js} +3 -3
  43. package/dist/{chunk-6OUHGKFD.js.map → chunk-GMZ5TGYP.js.map} +1 -1
  44. package/dist/{chunk-6JQOUUOB.js → chunk-JQISFW6U.js} +3 -3
  45. package/dist/{chunk-6JQOUUOB.js.map → chunk-JQISFW6U.js.map} +1 -1
  46. package/dist/{chunk-NAVPFIG5.cjs → chunk-K623Q6WD.cjs} +35 -3
  47. package/dist/chunk-K623Q6WD.cjs.map +1 -0
  48. package/dist/{chunk-JEQ7FLOD.cjs → chunk-KIGVVO6N.cjs} +16 -10
  49. package/dist/chunk-KIGVVO6N.cjs.map +1 -0
  50. package/dist/{chunk-2CB4KY7I.cjs → chunk-LTZ5WYOK.cjs} +29 -7
  51. package/dist/chunk-LTZ5WYOK.cjs.map +1 -0
  52. package/dist/{chunk-YHSQVQXX.js → chunk-MYQ7KZUQ.js} +135 -68
  53. package/dist/chunk-MYQ7KZUQ.js.map +1 -0
  54. package/dist/{chunk-DNQCEKUK.cjs → chunk-N32OWET6.cjs} +5 -5
  55. package/dist/{chunk-DNQCEKUK.cjs.map → chunk-N32OWET6.cjs.map} +1 -1
  56. package/dist/{chunk-HDWE5FRJ.js → chunk-OBA2RYZN.js} +3 -3
  57. package/dist/{chunk-HDWE5FRJ.js.map → chunk-OBA2RYZN.js.map} +1 -1
  58. package/dist/{chunk-MVIZJOO5.cjs → chunk-PXNTCCPE.cjs} +8 -8
  59. package/dist/{chunk-MVIZJOO5.cjs.map → chunk-PXNTCCPE.cjs.map} +1 -1
  60. package/dist/{chunk-ZGGXCFR6.js → chunk-RDH6PUOP.js} +282 -4
  61. package/dist/chunk-RDH6PUOP.js.map +1 -0
  62. package/dist/{chunk-EF2NQUIQ.js → chunk-RMRJGMDE.js} +3 -3
  63. package/dist/{chunk-EF2NQUIQ.js.map → chunk-RMRJGMDE.js.map} +1 -1
  64. package/dist/{chunk-IVPRUGTY.js → chunk-SOZUG52O.js} +4 -4
  65. package/dist/{chunk-IVPRUGTY.js.map → chunk-SOZUG52O.js.map} +1 -1
  66. package/dist/{chunk-DSA4UX5B.cjs → chunk-TQG5FNNR.cjs} +3 -2
  67. package/dist/chunk-TQG5FNNR.cjs.map +1 -0
  68. package/dist/{chunk-GCDZZNIN.js → chunk-UWUP2VMT.js} +16 -10
  69. package/dist/chunk-UWUP2VMT.js.map +1 -0
  70. package/dist/{chunk-IESEVHXL.js → chunk-VVYVFCML.js} +12 -3
  71. package/dist/chunk-VVYVFCML.js.map +1 -0
  72. package/dist/{chunk-NMPEMSU4.js → chunk-W53J3BJ2.js} +3 -3
  73. package/dist/chunk-W53J3BJ2.js.map +1 -0
  74. package/dist/{chunk-RZ6H7OZK.js → chunk-WCA4VENG.js} +87 -12
  75. package/dist/chunk-WCA4VENG.js.map +1 -0
  76. package/dist/{chunk-HIKBY7MS.cjs → chunk-XWVDSM2L.cjs} +12 -3
  77. package/dist/chunk-XWVDSM2L.cjs.map +1 -0
  78. package/dist/{collection-config-JgHOpFCG.d.ts → collection-config-BTzAvKt2.d.cts} +25 -0
  79. package/dist/{collection-config-JgHOpFCG.d.cts → collection-config-BTzAvKt2.d.ts} +25 -0
  80. package/dist/config-6FB2BXMP.js +6 -0
  81. package/dist/{config-HFXANXCC.js.map → config-6FB2BXMP.js.map} +1 -1
  82. package/dist/config-OCH7S4WK.cjs +19 -0
  83. package/dist/{config-ON6FNMYX.cjs.map → config-OCH7S4WK.cjs.map} +1 -1
  84. package/dist/{define-plugin-BzNHc1ZI.d.ts → define-plugin-BYIey6sp.d.ts} +1 -1
  85. package/dist/{define-plugin-IWDKYaVm.d.cts → define-plugin-DsKiGu1q.d.cts} +1 -1
  86. package/dist/document-projection-4HG75S5S.js +4 -0
  87. package/dist/{document-projection-YYMC6I4U.js.map → document-projection-4HG75S5S.js.map} +1 -1
  88. package/dist/document-projection-JQHSTSFD.cjs +13 -0
  89. package/dist/{document-projection-TDWRJX3Z.cjs.map → document-projection-JQHSTSFD.cjs.map} +1 -1
  90. package/dist/index.cjs +928 -378
  91. package/dist/index.cjs.map +1 -1
  92. package/dist/index.d.cts +200 -12
  93. package/dist/index.d.ts +200 -12
  94. package/dist/index.js +612 -75
  95. package/dist/index.js.map +1 -1
  96. package/dist/middleware.cjs +37 -34
  97. package/dist/middleware.d.cts +2 -2
  98. package/dist/middleware.d.ts +2 -2
  99. package/dist/middleware.js +8 -5
  100. package/dist/migrations-HZJ6U6SX.js +4 -0
  101. package/dist/{migrations-WCAVBD7C.js.map → migrations-HZJ6U6SX.js.map} +1 -1
  102. package/dist/migrations-VQAFXMU7.cjs +13 -0
  103. package/dist/{migrations-NJJWQUKK.cjs.map → migrations-VQAFXMU7.cjs.map} +1 -1
  104. package/dist/{plugin-bootstrap-B8ThJU21.d.cts → plugin-bootstrap-BHWQ2df8.d.cts} +1 -1
  105. package/dist/{plugin-bootstrap-qu8hJgUt.d.ts → plugin-bootstrap-Bj4fxX1q.d.ts} +1 -1
  106. package/dist/plugins.cjs +40 -40
  107. package/dist/plugins.d.cts +2 -2
  108. package/dist/plugins.d.ts +2 -2
  109. package/dist/plugins.js +3 -3
  110. package/dist/rbac-7QZ4JZ2E.cjs +14 -0
  111. package/dist/{rbac-VONLJJKB.cjs.map → rbac-7QZ4JZ2E.cjs.map} +1 -1
  112. package/dist/rbac-Y43IEQOP.js +5 -0
  113. package/dist/{rbac-O73MFKDA.js.map → rbac-Y43IEQOP.js.map} +1 -1
  114. package/dist/routes.cjs +34 -34
  115. package/dist/routes.d.cts +2 -2
  116. package/dist/routes.d.ts +2 -2
  117. package/dist/routes.js +14 -14
  118. package/dist/services.cjs +42 -42
  119. package/dist/services.d.cts +16 -3
  120. package/dist/services.d.ts +16 -3
  121. package/dist/services.js +3 -3
  122. package/dist/{telemetry-B9vIV4wh.d.cts → telemetry-Cku1ax74.d.cts} +1 -1
  123. package/dist/{telemetry-B9vIV4wh.d.ts → telemetry-Cku1ax74.d.ts} +1 -1
  124. package/dist/templates.cjs +17 -17
  125. package/dist/templates.d.cts +2 -24
  126. package/dist/templates.d.ts +2 -24
  127. package/dist/templates.js +3 -3
  128. package/dist/{types-Dea1eNxU.d.ts → types-DT7XN5TX.d.cts} +1 -1
  129. package/dist/{types-Dea1eNxU.d.cts → types-DT7XN5TX.d.ts} +1 -1
  130. package/dist/types.d.cts +2 -2
  131. package/dist/types.d.ts +2 -2
  132. package/dist/utils.cjs +8 -8
  133. package/dist/utils.d.cts +2 -2
  134. package/dist/utils.d.ts +2 -2
  135. package/dist/utils.js +2 -2
  136. package/package.json +1 -1
  137. package/dist/admin-documents-form.template-KN7JF66Q.cjs +0 -19
  138. package/dist/admin-documents-form.template-NLSI6Z42.js +0 -6
  139. package/dist/admin-layout-catalyst.template-WHJGSWWD.js +0 -7
  140. package/dist/admin-layout-catalyst.template-ZK5HD545.cjs +0 -17
  141. package/dist/chunk-2CB4KY7I.cjs.map +0 -1
  142. package/dist/chunk-3TB6AT6X.js.map +0 -1
  143. package/dist/chunk-AAWNRBRB.cjs.map +0 -1
  144. package/dist/chunk-BDDABDAB.cjs.map +0 -1
  145. package/dist/chunk-BLMTL57B.js.map +0 -1
  146. package/dist/chunk-DSA4UX5B.cjs.map +0 -1
  147. package/dist/chunk-GCDZZNIN.js.map +0 -1
  148. package/dist/chunk-H2AXVCLS.cjs.map +0 -1
  149. package/dist/chunk-HIKBY7MS.cjs.map +0 -1
  150. package/dist/chunk-IESEVHXL.js.map +0 -1
  151. package/dist/chunk-JEQ7FLOD.cjs.map +0 -1
  152. package/dist/chunk-LRZIAW7U.cjs.map +0 -1
  153. package/dist/chunk-NAVPFIG5.cjs.map +0 -1
  154. package/dist/chunk-NLJVSER2.js.map +0 -1
  155. package/dist/chunk-NMPEMSU4.js.map +0 -1
  156. package/dist/chunk-QAYFOER6.cjs.map +0 -1
  157. package/dist/chunk-RZ6H7OZK.js.map +0 -1
  158. package/dist/chunk-VD2EA3WT.js.map +0 -1
  159. package/dist/chunk-VXE42MYF.cjs.map +0 -1
  160. package/dist/chunk-YHSQVQXX.js.map +0 -1
  161. package/dist/chunk-ZEZ245PW.js.map +0 -1
  162. package/dist/chunk-ZGGXCFR6.js.map +0 -1
  163. package/dist/config-HFXANXCC.js +0 -6
  164. package/dist/config-ON6FNMYX.cjs +0 -19
  165. package/dist/document-projection-TDWRJX3Z.cjs +0 -13
  166. package/dist/document-projection-YYMC6I4U.js +0 -4
  167. package/dist/migrations-NJJWQUKK.cjs +0 -13
  168. package/dist/migrations-WCAVBD7C.js +0 -4
  169. package/dist/rbac-O73MFKDA.js +0 -5
  170. package/dist/rbac-VONLJJKB.cjs +0 -14
@@ -1,22 +1,21 @@
1
- import { isFirstUserRegistration, isRegistrationEnabled, authValidationService } from './chunk-IESEVHXL.js';
2
- import { renderDocumentFormPage, renderAlert } from './chunk-EF2NQUIQ.js';
3
- import { getCacheService, CACHE_CONFIGS, SettingsService, getLogger, getAppInstance, buildRouteList, CATEGORY_INFO } from './chunk-ZEZ245PW.js';
4
- import { DocumentTypeRegistry, requireAuth, requireRole, optionalAuth, isPluginActive, rateLimit, AuthManager, getJwtExpirySecondsFromDb, getJwtRefreshGraceSecondsFromDb, logActivity, generateCsrfToken } from './chunk-RZ6H7OZK.js';
5
- import { DocumentsService, documentSecondsToMs, RbacService } from './chunk-BLMTL57B.js';
6
- import { nanoid } from './chunk-GCDZZNIN.js';
7
- import { getCollectionRegistry, collectionRecordToRow, loadCollectionConfigs, getVisibleCollections, PluginService, PLUGIN_REGISTRY, findPluginByCodeName, isCodeCollectionInternal, isDbDocTypeInternal, invalidateTenantCache } from './chunk-ZGGXCFR6.js';
8
- import { MigrationService } from './chunk-NLJVSER2.js';
9
- import { renderCheckboxPage, renderAlert as renderAlert$1, renderTable, renderPagination, renderConfirmationDialog, getConfirmationDialogScript, renderAdminLayout, adminLayoutV2, renderForm } from './chunk-HDWE5FRJ.js';
10
- import { init_admin_layout_catalyst_template, renderAdminLayoutCatalyst } from './chunk-3TB6AT6X.js';
11
- import { createServiceSingleton, definePlugin, getPluginDefinition, applySchemaDefaults, renderSchemaFields, parseFormDataToSettings } from './chunk-6OUHGKFD.js';
1
+ import { isFirstUserRegistration, isRegistrationEnabled, authValidationService } from './chunk-VVYVFCML.js';
2
+ import { renderDocumentFormPage, renderAlert } from './chunk-RMRJGMDE.js';
3
+ import { getCacheService, CACHE_CONFIGS, SettingsService, getLogger, getAppInstance, buildRouteList, CATEGORY_INFO } from './chunk-2XAQTPAE.js';
4
+ import { DocumentTypeRegistry, requireAuth, requireRole, optionalAuth, isPluginActive, rateLimit, AuthManager, getJwtExpirySecondsFromDb, getJwtRefreshGraceSecondsFromDb, logActivity, generateCsrfToken } from './chunk-WCA4VENG.js';
5
+ import { DocumentsService, documentSecondsToMs, RbacService } from './chunk-3TMTYJAJ.js';
6
+ import { nanoid } from './chunk-UWUP2VMT.js';
7
+ import { getCollectionRegistry, collectionRecordToRow, loadCollectionConfigs, getVisibleCollections, PluginService, PLUGIN_REGISTRY, findPluginByCodeName, isCodeCollectionInternal, isDbDocTypeInternal, invalidateTenantCache } from './chunk-RDH6PUOP.js';
8
+ import { MigrationService } from './chunk-DSXEVMOM.js';
9
+ import { renderCheckboxPage, renderAlert as renderAlert$1, renderTable, renderPagination, renderConfirmationDialog, getConfirmationDialogScript, renderAdminLayout, adminLayoutV2, renderForm } from './chunk-OBA2RYZN.js';
10
+ import { init_admin_layout_catalyst_template, renderAdminLayoutCatalyst } from './chunk-5V62WT6M.js';
11
+ import { createServiceSingleton, definePlugin, getPluginDefinition, applySchemaDefaults, renderSchemaFields, parseFormDataToSettings } from './chunk-GMZ5TGYP.js';
12
12
  import { hasHookSystem, getTypedHooks } from './chunk-RNZFGN4R.js';
13
13
  import { QueryFilterBuilder, getBlocksFieldConfig, parseBlocksValue } from './chunk-QZGABF2M.js';
14
14
  import { metricsTracker } from './chunk-FICTAGD4.js';
15
- import { getCoreVersion } from './chunk-NMPEMSU4.js';
15
+ import { getCoreVersion } from './chunk-W53J3BJ2.js';
16
16
  import { escapeHtml, sanitizeRichText, sanitizeInput } from './chunk-TQABQWOP.js';
17
17
  import { Hono } from 'hono';
18
18
  import { z } from 'zod';
19
- import { cors } from 'hono/cors';
20
19
  import { setCookie, getCookie } from 'hono/cookie';
21
20
  import { html, raw } from 'hono/html';
22
21
 
@@ -25,6 +24,7 @@ var DocumentPermissionsService = class {
25
24
  constructor(db) {
26
25
  this.db = db;
27
26
  }
27
+ db;
28
28
  // Deny wins. Overrides beat base grants. Empty ACL falls back to base grants.
29
29
  async isAllowed(principalSet, rootId, permission, typeSettings, tenantId) {
30
30
  const overrides = await this.getDocumentPermissions(rootId, principalSet, permission, tenantId);
@@ -133,6 +133,8 @@ var DocumentRepository = class {
133
133
  this.tenantId = tenantId;
134
134
  this.permissions = new DocumentPermissionsService(db);
135
135
  }
136
+ db;
137
+ tenantId;
136
138
  permissions;
137
139
  // ─── Reads ───────────────────────────────────────────────────────────────
138
140
  async getById(id) {
@@ -748,7 +750,7 @@ adminDocumentsRoutes.post("/types/:typeId/reindex", async (c) => {
748
750
  const reindexTenant = effectiveTenantForType(getRequestTenant(c), docType.settings);
749
751
  const reindexDenied = await denyIfNotAllowed(c, db, "", "manage", docType.settings, reindexTenant);
750
752
  if (reindexDenied) return reindexDenied;
751
- const { DocumentProjection } = await import('./document-projection-YYMC6I4U.js');
753
+ const { DocumentProjection } = await import('./document-projection-4HG75S5S.js');
752
754
  const projection = new DocumentProjection(db);
753
755
  const rebuilt = await projection.reindexType(typeId, reindexTenant, docType.queryableFields);
754
756
  return c.json({ rebuilt });
@@ -1260,16 +1262,6 @@ apiRoutes.use("*", async (c, next) => {
1260
1262
  c.set("cacheEnabled", cacheEnabled);
1261
1263
  await next();
1262
1264
  });
1263
- apiRoutes.use("*", cors({
1264
- origin: (origin, c) => {
1265
- const allowed = c.env?.CORS_ORIGINS;
1266
- if (!allowed) return null;
1267
- const list = allowed.split(",").map((s) => s.trim());
1268
- return list.includes(origin) ? origin : null;
1269
- },
1270
- allowMethods: ["GET", "POST", "PUT", "DELETE", "OPTIONS"],
1271
- allowHeaders: ["Content-Type", "Authorization", "X-API-Key"]
1272
- }));
1273
1265
  function addTimingMeta(c, meta = {}, executionStartTime) {
1274
1266
  const totalTime = Date.now() - c.get("startTime");
1275
1267
  const executionTime = executionStartTime ? Date.now() - executionStartTime : void 0;
@@ -2202,6 +2194,8 @@ var MediaDocumentService = class {
2202
2194
  this.db = db;
2203
2195
  this.tenantId = tenantId;
2204
2196
  }
2197
+ db;
2198
+ tenantId;
2205
2199
  /** Create a media_asset document from R2 upload metadata. Published-on-create (immediately usable). */
2206
2200
  async createFromUpload(meta, createdBy) {
2207
2201
  const svc = new DocumentsService(this.db, { queryableFields: MEDIA_QUERYABLE, tenantId: this.tenantId, maxVersionsPerRoot: 5 });
@@ -3400,7 +3394,7 @@ adminApiRoutes.patch("/collections/:id", collectionsReadOnly);
3400
3394
  adminApiRoutes.delete("/collections/:id", collectionsReadOnly);
3401
3395
  adminApiRoutes.get("/migrations/status", async (c) => {
3402
3396
  try {
3403
- const { MigrationService: MigrationService2 } = await import('./migrations-WCAVBD7C.js');
3397
+ const { MigrationService: MigrationService2 } = await import('./migrations-HZJ6U6SX.js');
3404
3398
  const db = c.env.DB;
3405
3399
  const migrationService = new MigrationService2(db);
3406
3400
  const status = await migrationService.getMigrationStatus();
@@ -3443,7 +3437,7 @@ adminApiRoutes.post("/migrations/run", async (c) => {
3443
3437
  });
3444
3438
  adminApiRoutes.get("/migrations/validate", async (c) => {
3445
3439
  try {
3446
- const { MigrationService: MigrationService2 } = await import('./migrations-WCAVBD7C.js');
3440
+ const { MigrationService: MigrationService2 } = await import('./migrations-HZJ6U6SX.js');
3447
3441
  const db = c.env.DB;
3448
3442
  const migrationService = new MigrationService2(db);
3449
3443
  const validation = await migrationService.validateSchema();
@@ -3602,7 +3596,7 @@ function renderLoginPage(data, demoLoginActive = false) {
3602
3596
  <!-- Form -->
3603
3597
  <form
3604
3598
  id="login-form"
3605
- hx-post="/auth/login/form"
3599
+ hx-post="/auth/login/form${data.redirect ? `?redirect=${encodeURIComponent(data.redirect)}` : ""}"
3606
3600
  hx-target="#form-response"
3607
3601
  hx-swap="innerHTML"
3608
3602
  class="space-y-6"
@@ -5590,6 +5584,79 @@ function renderDynamicField(field, options = {}) {
5590
5584
  `;
5591
5585
  break;
5592
5586
  }
5587
+ case "json": {
5588
+ const jsonParsedValue = value !== null && value !== void 0 && typeof value !== "string" ? value : typeof value === "string" && value !== "" ? (() => {
5589
+ try {
5590
+ return JSON.parse(value);
5591
+ } catch {
5592
+ return value;
5593
+ }
5594
+ })() : null;
5595
+ const jsonDisplayValue = jsonParsedValue !== null && typeof jsonParsedValue !== "string" ? JSON.stringify(jsonParsedValue, null, 2) : typeof jsonParsedValue === "string" ? jsonParsedValue : "";
5596
+ const viewerId = `${fieldId}-viewer`;
5597
+ const textareaId = `${fieldId}-textarea`;
5598
+ const jsonDataAttr = escapeHtml2(JSON.stringify(jsonParsedValue ?? null));
5599
+ const isEmpty = jsonParsedValue === null || jsonDisplayValue === "";
5600
+ if (disabled) {
5601
+ fieldHTML = `
5602
+ <div
5603
+ id="${viewerId}"
5604
+ class="json-viewer-host rounded-lg px-3 py-2 text-xs bg-white dark:bg-zinc-800 shadow-sm ring-1 ring-inset ring-zinc-950/10 dark:ring-white/10 min-h-[2.5rem] overflow-auto"
5605
+ data-json-viewer
5606
+ data-json="${jsonDataAttr}"
5607
+ data-open="${opts.open ?? 2}"
5608
+ >${isEmpty ? '<span class="text-zinc-400 dark:text-zinc-500 italic">empty</span>' : ""}</div>
5609
+ ${getJsonViewerScript()}
5610
+ `;
5611
+ } else {
5612
+ fieldHTML = `
5613
+ <div class="json-field-wrapper space-y-2">
5614
+ <div class="flex items-center justify-end">
5615
+ <button
5616
+ type="button"
5617
+ id="${fieldId}-toggle"
5618
+ class="text-xs text-zinc-500 dark:text-zinc-400 hover:text-zinc-700 dark:hover:text-zinc-200 underline transition-colors"
5619
+ data-json-toggle
5620
+ data-viewer="${viewerId}"
5621
+ data-textarea="${textareaId}"
5622
+ data-hidden-input="${fieldId}"
5623
+ >Edit JSON</button>
5624
+ </div>
5625
+
5626
+ <div
5627
+ id="${viewerId}"
5628
+ class="json-viewer-host rounded-lg px-3 py-2 text-xs bg-white dark:bg-zinc-800 shadow-sm ring-1 ring-inset ring-zinc-950/10 dark:ring-white/10 min-h-[2.5rem] overflow-auto"
5629
+ data-json-viewer
5630
+ data-json="${jsonDataAttr}"
5631
+ data-open="${opts.open ?? 2}"
5632
+ >${isEmpty ? '<span class="text-zinc-400 dark:text-zinc-500 italic">empty \u2014 click &quot;Edit JSON&quot; to add data</span>' : ""}</div>
5633
+
5634
+ <textarea
5635
+ id="${textareaId}"
5636
+ rows="${opts.rows || 8}"
5637
+ placeholder="${opts.placeholder || "{}"}"
5638
+ class="${baseClasses} ${errorClasses} resize-y font-mono text-xs hidden"
5639
+ aria-label="${escapeHtml2(field.field_label)}"
5640
+ data-json-edit-area
5641
+ data-viewer="${viewerId}"
5642
+ data-hidden-input="${fieldId}"
5643
+ >${escapeHtml2(jsonDisplayValue)}</textarea>
5644
+
5645
+ <input
5646
+ type="hidden"
5647
+ id="${fieldId}"
5648
+ name="${fieldName}"
5649
+ value="${escapeHtml2(jsonDisplayValue)}"
5650
+ ${required}
5651
+ >
5652
+
5653
+ <div id="${fieldId}-json-error" class="text-xs text-pink-500 dark:text-pink-400 hidden"></div>
5654
+ </div>
5655
+ ${getJsonViewerScript()}
5656
+ `;
5657
+ }
5658
+ break;
5659
+ }
5593
5660
  default:
5594
5661
  fieldHTML = `
5595
5662
  <input
@@ -6086,6 +6153,120 @@ function normalizeBlockField(fieldConfig, fieldName) {
6086
6153
  options
6087
6154
  };
6088
6155
  }
6156
+ function getJsonViewerScript() {
6157
+ return `
6158
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/json-formatter-js@2.5.23/dist/json-formatter.min.css" id="json-formatter-css" onload="this.removeAttribute('onload')" onerror="">
6159
+ <script>
6160
+ (function() {
6161
+ var JS_URL = 'https://cdn.jsdelivr.net/npm/json-formatter-js@2.5.23/dist/json-formatter.umd.min.js';
6162
+
6163
+ function isDark() {
6164
+ return document.documentElement.classList.contains('dark') ||
6165
+ document.documentElement.dataset.theme === 'dark' ||
6166
+ window.matchMedia('(prefers-color-scheme: dark)').matches;
6167
+ }
6168
+
6169
+ function initViewer(el) {
6170
+ var raw = el.dataset.json;
6171
+ var open = parseInt(el.dataset.open || '2', 10);
6172
+ if (!raw || raw === 'null') return;
6173
+ var data;
6174
+ try { data = JSON.parse(raw); } catch(e) { el.textContent = raw; return; }
6175
+ var fmt = new JSONFormatter(data, open, {
6176
+ hoverPreviewEnabled: true,
6177
+ hoverPreviewArrayCount: 5,
6178
+ hoverPreviewFieldCount: 5,
6179
+ theme: isDark() ? 'dark' : '',
6180
+ animateOpen: true,
6181
+ animateClose: true,
6182
+ });
6183
+ el.innerHTML = '';
6184
+ el.appendChild(fmt.render());
6185
+ }
6186
+
6187
+ function initAllViewers() {
6188
+ document.querySelectorAll('[data-json-viewer]').forEach(function(el) { initViewer(el); });
6189
+ }
6190
+
6191
+ function ensureLoaded(cb) {
6192
+ if (window.JSONFormatter) { cb(); return; }
6193
+ if (window.__jsonFormatterCallbacks) { window.__jsonFormatterCallbacks.push(cb); return; }
6194
+ window.__jsonFormatterCallbacks = [cb];
6195
+ var s = document.createElement('script');
6196
+ s.src = JS_URL;
6197
+ s.onload = function() {
6198
+ (window.__jsonFormatterCallbacks || []).forEach(function(fn) { fn(); });
6199
+ window.__jsonFormatterCallbacks = null;
6200
+ };
6201
+ document.head.appendChild(s);
6202
+ }
6203
+
6204
+ if (!window.__sonicJsonViewerInit) {
6205
+ window.__sonicJsonViewerInit = true;
6206
+
6207
+ // Toggle between viewer and edit textarea
6208
+ document.addEventListener('click', function(e) {
6209
+ var btn = e.target.closest('[data-json-toggle]');
6210
+ if (!btn) return;
6211
+ var viewerId = btn.dataset.viewer;
6212
+ var textareaId = btn.dataset.textarea;
6213
+ var hiddenId = btn.dataset.hiddenInput;
6214
+ var viewer = document.getElementById(viewerId);
6215
+ var textarea = document.getElementById(textareaId);
6216
+ var hidden = document.getElementById(hiddenId);
6217
+ var errorEl = hidden ? document.getElementById(hiddenId + '-json-error') : null;
6218
+ if (!viewer || !textarea) return;
6219
+ var isEditing = !textarea.classList.contains('hidden');
6220
+ if (isEditing) {
6221
+ // Switching back to viewer \u2014 validate + refresh
6222
+ var raw = textarea.value.trim();
6223
+ if (raw) {
6224
+ try {
6225
+ var parsed = JSON.parse(raw);
6226
+ if (hidden) hidden.value = raw;
6227
+ viewer.dataset.json = JSON.stringify(parsed);
6228
+ ensureLoaded(function() { initViewer(viewer); });
6229
+ if (errorEl) { errorEl.textContent = ''; errorEl.classList.add('hidden'); }
6230
+ } catch(ex) {
6231
+ if (errorEl) { errorEl.textContent = 'Invalid JSON: ' + ex.message; errorEl.classList.remove('hidden'); }
6232
+ return;
6233
+ }
6234
+ } else {
6235
+ if (hidden) hidden.value = '';
6236
+ viewer.innerHTML = '<span class="text-zinc-400 dark:text-zinc-500 italic">empty</span>';
6237
+ }
6238
+ textarea.classList.add('hidden');
6239
+ viewer.classList.remove('hidden');
6240
+ btn.textContent = 'Edit JSON';
6241
+ } else {
6242
+ // Switching to edit \u2014 populate textarea from hidden input
6243
+ if (hidden && hidden.value) {
6244
+ try {
6245
+ textarea.value = JSON.stringify(JSON.parse(hidden.value), null, 2);
6246
+ } catch(e) {
6247
+ textarea.value = hidden.value;
6248
+ }
6249
+ }
6250
+ viewer.classList.add('hidden');
6251
+ textarea.classList.remove('hidden');
6252
+ btn.textContent = 'Preview';
6253
+ }
6254
+ });
6255
+ }
6256
+
6257
+ function run() {
6258
+ ensureLoaded(initAllViewers);
6259
+ }
6260
+
6261
+ if (document.readyState === 'loading') {
6262
+ document.addEventListener('DOMContentLoaded', run);
6263
+ } else {
6264
+ run();
6265
+ }
6266
+ })();
6267
+ </script>
6268
+ `;
6269
+ }
6089
6270
  function getStructuredFieldScript() {
6090
6271
  return `
6091
6272
  ${getReadFieldValueScript()}
@@ -6946,10 +7127,12 @@ var authRoutes = new Hono();
6946
7127
  authRoutes.get("/login", async (c) => {
6947
7128
  const error = c.req.query("error");
6948
7129
  const message = c.req.query("message");
7130
+ const redirect = c.req.query("redirect");
6949
7131
  const pageData = {
6950
7132
  error: error || void 0,
6951
7133
  message: message || void 0,
6952
- version: c.get("appVersion")
7134
+ version: c.get("appVersion"),
7135
+ redirect: redirect && redirect.startsWith("/") ? redirect : void 0
6953
7136
  };
6954
7137
  const db = c.env.DB;
6955
7138
  let demoLoginActive = false;
@@ -7093,7 +7276,7 @@ authRoutes.post(
7093
7276
  }
7094
7277
  const { email, password } = validation.data;
7095
7278
  const normalizedEmail = email.toLowerCase();
7096
- const { createAuth } = await import('./config-HFXANXCC.js');
7279
+ const { createAuth } = await import('./config-6FB2BXMP.js');
7097
7280
  const auth = createAuth(c.env);
7098
7281
  const baReq = new Request(new URL("/auth/sign-in/email", c.req.url).href, {
7099
7282
  method: "POST",
@@ -7115,6 +7298,20 @@ authRoutes.post(
7115
7298
  await setCsrfCookie(c);
7116
7299
  const baBody = await baRes.json();
7117
7300
  const user = baBody.user ?? {};
7301
+ const tokenTtl = await getJwtExpirySecondsFromDb(c.env.DB, c.env);
7302
+ const token = await AuthManager.generateToken(
7303
+ user.id,
7304
+ user.email,
7305
+ user.role ?? "viewer",
7306
+ c.env.JWT_SECRET,
7307
+ tokenTtl
7308
+ );
7309
+ setCookie(c, "auth_token", token, {
7310
+ httpOnly: true,
7311
+ secure: true,
7312
+ sameSite: "Strict",
7313
+ maxAge: tokenTtl
7314
+ });
7118
7315
  return c.json({
7119
7316
  user: {
7120
7317
  id: user.id,
@@ -7122,7 +7319,8 @@ authRoutes.post(
7122
7319
  firstName: user.name?.split(" ")[0] ?? "",
7123
7320
  lastName: user.name?.split(" ").slice(1).join(" ") ?? "",
7124
7321
  role: user.role ?? "viewer"
7125
- }
7322
+ },
7323
+ token
7126
7324
  });
7127
7325
  } catch (error) {
7128
7326
  console.error("Login error:", error);
@@ -7132,7 +7330,7 @@ authRoutes.post(
7132
7330
  );
7133
7331
  authRoutes.post("/logout", async (c) => {
7134
7332
  try {
7135
- const { createAuth } = await import('./config-HFXANXCC.js');
7333
+ const { createAuth } = await import('./config-6FB2BXMP.js');
7136
7334
  const auth = createAuth(c.env);
7137
7335
  const baReq = new Request(new URL("/auth/sign-out", c.req.url).href, {
7138
7336
  method: "POST",
@@ -7148,7 +7346,7 @@ authRoutes.post("/logout", async (c) => {
7148
7346
  });
7149
7347
  authRoutes.get("/logout", async (c) => {
7150
7348
  try {
7151
- const { createAuth } = await import('./config-HFXANXCC.js');
7349
+ const { createAuth } = await import('./config-6FB2BXMP.js');
7152
7350
  const auth = createAuth(c.env);
7153
7351
  const baReq = new Request(new URL("/auth/sign-out", c.req.url).href, {
7154
7352
  method: "POST",
@@ -7355,7 +7553,7 @@ authRoutes.post(
7355
7553
  </div>
7356
7554
  `);
7357
7555
  }
7358
- const { createAuth } = await import('./config-HFXANXCC.js');
7556
+ const { createAuth } = await import('./config-6FB2BXMP.js');
7359
7557
  const auth = createAuth(c.env);
7360
7558
  const baReq = new Request(new URL("/auth/sign-in/email", c.req.url).href, {
7361
7559
  method: "POST",
@@ -7379,6 +7577,8 @@ authRoutes.post(
7379
7577
  }
7380
7578
  }
7381
7579
  await setCsrfCookie(c);
7580
+ const rawRedirect = c.req.query("redirect");
7581
+ const redirectUrl = rawRedirect && rawRedirect.startsWith("/") ? rawRedirect : "/admin/content";
7382
7582
  return c.html(html`
7383
7583
  <div id="form-response">
7384
7584
  <div class="rounded-lg bg-green-100 dark:bg-lime-500/10 p-4 ring-1 ring-green-400 dark:ring-lime-500/20">
@@ -7391,7 +7591,7 @@ authRoutes.post(
7391
7591
  </div>
7392
7592
  </div>
7393
7593
  <script>
7394
- setTimeout(() => { window.location.href = '/admin/content'; }, 500);
7594
+ setTimeout(() => { window.location.href = '${redirectUrl}'; }, 500);
7395
7595
  </script>
7396
7596
  </div>
7397
7597
  </div>
@@ -12866,7 +13066,7 @@ adminContentRoutes.post("/documents/:typeId/:documentId/delete", async (c) => {
12866
13066
  adminContentRoutes.get("/documents/:typeId/:rootId/versions", async (c) => {
12867
13067
  const { typeId, rootId } = c.req.param();
12868
13068
  const db = c.env.DB;
12869
- const { renderVersionHistoryFragment } = await import('./admin-documents-form.template-NLSI6Z42.js');
13069
+ const { renderVersionHistoryFragment } = await import('./admin-documents-form.template-DDSH6ROU.js');
12870
13070
  const registry = new DocumentTypeRegistry(db);
12871
13071
  const docType = await registry.findById(typeId);
12872
13072
  if (!docType) return c.html("<div>Unknown type.</div>", 404);
@@ -14739,6 +14939,7 @@ var TenantService = class {
14739
14939
  constructor(db) {
14740
14940
  this.db = db;
14741
14941
  }
14942
+ db;
14742
14943
  async listTenants() {
14743
14944
  const { results } = await this.db.prepare(`
14744
14945
  SELECT * FROM auth_tenant
@@ -19137,6 +19338,8 @@ function escapeHtmlAttr(value) {
19137
19338
  }
19138
19339
  function renderPluginSettingsPage(data) {
19139
19340
  const { plugin, activity = [], user } = data;
19341
+ const hasUserSettings = Object.keys(plugin.settings || {}).some((k) => !k.startsWith("_"));
19342
+ const defaultTab = hasUserSettings ? "settings" : "info";
19140
19343
  const pageContent = `
19141
19344
  <div class="w-full px-4 sm:px-6 lg:px-8 py-6">
19142
19345
  <!-- Header with Back Button -->
@@ -19147,13 +19350,24 @@ function renderPluginSettingsPage(data) {
19147
19350
  ${plugin.description}
19148
19351
  </p>
19149
19352
  </div>
19150
- <div class="mt-4 sm:mt-0 sm:ml-16 sm:flex-none">
19353
+ <div class="mt-4 sm:mt-0 sm:ml-16 flex items-center gap-3">
19151
19354
  <a href="/admin/plugins" 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">
19152
19355
  <svg class="-ml-0.5 mr-1.5 h-5 w-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
19153
19356
  <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 19l-7-7m0 0l7-7m-7 7h18"/>
19154
19357
  </svg>
19155
19358
  Back to Plugins
19156
19359
  </a>
19360
+ ${plugin.settings?._adminPath ? `
19361
+ <a
19362
+ href="${plugin.settings._adminPath}"
19363
+ class="inline-flex items-center justify-center gap-1.5 rounded-lg bg-gradient-to-r from-cyan-500 to-purple-600 hover:from-cyan-400 hover:to-purple-500 px-3.5 py-2.5 text-sm font-semibold text-white shadow-sm transition-all duration-200"
19364
+ >
19365
+ <svg class="-ml-0.5 h-4 w-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
19366
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14"/>
19367
+ </svg>
19368
+ View Page
19369
+ </a>
19370
+ ` : ""}
19157
19371
  </div>
19158
19372
  </div>
19159
19373
 
@@ -19186,23 +19400,25 @@ function renderPluginSettingsPage(data) {
19186
19400
  <!-- Tabs -->
19187
19401
  <div class="mb-6">
19188
19402
  <nav class="flex space-x-8" aria-label="Tabs">
19189
- <button onclick="showTab('settings')" id="settings-tab" class="tab-button active border-b-2 border-blue-400 py-2 px-1 text-sm font-medium text-blue-400">
19403
+ ${hasUserSettings ? `
19404
+ <a href="#settings" onclick="showTab('settings')" id="settings-tab" class="tab-button border-b-2 border-transparent py-2 px-1 text-sm font-medium text-gray-400 hover:text-gray-300">
19190
19405
  Settings
19191
- </button>
19192
- <button onclick="showTab('activity')" id="activity-tab" class="tab-button border-b-2 border-transparent py-2 px-1 text-sm font-medium text-gray-400 hover:text-gray-300">
19193
- Activity Log
19194
- </button>
19195
- <button onclick="showTab('info')" id="info-tab" class="tab-button border-b-2 border-transparent py-2 px-1 text-sm font-medium text-gray-400 hover:text-gray-300">
19406
+ </a>
19407
+ ` : ""}
19408
+ <a href="#info" onclick="showTab('info')" id="info-tab" class="tab-button border-b-2 border-transparent py-2 px-1 text-sm font-medium text-gray-400 hover:text-gray-300">
19196
19409
  Information
19197
- </button>
19410
+ </a>
19411
+ <a href="#activity" onclick="showTab('activity')" id="activity-tab" class="tab-button border-b-2 border-transparent py-2 px-1 text-sm font-medium text-gray-400 hover:text-gray-300">
19412
+ Activity Log
19413
+ </a>
19198
19414
  </nav>
19199
19415
  </div>
19200
19416
 
19201
19417
  <!-- Tab Content -->
19202
19418
  <div id="tab-content">
19203
19419
  <!-- Settings Tab -->
19204
- <div id="settings-content" class="tab-content">
19205
- ${renderSettingsTab(plugin)}
19420
+ <div id="settings-content" class="tab-content hidden">
19421
+ ${hasUserSettings ? renderSettingsTab(plugin) : ""}
19206
19422
  </div>
19207
19423
 
19208
19424
  <!-- Activity Tab -->
@@ -19218,27 +19434,42 @@ function renderPluginSettingsPage(data) {
19218
19434
  </div>
19219
19435
 
19220
19436
  <script>
19437
+ const VALID_TABS = [${hasUserSettings ? "'settings', " : ""}'activity', 'info'];
19438
+
19221
19439
  function showTab(tabName) {
19222
- // Hide all tab contents
19440
+ if (!VALID_TABS.includes(tabName)) tabName = '${defaultTab}';
19441
+
19223
19442
  document.querySelectorAll('.tab-content').forEach(content => {
19224
19443
  content.classList.add('hidden');
19225
19444
  });
19226
-
19227
- // Remove active class from all tabs
19445
+
19228
19446
  document.querySelectorAll('.tab-button').forEach(tab => {
19229
19447
  tab.classList.remove('active', 'border-blue-400', 'text-blue-400');
19230
19448
  tab.classList.add('border-transparent', 'text-gray-400');
19231
19449
  });
19232
-
19233
- // Show selected tab content
19234
- document.getElementById(tabName + '-content').classList.remove('hidden');
19235
-
19236
- // Add active class to selected tab
19450
+
19451
+ const contentEl = document.getElementById(tabName + '-content');
19452
+ if (contentEl) contentEl.classList.remove('hidden');
19453
+
19237
19454
  const activeTab = document.getElementById(tabName + '-tab');
19238
- activeTab.classList.add('active', 'border-blue-400', 'text-blue-400');
19239
- activeTab.classList.remove('border-transparent', 'text-gray-400');
19455
+ if (activeTab) {
19456
+ activeTab.classList.add('active', 'border-blue-400', 'text-blue-400');
19457
+ activeTab.classList.remove('border-transparent', 'text-gray-400');
19458
+ }
19459
+
19460
+ if (window.location.hash !== '#' + tabName) {
19461
+ history.replaceState(null, '', '#' + tabName);
19462
+ }
19240
19463
  }
19241
19464
 
19465
+ function initTabFromHash() {
19466
+ const hash = window.location.hash.replace('#', '');
19467
+ showTab(VALID_TABS.includes(hash) ? hash : '${defaultTab}');
19468
+ }
19469
+
19470
+ window.addEventListener('hashchange', initTabFromHash);
19471
+ initTabFromHash();
19472
+
19242
19473
  async function togglePlugin(pluginId, action) {
19243
19474
  const button = event.target;
19244
19475
  const originalText = button.textContent;
@@ -19411,6 +19642,7 @@ function renderToggleButton(plugin) {
19411
19642
  function renderSettingsTab(plugin) {
19412
19643
  const settings = plugin.settings || {};
19413
19644
  const pluginId = plugin.id || plugin.name;
19645
+ const hasUserKeys = Object.keys(settings).some((k) => !k.startsWith("_"));
19414
19646
  const customRenderer = pluginSettingsComponents[pluginId];
19415
19647
  if (customRenderer) {
19416
19648
  return `
@@ -19446,9 +19678,9 @@ function renderSettingsTab(plugin) {
19446
19678
  `}
19447
19679
 
19448
19680
  <form id="settings-form" class="space-y-6">
19449
- ${isAuthPlugin && Object.keys(settings).length > 0 ? renderAuthSettingsForm(settings) : isTurnstilePlugin && Object.keys(settings).length > 0 ? renderTurnstileSettingsForm(settings) : Object.keys(settings).length > 0 ? renderSettingsFields(settings) : renderNoSettings(plugin)}
19681
+ ${isAuthPlugin && hasUserKeys ? renderAuthSettingsForm(settings) : isTurnstilePlugin && hasUserKeys ? renderTurnstileSettingsForm(settings) : hasUserKeys ? renderSettingsFields(settings) : renderNoSettings(plugin)}
19450
19682
 
19451
- ${Object.keys(settings).length > 0 ? `
19683
+ ${hasUserKeys ? `
19452
19684
  <div class="flex items-center justify-end pt-6 border-t border-white/10">
19453
19685
  <button
19454
19686
  type="button"
@@ -19465,7 +19697,7 @@ function renderSettingsTab(plugin) {
19465
19697
  `;
19466
19698
  }
19467
19699
  function renderSettingsFields(settings) {
19468
- return Object.entries(settings).map(([key, value]) => {
19700
+ return Object.entries(settings).filter(([key]) => !key.startsWith("_")).map(([key, value]) => {
19469
19701
  const fieldId = `setting_${key}`;
19470
19702
  const displayName = key.replace(/([A-Z])/g, " $1").replace(/^./, (str) => str.toUpperCase());
19471
19703
  if (typeof value === "boolean") {
@@ -19654,6 +19886,38 @@ function renderActivityTab(activity) {
19654
19886
  }
19655
19887
  function renderInformationTab(plugin) {
19656
19888
  return `
19889
+ ${plugin.description ? `
19890
+ <!-- About -->
19891
+ <div class="backdrop-blur-md bg-black/20 rounded-xl border border-white/10 shadow-xl p-6 mb-6">
19892
+ <h2 class="text-xl font-semibold text-white mb-3">About</h2>
19893
+ <p class="text-gray-300 leading-relaxed">${plugin.description}</p>
19894
+ </div>
19895
+ ` : ""}
19896
+
19897
+ ${(plugin.settings?._routes?.length ?? 0) > 0 ? `
19898
+ <!-- Routes -->
19899
+ <div class="backdrop-blur-md bg-black/20 rounded-xl border border-white/10 shadow-xl p-6 mb-6">
19900
+ <h2 class="text-xl font-semibold text-white mb-4">Routes</h2>
19901
+ <div class="space-y-2">
19902
+ ${plugin.settings._routes.map((r) => {
19903
+ const badge = r.method === "GET" ? "bg-emerald-500/20 text-emerald-300 border border-emerald-500/30" : r.method === "POST" ? "bg-blue-500/20 text-blue-300 border border-blue-500/30" : r.method === "DELETE" ? "bg-red-500/20 text-red-300 border border-red-500/30" : "bg-white/10 text-gray-300 border border-white/20";
19904
+ const pathHtml = r.method === "GET" ? `<a href="${r.path}" class="font-mono text-sm text-blue-400 hover:text-blue-300 hover:underline">${r.path}</a>` : `<span class="font-mono text-sm text-gray-200">${r.path}</span>`;
19905
+ const authBadge = r.requiresAuth ? `<span class="ml-2 text-xs text-amber-400/80">\u{1F512} auth</span>` : "";
19906
+ return `
19907
+ <div class="flex items-start gap-3 py-2 border-b border-white/5 last:border-0">
19908
+ <span class="shrink-0 inline-block px-2 py-0.5 rounded text-xs font-bold ${badge}">${r.method}</span>
19909
+ <div class="min-w-0">
19910
+ <div class="flex items-center gap-1 flex-wrap">
19911
+ ${pathHtml}${authBadge}
19912
+ </div>
19913
+ ${r.description ? `<p class="text-xs text-gray-400 mt-0.5">${r.description}</p>` : ""}
19914
+ </div>
19915
+ </div>`;
19916
+ }).join("")}
19917
+ </div>
19918
+ </div>
19919
+ ` : ""}
19920
+
19657
19921
  <div class="grid grid-cols-1 lg:grid-cols-2 gap-6">
19658
19922
  <!-- Plugin Details -->
19659
19923
  <div class="backdrop-blur-md bg-black/20 rounded-xl border border-white/10 shadow-xl p-6">
@@ -20684,7 +20948,9 @@ adminPluginRoutes.post("/:id/configure", async (c) => {
20684
20948
  description: def.description,
20685
20949
  author: typeof def.author === "object" ? def.author?.name : def.author
20686
20950
  });
20687
- await pluginService.updatePluginSettings(pluginId, parsed);
20951
+ const existingPlugin = await pluginService.getPlugin(pluginId);
20952
+ const existingSettings = existingPlugin?.settings ?? {};
20953
+ await pluginService.updatePluginSettings(pluginId, { ...existingSettings, ...parsed });
20688
20954
  return c.redirect(`/admin/plugins/${encodeURIComponent(pluginId)}/configure`);
20689
20955
  } catch (error) {
20690
20956
  console.error("Error saving schema settings:", error);
@@ -26638,6 +26904,6 @@ var ROUTES_INFO = {
26638
26904
  reference: "https://github.com/sonicjs/sonicjs"
26639
26905
  };
26640
26906
 
26641
- export { DocumentRepository, ROUTES_INFO, TenantService, VALID_MEMBER_ROLES, adminCheckboxRoutes, adminCollectionsRoutes, adminDocumentsRoutes, adminLogsRoutes, adminMediaRoutes, adminPluginRoutes, adminSettingsRoutes, admin_api_default, admin_content_default, apiDocumentsRoutes, api_content_crud_default, api_default, api_media_default, api_system_default, auth_default, createUserProfilesPlugin, defineUserProfile, denyIfNotAllowed, dispatchHookEvent, getConfirmationDialogScript2 as getConfirmationDialogScript, getCustomData, getEmailService, getUserProfileConfig, getVariablesCached, hasEmailService, invalidateVariablesCache, isValidMemberRole, lexicalEditorPlugin, renderConfirmationDialog2 as renderConfirmationDialog, renderTable2 as renderTable, resolveDocScope, resolveVariablesInObject, router, router2, setEmailService, setVariablesCache, test_cleanup_default, userProfilesPlugin, userRoutes };
26642
- //# sourceMappingURL=chunk-VD2EA3WT.js.map
26643
- //# sourceMappingURL=chunk-VD2EA3WT.js.map
26907
+ export { DocumentRepository, ROUTES_INFO, TenantService, VALID_MEMBER_ROLES, adminCheckboxRoutes, adminCollectionsRoutes, adminDocumentsRoutes, adminLogsRoutes, adminMediaRoutes, adminPluginRoutes, adminSettingsRoutes, admin_api_default, admin_content_default, apiDocumentsRoutes, api_content_crud_default, api_default, api_media_default, api_system_default, auth_default, createDocumentSchema, createUserProfilesPlugin, defineUserProfile, denyIfNotAllowed, dispatchHookEvent, getConfirmationDialogScript2 as getConfirmationDialogScript, getCustomData, getEmailService, getUserProfileConfig, getVariablesCached, hasEmailService, invalidateVariablesCache, isValidMemberRole, lexicalEditorPlugin, renderConfirmationDialog2 as renderConfirmationDialog, renderTable2 as renderTable, resolveDocScope, resolveVariablesInObject, router, router2, setEmailService, setVariablesCache, test_cleanup_default, userProfilesPlugin, userRoutes };
26908
+ //# sourceMappingURL=chunk-5UCMLBRQ.js.map
26909
+ //# sourceMappingURL=chunk-5UCMLBRQ.js.map