@elementor/editor-canvas 4.5.0-1150 → 4.5.0-1154

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/dist/index.js CHANGED
@@ -4342,7 +4342,7 @@ function initTabsModelExtensions() {
4342
4342
  }
4343
4343
 
4344
4344
  // src/mcp/canvas-mcp.ts
4345
- var import_editor_props8 = require("@elementor/editor-props");
4345
+ var import_editor_props9 = require("@elementor/editor-props");
4346
4346
 
4347
4347
  // src/mcp/resources/available-widgets-resource.ts
4348
4348
  var import_http_client3 = require("@elementor/http-client");
@@ -4714,6 +4714,7 @@ var initGeneralContextResource = (reg) => {
4714
4714
 
4715
4715
  // src/mcp/resources/selected-element-resource.ts
4716
4716
  var import_editor_elements11 = require("@elementor/editor-elements");
4717
+ var import_editor_props6 = require("@elementor/editor-props");
4717
4718
  var import_editor_v1_adapters21 = require("@elementor/editor-v1-adapters");
4718
4719
  var SELECTED_ELEMENT_URI = "elementor://context/selected-element";
4719
4720
  var initSelectedElementResource = (reg) => {
@@ -4821,13 +4822,19 @@ function getElementProperties(container, widgetType) {
4821
4822
  if (!settings || typeof settings !== "object") {
4822
4823
  return null;
4823
4824
  }
4824
- const widgetConfig = widgetType ? (0, import_editor_elements11.getWidgetsCache)()?.[widgetType] : null;
4825
+ const widgetsCache = (0, import_editor_elements11.getWidgetsCache)();
4826
+ const widgetConfig = widgetType ? widgetsCache?.[widgetType] : null;
4825
4827
  const controls = widgetConfig?.controls;
4828
+ const schemaType = widgetType ?? container.model.get("elType") ?? null;
4829
+ const propsSchema = schemaType ? widgetsCache?.[schemaType]?.atomic_props_schema : void 0;
4826
4830
  const filtered = {};
4827
4831
  for (const [key, value] of Object.entries(settings)) {
4828
4832
  if (value === void 0 || value === null || value === "") {
4829
4833
  continue;
4830
4834
  }
4835
+ if (import_editor_props6.Schema.isPropSensitive(propsSchema?.[key])) {
4836
+ continue;
4837
+ }
4831
4838
  const controlDefault = controls?.[key]?.default;
4832
4839
  if (controlDefault !== void 0 && JSON.stringify(value) === JSON.stringify(controlDefault)) {
4833
4840
  continue;
@@ -4861,11 +4868,11 @@ function getElementDisplayName(container) {
4861
4868
  // src/mcp/tools/configure-element/tool.ts
4862
4869
  var import_editor_elements14 = require("@elementor/editor-elements");
4863
4870
  var import_editor_mcp3 = require("@elementor/editor-mcp");
4864
- var import_editor_props7 = require("@elementor/editor-props");
4871
+ var import_editor_props8 = require("@elementor/editor-props");
4865
4872
 
4866
4873
  // src/mcp/utils/do-update-element-property.ts
4867
4874
  var import_editor_elements13 = require("@elementor/editor-elements");
4868
- var import_editor_props6 = require("@elementor/editor-props");
4875
+ var import_editor_props7 = require("@elementor/editor-props");
4869
4876
  var import_editor_styles4 = require("@elementor/editor-styles");
4870
4877
  var import_editor_v1_adapters23 = require("@elementor/editor-v1-adapters");
4871
4878
 
@@ -5018,7 +5025,7 @@ var UnsupportedPropertyError = class extends Error {
5018
5025
  };
5019
5026
  function resolvePropValue(value, forceKey) {
5020
5027
  const Utils = window.elementorV2.editorVariables.Utils;
5021
- return import_editor_props6.Schema.adjustLlmPropValueSchema(value, {
5028
+ return import_editor_props7.Schema.adjustLlmPropValueSchema(value, {
5022
5029
  forceKey,
5023
5030
  transformers: {
5024
5031
  ...Utils.globalVariablesLLMResolvers,
@@ -5077,7 +5084,7 @@ var doUpdateElementProperty = (params) => {
5077
5084
  }
5078
5085
  if (propertyRawSchema.kind === "plain") {
5079
5086
  if (typeof propertyMapValue[stylePropName] !== "object") {
5080
- const propUtil = (0, import_editor_props6.getPropSchemaFromCache)(propertyRawSchema.key);
5087
+ const propUtil = (0, import_editor_props7.getPropSchemaFromCache)(propertyRawSchema.key);
5081
5088
  if (propUtil) {
5082
5089
  const plainValue = propUtil.create(propertyMapValue[stylePropName]);
5083
5090
  propertyMapValue[stylePropName] = plainValue;
@@ -5125,7 +5132,7 @@ var doUpdateElementProperty = (params) => {
5125
5132
  }
5126
5133
  const propKey = elementPropSchema[propertyName].key;
5127
5134
  const value = resolvePropValue(propertyValue, propKey);
5128
- const { valid, jsonSchema } = import_editor_props6.Schema.validatePropValue(elementPropSchema[propertyName], propertyValue);
5135
+ const { valid, jsonSchema } = import_editor_props7.Schema.validatePropValue(elementPropSchema[propertyName], propertyValue);
5129
5136
  if (!valid) {
5130
5137
  throw new Error(
5131
5138
  `Invalid PropValue for elementId: ${elementId}. PropKey: ${propKey}, PropValue: ${JSON.stringify(
@@ -5372,7 +5379,7 @@ var initConfigureElementTool = (reg) => {
5372
5379
  const toUpdate = Object.entries(propertiesToUpdate);
5373
5380
  const skippedProps = [];
5374
5381
  for (const [propertyName, propertyValue] of toUpdate) {
5375
- if (!import_editor_props7.Schema.isPropKeyConfigurable(propertyName)) {
5382
+ if (!import_editor_props8.Schema.isPropKeyConfigurable(propertyName, widgetData.atomic_props_schema[propertyName])) {
5376
5383
  throw new Error(`Not allowed to update ${propertyName}`);
5377
5384
  }
5378
5385
  try {
@@ -5633,7 +5640,7 @@ var initGetPageStructureTool = (reg) => {
5633
5640
 
5634
5641
  // src/mcp/canvas-mcp.ts
5635
5642
  var initCanvasMcp = (reg) => {
5636
- import_editor_props8.Schema.setDynamicTagNamesResolver(getDynamicTagNamesByCategories);
5643
+ import_editor_props9.Schema.setDynamicTagNamesResolver(getDynamicTagNamesByCategories);
5637
5644
  initWidgetsSchemaResource(reg);
5638
5645
  initAvailableWidgetsResource(reg);
5639
5646
  initDocumentStructureResource(reg);
@@ -5829,12 +5836,12 @@ function shouldBlock(sourceElements, targetElements) {
5829
5836
 
5830
5837
  // src/style-commands/paste-style.ts
5831
5838
  var import_editor_elements18 = require("@elementor/editor-elements");
5832
- var import_editor_props10 = require("@elementor/editor-props");
5839
+ var import_editor_props11 = require("@elementor/editor-props");
5833
5840
  var import_editor_v1_adapters26 = require("@elementor/editor-v1-adapters");
5834
5841
 
5835
5842
  // src/utils/command-utils.ts
5836
5843
  var import_editor_elements16 = require("@elementor/editor-elements");
5837
- var import_editor_props9 = require("@elementor/editor-props");
5844
+ var import_editor_props10 = require("@elementor/editor-props");
5838
5845
  var import_i18n8 = require("@wordpress/i18n");
5839
5846
  function hasAtomicWidgets(args) {
5840
5847
  const { containers = [args.container] } = args;
@@ -5852,7 +5859,7 @@ function getClassesProp(container) {
5852
5859
  return null;
5853
5860
  }
5854
5861
  const [propKey] = Object.entries(propsSchema).find(
5855
- ([, propType]) => propType.kind === "plain" && propType.key === import_editor_props9.CLASSES_PROP_KEY
5862
+ ([, propType]) => propType.kind === "plain" && propType.key === import_editor_props10.CLASSES_PROP_KEY
5856
5863
  ) ?? [];
5857
5864
  return propKey ?? null;
5858
5865
  }
@@ -6001,8 +6008,8 @@ function pasteClasses(containers, classes) {
6001
6008
  return;
6002
6009
  }
6003
6010
  const classesSetting = (0, import_editor_elements18.getElementSetting)(container.id, classesProp);
6004
- const currentClasses = import_editor_props10.classesPropTypeUtil.extract(classesSetting) ?? [];
6005
- const newClasses = import_editor_props10.classesPropTypeUtil.create(Array.from(/* @__PURE__ */ new Set([...classes, ...currentClasses])));
6011
+ const currentClasses = import_editor_props11.classesPropTypeUtil.extract(classesSetting) ?? [];
6012
+ const newClasses = import_editor_props11.classesPropTypeUtil.create(Array.from(/* @__PURE__ */ new Set([...classes, ...currentClasses])));
6006
6013
  (0, import_editor_elements18.updateElementSettings)({
6007
6014
  id: container.id,
6008
6015
  props: { [classesProp]: newClasses }
package/dist/index.mjs CHANGED
@@ -4312,7 +4312,7 @@ function initTabsModelExtensions() {
4312
4312
  }
4313
4313
 
4314
4314
  // src/mcp/canvas-mcp.ts
4315
- import { Schema as Schema3 } from "@elementor/editor-props";
4315
+ import { Schema as Schema4 } from "@elementor/editor-props";
4316
4316
 
4317
4317
  // src/mcp/resources/available-widgets-resource.ts
4318
4318
  import { httpService as httpService3 } from "@elementor/http-client";
@@ -4686,6 +4686,7 @@ var initGeneralContextResource = (reg) => {
4686
4686
 
4687
4687
  // src/mcp/resources/selected-element-resource.ts
4688
4688
  import { getContainer as getContainer3, getSelectedElements, getWidgetsCache as getWidgetsCache3 } from "@elementor/editor-elements";
4689
+ import { Schema } from "@elementor/editor-props";
4689
4690
  import {
4690
4691
  __privateListenTo as listenTo4,
4691
4692
  commandEndEvent as commandEndEvent7
@@ -4796,13 +4797,19 @@ function getElementProperties(container, widgetType) {
4796
4797
  if (!settings || typeof settings !== "object") {
4797
4798
  return null;
4798
4799
  }
4799
- const widgetConfig = widgetType ? getWidgetsCache3()?.[widgetType] : null;
4800
+ const widgetsCache = getWidgetsCache3();
4801
+ const widgetConfig = widgetType ? widgetsCache?.[widgetType] : null;
4800
4802
  const controls = widgetConfig?.controls;
4803
+ const schemaType = widgetType ?? container.model.get("elType") ?? null;
4804
+ const propsSchema = schemaType ? widgetsCache?.[schemaType]?.atomic_props_schema : void 0;
4801
4805
  const filtered = {};
4802
4806
  for (const [key, value] of Object.entries(settings)) {
4803
4807
  if (value === void 0 || value === null || value === "") {
4804
4808
  continue;
4805
4809
  }
4810
+ if (Schema.isPropSensitive(propsSchema?.[key])) {
4811
+ continue;
4812
+ }
4806
4813
  const controlDefault = controls?.[key]?.default;
4807
4814
  if (controlDefault !== void 0 && JSON.stringify(value) === JSON.stringify(controlDefault)) {
4808
4815
  continue;
@@ -4836,7 +4843,7 @@ function getElementDisplayName(container) {
4836
4843
  // src/mcp/tools/configure-element/tool.ts
4837
4844
  import { getContainer as getContainer4, getWidgetsCache as getWidgetsCache6 } from "@elementor/editor-elements";
4838
4845
  import { dispatchMcpStylesAppliedEvent } from "@elementor/editor-mcp";
4839
- import { Schema as Schema2 } from "@elementor/editor-props";
4846
+ import { Schema as Schema3 } from "@elementor/editor-props";
4840
4847
 
4841
4848
  // src/mcp/utils/do-update-element-property.ts
4842
4849
  import {
@@ -4846,7 +4853,7 @@ import {
4846
4853
  updateElementSettings,
4847
4854
  updateElementStyle
4848
4855
  } from "@elementor/editor-elements";
4849
- import { getPropSchemaFromCache as getPropSchemaFromCache2, Schema } from "@elementor/editor-props";
4856
+ import { getPropSchemaFromCache as getPropSchemaFromCache2, Schema as Schema2 } from "@elementor/editor-props";
4850
4857
  import { getStylesSchema as getStylesSchema2, getVariantByMeta } from "@elementor/editor-styles";
4851
4858
  import { __privateRunCommandSync as runCommandSync2 } from "@elementor/editor-v1-adapters";
4852
4859
 
@@ -4999,7 +5006,7 @@ var UnsupportedPropertyError = class extends Error {
4999
5006
  };
5000
5007
  function resolvePropValue(value, forceKey) {
5001
5008
  const Utils = window.elementorV2.editorVariables.Utils;
5002
- return Schema.adjustLlmPropValueSchema(value, {
5009
+ return Schema2.adjustLlmPropValueSchema(value, {
5003
5010
  forceKey,
5004
5011
  transformers: {
5005
5012
  ...Utils.globalVariablesLLMResolvers,
@@ -5106,7 +5113,7 @@ var doUpdateElementProperty = (params) => {
5106
5113
  }
5107
5114
  const propKey = elementPropSchema[propertyName].key;
5108
5115
  const value = resolvePropValue(propertyValue, propKey);
5109
- const { valid, jsonSchema } = Schema.validatePropValue(elementPropSchema[propertyName], propertyValue);
5116
+ const { valid, jsonSchema } = Schema2.validatePropValue(elementPropSchema[propertyName], propertyValue);
5110
5117
  if (!valid) {
5111
5118
  throw new Error(
5112
5119
  `Invalid PropValue for elementId: ${elementId}. PropKey: ${propKey}, PropValue: ${JSON.stringify(
@@ -5353,7 +5360,7 @@ var initConfigureElementTool = (reg) => {
5353
5360
  const toUpdate = Object.entries(propertiesToUpdate);
5354
5361
  const skippedProps = [];
5355
5362
  for (const [propertyName, propertyValue] of toUpdate) {
5356
- if (!Schema2.isPropKeyConfigurable(propertyName)) {
5363
+ if (!Schema3.isPropKeyConfigurable(propertyName, widgetData.atomic_props_schema[propertyName])) {
5357
5364
  throw new Error(`Not allowed to update ${propertyName}`);
5358
5365
  }
5359
5366
  try {
@@ -5614,7 +5621,7 @@ var initGetPageStructureTool = (reg) => {
5614
5621
 
5615
5622
  // src/mcp/canvas-mcp.ts
5616
5623
  var initCanvasMcp = (reg) => {
5617
- Schema3.setDynamicTagNamesResolver(getDynamicTagNamesByCategories);
5624
+ Schema4.setDynamicTagNamesResolver(getDynamicTagNamesByCategories);
5618
5625
  initWidgetsSchemaResource(reg);
5619
5626
  initAvailableWidgetsResource(reg);
5620
5627
  initDocumentStructureResource(reg);
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@elementor/editor-canvas",
3
3
  "description": "Elementor Editor Canvas",
4
- "version": "4.5.0-1150",
4
+ "version": "4.5.0-1154",
5
5
  "private": false,
6
6
  "author": "Elementor Team",
7
7
  "homepage": "https://elementor.com/",
@@ -37,26 +37,26 @@
37
37
  "react-dom": "^18.3.1"
38
38
  },
39
39
  "dependencies": {
40
- "@elementor/editor": "4.5.0-1150",
41
- "@elementor/editor-controls": "4.5.0-1150",
42
- "@elementor/editor-documents": "4.5.0-1150",
43
- "@elementor/editor-elements": "4.5.0-1150",
44
- "@elementor/editor-interactions": "4.5.0-1150",
45
- "@elementor/editor-mcp": "4.5.0-1150",
46
- "@elementor/editor-notifications": "4.5.0-1150",
47
- "@elementor/editor-props": "4.5.0-1150",
48
- "@elementor/editor-responsive": "4.5.0-1150",
49
- "@elementor/editor-styles": "4.5.0-1150",
50
- "@elementor/editor-styles-repository": "4.5.0-1150",
51
- "@elementor/editor-ui": "4.5.0-1150",
52
- "@elementor/editor-v1-adapters": "4.5.0-1150",
53
- "@elementor/events": "4.5.0-1150",
54
- "@elementor/http-client": "4.5.0-1150",
55
- "@elementor/schema": "4.5.0-1150",
56
- "@elementor/twing": "4.5.0-1150",
40
+ "@elementor/editor": "4.5.0-1154",
41
+ "@elementor/editor-controls": "4.5.0-1154",
42
+ "@elementor/editor-documents": "4.5.0-1154",
43
+ "@elementor/editor-elements": "4.5.0-1154",
44
+ "@elementor/editor-interactions": "4.5.0-1154",
45
+ "@elementor/editor-mcp": "4.5.0-1154",
46
+ "@elementor/editor-notifications": "4.5.0-1154",
47
+ "@elementor/editor-props": "4.5.0-1154",
48
+ "@elementor/editor-responsive": "4.5.0-1154",
49
+ "@elementor/editor-styles": "4.5.0-1154",
50
+ "@elementor/editor-styles-repository": "4.5.0-1154",
51
+ "@elementor/editor-ui": "4.5.0-1154",
52
+ "@elementor/editor-v1-adapters": "4.5.0-1154",
53
+ "@elementor/events": "4.5.0-1154",
54
+ "@elementor/http-client": "4.5.0-1154",
55
+ "@elementor/schema": "4.5.0-1154",
56
+ "@elementor/twing": "4.5.0-1154",
57
57
  "@elementor/ui": "1.41.4",
58
- "@elementor/utils": "4.5.0-1150",
59
- "@elementor/wp-media": "4.5.0-1150",
58
+ "@elementor/utils": "4.5.0-1154",
59
+ "@elementor/wp-media": "4.5.0-1154",
60
60
  "@floating-ui/react": "^0.27.5",
61
61
  "@wordpress/i18n": "^5.13.0",
62
62
  "dompurify": "^3.2.6"
@@ -0,0 +1,106 @@
1
+ import { getContainer, getSelectedElements, getWidgetsCache } from '@elementor/editor-elements';
2
+
3
+ import { initSelectedElementResource } from '../selected-element-resource';
4
+
5
+ jest.mock( '@elementor/editor-elements', () => ( {
6
+ getContainer: jest.fn(),
7
+ getSelectedElements: jest.fn(),
8
+ getWidgetsCache: jest.fn(),
9
+ } ) );
10
+
11
+ jest.mock( '@elementor/editor-v1-adapters', () => ( {
12
+ __privateListenTo: jest.fn(),
13
+ commandEndEvent: jest.fn(),
14
+ } ) );
15
+
16
+ type ResourceHandler = () => Promise< { contents: { text: string }[] } >;
17
+
18
+ const stringProp = ( meta: Record< string, unknown > = {} ) => ( {
19
+ kind: 'plain',
20
+ key: 'string',
21
+ settings: {},
22
+ meta,
23
+ } );
24
+
25
+ const givenSelectedContainer = ( modelProps: Record< string, unknown >, settings: Record< string, unknown > ) => {
26
+ jest.mocked( getSelectedElements ).mockReturnValue( [ { id: 'el-1' } ] as never );
27
+ jest.mocked( getContainer ).mockReturnValue( {
28
+ id: 'el-1',
29
+ type: modelProps.widgetType ? 'widget' : ( modelProps.elType as string ),
30
+ model: {
31
+ get: ( key: string ) => modelProps[ key ],
32
+ config: { atomic: true },
33
+ },
34
+ settings: {
35
+ toJSON: () => settings,
36
+ },
37
+ } as never );
38
+ };
39
+
40
+ const readProperties = async () => {
41
+ const resource = jest.fn();
42
+ initSelectedElementResource( { resource, sendResourceUpdated: jest.fn() } as never );
43
+
44
+ const handler = resource.mock.calls[ 0 ][ 3 ] as ResourceHandler;
45
+ const result = await handler();
46
+
47
+ return JSON.parse( result.contents[ 0 ].text ).properties;
48
+ };
49
+
50
+ describe( 'selected-element-resource', () => {
51
+ beforeEach( () => {
52
+ jest.clearAllMocks();
53
+ } );
54
+
55
+ it( 'omits sensitive props of an atomic widget', async () => {
56
+ // Arrange.
57
+ jest.mocked( getWidgetsCache ).mockReturnValue( {
58
+ 'e-heading': {
59
+ atomic_props_schema: {
60
+ tag: stringProp(),
61
+ api_key: stringProp( { sensitive: true } ),
62
+ },
63
+ },
64
+ } as never );
65
+
66
+ givenSelectedContainer(
67
+ { elType: 'widget', widgetType: 'e-heading' },
68
+ {
69
+ tag: { $$type: 'string', value: 'h2' },
70
+ api_key: { $$type: 'string', value: 'secret' },
71
+ }
72
+ );
73
+
74
+ // Act.
75
+ const properties = await readProperties();
76
+
77
+ // Assert.
78
+ expect( properties ).toEqual( { tag: { $$type: 'string', value: 'h2' } } );
79
+ } );
80
+
81
+ it( 'omits sensitive props of an atomic element that has no widgetType', async () => {
82
+ // Arrange.
83
+ jest.mocked( getWidgetsCache ).mockReturnValue( {
84
+ 'e-form': {
85
+ atomic_props_schema: {
86
+ 'form-name': stringProp(),
87
+ 'mailchimp-api-key': stringProp( { sensitive: true } ),
88
+ },
89
+ },
90
+ } as never );
91
+
92
+ givenSelectedContainer(
93
+ { elType: 'e-form' },
94
+ {
95
+ 'form-name': { $$type: 'string', value: 'Contact' },
96
+ 'mailchimp-api-key': { $$type: 'string', value: 'secret' },
97
+ }
98
+ );
99
+
100
+ // Act.
101
+ const properties = await readProperties();
102
+
103
+ // Assert.
104
+ expect( properties ).toEqual( { 'form-name': { $$type: 'string', value: 'Contact' } } );
105
+ } );
106
+ } );
@@ -1,5 +1,6 @@
1
1
  import { getContainer, getSelectedElements, getWidgetsCache, type V1Element } from '@elementor/editor-elements';
2
2
  import { type MCPRegistryEntry } from '@elementor/editor-mcp';
3
+ import { Schema } from '@elementor/editor-props';
3
4
  import {
4
5
  __privateListenTo as listenTo,
5
6
  commandEndEvent,
@@ -167,9 +168,14 @@ function getElementProperties(
167
168
  return null;
168
169
  }
169
170
 
170
- const widgetConfig = widgetType ? getWidgetsCache()?.[ widgetType ] : null;
171
+ const widgetsCache = getWidgetsCache();
172
+ const widgetConfig = widgetType ? widgetsCache?.[ widgetType ] : null;
171
173
  const controls = widgetConfig?.controls as Record< string, { default?: unknown } > | undefined;
172
174
 
175
+ // Atomic elements (e.g. e-div-block, e-form) have no widgetType, their config is keyed by elType.
176
+ const schemaType = widgetType ?? container.model.get( 'elType' ) ?? null;
177
+ const propsSchema = schemaType ? widgetsCache?.[ schemaType ]?.atomic_props_schema : undefined;
178
+
173
179
  const filtered: Record< string, unknown > = {};
174
180
 
175
181
  for ( const [ key, value ] of Object.entries( settings ) ) {
@@ -177,6 +183,10 @@ function getElementProperties(
177
183
  continue;
178
184
  }
179
185
 
186
+ if ( Schema.isPropSensitive( propsSchema?.[ key ] ) ) {
187
+ continue;
188
+ }
189
+
180
190
  const controlDefault = controls?.[ key ]?.default;
181
191
  if ( controlDefault !== undefined && JSON.stringify( value ) === JSON.stringify( controlDefault ) ) {
182
192
  continue;
@@ -13,7 +13,7 @@ jest.mock( '@elementor/editor-mcp', () => ( {
13
13
  } ) );
14
14
 
15
15
  jest.mock( '@elementor/editor-props', () => ( {
16
- Schema: { isPropKeyConfigurable: () => true },
16
+ Schema: { isPropKeyConfigurable: jest.requireActual( '@elementor/editor-props' ).Schema.isPropKeyConfigurable },
17
17
  } ) );
18
18
 
19
19
  jest.mock( '../prompt', () => ( {
@@ -128,3 +128,55 @@ describe( 'configure-element handler unsupported props', () => {
128
128
  ).rejects.toThrow( /Invalid PropValue/ );
129
129
  } );
130
130
  } );
131
+
132
+ describe( 'configure-element handler sensitive props', () => {
133
+ beforeEach( () => {
134
+ jest.mocked( getWidgetsCache ).mockReturnValue( {
135
+ [ ELEMENT_TYPE ]: {
136
+ atomic_props_schema: {
137
+ title: { key: 'string', kind: 'plain', settings: {}, meta: {} },
138
+ api_key: { key: 'string', kind: 'plain', settings: {}, meta: { sensitive: true } },
139
+ },
140
+ },
141
+ } as never );
142
+ jest.mocked( getContainer ).mockReturnValue( {
143
+ settings: { get: () => ELEMENT_TYPE },
144
+ } as never );
145
+ jest.mocked( doUpdateElementProperty ).mockReset();
146
+ } );
147
+
148
+ it( 'rejects a write to a sensitive prop', async () => {
149
+ // Arrange
150
+ const handler = getHandler();
151
+
152
+ // Act & Assert
153
+ await expect(
154
+ handler( {
155
+ elementId: ELEMENT_ID,
156
+ elementType: ELEMENT_TYPE,
157
+ propertiesToChange: { api_key: { $$type: 'string', value: 'secret' } },
158
+ style: {},
159
+ } )
160
+ ).rejects.toThrow( 'Not allowed to update api_key' );
161
+
162
+ expect( doUpdateElementProperty ).not.toHaveBeenCalled();
163
+ } );
164
+
165
+ it( 'still writes non sensitive props', async () => {
166
+ // Arrange
167
+ jest.mocked( doUpdateElementProperty ).mockImplementation( () => undefined );
168
+ const handler = getHandler();
169
+
170
+ // Act
171
+ const result = await handler( {
172
+ elementId: ELEMENT_ID,
173
+ elementType: ELEMENT_TYPE,
174
+ propertiesToChange: { title: { $$type: 'string', value: 'Hi' } },
175
+ style: {},
176
+ } );
177
+
178
+ // Assert
179
+ expect( result.success ).toBe( true );
180
+ expect( doUpdateElementProperty ).toHaveBeenCalledTimes( 1 );
181
+ } );
182
+ } );
@@ -63,7 +63,7 @@ export const initConfigureElementTool = ( reg: MCPRegistryEntry ) => {
63
63
  const toUpdate = Object.entries( propertiesToUpdate );
64
64
  const skippedProps: string[] = [];
65
65
  for ( const [ propertyName, propertyValue ] of toUpdate as [ string, PropValue ][] ) {
66
- if ( ! Schema.isPropKeyConfigurable( propertyName ) ) {
66
+ if ( ! Schema.isPropKeyConfigurable( propertyName, widgetData.atomic_props_schema[ propertyName ] ) ) {
67
67
  throw new Error( `Not allowed to update ${ propertyName }` );
68
68
  }
69
69
  try {