Files
webstudio/apps/builder/app/shared/content-block-source-utils.ts
Oleg Isonen 0d448313ab fix: harden MCP mutations and validation (#6402)
## Summary

Fixes the reproducible MCP regressions reported today:

- validate font upload metadata locally instead of surfacing an HTTP 500
- replace only the addressed child when `insertIndex` is supplied
- support cross-parent duplication
- bind data-variable assignments in actions
- reject string-valued `style` bindings
- include descriptions for every advertised MCP tool
- preserve resource data-source exposure on full updates
- render mixed expression/element children in the Builder canvas
- preserve explicit outer Collection references in nested scopes
- reject unsupported `update-page-settings` fields instead of dropping
them
- reject unavailable asset-query variables and log server error details

Closes #6390
Closes #6391
Closes #6392
Closes #6393
Closes #6394
Closes #6395
Closes #6398
Closes #6399
Closes #6401
Closes #6404
Closes #6405

## Verification

- 484 project-build tests
- 62 CLI tests
- 35 Builder browser tests
- 25 SDK tests
- project-build, Builder, CLI, and SDK type checks
- root lint and generated runtime contracts
2026-09-17 10:16:11 +02:00

56 lines
1.4 KiB
TypeScript

import { resolveContentBlockSourceAssetId } from "@webstudio-is/project-build/runtime";
import {
ROOT_INSTANCE_ID,
type ContentBlockSource,
type Instances,
} from "@webstudio-is/sdk";
import type { InstanceSelector } from "@webstudio-is/project-build/runtime";
import { getInstanceVariableValues } from "./instance-utils/variable-values";
export const parseContentBlockRenderScope = (renderScope: string) => {
try {
const value: unknown = JSON.parse(renderScope);
if (
Array.isArray(value) &&
value.length > 0 &&
value.every((instanceId) => typeof instanceId === "string")
) {
return value as InstanceSelector;
}
} catch {
return;
}
};
export const resolveContentBlockOccurrenceAssetId = ({
source,
instanceSelector,
variableValuesByRenderScope,
}: {
source: ContentBlockSource;
instanceSelector: InstanceSelector;
variableValuesByRenderScope: ReadonlyMap<
string,
ReadonlyMap<string, unknown>
>;
}) =>
resolveContentBlockSourceAssetId({
source,
values: getInstanceVariableValues(
variableValuesByRenderScope,
instanceSelector
),
});
export const isRepeatedContentBlockOccurrence = ({
instanceSelector,
instances,
}: {
instanceSelector: InstanceSelector;
instances: Instances;
}) =>
instanceSelector.some(
(instanceId) =>
instanceId !== ROOT_INSTANCE_ID && instances.has(instanceId) === false
);