mirror of
https://github.com/webstudio-is/webstudio.git
synced 2026-11-02 18:18:35 +09:00
codex/fix-published-markdown-runtime
3457
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
97c18cc937 | fix: configure published asset origin | ||
|
|
1aa918d2ed | refactor: centralize published asset origins | ||
|
|
0e784063a8 | docs: use hosted deployment terminology | ||
|
|
c01daa1dba | refactor: remove SaaS terminology from builder paths | ||
|
|
4210590729 | refactor: rename publish target resolver | ||
|
|
cca0c76fb8 | fix: use local asset origin for runtime documents | ||
|
|
0bb630b4a9 | fix: keep published runtime artifacts index-only | ||
|
|
d439fd4eb0 | fix: bypass challenged asset origin for published documents | ||
|
|
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 |
||
|
|
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. |
||
|
|
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 |
||
|
|
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
|
||
|
|
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. |
||
|
|
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 |
||
|
|
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. |
||
|
|
7ff42abfb5 |
docs: Simplify MCP setup (#6311)
## Summary - Add a short introduction with the only setup step: install the Codex desktop app or Claude Desktop and ask it to install Webstudio CLI and use MCP. - Keep the existing generated reference below a divider. - Remove documentation wording assertions across generators, CLI manuals and help, MCP guidance, tool descriptions, and operation docs. - Retain structured and executable coverage for command catalogs, schemas, examples, runtime behavior, errors, and UI contracts. ## Implementation The introduction lives in the MCP page template, and the generated GitBook page is committed with it. Documentation prose is now free to change without breaking tests; tests continue to cover machine-readable contracts and observable behavior. ## Checklist - [x] Add the concise introduction to the MCP template. - [x] Regenerate the authoritative `docs/` page. - [x] Audit the repository for documentation prose assertions. - [x] Remove prose-only generator, manual, help, guidance, schema-description, and operation-description assertions. - [x] Preserve structured and executable contract coverage. - [x] Review documentation impact: the existing MCP page is updated; navigation and other documentation are unaffected. - [x] Run targeted tests, typechecks, formatting, and lint checks. ## Verification - CLI: 121 tests passed across the affected suites (119 in the sandboxed run; 2 link tests passed separately with config-directory access). - Project build: 513 tests passed. - Protocol: 23 tests passed. - Content engine reference: 1 test passed. - `pnpm docs:mcp:typecheck` - Typechecks for `webstudio`, `@webstudio-is/project-build`, and `@webstudio-is/protocol` - `oxlint --deny-warnings` on all changed TypeScript files - `oxfmt` and `git diff --check` ## Compatibility and limitations Documentation and test-only changes. No runtime behavior, schemas, fixture inputs or outputs, or external integrations are affected. |
||
|
|
f76dadcef9 |
fix: Restore command, form, and split-button states (#6313)
Closes #6312 ## Summary - Restore the Commands & search header to the command panel surface so its embedded input no longer appears darker or exposes rounded bottom-corner cutouts. - Restore unchecked checkboxes to the borderless resting treatment used by inputs and textareas. - Restore unchecked switches to the neutral control surface used before the redesign. - Restore the header split button's open background on the dropdown segment. - Keep checkbox hover and keyboard-focus boundaries visible. ## Technical choices - Override the generic `InputField` background only in the command component; ordinary inputs continue using the secondary control surface. - Use a transparent resting checkbox border to preserve dimensions, then apply the existing default border on hover and focus border on keyboard focus. - Share the existing neutral button surface recipe with the unchecked Switch track, preserving the historical relationship without adding a new semantic theme variable. - Match the split-menu trigger's semantic `aria-expanded` state because the nested tooltip owns and overwrites `data-state`. - Remove the obsolete forced 3:1 resting-boundary recipe. ## Todo - [x] Audit text inputs, textareas, search, selects, comboboxes, checkbox, radio, switch, toggle, and nested control surfaces. - [x] Restore the command header's panel-background override. - [x] Remove the checkbox's high-contrast resting border. - [x] Restore the unchecked Switch's neutral track surface. - [x] Preserve checkbox hover and focus feedback. - [x] Restore the split-button dropdown segment's open background. - [x] Add light- and dark-mode regression coverage and confirm the tests fail before each fix and pass after it. - [x] Visually verify affected controls and the open split button in Storybook in light and dark modes. - [x] Review documentation impact; no user-facing documentation update is required for restoring the previous visual treatment. - [x] Review fixture impact; no fixture inputs or generated outputs are affected. ## Verification - `pnpm --filter @webstudio-is/design-system test` — 19 files and 228 tests passed. - `pnpm --filter @webstudio-is/design-system typecheck` - Targeted Oxlint, formatting, and `git diff --check` - Storybook audit and visual review in light and dark modes |
||
|
|
e07cb22d29 |
fix: Remove default favicon from exports (#6310)
## Summary Remove the default Webstudio `/favicon.ico` from dynamic export templates and their generated fixtures. Exported sites now rely only on the configured favicon referenced by the generated `<link rel="icon">`; projects without one naturally return 404 for `/favicon.ico`. ## Implementation - Delete the root favicon from the legacy/default and React Router base templates. - Remove the derived favicon from Docker, Cloudflare, Netlify, Vercel, and feature fixtures. - Add regression coverage for legacy dynamic, React Router dynamic, and SSG exports. - Preserve and verify configured favicon link generation in every mode. ## Todo - [x] Remove the default favicon from export template sources. - [x] Regenerate the affected fixture outputs. - [x] Add fail/pass regression coverage. - [x] Run CLI tests, typecheck, lint, and formatting checks. - [x] Review documentation impact; no documentation changes are needed. ## Verification - `pnpm --filter webstudio exec vitest run src/prebuild.test.ts` — 69 tests passed. - `pnpm --filter webstudio typecheck` — passed. - `pnpm exec oxlint --deny-warnings packages/cli/src/prebuild.test.ts` — passed. - `pnpm exec oxfmt --check packages/cli/src/prebuild.test.ts` — passed. - Regression test failed for the two affected templates before the fix and passes for all three export modes after it. - All six affected fixture builds completed with the repository React preload. The full `pnpm fixtures` command could not pass its initial link phase in this fresh worktree because the local CLI loaded JSX without a React global. Closes #5218 |
||
|
|
d4b1994a6a |
fix: Improve editor selection and project tag contrast (#6302)
Closes #6301 ## Summary - Restore Dashboard project tags to the pre-color-refactor treatment: fixed white text over a 30% black scrim in both application themes. - Use one high-contrast text-selection treatment across native inputs, textareas, contenteditable fields, and every shared CodeMirror editor. - Preserve the existing subtle selection treatment for Navigator, Project Settings, command menus, Dashboard navigation, and other selected controls. - Add direct Storybook coverage for the CSS fragment editor. - Simplify chromatic color derivation from 571 to 329 lines without changing computed colors. ## Technical choices - Keep project tags independent from application-theme polarity because they overlay arbitrary thumbnail artwork. - Keep the existing `selectionBackground` control-state export unchanged at its original 12% light / 20% dark accent blend. - Define separate `--background-text-selection` and `--foreground-on-text-selection` tokens exclusively for selected text. - Use the bounded accent in light mode and a luminance-lifted accent in dark mode so selected text remains distinct even with extreme custom theme colors. - Style CodeMirror through its existing selection layer and `::selection` CSS hooks; no selection tracking or editor-state logic is added. - Leave canvas rich-text selection independent: authored canvas documents do not load the Builder UI theme stylesheet. - Replace five duplicated XYZ clamp formulas with the exact upper-luminance cap they reduce to. The removed lower-bound and white-mixing branches were unreachable because the minimum was fixed at zero. ## Todo - [x] Restore the original project-tag scrim and foreground in both themes. - [x] Inventory native, CodeMirror, and canvas rich-text selection paths. - [x] Unify native and shared CodeMirror text-selection colors. - [x] Keep text selection independent from selected control and navigation states. - [x] Add the missing CSS fragment editor story. - [x] Add light- and dark-mode browser regressions and confirm they fail before the fix. - [x] Enforce 4.5:1 selected-text contrast and 3:1 highlight-to-surface contrast across supported theme inputs. - [x] Remove duplicated and unreachable chromatic color derivation while preserving outputs. - [x] Review documentation impact; the design-system color-token reference is updated, with no user-facing product documentation change required. - [x] Verify fixture impact; no fixture inputs or generated outputs are affected. ## Verification - `pnpm --filter @webstudio-is/design-system test` — 227 tests passed, including the control/text separation regression, Navigator tree interaction, default-palette comparisons, and the full supported-theme contrast sweep - `pnpm --filter @webstudio-is/design-system typecheck` - `pnpm --filter @webstudio-is/builder exec vitest run app/shared/code-editor-base.browser.test.tsx --project app-browser-shared` - `pnpm --filter @webstudio-is/builder exec vitest run app/dashboard/projects/project-card.browser.test.tsx --project app-browser-canvas-dashboard` - `pnpm --filter @webstudio-is/builder typecheck` - Targeted `oxlint`, formatting, and `git diff --check` - Live dark-mode Dashboard verification of the restored subtle navigation selection - Storybook visual checks for the full color system and input/CodeMirror selection in light and dark modes |
||
|
|
c9618de88b |
fix: Scaffold projects with attribute aliases (#6300)
## Summary - recover from every standard HTML/SVG and React attribute alias collision during generated JSX export - keep the last persisted value for non-class collisions, matching existing duplicate-prop recovery - merge distinct class aliases with generated atomic classes - keep shared collision validation strict in authoring, import, MDX, and instance-conversion paths ## Implementation The React SDK generator now normalizes safe instance props before generating JSX. One map keyed by the final JSX name provides deterministic last-value recovery for exact duplicates and non-class aliases. A second map keyed by the original class spelling preserves one value per class alias so those composable values can be merged into the single emitted `className` attribute. Projected resource props use the same normalized-name set, avoiding a second route to duplicate generated JSX properties. ## Checklist - [x] Reproduce the reported `class`/`className` failure on unchanged `main` - [x] Reproduce non-class failures including `tabindex`/`tabIndex`, `for`/`htmlFor`, and `readonly`/`readOnly` - [x] Cover every current standard-to-React alias pair in both persistence orders - [x] Preserve exact duplicate-prop last-value behavior - [x] Merge distinct class aliases with atomic classes - [x] Keep strict shared validation outside generated JSX recovery - [x] Review documentation impact; no user-facing documentation changes are required - [x] Review fixture impact; no fixture inputs or generated fixture outputs are affected - [x] Run targeted tests, typecheck, lint, build, and direct generator reproducers - [ ] Run `pnpm evaluations` if explicitly approved ## Verification - `pnpm --filter @webstudio-is/react-sdk exec vitest run src/component-generator.test.tsx --pool=forks` — 156 passed - `pnpm --filter @webstudio-is/content-engine exec vitest run src/jsx-attributes.test.ts --pool=forks` — 3 passed - `pnpm --filter @webstudio-is/react-sdk typecheck` - `pnpm --filter @webstudio-is/react-sdk build` - `pnpm exec oxlint --deny-warnings packages/react-sdk/src/component-generator.ts packages/react-sdk/src/component-generator.test.tsx` - direct generator reproducers now emit one normalized property for `tabIndex`, `htmlFor`, and `readOnly` The exhaustive regression test is derived from the shared attribute mapping, currently covering 105 non-class pairs in both orders; the separate class test covers exact duplicate recovery, distinct alias merging, and atomic classes. Agent evaluations were not run because they require explicit approval. Closes #6299 |
||
|
|
1de752f2ae |
fix: Keep Slot colors consistent (#6296)
## Summary - Define the purple treatment as a semantic secondary-accent CSS color family. - Use its foreground in the Layers panel and its background/on-background pair on the canvas. - Add visual regression coverage that shows the actual Navigator and canvas Slot treatments together. - Keep the same purple in light mode and use a more chromatic, readable foreground in dark mode. ## Implementation The dark-theme migration replaced the former reusable-instance color with two unrelated choices: the blue accent foreground in the navigator and an accent-derived purple canvas fill. This change adds three generated, theme-aware semantic colors using Craft's existing naming and explicit foreground pairing conventions: - `--background-accent-secondary` for Slot canvas labels and outlines. - `--foreground-accent-secondary` for reusable instances in the navigator. - `--foreground-on-accent-secondary` for content on the strong secondary-accent background. The secondary accent derives from the theme accent. Its foreground keeps the existing strong purple in light mode and raises dark-mode lightness without washing out its chroma, so reusable instances remain visibly distinct from ordinary Navigator text. Portable light and dark visual stories render the real `NavigatorTree` beside the real canvas `Outline` and `Label` Slot variant. This covers the user-reported cross-surface consistency and the dark-mode foreground directly. ## Todo - [x] Trace the regression to the color-system migration. - [x] Add the secondary-accent semantic CSS family and generated types. - [x] Add foreground/background contrast contracts across supported themes. - [x] Update navigator and canvas consumers. - [x] Add light and dark visual regression coverage for the actual Navigator and canvas treatments. - [x] Confirm the visual comparison fails before approval and inspect the rendered screenshot. - [x] Run Design System and focused Builder tests. - [x] Run Design System and Builder typechecks, scoped lint, and formatting checks. - [x] Review fixture impact; no fixture inputs or generated fixture outputs are affected. - [x] Review documentation impact; update the internal color-system reference. Authoritative user documentation is unaffected. ## Verification - `pnpm --filter @webstudio-is/design-system test` — 223 tests passed. - `pnpm --filter @webstudio-is/builder exec vitest run --project core-browser-builder-features app/builder/features/navigator/navigator-tree.test.ts` — 20 tests passed. - The dark secondary-accent regression test was confirmed to fail with the washed-out foreground, then pass with the stronger chromatic foreground. - `pnpm --filter @webstudio-is/design-system typecheck` — passed, including generated color-type freshness. - `pnpm --filter @webstudio-is/builder typecheck` — passed. - Scoped `oxlint --deny-warnings` — passed. - Scoped `oxfmt --check` — passed. - `pnpm visual-regression -- --base origin/main --grep "Builder/Navigator/Navigator tree"` — expected failure with two added visual stories; both light and dark screenshots were inspected. The source-contract test was confirmed to fail before the semantic variables were added, then pass with the implementation. Browser contrast tests cover both new pairings across light/dark modes and the complete supported theme parameter range. Closes #6295 |
||
|
|
81d3ddf076 |
fix: tolerate duplicate props during JSX export (#6294)
## Summary - tolerate duplicate persisted props during JSX generation - preserve the last value for a duplicate prop name - add regression coverage for duplicate Image width props ## Verification - `pnpm --filter @webstudio-is/react-sdk exec vitest run src/component-generator.test.tsx --pool=forks` - `pnpm --filter @webstudio-is/content-engine exec vitest run src/jsx-attributes.test.ts --pool=forks` - `pnpm --filter @webstudio-is/react-sdk typecheck` |
||
|
|
7bec7c0488 |
fix: Share split button active state (#6290)
Ref #3818 ## Summary - Apply the primary toggle’s pressed surface to both split-button segments. - Keep both buttons independently actionable and preserve their shared hover behavior. ## Implementation The split-button directly styles the adjacent menu segment when the primary segment has `aria-pressed`. The menu segment keeps its separate action and expanded hit target, so Builder state and color logic are not duplicated. ## Todo - [x] Share the active surface across both segments. - [x] Preserve independent actions, disabled behavior, and shared hover behavior. - [x] Verify light and dark Storybook rendering. - [x] Run typecheck and lint. - [x] Review documentation impact — no documentation changes are required for this restored component behavior. ## Verification - `pnpm --filter @webstudio-is/design-system typecheck` - `pnpm lint` No fixture inputs or generated fixture outputs are affected. |
||
|
|
a8c1726418 |
fix: stabilize CLI bundle contract after publish (#6293)
## Summary - bundle Zod into the published CLI because `bundleVersion` derives from Zod schema internals - bundle `@emotion/hash`, which produces the contract identifier - prevent compatible dependency updates at install time from changing an already-published CLI's contract - add regression coverage for the CLI bundling boundary ## Root cause `webstudio@0.294.0` externalized `zod` and declared `^4.4.3`. The Builder was built with the lockfile version, while a fresh `npx webstudio@latest` installation resolved Zod 4.5.4. Because the project bundle contract is calculated at runtime from Zod definitions, the Builder expected `bundle-1mym82p` while the freshly installed CLI sent `bundle-8e39e9` despite both being the same Webstudio release. ## Packaged CLI reproduction Tested the CLI built from the parent commit and this branch in the same isolated `webstudio@0.294.0` installation with Zod 4.5.4. Both builds executed the real local `webstudio sync` command against the same capture server. - Before: `{"label":"before","zod":"4.5.4","bundleVersion":"bundle-8e39e9"}` - After: `{"label":"after","zod":"4.5.4","bundleVersion":"bundle-1mym82p"}` - Live Builder: `{"bundleVersion":"bundle-1mym82p"}` The fixed local CLI now sends the exact contract required by the live Builder even though the install environment still contains Zod 4.5.4. ## Verification - isolated before/after packaged CLI test through the real `sync` request path - `pnpm --filter webstudio exec vitest run src/cli-bundle-externals.test.ts` - `pnpm --filter webstudio typecheck` - `pnpm --filter webstudio build` - verified emitted CLI files contain no external imports from `zod` or `@emotion/hash` - `pnpm exec oxfmt --check packages/cli/vite.config.ts packages/cli/src/cli-bundle-externals.test.ts` - `git diff --check` |
||
|
|
f953d1be37 |
fix: Restore the login background gradient (#6286)
## Summary Restores the original Webstudio login gradient after the color-system migration added a dark scrim over it. Fixed Webstudio identity artwork now belongs to the Design System, while generic surfaces, content, translucency, and overlays use the semantic color system instead of a Builder-local brand color bag. ## Architecture - The Design System exports only the fixed Webstudio background gradient, progress gradient, and progress shadow as brand artwork. - Generic black, white, translucent panel, and scrim entries were removed rather than moved. - Login and error surfaces use semantic light/dark pairings. - Project-card tags derive their local 30% scrim from the semantic overlay color. ## Todo - [x] Restore the original login gradient without a scheme-dependent scrim. - [x] Move fixed identity artwork into the Design System package. - [x] Remove the Builder-local brand color registry. - [x] Replace generic fixed colors with semantic colors or local derivations. - [x] Add explicit dark-mode Storybook coverage for the login screen. - [x] Run Design System and Builder typechecks. - [x] Run Design System tests, scoped lint, formatting, and package-boundary validation. - [x] Review documentation impact and document ownership in the Design System color README. ## Verification - Design System tests: 222 passed. - Design System and Builder typechecks: passed. - Scoped Oxlint and formatting: passed. - Package-boundary validation: passed. - Focused visual regression: 23 affected stories compared; the newly added dark login story is the only difference. - Fixture impact: no fixture inputs or generated outputs are affected. Ref #3818 |
||
|
|
4273b7001f |
refactor: Organize Builder development and test tooling (#6285)
## Outcome Builder development, backend, E2E, and CI tooling now share one ownership model: Builder defines named commands and backend modes, while CI only schedules those commands. ## Technical choices - Group shared Compose files, PostgreSQL initialization, and backend helpers under `apps/builder/backend`. - Resolve `compose.<mode>.yaml` by convention instead of maintaining Compose filename lists in scripts and workflows. - Keep persistent development and disposable test Compose projects separate by default, while allowing the standard `COMPOSE_PROJECT_NAME` override. - Make schema snapshots invalidate from discovered migration sources and backend files. - Move E2E behavior recipes into named Builder commands; retain concise root proxies for developer entry points. - Let Vitest allocate available browser ports instead of maintaining a cross-package port registry. - Keep test-suite scheduling explicit in `main.yml`, but move executable test commands to root package scripts. - Move fixture-size enforcement from inline GitHub JavaScript into a locally runnable repository script. ## Todo - [x] Consolidate Builder backend and Compose ownership. - [x] Add named development, E2E, schema-cache, Supabase, and CI-shard commands. - [x] Remove Compose topology and behavior flags from CI. - [x] Remove the static Vitest browser-port registry. - [x] Extract fixture-size checking from the workflow. - [x] Verify migration bootstrap, snapshot-backed E2E, tests, builds, types, formatting, lint, generated contracts, and workflow syntax. - [x] Review documentation impact: updated the E2E developer guide; no user-facing `docs/` content is affected. ## Verification - Full package, CLI, Builder core, and Builder app test suites - Full workspace typecheck - Builder production build - Schema-cache generation through the complete migration history - Supabase migration compatibility - Snapshot-backed Playwright animation workflow - Backend regression tests, including demonstrated fail/pass coverage - All four Compose mode configurations - `oxfmt`, `oxlint`, package boundaries, generated API, and generated docs checks - `actionlint` and Bash syntax checks The fixture-size checker preserves the existing Linux `du` thresholds. Its three inputs build locally; macOS allocation sizes are not directly comparable to the Linux CI thresholds, so CI remains the authoritative size result. |