mirror of
https://github.com/webstudio-is/webstudio.git
synced 2026-10-23 03:27:27 +09:00
main
6761
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
be74d8d698 |
fix: Validate response headers and expose MCP rule edits (#6444)
Header rules previously accepted `null` values, which silently turned a rule into a header-removal instruction even though the settings UI only offers adding a string value or deleting a rule. Require a nonempty string throughout the SDK, Builder, CLI generator, and API contract. Expose configured rules to MCP through `list-response-headers`, `set-response-header`, and `delete-response-header`. Setting a rule adds or replaces the header for the same route and case-insensitive name; `/` and `/*` remain distinct. The Builder UI and MCP operations now share the same rule-key, edit, and Zod validation logic. The generated JSON Schema advertises the header-name pattern and nonempty value, while server-side Zod validation enforces route syntax, forbidden headers, duplicates, and total size. The generic `update-project-settings` operation still supports replacing the whole list. Validation: SDK, project-build runtime and MCP, CLI command and prebuild tests; SDK, Builder, project-build, CLI, and protocol typechecks; lint, package boundaries, generated API and docs checks. Local fixture sync against the development API is blocked by differing bundle versions; PR CI tests fixtures against its deployed Builder host. |
||
|
|
a4c3b37fc2 |
fix: Unblock reported MCP workflows and improve issue diagnostics (#6438)
## What this fixes
MCP authors can reuse an existing design token in JSX fragments, create
valid border shorthands with CSS variables, and bypass a font that never
settles during responsive screenshots. Common fixed page titles with
spaced separators are also accepted. Issue reports now include the
project ID and safe, bounded IDs from the failed operation, plus clearer
response and browser-startup diagnostics.
## Scope and tradeoffs
- `token("name")` attaches an existing design token; an unknown name
returns a not-found error. Empty token definitions from Builder/UI
remain definitions and follow the normal conflict rules.
- Border shorthands map a single unresolved `var()` to the remaining
width, style, or color field when the other fields are explicit.
- `waitForFonts: false` skips font readiness but still waits for stable
layout frames. The default remains unchanged.
- Fixed titles such as `Pricing - Plans` stay literal. Addition such as
`first + second` remains an expression. Wrap ambiguous subtraction in
parentheses, for example `(first - second)`. Other ambiguous title forms
may still need an exact report.
- Only recognized operation-level IDs are attached to a public GitHub
issue. Authored values, raw arguments, URLs, and credentials are
excluded. IDs from later successful diagnostic reads are not captured.
- This does not fix the underlying response-transform failure; it
improves future reports for that case.
Closes #6424
Closes #6425
Closes #6434
Closes #6439
Ref #6435
Ref #6430
Ref #6417
## Verification
- [x] Reproduced the privacy, page-expression, empty-token, and
content-mode token-reference regressions with failing tests, then
confirmed the fixes pass. A regression test also covers parenthesized
subtraction.
- [x] Full protocol, template, vision, project-build, and CLI test
suites pass; focused Builder issue-report and fragment tests pass. The
protocol, CLI, and project-build suites were rerun after the CI fix.
- [x] Relevant package typechecks, lint, package-boundary check, fixture
pipeline, generated API check, and generated docs check pass. Fixture
output has no diff.
- [x] Reviewed the authoritative MCP documentation and regenerated the
API metadata and MCP docs.
- [x] CSS parser regressions cover border, each side shorthand, and
unresolved variables in width, style, and color positions; css-data
tests, typecheck, and lint pass.
- [x] Fixed the local evaluation runner to pass the task and Webstudio
MCP tools to Luna/low. Each of the six fixtures passed at least once;
focused MCP/evaluator tests, CLI and project-build typechecks, lint, and
formatting pass.
- [x] The complete Luna/low suite passed all six fixtures in two
consecutive sequential runs. Baselines remain incompatible with this
model/effort override and were not updated.
## Follow-up
- If another fixed-title form still fails, use the new project-level
report context and the exact title shape to narrow the parser case.
|
||
|
|
2c9fd16689 |
feat: configure custom response headers by route (#6429)
## Description Project Settings starts with an empty response-header rule list. Users can add valid HTTP response headers for all paths (`/*`) or an Authentication-style route such as `/private/*`, and remove any configured rule. The Headers and Authentication views share the accessible rule-list form. The header form suggests standard response-header names and common values for the selected header, while accepting custom names and values. `Set-Cookie` is not suggested because a rule can store only one value per header and would replace existing cookies. `X-Powered-By`, `X-Content-Type-Options`, and `Strict-Transport-Security` are dispatcher-owned and cannot be configured. Users may configure `Content-Security-Policy`, `X-Frame-Options`, and `Referrer-Policy`; when absent, the dispatcher supplies their defaults. The SDK validates header names, values, routes, duplicates, and size limits. The CLI emits only configured rules. Customization requires Pro for custom-domain publishing, while unchanged defaults and staging remain available on Free plans. The server checks the saved production snapshot against the project owner's plan. Companion Cloud worker PR: https://github.com/webstudio-is/webstudio-saas/pull/664. Deploy its dispatcher support before exposing these settings in the Builder. Other hosts need an adapter that applies the generated rules; Webstudio Cloud dispatcher defaults do not apply automatically elsewhere. Static exports do not apply headers automatically. ## Validation - SDK, CLI, Builder browser, publish-warning, and production-build tests pass. - Builder, SDK, and CLI typechecks and lint pass. - The companion Cloud worker tests, typecheck, and lint pass. Replaces https://github.com/webstudio-is/webstudio/pull/6428 to use `headers.staging`. Closes https://github.com/webstudio-is/webstudio/issues/4748 |
||
|
|
30b4f994dc |
fix: restore publish countdown (#6443)
## Summary - Keep the publish countdown visible while the publish action is in progress. - Show the pending spinner after the 60-second countdown expires. The refactor in `804cd39bc` applied the design system's pending button state immediately. That state hides the button text, including the countdown label. Progress still disables the action throughout publishing, while the pending visual state now waits until the countdown ends. ## Verification - `git diff --check` |
||
|
|
cd64a6627e |
fix: Load unbound resource previews in the variable dialog (#6432)
New resources can fail to show data in the **New variable** dialog because a page-plan refresh cancels their preview request before it finishes. This change keeps explicitly requested previews alive until the dialog releases them. Changing inputs, changing resource type, or closing the dialog cancels obsolete work and prevents old data from showing. Unused page resources remain lazy; a preview still makes an on-demand request when **Load data** is clicked. The dialog stays usable while unrelated page resources are loading. Follow-up to #6030. ### Checklist - [x] Reproduce the cancellation with a regression test that fails before the fix. - [x] Keep dialog previews independent of page resource discovery, using the existing loader, cache, and request versions. - [x] Clear old previews on input changes and release requests on dialog close. - [x] Cover new Current date, Sitemap, HTTP, and existing unbound resources, plus repeated loads and stale responses. - [x] Keep tests for obsolete page-request cancellation and async resource dependencies passing. - [x] Test the unsaved dialog with an unrelated page request pending and a page-plan recalculation. - [x] Clear the old preview when switching resource types or starting an asynchronous body edit. - [x] Review documentation impact: no update needed; this restores the documented preview behavior. - [ ] Confirm GitHub CI passes. ### Verification - The dialog loading, type-switch, and body-edit regression tests failed before their fixes and passed afterward. - 82 focused tests and the settings-panel suite (588 tests) passed. - Builder typecheck and repository lint passed. - With preview retention temporarily disabled, all nine new loader regression cases failed as expected. |
||
|
|
9845517029 |
fix: hydrate published Markdown assets (#6422)
Migrated from #6421 to the short .staging branch name. |
||
|
|
3d0a0657aa |
feat: Support async resource dependencies (#6030)
## Summary Make `Resource<Document>` the lazy document-resolution abstraction shared by Content Engine graphs, generated sites, and Builder previews. Expressions use one async computation interface: referenced resource documents resolve first, independent requests run concurrently, and unused resources stay unloaded. Ref #6029 Ref #6031 ## Implementation checklist - [x] Define one resource contract for synchronous or asynchronous document resolution. - [x] Resolve explicit roots lazily with memoization, bounded concurrency, cancellation, and structured errors. - [x] Preserve cycle, duplicate, and missing-resource diagnostics. - [x] Extract resource dependencies with the existing expression AST. - [x] Discover consumed resource roots from the current page tree and page metadata. - [x] Generate a lazy request graph for published page data, including independent requests. - [x] Resolve dependency documents before evaluating dependent request expressions. - [x] Integrate dependency-first loading with Builder preview caching and invalidation. - [x] Expose safe Resource bindings in the editor and reject self/indirect cycles. - [x] Adapt REST, GraphQL, Assets, date, and sitemap requests through the same Resource contract. - [x] Cover laziness, chains, shared dependencies, concurrency, invalidation, cancellation, failures, and cycles with fail/pass tests. - [x] Review documentation impact and document dependent Resources in the Data variables guide. - [x] Track collection-item and component-parameter-dependent resources as follow-up #6031. - [x] Regenerate and review affected fixtures. - [x] Resolve action-resource request dependencies when an action is invoked. - [x] Reproduce and fix cached form submissions and multi-root dependency-cycle hangs. - [x] Document uncached form actions and regenerate affected fixtures. - [x] Preserve single and multi-selected content until a cut successfully writes to the clipboard. - [x] Preserve boolean expression values in the search-exclusion checkbox. - [x] Cancel cut deletion if project data changes while preparing or writing the clipboard; cover content/property edits and project switches for single and multi-selection, and document the retry behavior. - [x] Validate pending cuts after the final await, immediately before deletion, and reproduce the queued-update race for single and multi-selection. ## Technical direction The persisted, revisioned `DocumentGraph` remains the Content Engine artifact. `Resource<Document>` is the execution abstraction for obtaining a document; its resolver evaluates only the dependency closure reachable from requested roots. Static and remote documents therefore differ by Resource implementation, not by expression value type. Generated pages always emit a `ResourceRequestGraph`. Each node owns its output name, dependencies, and request factory. Roots come from resource variables actually referenced by the current page's metadata, props, actions, or expression children. Unused and off-page resources remain unresolved. The loader still accepts legacy request maps for compatibility. Builder preview uses the same page-root discovery as published generation. Its existing cache remains the lifecycle boundary: cached dependency documents unlock dependent requests, while invalidation removes downstream requests until their inputs resolve again. The separate canvas frame recomputes its local plan from the synchronized cache so rendered expressions receive those documents. Action requests and their dependencies resolve when a form is submitted. Each submission sends a new action request, bypassing Webstudio's resource cache. Dependency requests still use their configured cache lifetime. ## Review simplifications - Consolidated page resource-root discovery in the SDK and reused it in Builder. - Scoped root and action discovery to the current page tree. - Removed the redundant immediate-resource helper; `Resource.resolve` already accepts `Document | Promise<Document>`. - Moved output names onto graph nodes and removed the duplicate graph-level map. - Removed unused planner output and corrected transitive cycle discovery to include only Resource data sources. - Regenerated fixtures so independent resources also use lazy graph execution. - Reused one abort-aware concurrency limiter for document sessions and Resource resolution. - Collapsed duplicate generator action scans and removed redundant generated-resource bookkeeping. - Unified legacy request maps and request graphs through one resolution path. - Shared the 20-request concurrency limit between SDK, Builder preview, and the server batch boundary. - Preserved dependency failure paths and original causes, including the first cancellation reason. - Removed invalid-request logging that could expose Resource headers or request bodies. - Made editor cycle detection alias-safe by comparing underlying Resource IDs. - Memoized page settings values to prevent repeated async validation renders. ## Verification Latest local verification for `bbca6395e3`: - Both queued-update regression cases failed before the fix and passed afterward. Validation now runs synchronously immediately before deletion, after the final await, in both cut paths. - Passed: 255 copy/paste and command tests, Builder typecheck, lint, package boundaries, formatting, and diff checks. - Reviewed documentation: the existing copy/paste safety description remains accurate. Fixture inputs and outputs are unaffected; no fixture regeneration was needed. Agent evaluations were not run because separate approval is required. - CI for the new commit is pending. Previous local verification for `ffbc75b152`: - Six regression cases failed before the fix and passed afterward: content edits, property edits, and project switches during a pending cut, with both single and multiple selections. - Passed: 253 copy/paste and command tests, Builder typecheck, lint, package boundaries, source formatting, and diff checks. - An unchanged content-block test file initially failed to import in the browser. Its isolated rerun and the full 253-test rerun passed without code changes. - The guard conservatively treats any project-data change as a reason to keep the clipboard copy without deleting content. It shows a retry message. Copy/paste documentation now describes this behavior. - Fixture inputs and outputs are unaffected; fixtures were not regenerated. Agent evaluations were not run because separate approval is required. CI for the new commit is pending. Previous local verification for `3eb580697c`: - Reproduced both regressions with failing tests before fixing them: premature deletion during cut and false search exclusion appearing checked. - Passed: 203 copy/paste and page-settings tests, Builder typecheck, lint, package boundaries, formatting, and diff checks. - Cut coverage includes keyboard and programmatic entry points, single and multiple selections, delayed successful writes, rejected writes, and disabled copying. - Reviewed documentation impact: these fixes restore existing behavior; no documentation update is needed. Only Builder UI and clipboard files changed; fixture inputs and outputs are unaffected, so fixtures were not regenerated for this commit. - CI status for this older commit was recorded as pending at handoff. Agent evaluations were not run; they require separate approval. Previous local verification for `858b348ad`, rebased onto `cf606ca4c`: - Regression tests failed before each fix and passed afterward: repeated submissions in both generated route templates, plus three multi-root/branching cycle cases. - Passed: 590 SDK tests, 1,129 CLI tests, 72 focused Builder tests, SDK/CLI/Builder typechecks, lint, package boundaries, and fixture link/sync/build. - Initial concurrent runs hit timeouts. The complete CLI suite passed with one worker; the focused Builder suites passed without file parallelism. - Documentation and generated fixture changes reviewed. Agent evaluations were not run; they require separate approval. - CI for `858b348ad` passed: Main (including all six E2E shards), Visual Regression, Lint PR, and Check submodules. Earlier verification (before this update): TDD fail/pass evidence includes resolver creation, AST dependency discovery, published graph reachability, dependency-gated request generation, Builder dependency-first planning, Resource editor cycle filtering, page-tree root scoping, off-page action isolation, transitive Resource-only cycle discovery, abort/timeout precedence, server batch limits, and the rebased SSG fixture consuming its lazy Resource. - `pnpm checks` passed after rebasing onto `ce84ddcf12`; it covered workspace tests, typechecks, lint, package boundaries, generated API/docs validation, and fixture link/sync/build. - Earlier focused checks passed: Builder typecheck, 12 page-settings/pages unit tests, lint, formatting, and `git diff --check`. - Local generated-resource E2E passed for HTTP, GraphQL, and current-date resources (3 tests). - The page-actions and Marketplace page-settings persistence E2Es both pass locally. - CI for `6b8b08a70` passed: Main workflow (including all six Builder E2E shards), Visual Regression, Lint PR, and Check submodules. - Agent evaluations were not run because they require separate explicit approval. ## Current behavior and limitations - A failed dependency blocks its dependents and reports the resource path and cause. - One published resolution call is the memoization boundary; Builder maps dependency readiness onto its versioned request-cache lifecycle. - Scoped collection-item and component-parameter resources remain in #6031. - Builder skips cyclic dependency paths without blocking independent resources. |
||
|
|
d506525915 |
fix: allow re-uploading fonts with invalid metadata (#6423)
## Summary After #6419, a project with broken font metadata can load again, but uploading the same font still returns the broken asset. Deleting it first does not help: the upload reuses the deleted file. This lets a normal re-upload read the font again and create a valid asset. ## Changes - Reuse the existing font-metadata validation before restoring or creating a deduplicated asset. - Clear only the broken file's content hash so a fresh upload can proceed. Keep its bytes, metadata, and existing references unchanged. - Check that the metadata still matches before clearing the hash. If another request repaired it, reuse that valid file. - Keep normal deduplication for later uploads of the new valid font. No schema changes or migrations. Existing references are not automatically replaced, and the original font bytes must still be valid. ## Checklist - [x] Reproduce the bug before fixing it. - [x] Cover invalid JSON and invalid font metadata, with both active and deleted assets, using real WOFF2 bytes. - [x] Cover a concurrent metadata repair, including a failing run with the update guard removed. - [x] Pass all 306 asset-uploader tests, package typecheck, and lint/format checks for both changed files. - [x] Verify fixture impact: no fixture inputs, outputs, or bundle contracts changed; all 17 fixture checks pass. Regeneration is not needed. - [x] Review documentation impact: the custom-font and asset guides already describe normal uploading; no documentation changes needed. Agent evaluations and browser E2E were not run; both require separate approval. Ref #6419 |
||
|
|
804cd39bc2 |
fix: Stop slow diagnostics from blocking publishing and clarify publish status (#6416)
Closes #6406 ## What changes Publishing no longer waits for advisory content-database and MDX diagnostics. Those checks run alongside the publish request, so a slow diagnostic does not prevent publishing from starting. Permissions, pending content saves, and blocking project checks still run before publishing. The server continues to enforce publish authorization and build integrity. ### Publish dialog - Add a green **Validate** button beside the blue **Publish** button, with equal widths. - Show waiting states and disable the actions while their work is running. - Let users validate without publishing. Successful validation shows a persistent “Validation passed. Ready to publish.” toast. - Clear the button's **Validated** state when the popover closes. Reopening still reflects an active publish job. - Move **Add new domain**, **Export**, and **Publish settings** into the header's ellipsis menu. - Show yellow progress icons for publishing domains, green checkmarks for completed publishes, red icons for failures, and neutral icons for unpublished domains. Built-in and custom domains share the status mapping. ### CLI and MCP Add `check-publish-readiness` to check the saved project without starting a publish. It checks permissions, rejects empty or unusable domain selections, reuses the existing build-integrity checks, and returns content diagnostics. Broken resource references no longer produce a false `valid: true` result. ### Content checks Run independent collection reads with bounded concurrency instead of processing every collection sequentially. This reduces serial waiting, but does not eliminate the underlying storage reads or content processing. ## Checklist - [x] Keep authorization and blocking project checks in place. - [x] Run advisory content diagnostics alongside publishing. - [x] Add standalone validation, waiting states, and popover-local validation results. - [x] Consolidate secondary actions in the publish menu. - [x] Distinguish pending, completed, failed, and unpublished domain states. - [x] Add CLI/MCP readiness checks using existing integrity and verified-domain logic. - [x] Bound concurrent collection reads. - [x] Add regression tests, including invalid domains, missing resources, status transitions, and popover state. - [x] Demonstrate the latest regression tests failing without the fixes and passing with them. - [x] Review documentation impact: update CLI operation guidance and metadata, and document domain status colors in the publishing guide. - [x] Run focused Builder, CLI, and asset-uploader tests, Builder typechecking, lint, formatting, and the generated-API check. ## Verification and limits The latest UI check passed all 49 publish tests. The preceding readiness fix passed 98 focused Builder tests and 130 CLI tests; collection coverage passed 112 tests. Typechecking, lint, formatting, and generated-API checks passed. The latest fixes do not affect fixture inputs or generated site output. Storybook screenshots and agent evaluations were not run because approval was not given. A live production publish was not performed during the latest verification. Publish can finish before advisory diagnostics do. Returned warnings appear afterward and cannot stop a publish that has already started. Standalone validation still waits for diagnostics, and actual publishing still requires content synchronization, server checks, and build/deployment work. This does not promise that every publishing timeout is eliminated. |
||
|
|
cf606ca4c3 |
fix: tolerate invalid asset metadata on load (#6419)
Malformed persisted asset metadata can prevent an entire project from opening. This PR recovers safely from invalid stored metadata and prevents the same invalid font records from being written again. ## Summary - Safely parse persisted asset metadata; malformed assets load as generic files instead of breaking the project. - Log structured diagnostics for invalid persisted font metadata without exposing the metadata contents. - Detect font uploads by extension even when sent as generic files, and preserve parsed font metadata. - Reject invalid font metadata overrides and file/font schema combinations before persistence. - Add regression coverage for the reported empty metadata, upload parsing, validation, write rejection, and read fallback. Existing malformed rows are not rewritten. They remain identifiable as generic files and can be re-uploaded after the fix is deployed. Fixes #6418 ## Verification - `pnpm --filter @webstudio-is/asset-uploader test` (301 passed) - `pnpm --filter @webstudio-is/sdk test` (573 passed) - Relevant typechecks, generated API check, formatting, and `git diff --check` passed. |
||
|
|
ade7a30560 |
perf: prepare content collections concurrently (#6412)
Ref #6396 Publishing could spend the entire serverless request budget preparing content collections one folder at a time. Projects with several collections could therefore time out before the publish diagnostics or bundle response was ready. This change: - validates independent collection folders concurrently; - discovers reserved collection files concurrently; - removes collection configuration and template files from the content index concurrently; - reuses the existing bounded content-read limit, so storage and parsing work remains capped; - keeps validation rules and published project semantics unchanged. Todo: - [x] Reproduce the affected production project returning HTTP 504 after about 15.45 seconds. - [x] Confirm the diagnostics calculation is fast locally and isolate the delay to publication asset preparation. - [x] Add regression tests for concurrent validation, reserved-file discovery, and index preparation. - [x] Demonstrate the new tests fail against the previous serial implementation. - [x] Run the full asset-uploader test suite, typecheck, formatter, linter, and diff checks. - [x] Review documentation impact: no user-facing documentation changes are needed for this internal performance fix. Verification: - pnpm --filter @webstudio-is/asset-uploader test: 296 tests passed - pnpm --filter @webstudio-is/asset-uploader typecheck - pnpm exec oxfmt --check on changed files - pnpm exec oxlint --deny-warnings on changed files - git diff --check Known limitation: The affected production deployment must be retested after this PR is deployed. The local reproduction confirms the old behavior and the focused regression tests confirm the reduced serial work, but the remote project cannot execute new server code from this branch. |
||
|
|
2a389b878c |
fix: load embedded MDX documents in previews (#6415)
## What changed Published MDX Content Blocks could build with document bindings but fail at runtime when the content index did not include the MDX source text. Dynamic article routes then returned an asset-query 500 or crashed during SSR. This change: - hydrates missing local MDX source text during CLI prebuild; - resolves document-graph references from embedded content before making an HTTP request; - adds a regression test for embedded document loading. ## Verification - published runtime tests passed (17 tests) - prebuild tests passed (69 tests) - content-engine and CLI typechecks passed - exact imported marketplace project reproduced locally and verified: SSG generated 10 pages, `/posts/designing-with-intent` returned HTTP 200 with article content, and no `ReferenceError` or asset-query 500 occurred |
||
|
|
cd1881bde6 |
fix: upload asset tickets serially (#6414)
## Summary - Reserve and complete each asset upload before requesting the next upload ticket. - Prevent concurrent identical uploads from triggering the server's in-progress deduplication error. - Keep the upload result mapping keyed by the folder-scoped upload key. ## Verification - `pnpm --filter @webstudio-is/builder exec vitest run app/builder/shared/assets/upload-assets.test.ts app/builder/shared/assets/directory-drop.test.ts app/builder/shared/assets/asset-upload.test.tsx` - 41 tests passed. |
||
|
|
0e30263787 |
fix: Fix multi-file asset drops and folder-scoped deduplication (#6413)
## Summary - Preserve all files when dropping multiple local files into Assets. - Scope client-side duplicate detection by folder. - Allow the same underlying file to have asset entries in different folders. ## Validation - Focused asset upload and directory-drop tests passed locally. - `git diff --check` passed. |
||
|
|
d6c1a3c763 |
fix: Show one Alert styling target in Markdown Embed (#6411)
Markdown Embed currently adds one general Alert descendant plus five variant-specific descendants. This shows six Alert entries in the Navigator even though they represent one element type. This keeps one Alert descendant. Note, tip, important, warning, and caution still render normally and retain their state-specific default backgrounds. Ref #6278 ## Implementation - Remove the five variant-specific Alert descendants from the Markdown Embed template. - Keep the shared Alert descendant and its `data-state` style rules. - Add a regression test for the single Alert styling target. ## Checklist - [x] Reproduce the six Alert descendants in a failing test. - [x] Keep one Alert descendant. - [x] Preserve default styles for all five variants. - [x] Run the SDK components test suite. - [x] Run SDK components typecheck and declaration generation. - [x] Run repository lint. - [x] Review documentation impact: no documentation change is needed because Markdown syntax and rendered behavior are unchanged. - [x] Review fixture impact: no fixture inputs or generated fixture bundles are affected. |
||
|
|
e7181fffdc |
feat: Add GitHub-style Alert component (#6279)
## Summary - Add one official `Alert` component with a content-editable `variant` property for note, tip, important, warning, and caution. - Register Alert in the component catalog with a generated title descendant and Storybook story. - Render GitHub-style alerts in Markdown Embed using the same DOM, class, role, and variant contract. - Materialize connected Content Block MDX alerts as actual Alert instances and serialize content or variant edits back to `> [!TYPE]`. - Document the component and both Markdown workflows. ## Implementation Alert labels and variants live in Content Engine and are shared across the component, Markdown renderer, and MDX adapters. 1. The Alert React component owns the wrapper, generated title, stable classes, `role="note"`, and `data-variant`. 2. Markdown Embed transforms candidate micromark HTML before the existing sanitizer and emits the same markup contract. It remains sanitized HTML rather than a Builder instance tree. 3. Content Engine retains alert metadata on parsed Markdown blockquotes. Project Build maps those nodes to Alert instances, reconciles their authored children, and restores canonical GitHub syntax during MDX serialization. 4. The component registry exports one Alert insertion template with a styleable title descendant. Unsupported, lowercase, misplaced, and malformed markers remain ordinary blockquotes. There are no schema, migration, persisted-data, or sanitizer-policy changes. ## Checklist - [x] Add Alert as an official component with one Variant property. - [x] Support all five GitHub alert types. - [x] Share alert metadata and marker recognition. - [x] Preserve nested Markdown and ordinary blockquote behavior. - [x] Keep URL and HTML sanitization in the existing security boundary. - [x] Add shared, title, and type-specific Markdown Embed descendants. - [x] Materialize Content Block alerts as Alert instances. - [x] Preserve alert content and variant changes through MDX serialization. - [x] Regenerate component props and Storybook artifacts from source. - [x] Review documentation impact and update Alert, Markdown Embed, Content Block, and navigation docs. - [x] Verify fixture impact; no fixture inputs or generated fixture outputs are changed. ## Verification - [x] New tests demonstrated failure before implementation and pass afterward. - [x] `pnpm --filter @webstudio-is/content-engine test` — 417 passed. - [x] `pnpm --filter @webstudio-is/project-build test` — 2,282 passed. - [x] `pnpm --filter @webstudio-is/sdk-components-react test` — 144 passed, 1 skipped. - [x] SDK component registry tests. - [x] Relevant package typechecks, declaration builds, and production builds. - [x] Root lint, formatting, package-boundary, generated-doc, and diff checks. - [x] GitHub Actions main, E2E, lint, submodule, deployment, and approved visual-regression checks. ## Known limitations Alert identifiers must be uppercase and appear at the start of the blockquote's first paragraph, matching the documented syntax. Markdown Embed emits the component's markup contract but cannot create Builder instances inside sanitized HTML. Closes #6278 |
||
|
|
18d171212f |
feat: Resolve asset paths in HTML embeds (#6409)
## Description - Resolve root-relative script, stylesheet, image, and other asset attributes in HTML Embed markup. - Use the same asset-path map in Builder Canvas and generated published sites. - Keep SaaS asset proxy URLs deployment-relative instead of hard-coding the `p-….apps.webstudio.is` project origin. - Preserve canonical `/cgi/asset/` versus `/cgi/image/` routing and `?format=raw` behavior in Canvas. ## Regression coverage Added coverage for SaaS prebuild URLs, the real Builder asset-map-to-HTML-Embed integration, every supported asset attribute, HTML character references, and responsive-image `srcset` edge cases. ## Verification - [x] CLI prebuild suite: 69 passed - [x] HTML Embed suites: 63 passed - [x] Full Builder browser suite: 2,646 passed - [x] Asset URL map tests: 2 passed - [x] CLI, Builder, React SDK, and project-build typechecks - [x] Lint and package-boundary checks - [x] Previous PR CI: 29 successful, 1 skipped ## Code Review - [x] Self-reviewed - [x] Added regression and integration tests |
||
|
|
60c549c46f |
fix: preserve local styles and improve issue diagnostics (#6408)
Fixes #6386 ## Summary - Keep local `ws:style` declarations after `ws:tokens` so instance styles override token defaults. - Capture privacy-safe HTTP timing/status, exceptional session namespace states, preview freshness/version agreement, and validation paths in issue reports. - Derive reportable validation roots from the public operation catalog instead of maintaining a duplicate allowlist. - Keep captured failures current by clearing them after a successful tool call. ## Verification - Protocol issue-report tests: 3 passed - Project build MCP: 128 tests passed - CLI project session: 27 tests passed - Builder issue reporter: 5 tests passed - Relevant package typechecks passed - Generated API metadata is clean |
||
|
|
dd4bbabf79 |
fix: preserve text animation content during cleanup (#6383)
Updates the animation component to include webstudio-is/sdk-components-animation#35. On canvas, HTML Embed can replace its DOM before Text Animation cleanup runs. Cleanup now avoids detached sibling references and preserves the replacement content. This PR currently points to the reviewed branch commit from animation PR #35 and should merge after that PR. If #35 is squash-merged, the submodule pointer must be refreshed to its resulting main commit. Tests: - Focused browser tests pass in Chromium and Firefox: 14/14 assertions. |
||
|
|
fc15ebf81a |
perf: avoid repeated MDX parsing in publish diagnostics (#6407)
## Description The cold `build.contentDatabasePublishDiagnostics` path was parsing the same reachable MDX documents while the publication plan converged, then parsing them a third time to produce omission diagnostics. Content-heavy projects can approach or exceed the 15-second serverless limit on that first request. This change: - creates a request-scoped MDX dependency resolver that reuses parse results by asset revision while the publication plan converges; - carries the final template omissions out of the existing publication pass, so the diagnostics endpoint does not walk the artifact again; - keeps the existing sequential asset validation/preparation/stability checks unchanged; - does not use module-level caching or depend on a warm serverless instance; - leaves the timeout error handling from #6406 unchanged. ## Performance evidence An isolated cold-path benchmark used the same MDX payload (2,000 sections) and compared the previous three independent dependency-resolution walks with the new request-scoped convergence path: | path | time | | --- | ---: | | before | 1,178 ms | | after | 404 ms | That is a 66% reduction in the measured MDX resolution phase. The tests also assert the underlying work reduction directly: an unchanged revision is parsed once across convergence passes, while a changed revision is parsed again. For a stable 214-document candidate set, this removes up to 428 of the previous 642 parse operations. ## Verification - `pnpm --filter @webstudio-is/project-build test` — 2,420 tests passed - `pnpm --filter @webstudio-is/builder exec vitest run --project core-server` — 336 tests passed, including server-side e2e runner tests - `pnpm --filter @webstudio-is/project-build typecheck` - `pnpm --filter @webstudio-is/builder typecheck` - `pnpm lint` - `pnpm check:package-boundaries` - `pnpm check:generated-api` ## Code Review - [x] made a self-review - [x] added comments for the request-scoped cache and revision safety - [x] added tests for parse reuse, revision invalidation, and the optimized endpoint integration path ## Before merging - [ ] tested on a deployment preview with a production-sized content project ## Additional content-read optimization Successive compilation plans now share already-fetched, revision-keyed content bytes within one callback-scoped preparation session. The byte store: - is created inside one asset-stability attempt and discarded when that attempt finishes; - is not stored on the repository, in a module, or outside the request; - remains bounded by the existing 2 MiB hydration limit; - refetches changed revisions and starts clean on stability retries. Tests verify that two overlapping plans read unchanged content once, a revision change forces another read, a new session reads again, and a stability retry creates a new session. A fully overlapping two-pass workload therefore performs up to 50% fewer object-storage content reads. Additional verification: - `pnpm --filter @webstudio-is/asset-uploader test` — 292 tests passed - `pnpm --filter @webstudio-is/asset-uploader typecheck` ## Remaining optimization assessment The percentages below estimate whole-request improvement and are workload-dependent; they are not additive. | optimization | estimated improvement | complexity | decision | | --- | ---: | ---: | --- | | Request-local content-byte reuse | 10–35% | 3/10 | Implemented | | Stop when the initial dependency plan is already a fixed point | 5–15% for static/known MDX; ~0% for dynamic discovery | 2/10 | Implemented | | Reuse a canonical source snapshot/materialized entries across different plans | 15–30% | 8/10 | Deferred: large semantic and invalidation surface | | Reuse the bundle's initial asset-data snapshot | 1–5% | 5/10 | Not worthwhile | | Add a diagnostics-specific bundle loader | 2–8% | 6/10 | Not worthwhile for this PR | | Parallelize or skip unrelated user/project metadata | 0–3% | 2/10 | Not meaningful | | Combine collection validation and reserved-asset inspection | 0–5% normally | 4/10 | Only meaningful for projects with many collections | The fixed-point fast path is covered by a test asserting one artifact preparation and one dependency-resolution call when the original plan is already stable. |
||
|
|
ea17eaa3c4 |
docs: explain the complete Content Engine workflow (#6403)
## What changed - Add the complete Content Engine video tutorial to the main guide. - Explain the launch benefits before the step-by-step setup: file-based content, visual MDX editing, designed templates, collection entry forms, and MCP automation. - Document collection entry creation and editing in Content mode. - Explain content collection folders in the Assets guide. - Document that shared Slots cannot be used inside Content Block Templates. - Add missing links between Content Engine and Content Block documentation. ## Release documentation audit Reviewed the shipped MDX-backed Content Block, MDX template, structured collection entry, collection authoring, query diagnostic, publication warning, and asset-path changes. The detailed feature docs already cover their implementation-specific behavior. This PR fills the remaining discovery and workflow gaps across the main Content Engine, Assets, Modes, and Content Block pages. ## Todo - [x] Add the launch video to the Content Engine guide. - [x] Update the main launch value proposition and supported scale. - [x] Document collection workflows in Assets and Content mode. - [x] Document the shared-Slot limitation for Content Block Templates. - [x] Review documentation impact and navigation. - [x] Verify generated documentation remains clean. - [x] Verify changed relative links resolve. ## Verification - Content Engine documentation tests: 2 passed - Generated Content Engine and MCP documentation checks: passed - Documentation TypeScript check: passed - Relative link check: passed - Git diff whitespace check: passed The repository formatter excludes these GitBook Markdown files, so the pre-commit formatting task had no eligible targets. No fixture inputs or generated fixture outputs are affected. |
||
|
|
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 |
||
|
|
aa1587c100 |
fix: Clarify publish timeout errors (#6406)
## Summary - detect pre-publish HTTP timeouts from the response metadata already attached to `TRPCClientError` - show a clear publish-specific message instead of the JSON parser error - cover both HTTP 504 and Vercel timeout responses ## Why When `build.contentDatabasePublishDiagnostics` exceeds the serverless function duration, the proxy returns HTML or plain text. tRPC's JSON parser fails, but the resulting client error still contains the original HTTP response. The publish flow now uses that response to report: > Pre-publish checks timed out. Publishing was not started. Please try again. This PR intentionally does not change the shared tRPC transport or claim to solve the underlying diagnostics performance problem. ## Verification - `pnpm --filter @webstudio-is/builder exec vitest run --project core-browser-builder-features app/builder/features/publish/publish-error.test.ts` - `pnpm --filter @webstudio-is/builder typecheck` - `pnpm exec oxlint --deny-warnings <changed files>` - `pnpm exec oxfmt --check <changed files>` |
||
|
|
f23007457d |
fix(content-engine): normalize asset path filters (#6389)
## Description Fixes Assets path filters so authors can use visible folder and file names while canonical stored paths remain URL-encoded. - normalizes path filter operands segment by segment without double encoding - preserves already encoded filters and literal string matching behavior - covers equality, inequality, membership, contains, starts-with, and ends-with operators with spaces and URL-significant characters - verifies local/Preview database execution and published runtime return the same result - documents visible path input in the generated Content Engine reference Closes #6388 ## Steps for reproduction 1. Create an Assets folder named `Tutorial posts`. 2. Add an MDX file inside it. 3. Create an Assets system resource with `path starts with "Tutorial posts/"`. 4. Preview the query and expect the MDX file to match. 5. Change the value to `Tutorial%20posts/` and expect the same result for backward compatibility. ## Regression proof Before the implementation, the focused reproduction failed because the matcher returned no items: expected `["alpha"]`, received `[]`. With the fix, the expanded path-operator regression suite passes. ## Verification - [x] Content Engine test suite: 47 files, 577 tests passed - [x] Content Engine typecheck - [x] CLI typecheck - [x] Repository lint with warnings denied - [x] Formatting check for every changed source/test file - [x] Content Engine documentation test - [x] Content Engine and MCP documentation generation is idempotent - [x] Webstudio Features fixture generation is idempotent and typechecks - [x] No agent evaluations were run ## Documentation impact Updated the authoritative CLI Content Engine reference source and regenerated the Builder Content Engine and MCP documentation. The new guidance tells users to enter visible path names and notes that existing encoded filters remain supported. ## Code Review - [ ] hi @kof, I need you to do - conceptual review (architecture, feature-correctness) - detailed review (read every line) - test it on preview ## Before requesting a review - [x] made a self-review - [x] added inline comments where behavior is not obvious ## Before merging - [ ] tested on preview environment (preview dev login: 0000) - [ ] updated test cases document (not needed; automated regression and authoritative user docs were updated) - [x] added tests - [x] no new environment variables |
||
|
|
3531089965 |
fix: fall back to pnpm for generated previews (#6382)
## Description Fixes #6381. Generated preview previously defaulted to npm whenever launcher metadata was unavailable, even when npm was absent and pnpm was installed. Resolve npm from PATH first and fall back to pnpm, using the same resolver for dependency installation and preview commands. The React Router Vite plugin is already declared by the generated template, so no dependency duplication or compatibility wrapper is needed. ## Verification - 47 focused preview/package-manager tests pass - CLI typecheck passes - repository lint passes - formatting and generated CLI docs are current ## Code Review - [x] made a self-review - [x] added regression tests - [x] no new environment variables |
||
|
|
b7a11e4bc2 |
feat: Delay canvas scripts until resources render (#6380)
HTML Embed scripts in canvas and preview now wait until the complete
resource queue settles. Their markup remains rendered while loading;
only executable scripts are delayed, so scripts can read the committed
resource-backed DOM without requiring a custom event.
## Implementation
- Add an internal `$resourcesState` atom with `pending` and `settled`
states, driven by the complete resource queue.
- Synchronize the atom from the Builder to the canvas iframe.
- At the Builder component-render boundary, pass only HTML Embed the
private prop `$ws$executeScripts={isSafeMode !== true && resourcesState
=== "settled"}`.
- In the SDK HTML Embed component, default `$ws$executeScripts` to
`true`, keep markup inert while it is false, and execute scripts after
React commits the transition to true.
- Treat failed requests as settled so scripts cannot wait forever.
- Keep the private prop out of generated component arguments and
metadata through the existing `$`-prefixed prop convention.
- Keep published rendering unchanged because published sites do not pass
the private Builder prop.
- Keep the existing standard `DOMContentLoaded` / `load` compatibility
and sequential script queue.
- Remove the canvas wrapper and component-registry override.
## Todo
- [x] Track collective resource readiness in the Builder.
- [x] Synchronize readiness into the canvas.
- [x] Delay HTML Embed scripts in both canvas and preview.
- [x] Combine safe mode and resource readiness into one private
execution prop.
- [x] Preserve rendered HTML while scripts are delayed.
- [x] Preserve pages with no resources and failed-resource behavior.
- [x] Keep the private prop out of user-facing component metadata.
- [x] Add resource-state, sync, Builder-prop, and browser regression
tests.
- [x] Review documentation impact; no user-facing documentation changes
are needed.
- [x] Review fixture impact; no fixture inputs or generated outputs are
affected.
## Verification
- SDK HTML Embed browser tests — 44 passed
- Builder private-prop tests — 15 passed
- Resource tests — 28 passed
- Sync tests — 14 passed
- React SDK, SDK components, and Builder typechecks — passed
- Focused Oxlint and formatting — passed
Closes #6379
|
||
|
|
9963c95ef8 |
fix: Sync OAuth profile fields on login (#6376)
Closes #6375 ## Summary - Refresh username, avatar, and provider fields when an existing user logs in through OAuth. - Avoid unnecessary database writes when profile fields are unchanged. - Preserve existing development-login behavior. - Add regression coverage for changed GitHub profile data. ## Testing - `pnpm --filter @webstudio-is/builder exec vitest run --project core-server app/shared/db/user.server.test.ts` - `pnpm --filter @webstudio-is/builder typecheck` |
||
|
|
2aec79774e |
fix: focus spacing input when popover opens (#6374)
## Description Restore automatic focus to the CSS value input when the spacing popover opens. The property label became focusable after its migration to `ResettableLabel`, making it the first tabbable element in the popover and causing Radix to focus the label. Marking the intended value input with `autoFocus` makes React focus it as the popover content mounts; Radix then detects that focus is already inside its focus scope and preserves it. ## Steps for reproduction 1. Select an element. 2. Open the Style panel spacing section. 3. Click any margin or padding value. 4. Verify focus is placed in the CSS value input. ## Verification - [x] Builder typecheck - [x] Prettier check - [x] Oxlint - [x] `git diff --check` ## Code Review - [ ] conceptual review - [ ] detailed review - [ ] test on preview |
||
|
|
bd414eb53e |
fix: Fix text animation crash with leading HTML embed text (#6378)
Updates the animation component to include webstudio-is/sdk-components-animation#34. An HTML Embed that starts with raw text no longer crashes when placed inside Text Animation. The component now restores adjacent text nodes in a safe order during cleanup. Tests: - Focused browser test passes in Chromium and Firefox: 12/12 assertions. |
||
|
|
649ee3669d |
fix: Batch asset queries during project import (#6368)
## Problem Project import sent every asset filename in one database request. Large projects produced an oversized URL and failed before assets could upload. Closes #6367 ## Changes - [x] Reuse the existing encoded filename chunking rule for imports - [x] Batch imported file lookup and restore requests - [x] Add regression coverage for long filename lists - [x] Review documentation impact: no user-facing documentation changes are needed ## Verification - [x] Builder import tests: 21 passed - [x] Asset uploader tests: 50 passed - [x] Builder and asset-uploader typechecks - [x] Lint, formatting, and diff checks - [x] Real CLI import passed the original metadata lookup and began uploading 380 assets - [ ] Agent evaluations were not run; they require separate approval The real import later reached the target project's separate 350-asset limit. That limit is outside this fix. |
||
|
|
5d34b77fac |
feat: Improve collection entry authoring (#6361)
Collection authors and editors get clearer field help, direct entry navigation, and actionable validation instead of warnings that point at the wrong place. Closes #6360 ## Implementation - [x] Keep resettable help open after a click while the label remains hovered - [x] Stop repeating the property label inside resettable help - [x] Store JSON Schema field descriptions and show them in entry forms - [x] Add an optional dynamic collection entry page for explicit canvas navigation - [x] Rename entry file actions to **Edit file** - [x] Add **Open on canvas** to entry menus and Entry settings - [x] Put the entry filename in the Entry settings title - [x] Make collection validation banners explain the problem and open the first affected entry - [x] Remove false output-only `UNOBSERVED_FIELD` warnings while keeping filter and sort diagnostics - [x] Encourage useful field descriptions in general MCP collection guidance - [x] Update Content Engine documentation - [x] Confirm no database migration is required - [x] Regenerate the affected asset-query runtime fixture - [ ] Visually review the affected Storybook states in light and dark themes - [ ] Run the complete local agent evaluation suite - [x] Run broader package and Builder checks - [x] Complete final diff review ## Technical notes - `entryPageId` lives in `collection.json` under `x-webstudio`; no database schema changes are needed. - Entry creation still leaves the current canvas unchanged. Canvas navigation only happens after the user selects **Open on canvas**. - An entry page must contain exactly one URL parameter. The entry filename supplies that parameter, so the page can identify the selected entry. - Output projection fields are schemaless and may be produced after reference resolution, so catalog absence is no longer reported there. Filter and sort fields still report catalog diagnostics. - The structured-query runtime change affects the generated `webstudio-features` fixture, which is regenerated in this PR. ## Verification - 561 Content Engine tests - 2,413 Project Build tests - 253 Design System tests - 1,794 Builder tests - 67 focused Builder regression tests after the final navigation change - 11 ResettableLabel browser tests - 128 focused MCP tests - Builder, Content Engine, Design System, and Project Build typechecks - Repository lint and package-boundary checks - Generated documentation checks - Full workspace fixture build with `pnpm -r fixtures:build` - Formatting and diff checks - New regression tests were demonstrated failing before their fixes and passing afterward ## Documentation impact - [x] Updated the Content Engine guide for field descriptions, dynamic entry pages, actionable validation, **Edit file**, and **Open on canvas** - [x] Updated MCP guidance so collection fields include editor-facing descriptions |
||
|
|
d6375096ff |
fix: improve asset upload retries and diagnostics (#6364)
## Summary - retry only transient asset upload failures after a short backoff - return ASSET_UPLOAD_RETRY_EXHAUSTED with retryability and HTTP status for persistent failures - preserve successful batch uploads and support retrying the failed JPEG alone ## Verification - pnpm --filter @webstudio-is/http-client test -- src/index.test.ts - pnpm --filter @webstudio-is/http-client typecheck - pnpm --filter webstudio test -- src/error-codes.test.ts Fixes #6363 |
||
|
|
39c290bfa7 |
fix: resolve MCP-reported runtime and component issues (#6362)
## Summary - harden MCP runtime behavior around asset uploads and resources, HTTP responses, component and Content Block application, data reads, and Chromium screenshots - reject shared Slots inside Content Block templates and avoid unsafe unused-asset findings when Content Blocks can hide MDX dependencies - expand named grid-area values according to CSS shorthand fallback rules - add a consent-safe YouTube preconnect control and only warm origins that are actually used - add focused and end-to-end regression coverage for the reported paths ## Verification - project-build: 2,419 tests passed - css-data: 4,623 tests passed, 1 skipped - sdk-components-react: 134 tests passed, 1 skipped - high-impact CLI fixture: 7 tests passed - Builder asset REST service: 22 tests passed Closes #6336 Closes #6339 Closes #6353 Closes #6354 Closes #6355 Closes #6356 Closes #6357 Closes #6358 Closes #6359 |
||
|
|
eb61139e5a |
feat: Scale publishing allowance with workspace seats (#6352)
Builder already counts production builds for the project owner, including publishes created through MCP and CLI. This change scales the allowance used by Builder with the owner's paid seat capacity, so five seats at 100 publishes each give 500 publishes per day. Free stays at 10. Closes #6351 ## Implementation The existing `userPublishCount` endpoint still reads the owner-wide `user_publish_count` view. For a project, it now returns the project owner's base allowance multiplied by the owner, included member seats, and purchased extra seats. Builder uses that returned allowance in its existing publish UI. The count remains owner-wide. MCP and CLI publishes contribute to it because they create production build records, but their publish endpoints do not enforce this Builder-side limit. No database, server publish-path, dependency, fixture, or generated-file changes are included. ## Checklist - [x] Calculate the paid allowance from the owner, included seats, and purchased extra seats. - [x] Keep Free at 10 publishes per day. - [x] Reuse the existing owner-wide publish count. - [x] Use the calculated allowance in Builder. - [x] Review documentation impact; no Builder documentation changes are needed for this small allowance update. - [ ] Update the pricing page to explain the publishing allowance and how seats increase it. - [x] Review fixture impact; fixture inputs and outputs are unchanged. - [x] Review the final diff for unnecessary changes. ## Verification - The project router tests pass, including the five-seat 500-publish allowance. - The new assertion fails against the previous implementation and passes with this change. - Builder browser tests passed. - Project and Builder typechecks passed. - Formatting, lint, and package-boundary checks passed. - All GitHub Actions workflows passed. - Agent evaluations do not cover this flow and were not run. |
||
|
|
2c51bc9928 |
fix: Restore Cloudflare publishing with Wrangler 4 (#6350)
Publishing fails because Wrangler 3 cannot parse the JSON import attributes used by `html-tags@4`. Upgrade the CLI and Cloudflare template to Wrangler 4.130.0 and regenerate the fixture and lockfile used to package the publish artifact. Wrangler 4 also rejects Worker deployment when it finds the Pages configuration. Add a SaaS-only `wrangler.jsonc` that takes precedence over the Pages template's TOML configuration. Publish commands still supply the Worker name and compatibility date. Fix the staging smoke check's compatibility-date scope and shell expansion. - [x] Upgrade Wrangler and regenerate the publish fixture and lockfile. - [x] Reproduce the original parser failure and verify it passes with Wrangler 4. - [x] Build the packaged artifact and pass the staging smoke check and both SaaS publish dry runs, including dispatch-namespace arguments. - [x] Pass 383 existing template tests, CLI and fixture typechecks, repository lint, and all fixture generation from checked-in data. - [x] Review documentation impact: no user-facing documentation changes are required; the existing Node 22.12+ requirement remains sufficient. - [ ] Complete staging CI and manually test publishing. [Publish artifact build](https://github.com/webstudio-is/webstudio/actions/runs/34400149252) is running; [staging deployment](https://github.com/webstudio-is/webstudio/actions/runs/34400149301) is queued. Remix 2 still declares a Wrangler 3 peer dependency; the packaged production build and both publish dry runs passed with v4. Agent evaluations were not run. |
||
|
|
13952a7d34 |
fix: Preserve Global root tokens when importing templates (#6348)
Inserting the CMS Sitemap marketplace page could detach existing Global root tokens and break styles across existing pages. Preserve the root's existing style-source selections in their original order, then append mapped incoming sources without duplicates. Incoming local declarations continue to merge into the existing root local source. The MDX save fix is now included in main through `commitAssetContentUpdate`. This PR retains an E2E assertion that saved MDX revisions are not persisted again through `build.patch`. Closes #6347 Verification and delivery: - [x] Add four regression cases covering empty, local-only, token-only, and mixed incoming root selections, including repeated imports, token remapping, and local declaration merging. All four failed before the fix and pass after it. - [x] Rebase onto main and rerun style-copy and page-copy tests: 55 passed. Formatting and diff checks passed. - [x] Verify the cloned project locally: reproduce the broken Home canvas before the fix and restore it with Undo. After the fix, insert Sitemap and verify Home retains its logo sizing, typography, spacing, rounded corners, and both Global root tokens after reload. - [x] Verify the MDX E2E assertion fails with duplicate persistence and passes with the fix. Before rebase, all 13 shard 4 tests passed locally with four workers, along with relevant typecheck and lint checks. - [x] Resolve the rebase conflict using main's shared MDX implementation and remove the duplicate helper from this branch. - [x] Review documentation impact against marketplace, CSS-variable, and Content Block documentation: no documentation changes required. - [x] Review fixture impact: no fixture inputs, serialization formats, or generated contracts changed. No migrations are required. This prevents future imports from dropping root selections; it does not reconstruct selections already lost in previously saved projects. |
||
|
|
e69a3d2f8e |
feat: Create structured MDX entries from collection folders (#6317)
## Paragraph editing follow-up — |
||
|
|
d991b25b65 |
fix: Accept description-list groups wrapped in divs (#6346)
Pasting `<dl><div><dt>Company</dt><dd>XXX</dd></div></dl>` incorrectly warns that placing `dt` inside `div` violates HTML. The [HTML standard](https://html.spec.whatwg.org/multipage/grouping-content.html#the-dl-element) allows these groups. The shared validator now tracks the rendered HTML parent explicitly and gives a `div` directly under `dl` the description-group content model. Parent context passes through Slots and Fragments and works when validation starts within the list. Ordinary divs and extra HTML wrappers still reject `dt`/`dd`; group divs reject unrelated flow children. No synthetic category can be mistaken for an allowed HTML tag. - [x] Fix contextual validation without changing generated HTML data. - [x] Add nine regression cases with before/after failure verification. - [x] Run 170 tests covering content models, matching, components, and pre-publish audits. - [x] Pass project-build typecheck, repository lint, formatting, and diff checks. - [x] Review the patch and fix the internal-marker validation bypass. - [x] Review documentation impact: no update needed; this restores valid HTML support. - [x] Review fixture impact: no description-list fixture inputs or generated outputs are affected. - [x] Confirm CI passes on the final commit before merging: all workflows passed on `4ce4cf6696`, including all six browser-test shards. This remains a nesting check; enforcing term/definition order or counts is outside this fix. Agent evaluations and local browser E2E were not run; CI runs the browser suites. Closes #6345 |
||
|
|
e33ce76489 |
fix: Keep image picker width stable and accept quick clicks (#6344)
Choosing an image now works with a quick thumbnail click, and selecting an asset keeps the Source picker at its intended width, including long names and nested folder paths. The dialog's content-based width was overriding the floating panel's width. Focusing a thumbnail widened the panel, triggering resize handling that briefly disabled pointer events before mouse release. Pass the floating panel styles through the dialog's `css` override so the intended width wins. Explicit dimensions and drag/resize handlers remain as implemented. Closes #6343 - [x] Reproduce both failures in Chromium using the actual Source picker. - [x] Fix floating panel style precedence. - [x] Add three regressions for root and nested asset selection widths and an 80 ms thumbnail click. All three fail without the fix and pass with it. - [x] Run related Builder tests (50 passed), the design-system suite (228 passed), both package typechecks, repository lint, and formatting. - [x] Review documentation impact: the Image Source instructions already describe the restored behavior; no update needed. - [x] Verify no fixture inputs or generated outputs are affected. Validation used headless Chromium component tests. Full canvas E2E and Storybook screenshot checks were not run. |
||
|
|
722b3af113 |
feat: Copy links to instances from the context menu (#6342)
Right-click an instance in the Navigator and choose **Copy link to
instance** to share its full Builder URL. Opening it restores the page
and the same instance occurrence, including descendants of shared Slots.
The shared menu also exposes the action on the canvas.
Copying and opening a link use the same existing
`getDeepLinkedInstanceSelection` function, moved unchanged from
`use-switch-page.ts` into `shared/instance-utils/link.ts`, alongside URL
creation and the existing instance URL parser. It validates the instance
path and page access. The context menu and pre-publish “Show element”
links both call `getInstanceLink(instanceSelector)`. It lives in
`shared/instance-utils/link.ts` and owns validation and the complete URL
setup: project, page, full selector, origin, share token, editor mode,
and safe mode, using the existing `builderUrl`. There is no separate
link-permission implementation.
The link keeps the current share access and editor mode, clears
unrelated scroll anchors, and shows clipboard success or failure. Body
is supported; Global Root and multiple selections are unavailable.
Instance-only navigation now preserves loaded Builder data: the route
comparison recognizes the `instance` parameter as well as the older
`instanceId`. A functional regression test confirms that changing the
target does not change the data URL comparison, while changing share
access does.
MCP guidance explains how to extract the target ID from the link for
`inspect-instance`, verify the project and shared Slot context, and
avoid guessing when an instance no longer exists. This does not add a
URL-taking MCP endpoint.
1. [x] Add the menu action and reuse complete instance-link construction
with pre-publish links.
2. [x] Share existing instance-link validation between copying and
opening links.
3. [x] Update the Navigator and MCP guidance; regenerate CLI
documentation.
4. [x] Extend the existing functional test to round-trip a shared Slot
URL, including share access and editor mode. Verify it fails without the
instance parameter and passes after restoration.
5. [x] Remove the React/clipboard test harness and duplicate
permission-test matrix. Confirm no fixture inputs or outputs are
affected.
Validation: 28 focused Builder tests, Builder typecheck, repository
lint, and `git diff --check` pass on this revision. The earlier CLI
documentation checks passed and their inputs are unchanged. An earlier
GPT-5.4 mini subagent at low reasoning passed a focused native MCP test
against commit
|
||
|
|
05706b5425 |
feat: Make Content Block templates the MDX authoring interface (#6307)
Closes #6306 ## Outcome Content Block templates are now the public component model for MDX authoring. - Standard Markdown resolves through matching Content Block templates. - PascalCase JSX resolves to a named template first, then to a registered component. - Adding or changing a template immediately affects matching MDX, including content authored before that template existed. - Every supported standard MDX element is present in new Content Blocks by default. - Template `name` is a stable PascalCase JSX identifier. `label` remains optional display text only. - Lowercase JSX represents native HTML and SVG without exposing `ws.element` in authored syntax. - Unknown, ambiguous, and unsafe JSX stays in source, produces a source-ranged Builder diagnostic, and is omitted from published output. - Frontmatter images preserve exact `$ref` values and use the Asset description for `alt` text. - Keyboard and mouse insertion from the slash menu remove the trigger slash and preserve the selected template. ## Public MDX contract - Markdown is canonical for standard prose. - Lowercase JSX creates native elements: `<section><p>Text</p></section>`. - PascalCase JSX uses templates and registered components: `<PromotionCard />`, `<Heading tag="h1">Title</Heading>`, and `<YouTube src="https://youtu.be/KI5JHpzBK1s" />`. - Component-name collisions use stable qualified identifiers such as `Checkbox` and `RadixCheckbox`. - A self-closing template keeps its designed default subtree. An explicitly paired empty template clears it. - Static quoted values and bare booleans are supported. - Imports, exports, expressions, spreads, functions, executable JavaScript, unsafe attributes, `<$.*>`, and authored `<ws.element>` are rejected. - `ws` remains only for compiler primitives with no React component. ## Implementation - [x] Add stable, unique template names and keep them separate from labels. - [x] Parse and validate Markdown and JSX through their ASTs with precise source ranges. - [x] Share component identity between template JSX, Content MDX, Builder materialization, reload, copy, and publication. - [x] Resolve templates live after add, edit, rename, reorder, removal, undo/redo, collaboration updates, and reload. - [x] Preserve authored props, children, Asset references, template defaults, and the exact slash-menu template choice. - [x] Make one typed MDX semantic inventory drive default templates and slash-menu eligibility. - [x] Move component-dependent template assembly into the component registry. - [x] Replace production `$`, `animation`, and `radix` JSX namespaces with direct component imports. - [x] Keep only explicit compiler primitives in `ws` template JSX. - [x] Migrate repository templates, fixtures, stories, examples, MCP guidance, CLI guidance, and generated outputs. - [x] Add Builder unit and Playwright coverage for authoring, diagnostics, insertion, synchronization, reload, and publication. - [x] Review and update the authoritative Content Block and generated MCP documentation. ## Compatibility - Persisted project data continues to use namespaced component IDs and `ws:element` for generic HTML elements. No project-data migration is required. - Legacy `<ws.element ws:tag="…">`, `<ws.element ws:name="…">`, `<$.*>`, `<animation.*>`, and `<radix.*>` input remains readable during the compatibility window. - Current serializers and repository-owned sources emit only canonical Markdown, lowercase intrinsic JSX, or PascalCase identifiers. - Untouched user MDX is not rewritten automatically. Legacy syntax is canonicalized when its owning source is edited. - Deferred follow-up: remove legacy namespace readers and proxy support only after the canonical writer is deployed and existing projects are backfilled. This is intentionally outside this PR. ## Verification - [x] CI package tests, typechecks, lint, package boundaries, generated assets, migrations, and size checks pass. - [x] All six Builder E2E shards pass. - [x] Fixture checks pass on Ubuntu and Windows. - [x] Targeted local Content Engine, Template, SDK, registry, Project Build, migration, Builder, component, CLI, and Playwright tests pass. - [x] Runtime contracts, CLI docs, and MCP docs were regenerated from their owning sources. - [x] Local fixture generation completed without an unexpected fixture diff. - [x] Documentation impact reviewed and included in this PR. - [x] Review and approve the intentional List visual snapshot change. - [x] Run the complete agent evaluation suite after explicit approval. - [x] Run the network fixture link/sync pipeline against the matching PR deployment after explicit permission. ## Known visual change The generated List story now targets its actual default `ul` element instead of `ol`, so the default list styling appears in the visual snapshot. The visual change was reviewed and the approved visual check passes. |
||
|
|
2e39477303 |
feat: Expose Force Mount for Collapsible Content (#6338)
## Problem Closed Collapsible Content is removed from the HTML, and the Builder does not expose Radix’s Force Mount option. ## Solution - Expose **Force Mount** as a boolean on Collapsible Content. - Enable it for newly inserted Collapsible templates. - Keep closed force-mounted content visually collapsed with template styles. - Preserve the existing Radix default for existing instances that do not set the prop. - Add regression coverage for the template default and generated Builder metadata. ## Checklist - [x] Expose the Force Mount control - [x] Keep new Collapsible content mounted while closed - [x] Preserve existing-instance behavior - [x] Regenerate Collapsible prop metadata from source - [x] Add regression coverage - [x] Review documentation impact and update the Collapsible guide - [x] Verify fixture inputs and outputs are not affected ## Verification - [x] `pnpm --filter @webstudio-is/sdk-components-react-radix test` — 20 tests passed - [x] `pnpm --filter @webstudio-is/sdk-components-react-radix typecheck` - [x] `pnpm --filter @webstudio-is/sdk-components-react-radix build` - [x] Targeted Oxlint and formatting checks - [x] `git diff --check` ## Known limitations Storybook visual verification was not run because it requires separate approval. Closes #6337 |
||
|
|
55920c57c4 |
fix: Show all Markdown and Assets query diagnostics (#6308)
Ref #6305 ## Outcome Show actionable Markdown, MDX, and Assets query problems in the editor, query Diagnostics, API, and MCP. The current implementation substantially improves source diagnostics, query error aggregation, query scoping, exact paths, MCP feedback, and loading states. The exhaustive audit below also records what is not complete yet. ## Completion rule An error state is complete only when all applicable checks pass: - [x] The editor uses the production validator and shows every issue for the open file. - [x] Query execution uses the same validation and returns every issue for every file that matches the query, not only the returned page. - [ ] MCP can reproduce the state through a real tool call and returns the same code, severity, message, file, and location. - [x] Diagnostics shows fatal errors and nonfatal warnings in the correct place. - [x] Exact file is always present; line and column are present whenever the parser can determine them. - [x] Multiple issues in the same file, multiple files, and multiple validation phases are returned together. - [ ] A regression test proves failure without the behavior and success with it. ## Cross-surface contract ### Required validator parity - [x] Editor, query execution, and MCP file operations invoke the same exported production file-validation pipeline for byte decoding, source/frontmatter, Markdown/MDX, Content Block semantics, and references. Copied schemas, adapter-only checks, or reimplementations do not count as parity. - [x] Query builder, query execution, `validate-asset-query`, and `preview-asset-query` invoke the same exported structural and catalog-aware semantic query validator with the same project snapshot and context. - [x] Every surface preserves the same complete, deterministically ordered diagnostic array: severity, code, message, phase/scope, asset ID, file path, line/column/range, query path, and fatal-versus-warning/result behavior. UI, API, and MCP serializers must not drop or remap fields. - [ ] A table-driven contract suite calls the real editor, query, API, and MCP entry points—including MCP upload, update, download, validate, and preview—and compares full normalized arrays for multiple errors, multiple warnings, multiple files, and pre-pagination matches. - [x] Markdown and MDX source syntax/frontmatter use validateTextAssetSource in editor, query compilation, and MCP file tools. - [x] Query request execution and MCP local parsing use assetQueryRequest. - [x] Fatal query setup errors retain all detected semantic errors and accompanying warnings. - [x] Nonfatal query warnings retain a stable code and exact query path. - [x] Source diagnostics retain severity, phase, code, asset ID, path, and available source position. - [x] Query Diagnostics excludes diagnostics produced only by unrelated published queries. - [x] Query, Preview, and Diagnostics tabs show loading states. - [x] Authenticated diagnostics can show a sanitized internal message; public/pre-auth errors remain redacted. - [x] Share byte-level UTF-8 validation instead of decoding separately in query and MCP. - [x] Make the query editor and MCP call one literal shared query-validation function before execution. - [x] Share cross-file reference validation across editor, query, and MCP file operations. - [x] Share contextual Content Block/template validation across all applicable surfaces. - [x] Preserve an invalid stored query in the editor and explain it instead of replacing it with defaults. - [x] Define and enforce whether “matches the query” includes every pre-pagination match; current source validation follows returned/paginated IDs. - [x] Continue through source, reference, and runtime phases where safe so one phase does not hide later issues. - [x] Map every user-triggerable graph/storage/runtime failure to a structured public error instead of INTERNAL_ERROR. - [ ] Label candidate-file warnings separately from returned-file diagnostics. ## File transport and encoding - [x] Empty Markdown and MDX are accepted. - [x] UTF-8 BOM and CRLF are accepted. - [x] Whole Markdown/MDX file over 1 MiB is detected. - [x] Missing or unavailable selected content is reported. - [x] Invalid UTF-8 frontmatter returns the same structured diagnostic in query and MCP. - [x] Invalid UTF-8 body returns the same structured diagnostic in query and MCP. - [x] MCP download must use fatal UTF-8 decoding rather than replacement characters. - [x] Validate bytes before committing an upload, or return the committed Asset ID and explicit cleanup state when post-commit feedback fails. - [x] Reject filename/format mismatches instead of allowing either hint to bypass Markdown/MDX validation. - [x] Storage status, missing body, invalid metadata, revision mismatch, format mismatch, short read, and excess read each return structured file context. - [x] Content changing during validation has a clear retryable conflict diagnostic. ## Frontmatter - [x] No frontmatter. - [x] Empty frontmatter. - [x] Opening delimiter without a closing delimiter. - [x] Frontmatter over 64 KiB. - [x] Invalid YAML grammar. - [x] Multiple YAML parser errors. - [x] Duplicate keys. - [x] YAML aliases. - [x] Unsupported YAML tags. - [x] Scalar or array root instead of an object. - [x] Non-JSON values, NaN, Infinity, and unsafe integers. - [x] Nesting deeper than 8. - [x] More than 256 fields/array entries. - [x] One string over 16 KiB. - [x] Normalized indexed properties over 64 KiB. - [x] Frontmatter warnings remain nonfatal and visible. - [x] Collect all post-parse normalization/limit errors; this phase currently stops at the first. - [ ] Prove every state above through real MCP upload, update, download, query, and Diagnostics paths. ## Markdown body - [x] Treat ordinary CommonMark/GFM as permissive; malformed-looking Markdown and raw HTML are not automatically syntax errors. - [x] Preserve and validate the body when frontmatter is invalid. - [x] Detect the 1 MiB body/file limit. - [x] Handle body extraction and bounded excerpts. - [x] Return a shared structured invalid-UTF-8 body error from every byte-reading surface. - [ ] Distinguish author errors from internal excerpt-limit/configuration errors. - [ ] Prove body-size and decoding states through real MCP and Diagnostics. ## MDX grammar and safety - [x] Malformed MDX/JSX grammar. - [x] Imports. - [x] Exports. - [x] Executable flow expressions. - [x] Executable text expressions. - [x] JSX expression attributes. - [x] JSX spread attributes. - [x] Arbitrary components. - [x] HTML-looking JSX outside ws.element. - [x] Unsupported/raw MDX node types. - [x] Duplicate attributes and normalized alias collisions. - [x] Event-handler attributes. - [x] srcdoc, srcset, and dangerouslySetInnerHTML. - [x] Unsafe URL protocols in link/source/action-like props. - [x] Forbidden tags: base, link, meta, noscript, script, style, template, title. - [x] Conflicting, empty, or non-static ws:name and ws:tag. - [x] More than 20,000 nodes. - [x] Nesting deeper than 100. - [x] More than 4,000 props. - [x] Multiple recoverable unsafe-mdx warnings are collected. - [ ] Collect multiple fatal grammar/structural errors when parser recovery can do so; unrecoverable parsing currently stops at the first fatal error. - [x] Preserve sibling expression warnings when unsupported JSX is also present; {first()}, <Card />, {second()} currently reports only the Card warning. - [ ] Prove every state above through real MCP and Diagnostics, not only validator unit tests. ## Content Block semantics - [x] Unresolved template warning exists. - [x] Unknown template prop warning exists. - [x] Incompatible template prop warning exists. - [x] Design-only template prop warning exists. - [x] Stale template prop warning exists. - [x] Invalid materialized HTML content model error exists. - [x] Run these checks for an MDX file even when no active editor Content Block root has materialized it. - [x] Run applicable semantic checks in query Diagnostics. - [x] Run applicable semantic checks for MCP upload as well as contextual update/download. - [x] Return all Content Block frontmatter diagnostics; one path still throws only diagnostics[0]. - [ ] Add real MCP and UI coverage for every semantic state. ## Cross-file references - [x] Non-string $ref marker. - [x] Invalid reference URL. - [x] Invalid fragment encoding. - [x] Invalid fragment. - [x] Invalid JSON Pointer. - [x] Missing referenced document. - [x] Missing referenced JSON path. - [x] Missing referenced local Asset warning. - [x] Unsupported target representation. - [x] Reference cycle. - [x] Duplicate document ID or URL. - [x] Missing graph source or target. - [x] Root not found. - [x] Duplicate/unused/unresolved reference. - [x] Invalid resolved value. - [x] Content identity conflict. - [x] Target revision mismatch. - [x] Representation selector required/invalid. - [ ] Diagnose {$ref: value, extraKey: value} as an invalid marker or explicitly document it as ordinary data. - [x] Collect all bad references and targets instead of stopping at the first graph failure. - [x] Validate references from the editor and MCP file tools, not only query compilation. - [x] Map graph compilation/resolution, Markdown-document, and JSON-document errors to exact structured Diagnostics rows. - [x] Prevent an unrelated file's graph error or duplicate canonical URL from blocking an exact-file query. - [ ] Prove missing targets, cycles, bad representations, and bad JSON paths through real MCP. ## Query request and structure - [x] Invalid JSON, invalid request UTF-8, empty/non-object request, and request over 512 KiB. - [x] Missing query and unknown request/query keys. - [x] Invalid result mode. - [x] Malformed where/all/any/filter shape. - [x] More than 32 filters or children. - [x] Filter nesting deeper than 8. - [x] Empty field path or segment. - [x] Field path deeper than 9. - [x] Bare properties path. - [x] Unknown or nested standard field. - [x] Missing or unknown operator. - [x] Non-JSON operator value. - [x] Invalid in value or more than 1,000 in values. - [x] Non-boolean exists/isEmpty value. - [x] More than 8 sort entries. - [x] Invalid sort field or direction. - [x] first/last without a sort. - [x] Invalid output mode or includeMetadata. - [x] Duplicate output fields or more than 256 fields. - [x] No selected output. - [x] Negative, fractional, or over-1,000 limit. - [x] Negative, fractional, or over-1,000 offset. - [x] Invalid content mode. - [x] Invalid full/markdown-body-ref maxBytes outside 1..1 MiB. - [x] Invalid range offset/length or range over 256 KiB. - [x] Empty or over-255-character index revision. - [x] Multiple simultaneous schema issues retain exact query paths. - [x] Make content option objects strict; unknown keys are currently stripped. - [x] Show an invalid persisted resource body rather than silently loading the default query. - [x] Aggregate unknown-key errors with every other structural issue; MCP currently stops at the first unsupported key. - [x] Add field-value type validation, for example reject size gt "large" and id contains {}. - [x] Warn about unobserved dynamic fields selected only as output. - [ ] Prove the full structural matrix through the MCP server/API end to end; the current broad matrix tests the local adapter. ## Query semantic states - [x] INCOMPATIBLE_OPERATOR is fatal for standard fields. - [x] UNOBSERVED_FIELD is a nonfatal warning. - [x] INCOMPATIBLE_OBSERVED_TYPES is a nonfatal warning. - [x] STRUCTURED_SORT_ORDER is a nonfatal warning. - [x] Every incompatible standard-field operator is collected. - [x] Fatal semantic errors retain nonfatal warnings. - [x] Successful warnings appear with exact query paths. - [ ] Reproduce every catalog-dependent semantic state through real MCP. - [x] Test repeated warnings at distinct query paths without accidental deduplication. ## Query execution and hydration - [x] Stale index revision. - [x] result one matching multiple files, including matchedCount. - [x] Candidate document limit of 1,000. - [x] Result payload limit of 16 MiB. - [x] Hydrated file count limit of 20. - [x] Per-file hydration limit of 1 MiB. - [x] Total hydration limit of 2 MiB. - [x] Range limit of 256 KiB. - [x] Binary content requested as text. - [x] Invalid UTF-8 during hydration. - [x] Missing, stale, or conflicting content identity. - [x] Canonical metadata/byte-count mismatch. - [x] Storage returning more bytes than requested. - [x] Missing content reader. - [x] Selected content not returned. - [x] Runtime Asset URL unavailable. - [x] Document graph document-count/per-file/total limits. - [x] Classify candidate-document and result-byte limits as CONTENT_LIMIT_EXCEEDED instead of INVALID_REQUEST. - [x] Give unavailable URL, missing reader/content, storage, selection, and assembly failures stable codes and exact asset/file details instead of INTERNAL_ERROR. - [x] Never silently turn an exact-file unavailable-content failure into an empty successful result. - [x] Add direct regression tests for duplicate identity, excess bytes, and canonical byte mismatch. - [ ] Reproduce every runtime/hydration state through real MCP. ## Scoping and aggregation - [x] Errors and warnings from multiple loaded result files are returned together. - [x] Nonfatal errors do not suppress successful query results. - [x] Unrelated published-query diagnostics do not replace current-query diagnostics. - [x] File path and available line/column are shown. - [x] Exact nested query paths are shown. - [x] Validate and report every pre-pagination matching file if that is the product definition. - [ ] Explain candidate metadata warnings when invalid metadata prevents deciding whether a file matches. - [ ] Stop including METADATA_PREPARATION_FAILED globally unless the UI labels its candidate scope. - [x] Aggregate reference errors instead of stopping at the first. - [x] Aggregate across validation phases where safe. - [x] Add a matrix for same-file multiple errors, multiple files, outside-page errors, filter-only candidate files, and unrelated queries. ## Transport, authorization, cancellation, and internal failures - [x] UNAUTHORIZED and FORBIDDEN. - [x] REQUEST_CANCELLED in query HTTP paths. - [x] Sanitized authenticated internal message. - [x] Generic unauthenticated/public internal message. - [x] Preserve structured causes for document-load HTTP status/body/metadata failures. - [x] Preserve structured causes for object-storage read failures. - [x] Preserve structured causes for graph selection/assembly failures. - [ ] Test MCP/API cancellation directly. - [ ] Reproduce authorization, cancellation, storage, and sanitized-internal states through real MCP where safe. ## MCP reproduction - [x] Real MCP reproduction: multiple Markdown YAML errors. - [x] Real MCP reproduction: multiple simultaneous structural query errors. - [x] MCP update returns Markdown and MDX source diagnostics. - [x] MCP upload returns Markdown and MDX source diagnostics. - [x] MCP download returns Markdown and MDX source diagnostics. - [x] Temporary remote fixtures are removed after reproduction. - [ ] Real MCP reproduction for every frontmatter code. - [ ] Real MCP reproduction for every MDX fatal/warning class. - [ ] Real MCP reproduction for every Content Block semantic diagnostic. - [ ] Real MCP reproduction for every reference/graph error. - [ ] Real MCP reproduction for every semantic query warning/error. - [ ] Real MCP reproduction for every hydration/runtime/limit error. - [ ] Real MCP reproduction for auth, cancellation, storage, and internal errors where safe. - [ ] A durable table-driven test proves code/severity/message/path parity between editor, query, Diagnostics, and MCP. - [x] Preserve stable top-level error identity and structured details through MCP instead of flattening known errors to MCP_TOOL_FAILED. - [x] Prove failed post-commit MCP feedback reports whether a mutation committed and returns enough identity for cleanup. ## Real MCP recheck and follow-up fixes (2026-09-03) Ran the branch CLI against the PR preview backend. The first run exposed that the saved CLI origin pointed to a different backend, so those results were discarded. Every MCP result below came from the PR preview. All temporary remote and local fixtures were removed afterward. The failures found in that run were then fixed and covered by regression tests. - [x] Exact broken Markdown query returns FRONTMATTER_INVALID with severity, filename, message, line, and column. - [x] Exact MDX query returns unsafe-mdx with severity, filename, message, line, and column. - [x] A no-extension query returns warnings from both matching Markdown and MDX files. - [x] A Markdown-only query excludes the unrelated MDX warning. - [x] Two fatal MDX files inside the returned page are both reported; matching warnings remain attached. - [x] Structural query validation returns three independent errors with exact paths in one call. - [x] Semantic query validation returns three fatal operator errors and two warnings with exact paths in one call. - [x] MCP upload, update, download, and exact-file query return multiple source diagnostics for the same MDX source. - [x] Query preview reports a missing Asset reference as ASSET_NOT_FOUND with the source file and reference. - [x] All temporary MCP fixtures were deleted and the saved CLI connection was restored. - [x] Fixed after recheck: validate every matching file before pagination, including broken files outside the returned page. - [x] Fixed after recheck: unrelated graph failures no longer block an exact-file query. - [x] Fixed after recheck: update, download, editor, and query paths use shared reference validation. - [x] Fixed after recheck: graph failures map to structured diagnostics with the exact file. - [x] Fixed after recheck: shared fatal UTF-8 validation runs before upload writes and preserves structured error identity. - [x] Fixed after recheck: MCP rejects filename/format mismatches. - [x] Fixed after recheck: MDX validation keeps sibling and nested warnings around unsupported components. - [x] Fixed after recheck: MCP preserves stable top-level error codes and structured details. - [x] Fixed after recheck: query and MCP serializers preserve full normalized diagnostic fields. - [x] Fixed after recheck: unknown keys are aggregated with all other structural query errors. - [x] Fixed after recheck: shared query validation covers literal types, output-only fields, and strict content options. - [x] Fixed after recheck: unavailable selected content returns an exact-file diagnostic instead of a silent empty result. ## Tests and delivery - [x] Full Builder suite: 2,707 tests. - [x] Content Engine suite: 445 tests. - [x] Asset uploader suite: 211 tests. - [x] Project runtime/MCP targeted suite: 128 tests. - [x] CLI/MCP suite: 1,051 tests. - [x] Relevant package typechecks, lint, generated docs, and diff checks. - [x] Documentation impact reviewed and generated Content Engine/MCP reference updated. - [x] Add the missing cross-surface error matrix described above. - [ ] Demonstrate red/green behavior for every new matrix case. - [ ] Run the complete agent evaluation suite after explicit approval. - [ ] Re-run all checks after the remaining checklist is implemented. ## Compatibility and risk Normal query result and expression-binding shapes remain unchanged. Diagnostics add optional fields. Existing public/pre-auth error redaction remains intact. The remaining unchecked items are broader exhaustive real-MCP coverage, parser-recovery limits, candidate-warning labeling, cancellation coverage, and agent evaluations. |
||
|
|
cb1a17dc9b |
fix: Allow approved fork workflow checkouts (#6335)
Approved fork workflows currently fail before tests start. GitHub rejects the fork-head checkout in the trusted `pull_request_target` context even after the `safe-to-deploy` label is applied. ## Implementation - Opt into the fork checkout for every reusable Main workflow job only when the event is a `safe-to-deploy` label approval. - Apply the same guard to the nested fixture workflow. - Keep normal pushes and regular pull request checkouts unchanged. ## Todo - [x] Guard all Main workflow checkouts. - [x] Guard the nested fixture workflow checkout. - [x] Verify the opt-in remains false for normal pushes and pull requests. - [x] Review documentation impact: no product documentation is affected. - [x] Review fixture impact: no fixture inputs or generated outputs are affected. - [ ] Merge this change into `main`, then reapply `safe-to-deploy` to the affected fork PR. ## Verification - [x] Prettier check for both changed workflows. - [x] `git diff --check`. - [x] Confirmed all seven Main checkouts and the fixture checkout use the guarded opt-in. ## Known limitation GitHub loads `pull_request_target` workflow definitions from the default branch. The repaired approved-fork run can only be verified after this change reaches `main`. Ref #6332 Ref #6329 |
||
|
|
d292502037 |
fix: Paste in Firefox navigator (#6329)
## Summary - Read every clipboard mime type before the first await in both paste handlers. - Call the paste handler registered by the active mode from `emitPaste` instead of dispatching a synthetic clipboard event. - Add regression coverage for both paths: a clipboard event that disconnects after dispatch, and a Firefox-shaped `ClipboardEvent`. ## Root cause Two independent Firefox behaviors, one per entry point. Keyboard paste: the plugin loop re-read `event.clipboardData` on every iteration. Firefox disconnects a paste event's `DataTransfer` as soon as the handler yields, so once `pageText` — first in the list, and async — awaited, every later plugin read an empty string and `instanceText` never received the payload. Chrome keeps the data readable across microtasks, which is why this only surfaced in Firefox. Introduced in #5798, which put `pageText` at the head of the plugin list. Context menu paste: `emitPaste` dispatched `new ClipboardEvent("paste", { clipboardData })`. Gecko's `ClipboardEventInit` has no `clipboardData` member, so the event arrived with a non-null but empty `clipboardData`. `validateClipboardEvent` only rejects a null one, so the paste silently did nothing — no toast, no error. Measured in Firefox 134 against Chrome and Edge 152: `getData` after one microtask returns the payload in Chromium and an empty string in Firefox; a synthetic event's `getData` likewise returns the payload in Chromium and an empty string in Firefox. No behavior change in Chromium. Every plugin returns `pasteIgnored` before its first await, so reading all mime types up front yields the same input the loop received before. ## Verification - `pnpm --filter @webstudio-is/builder exec vitest run app/shared/copy-paste app/builder/shared/asset-manager app/shared/commands-emitter.test.ts` — 335 tests passed. - `pnpm --filter @webstudio-is/builder typecheck` — passed. - `pnpm exec oxlint --deny-warnings apps/builder/app/shared/copy-paste/` — passed. - `pnpm exec oxfmt --check apps/builder/app/shared/copy-paste/copy-paste.ts apps/builder/app/shared/copy-paste/copy-paste.test.ts` — passed. - Reverted each fix in turn against the new tests: 13 failures for the keyboard path, 2 for the context menu, all passing again once restored. - e2e runs Chromium only, and the previous test `DataTransfer` never disconnected, so neither path was covered before. Closes #6288 --------- Co-authored-by: Anmol <anmol@fathershops.com> Co-authored-by: Oleg Isonen <oleg008@gmail.com> |
||
|
|
0ffdf36665 |
fix: Explain dynamic Content Block asset sources (#6333)
## Summary Content Block source operations now explain how to resolve a dynamic Assets resource for one rendered occurrence. A caller can keep the persisted expression, supply the concrete resource result through `variables`, and receive safe structured diagnostics when the expression does not resolve to a non-empty MDX Asset id. The operation still does not load page routes or resource results itself. That work remains in the rendering or caller context. ## Checklist - [x] Reproduce the unresolved result-one Assets resource expression - [x] Preserve the dynamic source expression while validating a concrete Asset id - [x] Return the evaluated value shape without exposing supplied values - [x] Reuse the shared Content Block source resolver - [x] Describe `renderScope` and `variables` in the operation schema - [x] Add a result-one Assets resource example - [x] Verify connection keeps the dynamic expression after resolving the supplied result - [x] Add regression coverage for structured unresolved-source diagnostics - [x] Regenerate runtime contracts and CLI documentation - [x] Review fixture impact: fixture inputs and outputs are not affected - [x] Review documentation impact: MCP and CLI guidance are updated ## Verification - New diagnostic regression failed against the old generic error and passed with this fix - Project Build: 88 files, 2,284 tests passed - Project Build typecheck - CLI typecheck - Generated documentation and contract checks - Formatting and lint with warnings denied - Full CLI suite from the implementation review: 66 files, 1,038 tests passed Agent evaluations were not run because they require separate explicit approval. Closes #6330 |
||
|
|
e33a269802 |
fix: show unsupported browser warning in a dialog (#6332)
The unsupported-browser warning now uses the Builder’s regular modal dialog. Users can acknowledge it and continue, while the small-window state remains a blocking alert. Closes #6331 ## Implementation - Render the existing browser guidance and links inside the design-system `Dialog`. - Set the dialog to modal and keep close, Escape, outside-click, and **Continue** dismissal behavior. - Keep unsupported-browser detection, preview-mode suppression, and Builder-ready timing unchanged. - Keep the small-window alert blocking and remove its now-unused dismissible-alert path. - Add a focused Storybook state and browser regression test. - Increase Main and Visual Regression workflow job timeouts from five to seven minutes after otherwise healthy jobs were cancelled during slow dependency setup. - Run failed E2E diagnostics and service teardown through the backend shell script so cleanup does not depend on pnpm remaining on `PATH` after cancellation. - Route `safe-to-deploy` label events through one reusable gate that starts both Main and Vercel workflows. - Remove revision-specific deployment and visual approval labels in one synchronization-only cleanup job. - Reduce expected skipped jobs from 6 to 1 on a normal branch update and from 17 to 3 on a visual approval label event. No migrations or compatibility changes are required. ## Todo - [x] Replace the unsupported-browser alert with a modal dialog. - [x] Preserve the small-window blocking alert. - [x] Add regression coverage. - [x] Give CI enough time for slower dependency setup. - [x] Keep E2E cleanup available after runner cancellation. - [x] Simplify label-triggered Main and Vercel workflows. - [x] Consolidate revision-specific approval cleanup. - [x] Review documentation impact: no product documentation changes are needed for this presentation-only warning update. - [x] Review fixture impact: no fixture inputs or generated fixture outputs are affected. ## Verification - [x] Focused browser regression test - [x] Builder typecheck - [x] Oxlint on changed files - [x] Oxfmt and `git diff --check` - [x] Workflow YAML parsing and backend shell syntax checks - [x] Workflow trigger, nesting, permissions, and reusable-job contract assertions - [x] Prettier checks for changed workflows - [ ] Storybook screenshot review was not run locally because explicit visual-test approval was not available. ## Known limitations - The visual state was not screenshot-tested locally. - The reduced `pull_request_target` fan-out takes effect after these workflow files reach the default branch, because GitHub loads those workflow definitions from that branch. |
||
|
|
2e4efb52f9 |
docs: update Link target values (#6326)
## Summary Update the Link documentation to match the current code. The Builder uses `_self`, `_blank`, `_parent`, and `_top` as the Link `target` values. The old docs described these as `Self`, `Blank`, `Parent`, and `Top`, which could make setting a new-tab link confusing. ## Changes - Document the four current target values. - Explain that `_blank` opens a link in a new tab or window. - Remove the outdated Target screenshot. - Checked the rest of `docs/` for the same outdated target names; no other related occurrences were found. ## Verification - `git diff --check` passed. - Confirmed the values in `packages/sdk-components-react/src/__generated__/link.props.ts` and `packages/sdk-components-react/src/create-link.tsx`. - Checked that the docs file and navigation file exist. - `pnpm exec oxfmt --check docs/university/core-components/link.md` did not run because the Markdown file is excluded by the formatter configuration. ## Checklist - [x] Review the current Builder implementation. - [x] Review the authoritative docs page. - [x] Check for similar outdated documentation. - [x] Review documentation impact: this PR updates the affected page; no other docs need changes. - [ ] Merge the pull request. |
||
|
|
75840a119c |
fix: Start previews and diagnose runtime failures (#6321)
## Summary Preview startup now binds loopback directly instead of scanning network interfaces first. MCP no longer exposes or accepts a fixed preview host or port: the CLI asks the operating system for an available loopback port and returns the resulting URL. The CLI also returns safe, structured diagnostics when the runtime blocks preview networking or Chromium IPC, when generated IDs collide, and when a listening preview fails its HTTP readiness probe. Preview startup retries only a genuine automatic-port race; HTTP and connection failures return immediately instead of repeating the full startup timeout five times. ## Issue checklist - [x] #6318 — reproduced the `uv_interface_addresses` failure, replaced interface discovery with a direct TCP bind, and added a regression test for the exact failure. - [x] #6319 — reproduced Chromium aborting before DevTools startup when the managed runtime blocks browser IPC/socket operations. The host restriction cannot be bypassed by the CLI, but future reports now include a safe `browser_ipc_permission_denied` issue without raw stderr, paths, or tokens. - [x] #6320 — ran four reported insert variants sequentially across two pages; all generated unique IDs. Future collision errors now include the affected namespace and insertion stage without exposing the generated ID. - [x] #6324 — reproduced the generic readiness timeout with a real generated preview whose root probe returned HTTP 500 after the server printed its Local URL. The MCP contract and documentation also allowed agents to force a busy port; network binding is now runner-owned. - [x] #6325 — confirmed the responsive screenshot uses the same readiness path. Future reports distinguish HTTP, refused-connection, timeout, and permission failures, non-port failures are no longer retried, and screenshots cannot request a fixed preview port. - [x] Documentation impact reviewed. Updated MCP examples and vision guidance to omit runner-owned host and port fields. ## Technical notes - Removes the CLI's direct `get-port` dependency. That package calls `os.networkInterfaces()` even when a host is supplied. - Binds `{ host: "127.0.0.1", port: 0 }`, reads the assigned TCP port, then closes the temporary server. - Removes `host` and `port` from MCP preview and screenshot input schemas and rejects those fields at runtime. - Returns the selected preview URL from `preview.start`; managed screenshots reuse that active target. - Returns `PREVIEW_NETWORK_RESTRICTED` with a stable `network_permission_denied` issue when the OS rejects loopback binding. - Reads at most the last 4 KB of Chromium startup stderr, maps only the reproduced IPC/socket denial to a safe diagnostic, and discards the buffer after startup. - Preserves browser startup issues through CLI browser fallback aggregation and the MCP screenshot error boundary. - Reports generated record collisions with `generated_id_conflict`, the namespace constraint, and the fragment insertion stage. - Preserves structured readiness diagnostics when preview output is appended. - Reports HTTP 5xx and local connection failures without exposing raw fetch errors. - Retries with a newly allocated port only for `EADDRINUSE` / `PREVIEW_PORT_IN_USE`. ## Verification - [x] New regression tests were shown to fail before implementation and pass afterward. - [x] Reproduced the old generic timeout through the real preview controller; after the fix, the same path returned `PREVIEW_HTTP_ERROR` with `http_status:500`. - [x] Verified MCP advertised and accepted fixed host/port fields before the change, then rejected both fields after the change. - [x] Preview readiness/controller tests: 2 files, 29 tests passed. - [x] Vision tests: 13 files, 81 tests passed. - [x] Project-build tests: 88 files, 2,282 tests passed. - [x] CLI tests: 66 files, 1,038 tests passed. - [x] Vision, project-build, and CLI typechecks passed. - [x] Lint passed with warnings denied. - [x] Package-boundary and MCP documentation checks passed. - [x] Fixture impact reviewed; no fixture inputs or generated fixture outputs are affected. Generated documentation was updated; the generated runtime operation contract did not change. Agent evaluations were not run because they require separate approval. Closes #6318 Ref #6319 Ref #6320 Ref #6324 Ref #6325 |
||
|
|
b832a8e808 |
refactor: Centralize Builder ID generation (#6323)
## Outcome Builder-owned code now routes standard ID generation through `@webstudio-is/sdk/createId` while preserving existing NanoID and UUID formats. Closes #6322 ## Technical choices - Use `createId("nano")` for Builder records, assets, transaction IDs, and other existing NanoID-backed values. - Use `createId()` for UUID-backed database records and browser-side client IDs. - Keep `BuilderRuntimeContext.createId` as an injectable dependency. Runtime operations, copy/paste, and deterministic tests rely on that injection. - Keep Node's `randomUUID` in CLI paths that explicitly support running without the Web Crypto global. - Keep specialized generators for custom-alphabet project domains and actual hash generation. - Remove direct `nanoid` dependencies from packages where no specialized use remains. - Do not migrate existing data or change database schemas. ## Todo - [x] Migrate Builder app ID creation. - [x] Migrate project runtime and template defaults. - [x] Migrate asset, project, domain, and authorization-token IDs. - [x] Preserve runtime ID injection. - [x] Review remaining direct generators as explicit exceptions. - [x] Add NanoID-format regression coverage for the default runtime context. - [x] Review documentation impact: no user-facing documentation changes are needed. - [x] Review fixture impact: no fixture input or generated output format changes are needed. - [x] Run targeted tests, typechecks, lint, and package-boundary checks. ## Verification - Targeted Builder tests: 153 passed after preserving runtime-context injection. - Project-build runtime tests: 270 passed. - Asset uploader tests: 61 passed. - Authorization-token tests: 17 passed. - Project tests: 52 passed. - Domain tests: 18 passed. - CLI tests: 32 passed. - Typechecks passed for Builder, project-build, asset-uploader, authorization-token, project, and domain. - `pnpm lint` passed. - `pnpm check:package-boundaries` passed. - The runtime-context format test was demonstrated to fail with a UUID default and pass with the NanoID default. - Agent evaluations were not run because they require separate explicit approval. |