@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.
- package/bin/db-reset.js +39 -22
- package/dist/admin-documents-form.template-JWV5GITD.js +6 -0
- package/dist/{admin-documents-form.template-55V2ZGWT.js.map → admin-documents-form.template-JWV5GITD.js.map} +1 -1
- package/dist/admin-documents-form.template-UWKGVAMW.cjs +19 -0
- package/dist/{admin-layout-catalyst.template-6UQGLCKI.js.map → admin-documents-form.template-UWKGVAMW.cjs.map} +1 -1
- package/dist/admin-layout-catalyst.template-MOQ3BBXA.cjs +21 -0
- package/dist/{admin-layout-catalyst.template-3XZXDGF7.cjs.map → admin-layout-catalyst.template-MOQ3BBXA.cjs.map} +1 -1
- package/dist/admin-layout-catalyst.template-WCYMQVTZ.js +7 -0
- package/dist/{admin-documents-form.template-YNAVMJCV.cjs.map → admin-layout-catalyst.template-WCYMQVTZ.js.map} +1 -1
- package/dist/{chunk-KS24NPPL.js → chunk-2D3A4X52.js} +21 -2
- package/dist/chunk-2D3A4X52.js.map +1 -0
- package/dist/{chunk-DIBCKCUE.js → chunk-2OXFMMA3.js} +14 -29
- package/dist/chunk-2OXFMMA3.js.map +1 -0
- package/dist/{chunk-SOZUG52O.js → chunk-3KGY4IBW.js} +3 -3
- package/dist/{chunk-SOZUG52O.js.map → chunk-3KGY4IBW.js.map} +1 -1
- package/dist/{chunk-CTYLCWMO.cjs → chunk-6OA77UM7.cjs} +802 -481
- package/dist/chunk-6OA77UM7.cjs.map +1 -0
- package/dist/{chunk-URIBTX27.js → chunk-73RTFFMX.js} +3 -3
- package/dist/{chunk-URIBTX27.js.map → chunk-73RTFFMX.js.map} +1 -1
- package/dist/{chunk-SK5CHFJP.js → chunk-7P5OCUPS.js} +467 -149
- package/dist/chunk-7P5OCUPS.js.map +1 -0
- package/dist/{chunk-3TMTYJAJ.js → chunk-BDQ55MWV.js} +18 -2
- package/dist/chunk-BDQ55MWV.js.map +1 -0
- package/dist/{chunk-C3ZQP5NW.cjs → chunk-BJ6NJL2E.cjs} +7 -12
- package/dist/chunk-BJ6NJL2E.cjs.map +1 -0
- package/dist/{chunk-2MIYYAO4.js → chunk-C54MH5UI.js} +5 -4
- package/dist/chunk-C54MH5UI.js.map +1 -0
- package/dist/{chunk-BBEKHLTW.cjs → chunk-CN3T3TDI.cjs} +9 -9
- package/dist/{chunk-BBEKHLTW.cjs.map → chunk-CN3T3TDI.cjs.map} +1 -1
- package/dist/{chunk-DPLJYTHE.js → chunk-CWIGQYRR.js} +7 -12
- package/dist/chunk-CWIGQYRR.js.map +1 -0
- package/dist/{chunk-4WMZGHIC.cjs → chunk-D6FWEYQE.cjs} +6 -5
- package/dist/chunk-D6FWEYQE.cjs.map +1 -0
- package/dist/{chunk-A46IRC5A.js → chunk-D7RLBBHE.js} +2 -2
- package/dist/{chunk-A46IRC5A.js.map → chunk-D7RLBBHE.js.map} +1 -1
- package/dist/{chunk-IXUHXTHW.cjs → chunk-DLTT7QZU.cjs} +17 -6
- package/dist/chunk-DLTT7QZU.cjs.map +1 -0
- package/dist/{chunk-BHND5PEV.js → chunk-E3TQG7AA.js} +3 -3
- package/dist/{chunk-BHND5PEV.js.map → chunk-E3TQG7AA.js.map} +1 -1
- package/dist/{chunk-IS54FPB7.cjs → chunk-E7E3NL3Y.cjs} +27 -42
- package/dist/chunk-E7E3NL3Y.cjs.map +1 -0
- package/dist/{chunk-XXRR54AB.js → chunk-F26HP3B6.js} +36 -5
- package/dist/chunk-F26HP3B6.js.map +1 -0
- package/dist/{chunk-QZGABF2M.js → chunk-FVAK4C6L.js} +17 -6
- package/dist/chunk-FVAK4C6L.js.map +1 -0
- package/dist/{chunk-BJROXF4N.js → chunk-HSDJDWLV.js} +19 -4
- package/dist/chunk-HSDJDWLV.js.map +1 -0
- package/dist/{chunk-RFBW5RRH.cjs → chunk-I7MIRRFJ.cjs} +43 -12
- package/dist/chunk-I7MIRRFJ.cjs.map +1 -0
- package/dist/{chunk-LTZ5WYOK.cjs → chunk-JCBDXEY2.cjs} +18 -2
- package/dist/chunk-JCBDXEY2.cjs.map +1 -0
- package/dist/{chunk-UYJQDDEE.cjs → chunk-MI2YXCK4.cjs} +14 -8
- package/dist/chunk-MI2YXCK4.cjs.map +1 -0
- package/dist/{chunk-VGHEKIJL.cjs → chunk-MOGK3U4A.cjs} +2 -2
- package/dist/{chunk-VGHEKIJL.cjs.map → chunk-MOGK3U4A.cjs.map} +1 -1
- package/dist/{chunk-E66UVONV.cjs → chunk-OUBUS74I.cjs} +24 -9
- package/dist/chunk-OUBUS74I.cjs.map +1 -0
- package/dist/{chunk-GMMCCIQO.cjs → chunk-RSBZITK3.cjs} +3 -3
- package/dist/{chunk-GMMCCIQO.cjs.map → chunk-RSBZITK3.cjs.map} +1 -1
- package/dist/{chunk-THFZSDIU.js → chunk-SXC4HPK6.js} +14 -8
- package/dist/chunk-SXC4HPK6.js.map +1 -0
- package/dist/{chunk-JMJM7DMM.cjs → chunk-TT3TQSCZ.cjs} +5 -5
- package/dist/{chunk-JMJM7DMM.cjs.map → chunk-TT3TQSCZ.cjs.map} +1 -1
- package/dist/{chunk-AT4ZQGEZ.cjs → chunk-YAURVGUK.cjs} +21 -2
- package/dist/chunk-YAURVGUK.cjs.map +1 -0
- package/dist/config-4TIHSNW6.js +6 -0
- package/dist/{config-6FB2BXMP.js.map → config-4TIHSNW6.js.map} +1 -1
- package/dist/{config-OCH7S4WK.cjs → config-XN2ETAJ3.cjs} +5 -5
- package/dist/{config-OCH7S4WK.cjs.map → config-XN2ETAJ3.cjs.map} +1 -1
- package/dist/{define-plugin-D_6D9vVZ.d.ts → define-plugin-DDe8a_bh.d.ts} +3 -0
- package/dist/{define-plugin-DMcvEy_C.d.cts → define-plugin-rjXmGOgu.d.cts} +3 -0
- package/dist/index.cjs +1220 -353
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +38 -3
- package/dist/index.d.ts +38 -3
- package/dist/index.js +895 -30
- package/dist/index.js.map +1 -1
- package/dist/middleware.cjs +35 -35
- package/dist/middleware.d.cts +4 -1
- package/dist/middleware.d.ts +4 -1
- package/dist/middleware.js +6 -6
- package/dist/migrations-JAHMI5MK.js +4 -0
- package/dist/{migrations-XQ6EX6HX.js.map → migrations-JAHMI5MK.js.map} +1 -1
- package/dist/migrations-KU4V6T73.cjs +13 -0
- package/dist/{migrations-ZD7Y5NUC.cjs.map → migrations-KU4V6T73.cjs.map} +1 -1
- package/dist/plugins.cjs +40 -40
- package/dist/plugins.d.cts +1 -1
- package/dist/plugins.d.ts +1 -1
- package/dist/plugins.js +3 -3
- package/dist/rbac-AORZ6O3N.cjs +14 -0
- package/dist/{rbac-7QZ4JZ2E.cjs.map → rbac-AORZ6O3N.cjs.map} +1 -1
- package/dist/rbac-P44772FP.js +5 -0
- package/dist/{rbac-Y43IEQOP.js.map → rbac-P44772FP.js.map} +1 -1
- package/dist/routes.cjs +31 -31
- package/dist/routes.js +11 -11
- package/dist/services.cjs +18 -18
- package/dist/services.d.cts +1 -1
- package/dist/services.d.ts +1 -1
- package/dist/services.js +2 -2
- package/dist/{telemetry-Cku1ax74.d.cts → telemetry-QFlTv9f8.d.cts} +1 -1
- package/dist/{telemetry-Cku1ax74.d.ts → telemetry-QFlTv9f8.d.ts} +1 -1
- package/dist/templates.cjs +17 -17
- package/dist/templates.js +3 -3
- package/dist/types.d.cts +1 -1
- package/dist/types.d.ts +1 -1
- package/dist/utils.cjs +12 -12
- package/dist/utils.d.cts +1 -1
- package/dist/utils.d.ts +1 -1
- package/dist/utils.js +2 -2
- package/package.json +5 -10
- package/dist/admin-documents-form.template-55V2ZGWT.js +0 -6
- package/dist/admin-documents-form.template-YNAVMJCV.cjs +0 -19
- package/dist/admin-layout-catalyst.template-3XZXDGF7.cjs +0 -21
- package/dist/admin-layout-catalyst.template-6UQGLCKI.js +0 -7
- package/dist/chunk-2MIYYAO4.js.map +0 -1
- package/dist/chunk-3TMTYJAJ.js.map +0 -1
- package/dist/chunk-4WMZGHIC.cjs.map +0 -1
- package/dist/chunk-AT4ZQGEZ.cjs.map +0 -1
- package/dist/chunk-BJROXF4N.js.map +0 -1
- package/dist/chunk-C3ZQP5NW.cjs.map +0 -1
- package/dist/chunk-CTYLCWMO.cjs.map +0 -1
- package/dist/chunk-DIBCKCUE.js.map +0 -1
- package/dist/chunk-DPLJYTHE.js.map +0 -1
- package/dist/chunk-E66UVONV.cjs.map +0 -1
- package/dist/chunk-IS54FPB7.cjs.map +0 -1
- package/dist/chunk-IXUHXTHW.cjs.map +0 -1
- package/dist/chunk-KS24NPPL.js.map +0 -1
- package/dist/chunk-LTZ5WYOK.cjs.map +0 -1
- package/dist/chunk-QZGABF2M.js.map +0 -1
- package/dist/chunk-RFBW5RRH.cjs.map +0 -1
- package/dist/chunk-SK5CHFJP.js.map +0 -1
- package/dist/chunk-THFZSDIU.js.map +0 -1
- package/dist/chunk-UYJQDDEE.cjs.map +0 -1
- package/dist/chunk-XXRR54AB.js.map +0 -1
- package/dist/config-6FB2BXMP.js +0 -6
- package/dist/migrations-XQ6EX6HX.js +0 -4
- package/dist/migrations-ZD7Y5NUC.cjs +0 -13
- package/dist/rbac-7QZ4JZ2E.cjs +0 -14
- package/dist/rbac-Y43IEQOP.js +0 -5
package/dist/index.js
CHANGED
|
@@ -1,37 +1,37 @@
|
|
|
1
|
-
import { createAuth } from './chunk-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
13
|
-
import { RbacService, DocumentsService } from './chunk-
|
|
14
|
-
export { DocumentsService, RbacService } from './chunk-
|
|
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-
|
|
17
|
-
export { PluginBootstrapService, PluginService as PluginServiceClass, getAvailableCollectionNames, loadCollectionConfig, loadCollectionConfigs, registerCollections, validateCollectionConfig } from './chunk-
|
|
18
|
-
export { MigrationService } from './chunk-
|
|
19
|
-
export { renderFilterBar } from './chunk-
|
|
20
|
-
import { renderAdminLayout } from './chunk-
|
|
21
|
-
export { getConfirmationDialogScript, renderAlert, renderConfirmationDialog, renderForm, renderFormField, renderPagination, renderTable } from './chunk-
|
|
22
|
-
import { init_admin_layout_catalyst_template, renderAdminLayoutCatalyst } from './chunk-
|
|
23
|
-
export { renderAdminLayoutCatalyst } from './chunk-
|
|
24
|
-
import { TurnstileService, HookSystemImpl, createPluginWirer, registerPluginRoutes } from './chunk-
|
|
25
|
-
export { HookSystemImpl, HookUtils, PluginDependencyCycleError, PluginManager as PluginManagerClass, PluginRegistryImpl, PluginValidator as PluginValidatorClass, RegisterPluginsError, ScopedHookSystem as ScopedHookSystemClass, collectCronSchedules, collectCrons, createScheduledHandler, dispatchCronTick, registerPlugins, topoSort } from './chunk-
|
|
26
|
-
import { definePlugin, setPluginMenu, setPluginDefinitions, resolvePluginMenuItems } from './chunk-
|
|
27
|
-
export { applySchemaDefaults, definePlugin, getPluginMenu, isDefinedPlugin, parseConfigSchema, parseFormDataToSettings, renderSchemaFields, resetPluginMenu, resolvePluginMenuItems, setPluginMenu } from './chunk-
|
|
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-
|
|
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-
|
|
34
|
-
export { SONICJS_VERSION, getCoreVersion } from './chunk-
|
|
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-
|
|
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
|
-
|
|
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-
|
|
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">·</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">·</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 — <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 — <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
|