@sonicjs-cms/core 3.0.0-beta.23 → 3.0.0-beta.25

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 (139) hide show
  1. package/bin/db-reset.js +39 -22
  2. package/dist/admin-documents-form.template-JWV5GITD.js +6 -0
  3. package/dist/{admin-documents-form.template-55V2ZGWT.js.map → admin-documents-form.template-JWV5GITD.js.map} +1 -1
  4. package/dist/admin-documents-form.template-UWKGVAMW.cjs +19 -0
  5. package/dist/{admin-layout-catalyst.template-6UQGLCKI.js.map → admin-documents-form.template-UWKGVAMW.cjs.map} +1 -1
  6. package/dist/admin-layout-catalyst.template-MOQ3BBXA.cjs +21 -0
  7. package/dist/{admin-layout-catalyst.template-3XZXDGF7.cjs.map → admin-layout-catalyst.template-MOQ3BBXA.cjs.map} +1 -1
  8. package/dist/admin-layout-catalyst.template-WCYMQVTZ.js +7 -0
  9. package/dist/{admin-documents-form.template-YNAVMJCV.cjs.map → admin-layout-catalyst.template-WCYMQVTZ.js.map} +1 -1
  10. package/dist/{chunk-KS24NPPL.js → chunk-2D3A4X52.js} +21 -2
  11. package/dist/chunk-2D3A4X52.js.map +1 -0
  12. package/dist/{chunk-DIBCKCUE.js → chunk-2OXFMMA3.js} +14 -29
  13. package/dist/chunk-2OXFMMA3.js.map +1 -0
  14. package/dist/{chunk-SOZUG52O.js → chunk-3KGY4IBW.js} +3 -3
  15. package/dist/{chunk-SOZUG52O.js.map → chunk-3KGY4IBW.js.map} +1 -1
  16. package/dist/{chunk-CTYLCWMO.cjs → chunk-6OA77UM7.cjs} +802 -481
  17. package/dist/chunk-6OA77UM7.cjs.map +1 -0
  18. package/dist/{chunk-URIBTX27.js → chunk-73RTFFMX.js} +3 -3
  19. package/dist/{chunk-URIBTX27.js.map → chunk-73RTFFMX.js.map} +1 -1
  20. package/dist/{chunk-SK5CHFJP.js → chunk-7P5OCUPS.js} +467 -149
  21. package/dist/chunk-7P5OCUPS.js.map +1 -0
  22. package/dist/{chunk-3TMTYJAJ.js → chunk-BDQ55MWV.js} +18 -2
  23. package/dist/chunk-BDQ55MWV.js.map +1 -0
  24. package/dist/{chunk-C3ZQP5NW.cjs → chunk-BJ6NJL2E.cjs} +7 -12
  25. package/dist/chunk-BJ6NJL2E.cjs.map +1 -0
  26. package/dist/{chunk-2MIYYAO4.js → chunk-C54MH5UI.js} +5 -4
  27. package/dist/chunk-C54MH5UI.js.map +1 -0
  28. package/dist/{chunk-BBEKHLTW.cjs → chunk-CN3T3TDI.cjs} +9 -9
  29. package/dist/{chunk-BBEKHLTW.cjs.map → chunk-CN3T3TDI.cjs.map} +1 -1
  30. package/dist/{chunk-DPLJYTHE.js → chunk-CWIGQYRR.js} +7 -12
  31. package/dist/chunk-CWIGQYRR.js.map +1 -0
  32. package/dist/{chunk-4WMZGHIC.cjs → chunk-D6FWEYQE.cjs} +6 -5
  33. package/dist/chunk-D6FWEYQE.cjs.map +1 -0
  34. package/dist/{chunk-A46IRC5A.js → chunk-D7RLBBHE.js} +2 -2
  35. package/dist/{chunk-A46IRC5A.js.map → chunk-D7RLBBHE.js.map} +1 -1
  36. package/dist/{chunk-IXUHXTHW.cjs → chunk-DLTT7QZU.cjs} +17 -6
  37. package/dist/chunk-DLTT7QZU.cjs.map +1 -0
  38. package/dist/{chunk-BHND5PEV.js → chunk-E3TQG7AA.js} +3 -3
  39. package/dist/{chunk-BHND5PEV.js.map → chunk-E3TQG7AA.js.map} +1 -1
  40. package/dist/{chunk-IS54FPB7.cjs → chunk-E7E3NL3Y.cjs} +27 -42
  41. package/dist/chunk-E7E3NL3Y.cjs.map +1 -0
  42. package/dist/{chunk-XXRR54AB.js → chunk-F26HP3B6.js} +36 -5
  43. package/dist/chunk-F26HP3B6.js.map +1 -0
  44. package/dist/{chunk-QZGABF2M.js → chunk-FVAK4C6L.js} +17 -6
  45. package/dist/chunk-FVAK4C6L.js.map +1 -0
  46. package/dist/{chunk-BJROXF4N.js → chunk-HSDJDWLV.js} +19 -4
  47. package/dist/chunk-HSDJDWLV.js.map +1 -0
  48. package/dist/{chunk-RFBW5RRH.cjs → chunk-I7MIRRFJ.cjs} +43 -12
  49. package/dist/chunk-I7MIRRFJ.cjs.map +1 -0
  50. package/dist/{chunk-LTZ5WYOK.cjs → chunk-JCBDXEY2.cjs} +18 -2
  51. package/dist/chunk-JCBDXEY2.cjs.map +1 -0
  52. package/dist/{chunk-UYJQDDEE.cjs → chunk-MI2YXCK4.cjs} +14 -8
  53. package/dist/chunk-MI2YXCK4.cjs.map +1 -0
  54. package/dist/{chunk-VGHEKIJL.cjs → chunk-MOGK3U4A.cjs} +2 -2
  55. package/dist/{chunk-VGHEKIJL.cjs.map → chunk-MOGK3U4A.cjs.map} +1 -1
  56. package/dist/{chunk-E66UVONV.cjs → chunk-OUBUS74I.cjs} +24 -9
  57. package/dist/chunk-OUBUS74I.cjs.map +1 -0
  58. package/dist/{chunk-GMMCCIQO.cjs → chunk-RSBZITK3.cjs} +3 -3
  59. package/dist/{chunk-GMMCCIQO.cjs.map → chunk-RSBZITK3.cjs.map} +1 -1
  60. package/dist/{chunk-THFZSDIU.js → chunk-SXC4HPK6.js} +14 -8
  61. package/dist/chunk-SXC4HPK6.js.map +1 -0
  62. package/dist/{chunk-JMJM7DMM.cjs → chunk-TT3TQSCZ.cjs} +5 -5
  63. package/dist/{chunk-JMJM7DMM.cjs.map → chunk-TT3TQSCZ.cjs.map} +1 -1
  64. package/dist/{chunk-AT4ZQGEZ.cjs → chunk-YAURVGUK.cjs} +21 -2
  65. package/dist/chunk-YAURVGUK.cjs.map +1 -0
  66. package/dist/config-4TIHSNW6.js +6 -0
  67. package/dist/{config-6FB2BXMP.js.map → config-4TIHSNW6.js.map} +1 -1
  68. package/dist/{config-OCH7S4WK.cjs → config-XN2ETAJ3.cjs} +5 -5
  69. package/dist/{config-OCH7S4WK.cjs.map → config-XN2ETAJ3.cjs.map} +1 -1
  70. package/dist/{define-plugin-D_6D9vVZ.d.ts → define-plugin-DDe8a_bh.d.ts} +3 -0
  71. package/dist/{define-plugin-DMcvEy_C.d.cts → define-plugin-rjXmGOgu.d.cts} +3 -0
  72. package/dist/index.cjs +1220 -353
  73. package/dist/index.cjs.map +1 -1
  74. package/dist/index.d.cts +38 -3
  75. package/dist/index.d.ts +38 -3
  76. package/dist/index.js +895 -30
  77. package/dist/index.js.map +1 -1
  78. package/dist/middleware.cjs +35 -35
  79. package/dist/middleware.d.cts +4 -1
  80. package/dist/middleware.d.ts +4 -1
  81. package/dist/middleware.js +6 -6
  82. package/dist/migrations-JAHMI5MK.js +4 -0
  83. package/dist/{migrations-XQ6EX6HX.js.map → migrations-JAHMI5MK.js.map} +1 -1
  84. package/dist/migrations-KU4V6T73.cjs +13 -0
  85. package/dist/{migrations-ZD7Y5NUC.cjs.map → migrations-KU4V6T73.cjs.map} +1 -1
  86. package/dist/plugins.cjs +40 -40
  87. package/dist/plugins.d.cts +1 -1
  88. package/dist/plugins.d.ts +1 -1
  89. package/dist/plugins.js +3 -3
  90. package/dist/rbac-AORZ6O3N.cjs +14 -0
  91. package/dist/{rbac-7QZ4JZ2E.cjs.map → rbac-AORZ6O3N.cjs.map} +1 -1
  92. package/dist/rbac-P44772FP.js +5 -0
  93. package/dist/{rbac-Y43IEQOP.js.map → rbac-P44772FP.js.map} +1 -1
  94. package/dist/routes.cjs +31 -31
  95. package/dist/routes.js +11 -11
  96. package/dist/services.cjs +18 -18
  97. package/dist/services.d.cts +1 -1
  98. package/dist/services.d.ts +1 -1
  99. package/dist/services.js +2 -2
  100. package/dist/{telemetry-Cku1ax74.d.cts → telemetry-QFlTv9f8.d.cts} +1 -1
  101. package/dist/{telemetry-Cku1ax74.d.ts → telemetry-QFlTv9f8.d.ts} +1 -1
  102. package/dist/templates.cjs +17 -17
  103. package/dist/templates.js +3 -3
  104. package/dist/types.d.cts +1 -1
  105. package/dist/types.d.ts +1 -1
  106. package/dist/utils.cjs +12 -12
  107. package/dist/utils.d.cts +1 -1
  108. package/dist/utils.d.ts +1 -1
  109. package/dist/utils.js +2 -2
  110. package/package.json +5 -10
  111. package/dist/admin-documents-form.template-55V2ZGWT.js +0 -6
  112. package/dist/admin-documents-form.template-YNAVMJCV.cjs +0 -19
  113. package/dist/admin-layout-catalyst.template-3XZXDGF7.cjs +0 -21
  114. package/dist/admin-layout-catalyst.template-6UQGLCKI.js +0 -7
  115. package/dist/chunk-2MIYYAO4.js.map +0 -1
  116. package/dist/chunk-3TMTYJAJ.js.map +0 -1
  117. package/dist/chunk-4WMZGHIC.cjs.map +0 -1
  118. package/dist/chunk-AT4ZQGEZ.cjs.map +0 -1
  119. package/dist/chunk-BJROXF4N.js.map +0 -1
  120. package/dist/chunk-C3ZQP5NW.cjs.map +0 -1
  121. package/dist/chunk-CTYLCWMO.cjs.map +0 -1
  122. package/dist/chunk-DIBCKCUE.js.map +0 -1
  123. package/dist/chunk-DPLJYTHE.js.map +0 -1
  124. package/dist/chunk-E66UVONV.cjs.map +0 -1
  125. package/dist/chunk-IS54FPB7.cjs.map +0 -1
  126. package/dist/chunk-IXUHXTHW.cjs.map +0 -1
  127. package/dist/chunk-KS24NPPL.js.map +0 -1
  128. package/dist/chunk-LTZ5WYOK.cjs.map +0 -1
  129. package/dist/chunk-QZGABF2M.js.map +0 -1
  130. package/dist/chunk-RFBW5RRH.cjs.map +0 -1
  131. package/dist/chunk-SK5CHFJP.js.map +0 -1
  132. package/dist/chunk-THFZSDIU.js.map +0 -1
  133. package/dist/chunk-UYJQDDEE.cjs.map +0 -1
  134. package/dist/chunk-XXRR54AB.js.map +0 -1
  135. package/dist/config-6FB2BXMP.js +0 -6
  136. package/dist/migrations-XQ6EX6HX.js +0 -4
  137. package/dist/migrations-ZD7Y5NUC.cjs +0 -13
  138. package/dist/rbac-7QZ4JZ2E.cjs +0 -14
  139. package/dist/rbac-Y43IEQOP.js +0 -5
package/dist/index.js CHANGED
@@ -1,37 +1,37 @@
1
- import { createAuth } from './chunk-SOZUG52O.js';
2
- import { getEmailService, hasEmailService, setEmailService, reconcileMenuFromPlugins, invalidateVariablesCache, resolveVariablesInObject, resolveDocScope, denyIfNotAllowed, DocumentRepository, dispatchHookEvent, getCustomData, createDocumentSchema, renderTable, getVariablesCached, setVariablesCache, TenantService, isValidMemberRole, renderConfirmationDialog, getConfirmationDialogScript, VALID_MEMBER_ROLES, userProfilesPlugin, lexicalEditorPlugin, api_media_default, api_system_default, apiDocumentsRoutes, api_default, adminDocumentsRoutes, admin_api_default, adminCollectionsRoutes, adminSettingsRoutes, router2, admin_content_default, adminMediaRoutes, router, adminPluginRoutes, adminLogsRoutes, userRoutes, auth_default, test_cleanup_default } from './chunk-SK5CHFJP.js';
3
- export { DocumentRepository, ROUTES_INFO, admin_api_default as adminApiRoutes, adminCheckboxRoutes, adminCollectionsRoutes, admin_content_default as adminContentRoutes, router as adminDashboardRoutes, adminLogsRoutes, adminMediaRoutes, adminPluginRoutes, adminSettingsRoutes, 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, createUserProfilesPlugin, defineUserProfile, getUserProfileConfig, userProfilesPlugin } from './chunk-SK5CHFJP.js';
1
+ import { createAuth } from './chunk-3KGY4IBW.js';
2
+ import { getEmailService, hasEmailService, setEmailService, reconcileMenuFromPlugins, invalidateVariablesCache, resolveVariablesInObject, resolveDocScope, denyIfNotAllowed, DocumentRepository, dispatchHookEvent, getCustomData, createDocumentSchema, renderTable, getVariablesCached, setVariablesCache, TenantService, isValidMemberRole, renderConfirmationDialog, getConfirmationDialogScript, VALID_MEMBER_ROLES, userProfilesPlugin, lexicalEditorPlugin, api_media_default, api_system_default, apiDocumentsRoutes, api_default, adminDocumentsRoutes, admin_api_default, adminCollectionsRoutes, adminSettingsRoutes, router2, admin_content_default, adminMediaRoutes, router, adminPluginRoutes, adminLogsRoutes, userRoutes, auth_default, test_cleanup_default, getDocumentRequestContext, updateDocumentSchema, effectiveTenantForType } from './chunk-7P5OCUPS.js';
3
+ export { DocumentRepository, ROUTES_INFO, admin_api_default as adminApiRoutes, adminCheckboxRoutes, adminCollectionsRoutes, admin_content_default as adminContentRoutes, router as adminDashboardRoutes, adminLogsRoutes, adminMediaRoutes, adminPluginRoutes, adminSettingsRoutes, 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, createUserProfilesPlugin, defineUserProfile, getUserProfileConfig, userProfilesPlugin } from './chunk-7P5OCUPS.js';
4
4
  import './chunk-VVYVFCML.js';
5
- import './chunk-BHND5PEV.js';
5
+ import './chunk-E3TQG7AA.js';
6
6
  import { SettingsService, setAppInstance } from './chunk-2XAQTPAE.js';
7
7
  export { Logger, getLogger, initLogger } from './chunk-2XAQTPAE.js';
8
8
  import { getAllCacheStats, CACHE_CONFIGS, getCacheService, clearAllCaches, parseCacheKey } from './chunk-K25XHMM3.js';
9
9
  import { schema_exports } from './chunk-AI663NBO.js';
10
10
  export { apiTokens, content, contentVersions, insertContentSchema, insertLogConfigSchema, insertMediaSchema, insertPluginActivityLogSchema, insertPluginAssetSchema, insertPluginHookSchema, insertPluginRouteSchema, insertPluginSchema, insertSystemLogSchema, insertUserSchema, insertWorkflowHistorySchema, logConfig, media, pluginActivityLog, pluginAssets, pluginHooks, pluginRoutes, plugins, selectContentSchema, selectLogConfigSchema, selectMediaSchema, selectPluginActivityLogSchema, selectPluginAssetSchema, selectPluginHookSchema, selectPluginRouteSchema, selectPluginSchema, selectSystemLogSchema, selectUserSchema, selectWorkflowHistorySchema, systemLogs, users, workflowHistory } from './chunk-AI663NBO.js';
11
- import { requireAuth, DocumentTypeRegistry, requireRbac, requireRole, getJwtExpirySecondsFromDb, AuthManager, metricsMiddleware, bootstrapMiddleware, securityHeadersMiddleware, csrfProtection } from './chunk-DIBCKCUE.js';
12
- export { AuthManager, PermissionManager, bootstrapDocumentTypes, bootstrapMiddleware, cacheHeaders, compressionMiddleware, detailedLoggingMiddleware, getActivePlugins, isPluginActive, logActivity, loggingMiddleware, optionalAuth, performanceLoggingMiddleware, requireActivePlugin, requireActivePlugins, requireAnyPermission, requireAuth, requirePermission, requireRole, securityHeadersMiddleware as securityHeaders, securityLoggingMiddleware } from './chunk-DIBCKCUE.js';
13
- import { RbacService, DocumentsService } from './chunk-3TMTYJAJ.js';
14
- export { DocumentsService, RbacService } from './chunk-3TMTYJAJ.js';
11
+ import { requireAuth, DocumentTypeRegistry, requireRbac, requireRole, getJwtExpirySecondsFromDb, AuthManager, metricsMiddleware, bootstrapMiddleware, securityHeadersMiddleware, csrfProtection } from './chunk-2OXFMMA3.js';
12
+ export { AuthManager, PermissionManager, bootstrapDocumentTypes, bootstrapMiddleware, cacheHeaders, compressionMiddleware, detailedLoggingMiddleware, getActivePlugins, isPluginActive, logActivity, loggingMiddleware, optionalAuth, performanceLoggingMiddleware, requireActivePlugin, requireActivePlugins, requireAnyPermission, requireAuth, requirePermission, requireRole, securityHeadersMiddleware as securityHeaders, securityLoggingMiddleware } from './chunk-2OXFMMA3.js';
13
+ import { RbacService, DocumentsService } from './chunk-BDQ55MWV.js';
14
+ export { DocumentsService, RbacService } from './chunk-BDQ55MWV.js';
15
15
  import { nanoid } from './chunk-UWUP2VMT.js';
16
- import { PluginService, PLUGIN_REGISTRY, invalidateTenantCache, getCollectionRegistry, TENANT_COOKIE, MULTI_TENANT_PLUGIN_ID, collectionRecordToRow, tenantMiddleware } from './chunk-KS24NPPL.js';
17
- export { PluginBootstrapService, PluginService as PluginServiceClass, getAvailableCollectionNames, loadCollectionConfig, loadCollectionConfigs, registerCollections, validateCollectionConfig } from './chunk-KS24NPPL.js';
18
- export { MigrationService } from './chunk-A46IRC5A.js';
19
- export { renderFilterBar } from './chunk-URIBTX27.js';
20
- import { renderAdminLayout } from './chunk-BJROXF4N.js';
21
- export { getConfirmationDialogScript, renderAlert, renderConfirmationDialog, renderForm, renderFormField, renderPagination, renderTable } from './chunk-BJROXF4N.js';
22
- import { init_admin_layout_catalyst_template, renderAdminLayoutCatalyst } from './chunk-THFZSDIU.js';
23
- export { renderAdminLayoutCatalyst } from './chunk-THFZSDIU.js';
24
- import { TurnstileService, HookSystemImpl, createPluginWirer, registerPluginRoutes } from './chunk-XXRR54AB.js';
25
- export { HookSystemImpl, HookUtils, PluginDependencyCycleError, PluginManager as PluginManagerClass, PluginRegistryImpl, PluginValidator as PluginValidatorClass, RegisterPluginsError, ScopedHookSystem as ScopedHookSystemClass, collectCronSchedules, collectCrons, createScheduledHandler, dispatchCronTick, registerPlugins, topoSort } from './chunk-XXRR54AB.js';
26
- import { definePlugin, setPluginMenu, setPluginDefinitions, resolvePluginMenuItems } from './chunk-2MIYYAO4.js';
27
- export { applySchemaDefaults, definePlugin, getPluginMenu, isDefinedPlugin, parseConfigSchema, parseFormDataToSettings, renderSchemaFields, resetPluginMenu, resolvePluginMenuItems, setPluginMenu } from './chunk-2MIYYAO4.js';
16
+ import { PluginService, PLUGIN_REGISTRY, invalidateTenantCache, getCollectionRegistry, TENANT_COOKIE, MULTI_TENANT_PLUGIN_ID, collectionRecordToRow, tenantMiddleware } from './chunk-2D3A4X52.js';
17
+ export { PluginBootstrapService, PluginService as PluginServiceClass, getAvailableCollectionNames, loadCollectionConfig, loadCollectionConfigs, registerCollections, validateCollectionConfig } from './chunk-2D3A4X52.js';
18
+ export { MigrationService } from './chunk-D7RLBBHE.js';
19
+ export { renderFilterBar } from './chunk-73RTFFMX.js';
20
+ import { renderAdminLayout } from './chunk-HSDJDWLV.js';
21
+ export { getConfirmationDialogScript, renderAlert, renderConfirmationDialog, renderForm, renderFormField, renderPagination, renderTable } from './chunk-HSDJDWLV.js';
22
+ import { init_admin_layout_catalyst_template, renderAdminLayoutCatalyst } from './chunk-SXC4HPK6.js';
23
+ export { renderAdminLayoutCatalyst } from './chunk-SXC4HPK6.js';
24
+ import { TurnstileService, HookSystemImpl, createPluginWirer, registerPluginRoutes } from './chunk-F26HP3B6.js';
25
+ export { HookSystemImpl, HookUtils, PluginDependencyCycleError, PluginManager as PluginManagerClass, PluginRegistryImpl, PluginValidator as PluginValidatorClass, RegisterPluginsError, ScopedHookSystem as ScopedHookSystemClass, collectCronSchedules, collectCrons, createScheduledHandler, dispatchCronTick, registerPlugins, topoSort } from './chunk-F26HP3B6.js';
26
+ import { definePlugin, setPluginMenu, setPluginDefinitions, resolvePluginMenuItems } from './chunk-C54MH5UI.js';
27
+ export { applySchemaDefaults, definePlugin, getPluginMenu, isDefinedPlugin, parseConfigSchema, parseFormDataToSettings, renderSchemaFields, resetPluginMenu, resolvePluginMenuItems, setPluginMenu } from './chunk-C54MH5UI.js';
28
28
  import { setHookSystem } from './chunk-RNZFGN4R.js';
29
29
  export { getHookSystem, getTypedHooks, hasHookSystem, resetHookSystem, setHookSystem } from './chunk-RNZFGN4R.js';
30
- export { QueryFilterBuilder, TemplateRenderer, buildQuery, renderTemplate, templateRenderer } from './chunk-QZGABF2M.js';
30
+ export { QueryFilterBuilder, TemplateRenderer, buildQuery, renderTemplate, templateRenderer } from './chunk-FVAK4C6L.js';
31
31
  export { metricsTracker } from './chunk-FICTAGD4.js';
32
32
  import './chunk-X7ZAEI5S.js';
33
- import { getCoreVersion, package_default } from './chunk-DPLJYTHE.js';
34
- export { SONICJS_VERSION, getCoreVersion } from './chunk-DPLJYTHE.js';
33
+ import { getCoreVersion, package_default } from './chunk-CWIGQYRR.js';
34
+ export { SONICJS_VERSION, getCoreVersion } from './chunk-CWIGQYRR.js';
35
35
  import { escapeHtml, sanitizeInput } from './chunk-TQABQWOP.js';
36
36
  export { escapeHtml, sanitizeInput, sanitizeObject } from './chunk-TQABQWOP.js';
37
37
  export { HOOKS } from './chunk-QXOZI5Q2.js';
@@ -8112,7 +8112,7 @@ adminRoutes5.get("/settings", async (c) => {
8112
8112
  const db = c.env.DB;
8113
8113
  const user = c.get("user");
8114
8114
  const settings = await getSettings4(db);
8115
- const { renderAdminLayoutCatalyst: renderAdminLayoutCatalyst2 } = await import('./admin-layout-catalyst.template-6UQGLCKI.js');
8115
+ const { renderAdminLayoutCatalyst: renderAdminLayoutCatalyst2 } = await import('./admin-layout-catalyst.template-WCYMQVTZ.js');
8116
8116
  const content2 = `
8117
8117
  <div>
8118
8118
  <div class="mb-6">
@@ -11727,9 +11727,9 @@ function pluginMenuMiddleware() {
11727
11727
  if (!path.startsWith("/admin")) {
11728
11728
  return next();
11729
11729
  }
11730
+ const db = c.env.DB;
11730
11731
  let activeMenuItems = [];
11731
11732
  try {
11732
- const db = c.env.DB;
11733
11733
  const pluginIds = REGISTRY_MENU_PLUGINS.map((p) => p.id);
11734
11734
  if (pluginIds.length > 0) {
11735
11735
  const placeholders = pluginIds.map(() => "?").join(",");
@@ -11753,9 +11753,24 @@ function pluginMenuMiddleware() {
11753
11753
  }
11754
11754
  const user = c.get("user");
11755
11755
  const singletonItems = resolvePluginMenuItems(user ? { role: user.role } : void 0);
11756
+ const singletonPluginIds = [...new Set(
11757
+ singletonItems.map((i) => i.pluginId).filter((id) => !!id)
11758
+ )];
11759
+ let activeSingletonIds = /* @__PURE__ */ new Set();
11760
+ try {
11761
+ if (singletonPluginIds.length > 0) {
11762
+ const ph = singletonPluginIds.map(() => "?").join(",");
11763
+ const result = await db.prepare(
11764
+ `SELECT slug FROM documents WHERE type_id = 'plugin' AND tenant_id = 'default' AND slug IN (${ph}) AND q_plugin_status = 'active' AND is_current_draft = 1 AND deleted_at IS NULL`
11765
+ ).bind(...singletonPluginIds).all();
11766
+ activeSingletonIds = new Set((result.results || []).map((r) => r.slug));
11767
+ }
11768
+ } catch {
11769
+ }
11756
11770
  const existingPaths = new Set(activeMenuItems.map((i) => i.path));
11757
11771
  for (const item of singletonItems) {
11758
- if (!existingPaths.has(item.path)) {
11772
+ const isActive = !item.pluginId || activeSingletonIds.has(item.pluginId);
11773
+ if (isActive && !existingPaths.has(item.path)) {
11759
11774
  activeMenuItems.push({ label: item.label, path: item.path, icon: item.icon, order: item.order });
11760
11775
  }
11761
11776
  }
@@ -18250,7 +18265,7 @@ function createSonicJSApp(config = {}) {
18250
18265
  await next();
18251
18266
  });
18252
18267
  app2.use("*", metricsMiddleware());
18253
- app2.use("*", bootstrapMiddleware(config));
18268
+ app2.use("*", bootstrapMiddleware(config, [...corePluginsBeforeCatchAll, ...corePluginsAfterCatchAll, ...config.plugins?.register ?? []]));
18254
18269
  const boot = async (env) => {
18255
18270
  if (config.plugins?.disableAll) return;
18256
18271
  firstRequestEnv = env;
@@ -18322,6 +18337,29 @@ function createSonicJSApp(config = {}) {
18322
18337
  await next();
18323
18338
  });
18324
18339
  app2.use("*", apiKeyAuthMiddleware());
18340
+ app2.use("*", async (c, next) => {
18341
+ if (!c.get("user")) {
18342
+ const authHeader = c.req.header("Authorization");
18343
+ if (authHeader?.startsWith("Bearer ") && !authHeader.startsWith("Bearer sk_")) {
18344
+ const token = authHeader.slice(7);
18345
+ try {
18346
+ const secret = c.env?.JWT_SECRET;
18347
+ const payload = await AuthManager.verifyToken(token, secret);
18348
+ if (payload) {
18349
+ c.set("user", {
18350
+ userId: payload.userId,
18351
+ email: payload.email,
18352
+ role: payload.role,
18353
+ exp: payload.exp,
18354
+ iat: payload.iat
18355
+ });
18356
+ }
18357
+ } catch {
18358
+ }
18359
+ }
18360
+ }
18361
+ await next();
18362
+ });
18325
18363
  if (config.middleware?.afterAuth) {
18326
18364
  for (const middleware of config.middleware.afterAuth) {
18327
18365
  app2.use("*", middleware);
@@ -18347,7 +18385,7 @@ function createSonicJSApp(config = {}) {
18347
18385
  if (!user?.userId) return next();
18348
18386
  let perms = [];
18349
18387
  try {
18350
- const { RbacService: RbacService2 } = await import('./rbac-Y43IEQOP.js');
18388
+ const { RbacService: RbacService2 } = await import('./rbac-P44772FP.js');
18351
18389
  perms = await new RbacService2(c.env.DB, c.env.CACHE_KV).permissionsForUser(user.userId);
18352
18390
  } catch {
18353
18391
  return next();
@@ -18424,7 +18462,7 @@ function createSonicJSApp(config = {}) {
18424
18462
  const userPlugins = (config.plugins?.register ?? []).filter(
18425
18463
  (p) => !PLUGIN_REGISTRY[p.id]
18426
18464
  );
18427
- setPluginMenu(userPlugins.flatMap((p) => p.menu ?? []));
18465
+ setPluginMenu(userPlugins.flatMap((p) => (p.menu ?? []).map((m) => ({ ...m, pluginId: p.id }))));
18428
18466
  setPluginDefinitions(allMountedPlugins);
18429
18467
  }
18430
18468
  app2.get("/favicon.svg", (c) => {
@@ -22051,10 +22089,837 @@ var site_settings_collection_default = {
22051
22089
  function createDb(d1) {
22052
22090
  return drizzle(d1, { schema: schema_exports });
22053
22091
  }
22092
+ var mcpTypeConfigSchema = z.object({
22093
+ read: z.boolean().default(true),
22094
+ write: z.boolean().default(true)
22095
+ });
22096
+ var mcpConfigSchema = z.object({
22097
+ /** Collections exposed over MCP. Omitted → every active collection. */
22098
+ expose: z.array(z.string()).optional(),
22099
+ /** Per-collection read/write overrides, keyed by collection name. */
22100
+ types: z.record(z.string(), mcpTypeConfigSchema).default({}),
22101
+ /** Field names stripped from every tool response + write schema. */
22102
+ redactFields: z.array(z.string()).default([]),
22103
+ /** Max documents returned by list_* tools and document resources. */
22104
+ listLimit: z.number().int().positive().max(200).default(50)
22105
+ });
22106
+ function resolveMcpConfig(raw, collections) {
22107
+ const cfg = mcpConfigSchema.parse(raw ?? {});
22108
+ const exposeSet = cfg.expose ? new Set(cfg.expose) : null;
22109
+ const types = collections.filter((c) => exposeSet ? exposeSet.has(c.name) : true).map((c) => {
22110
+ const override = cfg.types[c.name];
22111
+ return {
22112
+ typeId: c.name,
22113
+ displayName: c.displayName ?? c.name,
22114
+ read: override?.read ?? true,
22115
+ write: override?.write ?? true
22116
+ };
22117
+ });
22118
+ return { types, redactFields: cfg.redactFields, listLimit: cfg.listLimit };
22119
+ }
22120
+
22121
+ // src/plugins/core-plugins/mcp-plugin/schema/field-to-jsonschema.ts
22122
+ var SYSTEM_FIELDS = /* @__PURE__ */ new Set([
22123
+ "id",
22124
+ "root_id",
22125
+ "rootId",
22126
+ "created_at",
22127
+ "createdAt",
22128
+ "updated_at",
22129
+ "updatedAt",
22130
+ "version_number",
22131
+ "versionNumber"
22132
+ ]);
22133
+ function fieldToJsonSchema(field) {
22134
+ const base = {};
22135
+ if (field.title) base.title = field.title;
22136
+ if (field.description) base.description = field.description;
22137
+ switch (field.type) {
22138
+ case "number":
22139
+ return {
22140
+ ...base,
22141
+ type: "number",
22142
+ ...field.min != null ? { minimum: field.min } : {},
22143
+ ...field.max != null ? { maximum: field.max } : {}
22144
+ };
22145
+ case "boolean":
22146
+ case "checkbox":
22147
+ return { ...base, type: "boolean" };
22148
+ case "date":
22149
+ case "datetime":
22150
+ return { ...base, type: "string", format: "date-time" };
22151
+ case "select":
22152
+ case "radio":
22153
+ return { ...base, type: "string", ...field.enum ? { enum: field.enum } : {} };
22154
+ case "multiselect":
22155
+ return {
22156
+ ...base,
22157
+ type: "array",
22158
+ items: { type: "string", ...field.enum ? { enum: field.enum } : {} }
22159
+ };
22160
+ case "array":
22161
+ return {
22162
+ ...base,
22163
+ type: "array",
22164
+ items: field.items ? fieldToJsonSchema(field.items) : {}
22165
+ };
22166
+ case "object":
22167
+ return {
22168
+ ...base,
22169
+ type: "object",
22170
+ ...field.properties ? { properties: mapProperties(field.properties) } : {}
22171
+ };
22172
+ case "json":
22173
+ return { ...base };
22174
+ // string-like: string, slug, email, url, richtext, markdown, textarea, editors,
22175
+ // reference, media, color, file, user
22176
+ default: {
22177
+ const node = { ...base, type: "string" };
22178
+ if (field.minLength != null) node.minLength = field.minLength;
22179
+ if (field.maxLength != null) node.maxLength = field.maxLength;
22180
+ if (field.pattern) node.pattern = field.pattern;
22181
+ if (field.format) node.format = field.format;
22182
+ return node;
22183
+ }
22184
+ }
22185
+ }
22186
+ function mapProperties(props) {
22187
+ const out = {};
22188
+ for (const [name, field] of Object.entries(props)) {
22189
+ out[name] = fieldToJsonSchema(field);
22190
+ }
22191
+ return out;
22192
+ }
22193
+ function collectionToJsonSchema(schema, opts = {}) {
22194
+ const properties = {};
22195
+ const required = [];
22196
+ const redact2 = new Set(opts.redactFields ?? []);
22197
+ const schemaRequired = new Set(schema.required ?? []);
22198
+ for (const [name, field] of Object.entries(schema.properties ?? {})) {
22199
+ if (redact2.has(name)) continue;
22200
+ if (opts.forWrite && SYSTEM_FIELDS.has(name)) continue;
22201
+ properties[name] = fieldToJsonSchema(field);
22202
+ if (field.required || schemaRequired.has(name)) required.push(name);
22203
+ }
22204
+ return { type: "object", properties, ...required.length ? { required } : {} };
22205
+ }
22206
+
22207
+ // src/plugins/core-plugins/mcp-plugin/tools/registry.ts
22208
+ var PHASE_FLAGS = { includeWrite: true, includeSearch: false };
22209
+ var EMPTY_OBJECT_SCHEMA = { type: "object", properties: {} };
22210
+ function buildToolRegistry(cfg, collections, opts = {}) {
22211
+ const tools = [];
22212
+ tools.push({
22213
+ name: "list_collections",
22214
+ description: "List every content collection exposed over MCP, with its read/write access.",
22215
+ inputSchema: EMPTY_OBJECT_SCHEMA,
22216
+ op: "list_collections"
22217
+ });
22218
+ if (opts.includeSearch) {
22219
+ tools.push({
22220
+ name: "search_content",
22221
+ description: "Search content across exposed collections by title or slug.",
22222
+ inputSchema: {
22223
+ type: "object",
22224
+ properties: { query: { type: "string", description: "Text matched against document title and slug." } },
22225
+ required: ["query"]
22226
+ },
22227
+ op: "search_content"
22228
+ });
22229
+ }
22230
+ for (const t of cfg.types) {
22231
+ const col = collections.get(t.typeId);
22232
+ const writeSchema = col ? collectionToJsonSchema(col.schema, { forWrite: true, redactFields: cfg.redactFields }) : EMPTY_OBJECT_SCHEMA;
22233
+ if (t.read) {
22234
+ tools.push({
22235
+ name: `list_${t.typeId}`,
22236
+ description: `List ${t.displayName} documents.`,
22237
+ inputSchema: {
22238
+ type: "object",
22239
+ properties: {
22240
+ status: {
22241
+ type: "string",
22242
+ enum: ["published", "draft"],
22243
+ description: "Lifecycle to list. Defaults to published."
22244
+ },
22245
+ limit: { type: "number", description: `Max documents to return (capped at ${cfg.listLimit}).` }
22246
+ }
22247
+ },
22248
+ op: "list",
22249
+ typeId: t.typeId
22250
+ });
22251
+ tools.push({
22252
+ name: `get_${t.typeId}`,
22253
+ description: `Get one ${t.displayName} document by id or slug.`,
22254
+ inputSchema: {
22255
+ type: "object",
22256
+ properties: {
22257
+ id: { type: "string", description: "Document id or root id." },
22258
+ slug: { type: "string", description: "Document slug (alternative to id)." }
22259
+ }
22260
+ },
22261
+ op: "get",
22262
+ typeId: t.typeId
22263
+ });
22264
+ }
22265
+ if (opts.includeWrite && t.write) {
22266
+ tools.push({
22267
+ name: `create_${t.typeId}`,
22268
+ description: `Create a ${t.displayName} document.`,
22269
+ inputSchema: {
22270
+ type: "object",
22271
+ properties: {
22272
+ title: { type: "string" },
22273
+ slug: { type: "string" },
22274
+ data: writeSchema,
22275
+ publish: { type: "boolean", description: "Publish immediately. Defaults to false (draft)." }
22276
+ }
22277
+ },
22278
+ op: "create",
22279
+ typeId: t.typeId
22280
+ });
22281
+ tools.push({
22282
+ name: `update_${t.typeId}`,
22283
+ description: `Update a ${t.displayName} document (saves a new draft).`,
22284
+ inputSchema: {
22285
+ type: "object",
22286
+ properties: {
22287
+ id: { type: "string", description: "Root id of the document to update." },
22288
+ title: { type: "string" },
22289
+ slug: { type: "string" },
22290
+ data: writeSchema
22291
+ },
22292
+ required: ["id"]
22293
+ },
22294
+ op: "update",
22295
+ typeId: t.typeId
22296
+ });
22297
+ tools.push({
22298
+ name: `publish_${t.typeId}`,
22299
+ description: `Publish a ${t.displayName} document.`,
22300
+ inputSchema: {
22301
+ type: "object",
22302
+ properties: { id: { type: "string", description: "Root id of the document to publish." } },
22303
+ required: ["id"]
22304
+ },
22305
+ op: "publish",
22306
+ typeId: t.typeId
22307
+ });
22308
+ tools.push({
22309
+ name: `delete_${t.typeId}`,
22310
+ description: `Delete a ${t.displayName} document.`,
22311
+ inputSchema: {
22312
+ type: "object",
22313
+ properties: { id: { type: "string", description: "Root id of the document to delete." } },
22314
+ required: ["id"]
22315
+ },
22316
+ op: "delete",
22317
+ typeId: t.typeId
22318
+ });
22319
+ }
22320
+ }
22321
+ return tools;
22322
+ }
22323
+
22324
+ // src/plugins/core-plugins/mcp-plugin/jsonrpc.ts
22325
+ var JSON_RPC = {
22326
+ PARSE_ERROR: -32700,
22327
+ INVALID_REQUEST: -32600,
22328
+ METHOD_NOT_FOUND: -32601,
22329
+ INVALID_PARAMS: -32602,
22330
+ INTERNAL_ERROR: -32603,
22331
+ /** Custom: no valid API key on the request. */
22332
+ UNAUTHORIZED: -32001
22333
+ };
22334
+ var McpToolError = class extends Error {
22335
+ constructor(message) {
22336
+ super(message);
22337
+ this.name = "McpToolError";
22338
+ }
22339
+ };
22340
+ function rpcResult(id, result) {
22341
+ return { jsonrpc: "2.0", id: id ?? null, result };
22342
+ }
22343
+ function rpcError(id, code, message, data) {
22344
+ return { jsonrpc: "2.0", id: id ?? null, error: { code, message, ...{} } };
22345
+ }
22346
+ function parseJsonRpc(body) {
22347
+ if (!body || typeof body !== "object" || Array.isArray(body)) {
22348
+ return { error: { code: JSON_RPC.INVALID_REQUEST, message: "Request must be a JSON object" } };
22349
+ }
22350
+ const b = body;
22351
+ if (b.jsonrpc !== "2.0") {
22352
+ return { error: { code: JSON_RPC.INVALID_REQUEST, message: 'jsonrpc must be "2.0"' } };
22353
+ }
22354
+ if (typeof b.method !== "string" || b.method.length === 0) {
22355
+ return { error: { code: JSON_RPC.INVALID_REQUEST, message: "method must be a non-empty string" } };
22356
+ }
22357
+ const id = b.id === void 0 ? null : b.id;
22358
+ const params = b.params && typeof b.params === "object" && !Array.isArray(b.params) ? b.params : {};
22359
+ return { jsonrpc: "2.0", id, method: b.method, params };
22360
+ }
22361
+
22362
+ // src/plugins/core-plugins/mcp-plugin/tools/documents.ts
22363
+ function redact(data, fields) {
22364
+ if (!fields.length) return data;
22365
+ const out = { ...data };
22366
+ for (const f of fields) delete out[f];
22367
+ return out;
22368
+ }
22369
+ function shapeDocument(doc, redactFields) {
22370
+ return {
22371
+ id: doc.id,
22372
+ rootId: doc.rootId,
22373
+ typeId: doc.typeId,
22374
+ title: doc.title,
22375
+ slug: doc.slug,
22376
+ status: doc.status,
22377
+ isPublished: doc.isPublished,
22378
+ publishedAt: doc.publishedAt,
22379
+ updatedAt: doc.updatedAt,
22380
+ data: redact(doc.data, redactFields)
22381
+ };
22382
+ }
22383
+ async function resolveType(ctx, typeId) {
22384
+ const docType = await new DocumentTypeRegistry(ctx.db).findById(typeId);
22385
+ if (!docType || !docType.isActive) throw new McpToolError(`Unknown document type: ${typeId}`);
22386
+ const effTenant = effectiveTenantForType(ctx.tenantId, docType.settings);
22387
+ const repo = new DocumentRepository(ctx.db, effTenant);
22388
+ return { docType, repo };
22389
+ }
22390
+ async function execList(ctx, typeId, args) {
22391
+ const { docType, repo } = await resolveType(ctx, typeId);
22392
+ const status = args.status === "draft" ? "draft" : "published";
22393
+ const limit = Math.min(Math.max(1, args.limit ?? ctx.listLimit), ctx.listLimit);
22394
+ const now = Math.floor(Date.now() / 1e3);
22395
+ const docs = await repo.list({
22396
+ typeId,
22397
+ status,
22398
+ timeWindow: status === "published",
22399
+ now,
22400
+ limit
22401
+ });
22402
+ const allowed = await Promise.all(
22403
+ docs.map((d) => repo.isAllowed(ctx.principalSet, d.rootId, "read", docType.settings))
22404
+ );
22405
+ return docs.filter((_, i) => allowed[i]).map((d) => shapeDocument(d, ctx.redactFields));
22406
+ }
22407
+ async function execGet(ctx, typeId, args) {
22408
+ const { docType, repo } = await resolveType(ctx, typeId);
22409
+ let doc = null;
22410
+ if (args.id) {
22411
+ doc = await repo.getById(args.id) ?? await repo.getPublished(args.id) ?? await repo.getCurrentDraft(args.id);
22412
+ } else if (args.slug) {
22413
+ doc = await repo.getBySlug(typeId, args.slug);
22414
+ } else {
22415
+ throw new McpToolError('get requires an "id" or "slug" argument');
22416
+ }
22417
+ if (!doc || doc.typeId !== typeId) throw new McpToolError("Document not found");
22418
+ const ok = await repo.isAllowed(ctx.principalSet, doc.rootId, "read", docType.settings);
22419
+ if (!ok) throw new McpToolError("Document not found");
22420
+ return shapeDocument(doc, ctx.redactFields);
22421
+ }
22422
+
22423
+ // src/plugins/core-plugins/mcp-plugin/tools/mutations.ts
22424
+ async function resolveWriteScope(ctx, typeId) {
22425
+ const docType = await new DocumentTypeRegistry(ctx.db).findById(typeId);
22426
+ if (!docType || !docType.isActive) throw new McpToolError(`Unknown document type: ${typeId}`);
22427
+ const effTenant = effectiveTenantForType(ctx.tenantId, docType.settings);
22428
+ const repo = new DocumentRepository(ctx.db, effTenant);
22429
+ const svc = new DocumentsService(ctx.db, {
22430
+ queryableFields: docType.queryableFields ?? [],
22431
+ typeSchemaVersion: docType.schemaVersion,
22432
+ maxVersionsPerRoot: docType.settings?.maxVersionsPerRoot,
22433
+ tenantId: effTenant,
22434
+ versioning: docType.settings?.versioning ?? false
22435
+ });
22436
+ return { docType, effTenant, repo, svc };
22437
+ }
22438
+ async function assertAllowed(scope, ctx, rootId, permission) {
22439
+ const ok = await scope.repo.isAllowed(ctx.principalSet, rootId, permission, scope.docType.settings ?? {});
22440
+ if (!ok) throw new McpToolError(`Permission denied: cannot ${permission} ${scope.docType.id}`);
22441
+ }
22442
+ function applyUserFieldDefaults(data, typeId, userId) {
22443
+ const col = getCollectionRegistry().getByName(typeId);
22444
+ if (!col?.schema?.properties) return data;
22445
+ const props = col.schema.properties;
22446
+ const patched = { ...data };
22447
+ for (const [name, field] of Object.entries(props)) {
22448
+ if (field.type === "user" && !patched[name]) patched[name] = userId;
22449
+ }
22450
+ return patched;
22451
+ }
22452
+ async function execCreate(ctx, typeId, args) {
22453
+ const scope = await resolveWriteScope(ctx, typeId);
22454
+ await assertAllowed(scope, ctx, "", "create");
22455
+ const data = redact(applyUserFieldDefaults(args.data ?? {}, typeId, ctx.userId), ctx.redactFields);
22456
+ const input = createDocumentSchema.parse({
22457
+ typeId,
22458
+ tenantId: scope.effTenant,
22459
+ title: args.title ?? null,
22460
+ slug: args.slug ?? null,
22461
+ data,
22462
+ ownerId: ctx.userId,
22463
+ publishOnCreate: Boolean(args.publish)
22464
+ });
22465
+ const doc = await scope.svc.create(input, ctx.userId);
22466
+ return shapeDocument(doc, ctx.redactFields);
22467
+ }
22468
+ async function execUpdate(ctx, typeId, args) {
22469
+ if (!args.id) throw new McpToolError('update requires an "id" (root id)');
22470
+ const scope = await resolveWriteScope(ctx, typeId);
22471
+ const current = await scope.repo.getCurrentDraft(args.id);
22472
+ if (!current || current.typeId !== typeId) throw new McpToolError("Document not found");
22473
+ await assertAllowed(scope, ctx, args.id, "update");
22474
+ const patch = updateDocumentSchema.parse({
22475
+ ...args.title !== void 0 ? { title: args.title } : {},
22476
+ ...args.slug !== void 0 ? { slug: args.slug } : {},
22477
+ ...args.data !== void 0 ? { data: redact(args.data, ctx.redactFields) } : {}
22478
+ });
22479
+ const doc = await scope.svc.saveDraft(args.id, patch, ctx.userId);
22480
+ return shapeDocument(doc, ctx.redactFields);
22481
+ }
22482
+ async function execPublish(ctx, typeId, args) {
22483
+ if (!args.id) throw new McpToolError('publish requires an "id" (root id)');
22484
+ const scope = await resolveWriteScope(ctx, typeId);
22485
+ const current = await scope.repo.getCurrentDraft(args.id);
22486
+ if (!current || current.typeId !== typeId) throw new McpToolError("Document not found");
22487
+ await assertAllowed(scope, ctx, args.id, "publish");
22488
+ const doc = await scope.svc.publish(current.id, ctx.userId);
22489
+ return shapeDocument(doc, ctx.redactFields);
22490
+ }
22491
+ async function execDelete(ctx, typeId, args) {
22492
+ if (!args.id) throw new McpToolError('delete requires an "id" (root id)');
22493
+ const scope = await resolveWriteScope(ctx, typeId);
22494
+ const current = await scope.repo.getCurrentDraft(args.id) ?? await scope.repo.getPublished(args.id);
22495
+ if (!current || current.typeId !== typeId) throw new McpToolError("Document not found");
22496
+ await assertAllowed(scope, ctx, args.id, "delete");
22497
+ if (scope.docType.settings?.pii) {
22498
+ await scope.svc.erase(args.id, scope.effTenant);
22499
+ return { rootId: args.id, deleted: true, erased: true };
22500
+ }
22501
+ const ids = /* @__PURE__ */ new Set();
22502
+ ids.add(current.id);
22503
+ if (current.isCurrentDraft) {
22504
+ const published = await scope.repo.getPublished(args.id);
22505
+ if (published) ids.add(published.id);
22506
+ } else {
22507
+ const draft = await scope.repo.getCurrentDraft(args.id);
22508
+ if (draft) ids.add(draft.id);
22509
+ }
22510
+ for (const id of ids) await scope.svc.softDelete(id);
22511
+ return { rootId: args.id, deleted: true, erased: false };
22512
+ }
22513
+
22514
+ // src/plugins/core-plugins/mcp-plugin/tools/static.ts
22515
+ function execListCollections(types) {
22516
+ return types.map((t) => ({ typeId: t.typeId, displayName: t.displayName, read: t.read, write: t.write }));
22517
+ }
22518
+
22519
+ // src/plugins/core-plugins/mcp-plugin/resources/schemas.ts
22520
+ function buildResourceList(cfg) {
22521
+ const out = [
22522
+ { uri: "sonicjs://collections", name: "All collections", mimeType: "application/json" }
22523
+ ];
22524
+ for (const t of cfg.types) {
22525
+ out.push({
22526
+ uri: `sonicjs://collections/${t.typeId}/schema`,
22527
+ name: `${t.displayName} schema`,
22528
+ mimeType: "application/json"
22529
+ });
22530
+ }
22531
+ return out;
22532
+ }
22533
+ var SCHEMA_URI = /^sonicjs:\/\/collections\/([^/]+)\/schema$/;
22534
+ function readResource(uri, cfg, collections) {
22535
+ if (uri === "sonicjs://collections") {
22536
+ const list = cfg.types.map((t) => ({
22537
+ typeId: t.typeId,
22538
+ displayName: t.displayName,
22539
+ read: t.read,
22540
+ write: t.write
22541
+ }));
22542
+ return { uri, mimeType: "application/json", text: JSON.stringify(list, null, 2) };
22543
+ }
22544
+ const m = uri.match(SCHEMA_URI);
22545
+ if (m) {
22546
+ const typeId = m[1];
22547
+ const exposed = cfg.types.find((t) => t.typeId === typeId);
22548
+ const col = collections.get(typeId);
22549
+ if (!exposed || !col) throw new McpToolError(`Unknown collection: ${typeId}`);
22550
+ const schema = collectionToJsonSchema(col.schema, { redactFields: cfg.redactFields });
22551
+ return { uri, mimeType: "application/json", text: JSON.stringify(schema, null, 2) };
22552
+ }
22553
+ throw new McpToolError(`Unknown resource URI: ${uri}`);
22554
+ }
22555
+
22556
+ // src/plugins/core-plugins/mcp-plugin/routes/mcp.ts
22557
+ var SERVER_INFO = { name: "sonicjs-mcp", version: "1.0.0" };
22558
+ var PROTOCOL_VERSION = "2024-11-05";
22559
+ function createMcpRoutes(options = {}) {
22560
+ const app2 = new Hono();
22561
+ app2.post("/", async (c) => {
22562
+ let body;
22563
+ try {
22564
+ body = await c.req.json();
22565
+ } catch {
22566
+ return c.json(rpcError(null, JSON_RPC.PARSE_ERROR, "Invalid JSON"));
22567
+ }
22568
+ const parsed = parseJsonRpc(body);
22569
+ if ("error" in parsed) {
22570
+ const id2 = body && typeof body === "object" ? body.id ?? null : null;
22571
+ return c.json(rpcError(id2, parsed.error.code, parsed.error.message));
22572
+ }
22573
+ const { id, method, params } = parsed;
22574
+ const user = c.get("user");
22575
+ if (!user) {
22576
+ return c.json(
22577
+ rpcError(id, JSON_RPC.UNAUTHORIZED, "Unauthorized: provide a valid API key via Authorization: Bearer sk_...")
22578
+ );
22579
+ }
22580
+ const { tenantId, principalSet, userId } = getDocumentRequestContext(c);
22581
+ const registry = getCollectionRegistry();
22582
+ const active = registry.listActive();
22583
+ const collections = new Map(active.map((col) => [col.name, col]));
22584
+ const cfg = resolveMcpConfig(options, active);
22585
+ const tools = buildToolRegistry(cfg, collections, PHASE_FLAGS);
22586
+ try {
22587
+ switch (method) {
22588
+ case "initialize":
22589
+ return c.json(
22590
+ rpcResult(id, {
22591
+ protocolVersion: PROTOCOL_VERSION,
22592
+ serverInfo: SERVER_INFO,
22593
+ capabilities: { tools: {}, resources: {} }
22594
+ })
22595
+ );
22596
+ case "tools/list":
22597
+ return c.json(
22598
+ rpcResult(id, {
22599
+ tools: tools.map((t) => ({ name: t.name, description: t.description, inputSchema: t.inputSchema }))
22600
+ })
22601
+ );
22602
+ case "tools/call": {
22603
+ const name = typeof params.name === "string" ? params.name : "";
22604
+ const args = params.arguments && typeof params.arguments === "object" ? params.arguments : {};
22605
+ const tool = tools.find((t) => t.name === name);
22606
+ if (!tool) return c.json(rpcError(id, JSON_RPC.METHOD_NOT_FOUND, `Unknown tool: ${name}`));
22607
+ const readCtx = {
22608
+ db: c.env.DB,
22609
+ tenantId,
22610
+ principalSet,
22611
+ listLimit: cfg.listLimit,
22612
+ redactFields: cfg.redactFields
22613
+ };
22614
+ const writeCtx = {
22615
+ db: c.env.DB,
22616
+ tenantId,
22617
+ principalSet,
22618
+ userId: userId ?? "",
22619
+ redactFields: cfg.redactFields
22620
+ };
22621
+ try {
22622
+ let result;
22623
+ switch (tool.op) {
22624
+ case "list_collections":
22625
+ result = execListCollections(cfg.types);
22626
+ break;
22627
+ case "list":
22628
+ result = await execList(readCtx, tool.typeId, args);
22629
+ break;
22630
+ case "get":
22631
+ result = await execGet(readCtx, tool.typeId, args);
22632
+ break;
22633
+ case "create":
22634
+ result = await execCreate(writeCtx, tool.typeId, args);
22635
+ break;
22636
+ case "update":
22637
+ result = await execUpdate(writeCtx, tool.typeId, args);
22638
+ break;
22639
+ case "publish":
22640
+ result = await execPublish(writeCtx, tool.typeId, args);
22641
+ break;
22642
+ case "delete":
22643
+ result = await execDelete(writeCtx, tool.typeId, args);
22644
+ break;
22645
+ default:
22646
+ return c.json(rpcError(id, JSON_RPC.METHOD_NOT_FOUND, `Tool not available: ${name}`));
22647
+ }
22648
+ return c.json(rpcResult(id, { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] }));
22649
+ } catch (e) {
22650
+ if (e instanceof McpToolError) {
22651
+ return c.json(rpcResult(id, { content: [{ type: "text", text: e.message }], isError: true }));
22652
+ }
22653
+ throw e;
22654
+ }
22655
+ }
22656
+ case "resources/list":
22657
+ return c.json(rpcResult(id, { resources: buildResourceList(cfg) }));
22658
+ case "resources/read": {
22659
+ const uri = typeof params.uri === "string" ? params.uri : "";
22660
+ if (!uri) return c.json(rpcError(id, JSON_RPC.INVALID_PARAMS, 'resources/read requires a "uri" param'));
22661
+ try {
22662
+ const contents = readResource(uri, cfg, collections);
22663
+ return c.json(rpcResult(id, { contents: [contents] }));
22664
+ } catch (e) {
22665
+ if (e instanceof McpToolError) return c.json(rpcError(id, JSON_RPC.INVALID_PARAMS, e.message));
22666
+ throw e;
22667
+ }
22668
+ }
22669
+ default:
22670
+ return c.json(rpcError(id, JSON_RPC.METHOD_NOT_FOUND, `Method not found: ${method}`));
22671
+ }
22672
+ } catch (e) {
22673
+ console.error("[mcp] handler error:", e);
22674
+ return c.json(rpcError(id, JSON_RPC.INTERNAL_ERROR, "Internal error"));
22675
+ }
22676
+ });
22677
+ return app2;
22678
+ }
22679
+
22680
+ // src/plugins/core-plugins/mcp-plugin/admin/templates.ts
22681
+ init_admin_layout_catalyst_template();
22682
+ function accessBadge(ok) {
22683
+ return ok ? `<span class="inline-flex items-center rounded-full bg-emerald-50 dark:bg-emerald-900/20 px-2 py-0.5 text-xs font-medium text-emerald-700 dark:text-emerald-400 ring-1 ring-emerald-600/20 dark:ring-emerald-400/20">Yes</span>` : `<span class="inline-flex items-center rounded-full bg-zinc-100 dark:bg-zinc-800 px-2 py-0.5 text-xs font-medium text-zinc-500 dark:text-zinc-400 ring-1 ring-zinc-200 dark:ring-zinc-700">No</span>`;
22684
+ }
22685
+ function toolNamesForType(typeId, tools) {
22686
+ const names = tools.filter((t) => t.typeId === typeId).map((t) => `<code class="text-xs font-mono text-zinc-500 dark:text-zinc-400">${escapeHtml(t.name)}</code>`);
22687
+ return names.length ? names.join('<span class="text-zinc-300 dark:text-zinc-600 mx-1">,</span>') : "\u2014";
22688
+ }
22689
+ function buildClaudeJson(endpointUrl) {
22690
+ return JSON.stringify(
22691
+ {
22692
+ mcpServers: {
22693
+ sonicjs: {
22694
+ type: "http",
22695
+ url: endpointUrl,
22696
+ headers: { Authorization: "Bearer sk_YOUR_API_KEY" }
22697
+ }
22698
+ }
22699
+ },
22700
+ null,
22701
+ 2
22702
+ );
22703
+ }
22704
+ function buildCursorJson(endpointUrl) {
22705
+ return JSON.stringify(
22706
+ {
22707
+ mcpServers: {
22708
+ sonicjs: {
22709
+ url: endpointUrl,
22710
+ headers: { Authorization: "Bearer sk_YOUR_API_KEY" }
22711
+ }
22712
+ }
22713
+ },
22714
+ null,
22715
+ 2
22716
+ );
22717
+ }
22718
+ function renderMcpDashboardPage(data) {
22719
+ const { endpointUrl, types, tools, user, version, dynamicMenuItems } = data;
22720
+ const safeEndpoint = escapeHtml(endpointUrl);
22721
+ const typeCount = types.length;
22722
+ const toolCount = tools.length;
22723
+ const typeRows = types.length ? types.map(
22724
+ (t) => `
22725
+ <tr class="border-t border-zinc-950/5 dark:border-white/10">
22726
+ <td class="py-3 pr-4 text-sm font-mono text-zinc-950 dark:text-white">${escapeHtml(t.typeId)}</td>
22727
+ <td class="py-3 pr-4 text-sm text-zinc-500 dark:text-zinc-400">${escapeHtml(t.displayName)}</td>
22728
+ <td class="py-3 pr-4">${accessBadge(t.read)}</td>
22729
+ <td class="py-3 pr-4">${accessBadge(t.write)}</td>
22730
+ <td class="py-3 text-sm">${toolNamesForType(t.typeId, tools)}</td>
22731
+ </tr>`
22732
+ ).join("") : `<tr><td colspan="5" class="py-8 text-center text-sm text-zinc-500 dark:text-zinc-400">No collections exposed. Register collections via <code class="font-mono">registerCollections()</code> in your app entry point.</td></tr>`;
22733
+ const claudeJson = escapeHtml(buildClaudeJson(endpointUrl));
22734
+ const cursorJson = escapeHtml(buildCursorJson(endpointUrl));
22735
+ const content2 = `
22736
+ <div class="space-y-8">
22737
+
22738
+ <!-- Header -->
22739
+ <div class="sm:flex sm:items-center sm:justify-between">
22740
+ <div class="sm:flex-auto">
22741
+ <h1 class="text-2xl/8 font-semibold text-zinc-950 dark:text-white sm:text-xl/8">MCP Server</h1>
22742
+ <p class="mt-2 text-sm/6 text-zinc-500 dark:text-zinc-400">
22743
+ Model Context Protocol endpoint for AI agents (Claude Code, Cursor, VS Code). Requests are authenticated with API keys.
22744
+ </p>
22745
+ </div>
22746
+ <div class="mt-4 sm:mt-0 sm:ml-16">
22747
+ <a href="/admin/plugins/api-keys"
22748
+ class="inline-flex items-center justify-center rounded-lg bg-cyan-600 px-4 py-2.5 text-sm font-semibold text-white hover:bg-cyan-500 transition-colors shadow-sm">
22749
+ Mint API Key
22750
+ </a>
22751
+ </div>
22752
+ </div>
22753
+
22754
+ <!-- Status -->
22755
+ <div class="rounded-xl bg-white/80 dark:bg-zinc-900/80 backdrop-blur-xl p-6 ring-1 ring-zinc-950/5 dark:ring-white/10 shadow-sm">
22756
+ <h2 class="text-sm font-semibold text-zinc-950 dark:text-white mb-4">Endpoint</h2>
22757
+ <div class="flex items-center gap-3">
22758
+ <code id="endpoint-url" class="flex-1 rounded-lg bg-zinc-50 dark:bg-zinc-800 px-3 py-2 text-sm font-mono text-zinc-950 dark:text-white ring-1 ring-zinc-950/5 dark:ring-white/5 break-all">${safeEndpoint}</code>
22759
+ <button type="button" onclick="copyEndpoint()"
22760
+ class="shrink-0 rounded-lg bg-zinc-100 dark:bg-zinc-800 px-3 py-2 text-sm font-medium text-zinc-700 dark:text-zinc-300 hover:bg-zinc-200 dark:hover:bg-zinc-700 ring-1 ring-zinc-950/5 dark:ring-white/10 transition-colors">
22761
+ Copy
22762
+ </button>
22763
+ </div>
22764
+ <div class="mt-4 flex flex-wrap gap-4 text-sm text-zinc-500 dark:text-zinc-400">
22765
+ <span>
22766
+ <span class="font-semibold text-zinc-950 dark:text-white">${typeCount}</span>
22767
+ collection${typeCount === 1 ? "" : "s"} exposed
22768
+ </span>
22769
+ <span class="text-zinc-300 dark:text-zinc-600">&middot;</span>
22770
+ <span>
22771
+ <span class="font-semibold text-zinc-950 dark:text-white">${toolCount}</span>
22772
+ tool${toolCount === 1 ? "" : "s"} available
22773
+ </span>
22774
+ <span class="text-zinc-300 dark:text-zinc-600">&middot;</span>
22775
+ <span>Auth via <a href="/admin/plugins/api-keys" class="text-cyan-600 dark:text-cyan-400 hover:underline">API Keys</a></span>
22776
+ </div>
22777
+ </div>
22778
+
22779
+ <!-- Exposed collections table -->
22780
+ <div class="rounded-xl bg-white/80 dark:bg-zinc-900/80 backdrop-blur-xl p-6 ring-1 ring-zinc-950/5 dark:ring-white/10 shadow-sm overflow-x-auto">
22781
+ <h2 class="text-sm font-semibold text-zinc-950 dark:text-white mb-4">Exposed collections</h2>
22782
+ <table class="w-full text-left">
22783
+ <thead>
22784
+ <tr class="text-xs font-semibold uppercase tracking-wide text-zinc-500 dark:text-zinc-400">
22785
+ <th class="pb-2 pr-4">ID</th>
22786
+ <th class="pb-2 pr-4">Display name</th>
22787
+ <th class="pb-2 pr-4">Read</th>
22788
+ <th class="pb-2 pr-4">Write</th>
22789
+ <th class="pb-2">Tools</th>
22790
+ </tr>
22791
+ </thead>
22792
+ <tbody>${typeRows}</tbody>
22793
+ </table>
22794
+ </div>
22795
+
22796
+ <!-- Integration guide -->
22797
+ <div class="rounded-xl bg-white/80 dark:bg-zinc-900/80 backdrop-blur-xl p-6 ring-1 ring-zinc-950/5 dark:ring-white/10 shadow-sm space-y-6">
22798
+ <div>
22799
+ <h2 class="text-sm font-semibold text-zinc-950 dark:text-white mb-1">Integration guide</h2>
22800
+ <p class="text-sm text-zinc-500 dark:text-zinc-400">
22801
+ <a href="/admin/plugins/api-keys" class="text-cyan-600 dark:text-cyan-400 hover:underline">Mint an API key</a>,
22802
+ then paste one of the configs below into your MCP client.
22803
+ Replace <code class="font-mono text-xs">sk_YOUR_API_KEY</code> with the key.
22804
+ </p>
22805
+ </div>
22806
+
22807
+ <!-- Claude Code -->
22808
+ <div>
22809
+ <div class="flex items-center justify-between mb-2">
22810
+ <h3 class="text-sm font-medium text-zinc-700 dark:text-zinc-300">
22811
+ Claude Code &mdash; <code class="font-mono text-xs">~/.claude/mcp.json</code>
22812
+ </h3>
22813
+ <button type="button" onclick="copyConfig('claude-config')"
22814
+ class="text-xs text-zinc-500 dark:text-zinc-400 hover:text-zinc-700 dark:hover:text-zinc-200 transition-colors">
22815
+ Copy
22816
+ </button>
22817
+ </div>
22818
+ <pre id="claude-config" class="rounded-lg bg-zinc-950 dark:bg-zinc-800 px-4 py-3 text-sm font-mono text-zinc-100 overflow-x-auto ring-1 ring-zinc-700 dark:ring-zinc-600 whitespace-pre">${claudeJson}</pre>
22819
+ </div>
22820
+
22821
+ <!-- Cursor -->
22822
+ <div>
22823
+ <div class="flex items-center justify-between mb-2">
22824
+ <h3 class="text-sm font-medium text-zinc-700 dark:text-zinc-300">
22825
+ Cursor &mdash; <code class="font-mono text-xs">~/.cursor/mcp.json</code>
22826
+ </h3>
22827
+ <button type="button" onclick="copyConfig('cursor-config')"
22828
+ class="text-xs text-zinc-500 dark:text-zinc-400 hover:text-zinc-700 dark:hover:text-zinc-200 transition-colors">
22829
+ Copy
22830
+ </button>
22831
+ </div>
22832
+ <pre id="cursor-config" class="rounded-lg bg-zinc-950 dark:bg-zinc-800 px-4 py-3 text-sm font-mono text-zinc-100 overflow-x-auto ring-1 ring-zinc-700 dark:ring-zinc-600 whitespace-pre">${cursorJson}</pre>
22833
+ </div>
22834
+
22835
+ <p class="text-xs text-zinc-400 dark:text-zinc-500">
22836
+ MCP v1 = HTTP POST only (no SSE stream). Clients that require stdio transport can use
22837
+ <code class="font-mono">npx mcp-remote ${safeEndpoint}</code> as a local bridge.
22838
+ </p>
22839
+ </div>
22840
+
22841
+ </div>
22842
+
22843
+ <script>
22844
+ function copyEndpoint() {
22845
+ navigator.clipboard.writeText(document.getElementById('endpoint-url').textContent.trim()).then(() => {
22846
+ window.showNotification && window.showNotification('Endpoint URL copied', 'success')
22847
+ })
22848
+ }
22849
+ function copyConfig(id) {
22850
+ navigator.clipboard.writeText(document.getElementById(id).textContent).then(() => {
22851
+ window.showNotification && window.showNotification('Config copied', 'success')
22852
+ })
22853
+ }
22854
+ </script>`;
22855
+ const layoutData = {
22856
+ title: "MCP Server",
22857
+ pageTitle: "MCP Server",
22858
+ currentPath: "/admin/mcp",
22859
+ user,
22860
+ content: content2,
22861
+ version,
22862
+ dynamicMenuItems
22863
+ };
22864
+ return renderAdminLayoutCatalyst(layoutData);
22865
+ }
22866
+
22867
+ // src/plugins/core-plugins/mcp-plugin/admin/routes.ts
22868
+ function createMcpAdminRoutes(options = {}) {
22869
+ const routes2 = new Hono();
22870
+ routes2.use("*", requireAuth());
22871
+ routes2.use("*", async (c, next) => {
22872
+ const user = c.get("user");
22873
+ if (user?.role !== "admin") return c.json({ error: "Access denied" }, 403);
22874
+ return next();
22875
+ });
22876
+ routes2.get("/", async (c) => {
22877
+ const url = new URL(c.req.url);
22878
+ const endpointUrl = `${url.protocol}//${url.host}/mcp`;
22879
+ const registry = getCollectionRegistry();
22880
+ const active = registry.listActive();
22881
+ const collections = new Map(active.map((col) => [col.name, col]));
22882
+ const cfg = resolveMcpConfig(options, active);
22883
+ const tools = buildToolRegistry(cfg, collections, PHASE_FLAGS);
22884
+ const user = c.get("user");
22885
+ return c.html(
22886
+ renderMcpDashboardPage({
22887
+ endpointUrl,
22888
+ types: cfg.types,
22889
+ tools,
22890
+ user: { name: user.email, email: user.email, role: user.role },
22891
+ version: c.get("appVersion"),
22892
+ dynamicMenuItems: c.get("pluginMenuItems")
22893
+ })
22894
+ );
22895
+ });
22896
+ return routes2;
22897
+ }
22898
+
22899
+ // src/plugins/core-plugins/mcp-plugin/index.ts
22900
+ var MCP_ICON = `<svg class="h-5 w-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 9l3 3-3 3m5 0h3M5 20h14a2 2 0 002-2V6a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z"/></svg>`;
22901
+ function mcpPlugin(options = {}) {
22902
+ return definePlugin({
22903
+ id: "mcp",
22904
+ version: "1.0.0",
22905
+ name: "MCP Server",
22906
+ description: "Exposes SonicJS content as Model Context Protocol tools for AI agents (Claude Code, Cursor, \u2026).",
22907
+ sonicjsVersionRange: "^3.0.0",
22908
+ author: { name: "SonicJS Team" },
22909
+ register(app2) {
22910
+ app2.route("/mcp", createMcpRoutes(options));
22911
+ app2.route("/admin/mcp", createMcpAdminRoutes(options));
22912
+ },
22913
+ menu: [{ label: "MCP Server", path: "/admin/mcp", icon: MCP_ICON, order: 87 }]
22914
+ });
22915
+ }
22916
+ function createMcpPlugin(options) {
22917
+ return mcpPlugin(options);
22918
+ }
22054
22919
 
22055
22920
  // src/index.ts
22056
22921
  var VERSION = package_default.version;
22057
22922
 
22058
- export { BUILT_IN_PROVIDERS, CloudflareEmailProvider2 as CloudflareEmailProvider, OAuthService, VERSION, createDb, createHelloWorldPlugin, createOAuthProvidersPlugin, createRedirectPlugin, createSonicJSApp, emailReconciliationPlugin, generateTriggersComment, helloWorldPlugin, oauthProvidersPlugin, parseCronTriggers, redirectPlugin, setupCoreMiddleware, setupCoreRoutes, site_settings_collection_default as siteSettingsCollection, updateWranglerTriggers };
22923
+ export { BUILT_IN_PROVIDERS, CloudflareEmailProvider2 as CloudflareEmailProvider, OAuthService, VERSION, createDb, createHelloWorldPlugin, createMcpPlugin, createOAuthProvidersPlugin, createRedirectPlugin, createSonicJSApp, emailReconciliationPlugin, generateTriggersComment, helloWorldPlugin, mcpPlugin, oauthProvidersPlugin, parseCronTriggers, redirectPlugin, setupCoreMiddleware, setupCoreRoutes, site_settings_collection_default as siteSettingsCollection, updateWranglerTriggers };
22059
22924
  //# sourceMappingURL=index.js.map
22060
22925
  //# sourceMappingURL=index.js.map