mirror of
https://github.com/webstudio-is/webstudio.git
synced 2026-10-23 03:27:27 +09:00
a6a90493993556264ee846d75bcc25b3aeb44bc2
6724
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
a6a9049399 |
fix: validate published MDX before publish (#6468)
## Related issue Related to #3550. ## Summary - Run the existing published-MDX materializer during pre-publish validation and surface its error diagnostics before starting dynamic or static publishing. - Reuse the dependency walk that builds the publication artifact to limit validation to reachable Content Blocks, including blocks whose asset is missing. - Add actionable fix hints for unavailable MDX assets and invalid HTML nesting. - Show a compact error/warning count in the publish dialog, with a details dialog that has counted Errors and Warnings tabs and hides empty tabs. - Include relevant IDs and navigation links in reports when available, with guidance when they are not; allow users to copy all reports and select the text. - Resolve missing-document IDs against loaded asset metadata and show the filename and Content Assets folder path when available. The page-tree pre-publish audit already checks HTML content models, but it cannot see content generated from MDX assets. This extends preflight to that content using the same materializer and diagnostics as the publish build. It also catches unavailable MDX assets before the publish job starts. ## Plan and status ### Implemented - [x] Reuse existing publish-time MDX discovery and materialization so preflight checks the content that will be published. - [x] Collect every page-tree audit error and warning, not only the first finding for each severity. - [x] Collect every MDX publish error and provide a location and remediation hint. - [x] Collect missing or ambiguous template warnings and content-database omission warnings. - [x] Show a compact error/warning total in the publish dialog. - [x] Add a details dialog with standard panel padding, spaced and separated findings, and counted Errors and Warnings tabs; hide empty tabs. - [x] Copy all reports from the dialog header and allow report text selection. - [x] Include diagnostic codes and relevant instance, asset, document, and resource IDs in reports. - [x] Keep “See issues” visible in the narrow publish panel. - [x] Keep element navigation available from page-tree audit findings and link content findings when the target is available. - [x] Use the same findings UI for dynamic and static publishing. - [x] Block publishing on errors and allow warnings to proceed. - [x] Keep unexpected preflight failures visible to the user. - [x] Show a preflight failure either in the open publish dialog or in a toast when the dialog is closed, avoiding duplicate reports. - [x] Replace opaque “Document … could not be loaded” errors with actionable guidance, including the asset filename and folder path when available. - [x] Load linked document sources during MDX validation and prebuild when they are absent from the compact content artifact. ### Regression checks completed - [x] No-findings validation preserves the normal publish path. - [x] Single and multiple findings show accurate totals and details. - [x] The “See issues” action is visible in the publish panel and opens diagnostics. - [x] “Show element” navigation remains wired to the affected element and closes the publish dialog. - [x] More than five MDX errors and more than ten missing-template warnings remain available in diagnostics. - [x] Mixed MDX errors, audit errors, template warnings, and database warnings are combined and counted. - [x] Errors stop dynamic and static publishing; warnings do not block publishing. - [x] Error-only, warning-only, and mixed states show the right tabs and counts, with empty tabs hidden. - [x] Copy-all includes every error and warning with context, and report text is selectable. - [x] An open dialog receives inline preflight failures without a toast; a closed dialog receives a toast without a duplicate inline report. - [x] Missing-document errors include filename/folder context when available and useful fallback guidance when metadata is unavailable. - [x] Reproduce the linked-author failure with the affected project’s hosted build, then confirm it builds successfully with the fix. ## Verification - `pnpm --filter @webstudio-is/project-build test -- src/runtime/published-mdx.test.ts` (26 tests passed) - `pnpm --filter @webstudio-is/project-build typecheck` - `pnpm --filter webstudio typecheck` - Affected project: `webstudio build --template react-router` reproduced the document load error before the fix and completed after it. - `pnpm --filter @webstudio-is/builder test -- app/builder/features/publish/publish-validation-results.test.tsx app/builder/features/publish/content-database-publish-warning.test.tsx app/builder/features/publish/publish-error.test.ts app/services/build-router.server.test.ts` (26 tests passed) - `pnpm --filter @webstudio-is/builder typecheck` - `pnpm exec oxfmt --check` on changed files - `git diff --check` - Reviewed dynamic/static preflight and element-navigation code paths. |
||
|
|
c0ddc4dca0 |
fix: Compile dynamic MDX from mutable variables (#6472)
## Summary A Content Block MDX source can come from a mutable project variable, so publication cannot safely narrow it to a single asset at compile time. Include all MDX assets in the published project as candidates and thread them through sync, dependency closure, and prebuild. Projects without Content Blocks continue to skip article-body indexing and downloads. Regression coverage exercises both the sync metadata and generated prebuild output. Follow-up to #6455. ## Checks - [x] Project-build tests and typecheck - [x] CLI sync tests and typecheck - [x] Luna/low evaluation suite (all six fixtures passed; baseline comparison unavailable for this model override) - [x] Documentation impact reviewed |
||
|
|
6044792b77 |
docs: Explain Radix force-mount animation requirements (#6471)
## Summary Document the animation constraints around Radix `forceMount`: closed content remains mounted and needs explicit closed-state CSS, while Radix suppresses CSS transitions and animations during height measurement, so the first opening may not animate. Updated Accordion and Collapsible docs, custom prop descriptions, and generated prop metadata so the guidance appears in component discovery. Closes #6197. ## Checks - [x] Accordion and Collapsible documentation updated - [x] Generated prop metadata refreshed - [x] Package typecheck - [x] Targeted Collapsible tests |
||
|
|
adf1fd3aaf |
fix: show publish status only for selected domain (#6473)
## Summary - Show the project-domain publish status only when the latest build targets that domain. - Keep the staging checkbox default tied to a staging publish. A pending publish to a custom domain no longer makes the staging domain appear to be publishing. ## Verification - `pnpm -r typecheck` passed locally. - GitHub Actions passed: checks, test matrix, builder end to end shards, visual regression, lint, and submodule check. |
||
|
|
432ca1172d |
fix: retain resources on XML pages (#6466)
## Summary - Start resource discovery from the rendered XML root because prebuild removes the page body wrapper before generating the route. - Add a regression test for a Sitemap resource used by a Collection on an XML page. ## Verification - The regression test failed before the fix: the generated request graph omitted `sitemap-resource` from `rootIds`. - `pnpm --filter webstudio test -- src/prebuild.test.ts` — 78 tests passed. - `pnpm --filter webstudio typecheck` — passed. - Formatting, lint, and `git diff --check` passed. - Rebuilt the imported Spazio Flow project locally. `/sitemap.xml` now returns all 12 eligible URLs; before the fix it returned an empty `<urlset>`. - Documentation impact reviewed: no user workflow or documented behavior changed, so no docs update is needed. - Fixture impact reviewed: no fixture inputs or generated contracts changed, so no fixture regeneration is needed. |
||
|
|
8a46350c9a |
fix: Compile MDX Content Blocks in hosted builds (#6455)
Hosted MDX pages can publish successfully and then fail to render because the publish runner skips their source files. Restore source downloads and compilation for MDX Content Blocks, including dynamic article queries and template dependencies. Reuse the existing publication planner and local content compiler. Markdown-only pages keep their bodies on demand; hosted MDX pages download article sources and pay the necessary compilation cost in the runner, not the publish API. Reject missing content databases and MDX materialization errors instead of deploying an incomplete page. Ref #6450 Ref #6454 ## Checklist - [x] Reproduce missing MDX content using the affected deployed build. - [x] Restore hosted MDX compilation without duplicating the static-export compiler. - [x] Add a sync → compile → generated query → React server-render regression with a metadata-only API bundle and a frontmatter-bound Content Block. - [x] Verify new regression checks fail without the required behavior and pass with it. - [x] Reject missing MDX sources and content databases; preserve remote article bodies when no MDX Content Blocks need compilation. - [x] Review documentation impact and update the Content Engine publishing explanation. - [x] Run CLI tests, typecheck, lint, formatting, and package-boundary checks. - [x] Run the full fixture link/sync/build pipeline; no generated changes. - [x] Rebuild the affected project locally and exercise its generated production request handler: HTTP 200 with the article title and body. Asset requests were served from synced local files. The live project was not modified or republished. Its existing title/description bindings still use an array access for a single-result query; that separate project-data issue is not changed here. Agent evaluations were not run. Affected sites need republishing after the updated CLI artifact is deployed. |
||
|
|
11c31bdc25 |
feat: Warn MCP agents when a newer CLI is available (#6462)
## What changes When MCP starts, the CLI checks npm's `latest` release while the project session and API contract are loading. If a newer CLI is available, the MCP initialization instructions tell the connected agent which versions are running and recommend restarting with the latest CLI. The CLI never updates or restarts itself. The registry request has a 1.5-second timeout and fails open on network or response errors. It may add up to 1.5 seconds to startup if the project session finishes before the check; the existing server compatibility check remains the authority for whether writes are supported. ## Verification - [x] Added tests for newer, same/older, invalid, and unavailable registry responses; the newer-version test failed when the check was temporarily disabled. - [x] Verified the update notice reaches the connected MCP client; the handshake test failed when the notice was temporarily omitted. - [x] Full CLI suite: 1,159 tests passed. - [x] CLI and project-build typechecks passed; focused MCP initialization integration test passed. - [x] Lint, formatting, and diff checks passed. - [x] Documentation impact reviewed: no docs change is needed because the notice is sent dynamically at MCP startup. - [ ] Full Luna/low agent evaluation suite: approval requested, not received; not run. Ref #6461 |
||
|
|
e1e5bc152e |
feat: append response header rules for last-match precedence (#6460)
Response headers now use list order when more than one rule sets the same name on a path: the last matching rule wins. New or edited rules currently move to the top of the Builder list, which would make older rules override them. Append those rules instead and explain the precedence in the settings UI. Authentication list behavior is unchanged. Validation: SDK response-header tests and typecheck, CLI response-header tests, SDK build and declaration build passed. |
||
|
|
7fd91301d6 |
fix: Retry responsive preview routes and report linked project IDs (#6458)
Responsive verification could reject an interior route while the refreshed preview was still settling. Managed responsive captures now use the same bounded retry as single screenshots. If the route keeps returning HTTP 4xx/5xx, the tool reports the route failure instead of calling it the wrong site. Issue reports now use the resolved linked project ID, including when the CLI was started without --project. This makes future project-specific reports traceable without adding URLs or customer content. The immediate false rejection is removed for transient failures. A batch may be recaptured up to twice with a one-second wait between attempts. Persistent route or server errors still fail and need investigation. Ref #6456 Ref #6452 Ref #6457 Ref #6396 ## Verification - [x] New responsive retry and HTTP-classification tests failed before the changes and pass afterward. - [x] Full CLI suite: 1,153 tests passed. CLI typecheck, formatting and targeted lint passed. - [x] Focused sitemap, bundle-loading, and API-compatibility tests passed. - [x] Reviewed authoritative docs: no user workflow or documented input changed, so no docs update is needed. - [x] Fixture inputs and generated outputs are unaffected; no fixture regeneration is needed. - [ ] Full Luna/low agent evaluation suite: approval requested, not yet received. - [ ] Verify the affected interior route on a released CLI. The original report lacks the project and route identity, so this PR does not claim that specific site is fixed. |
||
|
|
9b1100f25b |
fix: Restore hosted Assets queries (#6454)
Hosted Assets queries started returning 502 in 0.301.0 because publish sync omitted their query database. Restore that database for hosted builds while keeping Markdown body-reference queries on demand. Static exports still prepare their database in the build runner. Reject builds with Assets queries but no database before changing generated files, so this failure cannot silently produce another broken deployment or erase the previous generated output. Uses the existing shared query compiler; no MCP-specific logic or API schema changes. Closes #6450 Ref #6427 Replaces #6453 with the same commits on `assets.staging`, which matches the staging deployment branch policy. ## Checklist - [x] Reproduce the reported 502 and verify the fix on project and custom origins. - [x] Preserve static export behavior and on-demand Markdown loading. - [x] Add a regression test for rejecting missing databases; demonstrate failure before the fix and success afterward. - [x] Review documentation impact and update the Content Engine publishing explanation. - [x] Run relevant tests, Builder/CLI typechecks, lint, formatting, and package-boundary checks. - [x] Run the full fixture link, sync, and build pipeline against the patched preview API. Regenerate all eight JSON snapshots with the current formatter; parsed data is unchanged and generated application files are unchanged. Validation: 88 CLI tests, 22 Builder tests, and four no-body-read publication tests pass. Fixture size checks were unavailable without compiled app bundles. Agent evaluations were not run. Existing affected sites need republishing after the fix is deployed. |
||
|
|
d78e770d82 |
perf: Keep article indexing out of publish API requests (#6427)
Ref #6416 The publish workflow was doing too much work in one short-lived API request. This moves content indexing into the build runner and keeps article bodies out of hosted/SSR sync. ## What changed - The build-bundle API can return the lightweight project bundle without preparing a full content index. - The CLI downloads required assets directly from storage and builds the index locally for SSG. Asset downloads remain bounded to 10 concurrent requests. - Hosted/SSR sync skips Markdown and MDX article downloads and does not compile an article index. It still downloads regular assets needed by the build. - Markdown body queries use stored frontmatter and fetch only the requested article at runtime. MDX still needs source downloads and compilation for SSG. - Public MCP and content-engine docs explain the Markdown/MDX tradeoff. This removes article parsing and article-body transfer from the tRPC request. SSG still downloads article sources from storage and compiles MDX in the build runner. Hosted runtime article reads remain on demand. ## Checklist - [x] Keep the tRPC bundle request limited to project metadata and necessary records. - [x] Prepare SSG content indexes in the build runner; keep hosted article bodies out of sync. - [x] Cover no-body query preparation, direct asset reads, and SSG-versus-hosted sync behavior with regression tests. - [x] Update public CLI, MCP, and content-engine guidance. - [x] Regenerate and verify fixtures. - [x] Run workspace tests, typechecks, lint, formatting, package-boundary, generated API/docs, and fixture-size checks. - [ ] Verify the deployed publish flow has comfortable margin below the hosted API timeout. ## Verification - `pnpm -r --workspace-concurrency=1 test`: passed, including all 3,082 Builder tests and 1,150 CLI tests. - `pnpm -r typecheck`, `pnpm lint`, `pnpm check:package-boundaries`, `pnpm check:generated-api`, `pnpm check:generated-docs`, `pnpm check:fixture-sizes`, and `pnpm exec oxfmt --check`: passed. - The new hosted article-download regression test was confirmed to fail with the old behavior and pass after the fix. - A deployed end-to-end publish timing check is still needed, so this PR remains draft. |
||
|
|
df7ed327ab |
refactor: clarify pathname rule matchers (#6446)
Authentication and custom response headers use the same route-rule syntax, but the shared matcher and validator had auth-specific names. Give those functions generic names in `wsauth` and update the Builder header UI and SDK response-header schema to call them directly. All basic-auth logic remains in `wsauth`; this change adds no package or re-export. The project-build page matcher is different: it uses `URLPattern` and returns decoded parameters. Rename it to `matchUrlPattern` and document the behavior difference. For example, `/docs/*` matches `/docs` for authentication and headers, but not for the page matcher. Tests cover both behaviors. This renames the two public `wsauth` route exports. Published workers pinned to the older package retain the old API; the SaaS worker can adopt the new names after this package is released. Validation: `wsauth` tests, including its packaged consumer test; SDK page and response-header tests; project-build route and redirect tests; SDK, `wsauth`, project-build, and Builder typechecks. |
||
|
|
6e174f4677 |
fix: require screenshot target in MCP schema (#6447)
## Summary - Declare that screenshot requires exactly one target: `url` or `path`. - Add a regression test for the published MCP schema. This addresses the schema mismatch reported in #6417. It does not resolve the separate environment-specific Chromium `SIGABRT` report. |
||
|
|
be74d8d698 |
fix: Validate response headers and expose MCP rule edits (#6444)
Header rules previously accepted `null` values, which silently turned a rule into a header-removal instruction even though the settings UI only offers adding a string value or deleting a rule. Require a nonempty string throughout the SDK, Builder, CLI generator, and API contract. Expose configured rules to MCP through `list-response-headers`, `set-response-header`, and `delete-response-header`. Setting a rule adds or replaces the header for the same route and case-insensitive name; `/` and `/*` remain distinct. The Builder UI and MCP operations now share the same rule-key, edit, and Zod validation logic. The generated JSON Schema advertises the header-name pattern and nonempty value, while server-side Zod validation enforces route syntax, forbidden headers, duplicates, and total size. The generic `update-project-settings` operation still supports replacing the whole list. Validation: SDK, project-build runtime and MCP, CLI command and prebuild tests; SDK, Builder, project-build, CLI, and protocol typechecks; lint, package boundaries, generated API and docs checks. Local fixture sync against the development API is blocked by differing bundle versions; PR CI tests fixtures against its deployed Builder host. |
||
|
|
a4c3b37fc2 |
fix: Unblock reported MCP workflows and improve issue diagnostics (#6438)
## What this fixes
MCP authors can reuse an existing design token in JSX fragments, create
valid border shorthands with CSS variables, and bypass a font that never
settles during responsive screenshots. Common fixed page titles with
spaced separators are also accepted. Issue reports now include the
project ID and safe, bounded IDs from the failed operation, plus clearer
response and browser-startup diagnostics.
## Scope and tradeoffs
- `token("name")` attaches an existing design token; an unknown name
returns a not-found error. Empty token definitions from Builder/UI
remain definitions and follow the normal conflict rules.
- Border shorthands map a single unresolved `var()` to the remaining
width, style, or color field when the other fields are explicit.
- `waitForFonts: false` skips font readiness but still waits for stable
layout frames. The default remains unchanged.
- Fixed titles such as `Pricing - Plans` stay literal. Addition such as
`first + second` remains an expression. Wrap ambiguous subtraction in
parentheses, for example `(first - second)`. Other ambiguous title forms
may still need an exact report.
- Only recognized operation-level IDs are attached to a public GitHub
issue. Authored values, raw arguments, URLs, and credentials are
excluded. IDs from later successful diagnostic reads are not captured.
- This does not fix the underlying response-transform failure; it
improves future reports for that case.
Closes #6424
Closes #6425
Closes #6434
Closes #6439
Ref #6435
Ref #6430
Ref #6417
## Verification
- [x] Reproduced the privacy, page-expression, empty-token, and
content-mode token-reference regressions with failing tests, then
confirmed the fixes pass. A regression test also covers parenthesized
subtraction.
- [x] Full protocol, template, vision, project-build, and CLI test
suites pass; focused Builder issue-report and fragment tests pass. The
protocol, CLI, and project-build suites were rerun after the CI fix.
- [x] Relevant package typechecks, lint, package-boundary check, fixture
pipeline, generated API check, and generated docs check pass. Fixture
output has no diff.
- [x] Reviewed the authoritative MCP documentation and regenerated the
API metadata and MCP docs.
- [x] CSS parser regressions cover border, each side shorthand, and
unresolved variables in width, style, and color positions; css-data
tests, typecheck, and lint pass.
- [x] Fixed the local evaluation runner to pass the task and Webstudio
MCP tools to Luna/low. Each of the six fixtures passed at least once;
focused MCP/evaluator tests, CLI and project-build typechecks, lint, and
formatting pass.
- [x] The complete Luna/low suite passed all six fixtures in two
consecutive sequential runs. Baselines remain incompatible with this
model/effort override and were not updated.
## Follow-up
- If another fixed-title form still fails, use the new project-level
report context and the exact title shape to narrow the parser case.
|
||
|
|
2c9fd16689 |
feat: configure custom response headers by route (#6429)
## Description Project Settings starts with an empty response-header rule list. Users can add valid HTTP response headers for all paths (`/*`) or an Authentication-style route such as `/private/*`, and remove any configured rule. The Headers and Authentication views share the accessible rule-list form. The header form suggests standard response-header names and common values for the selected header, while accepting custom names and values. `Set-Cookie` is not suggested because a rule can store only one value per header and would replace existing cookies. `X-Powered-By`, `X-Content-Type-Options`, and `Strict-Transport-Security` are dispatcher-owned and cannot be configured. Users may configure `Content-Security-Policy`, `X-Frame-Options`, and `Referrer-Policy`; when absent, the dispatcher supplies their defaults. The SDK validates header names, values, routes, duplicates, and size limits. The CLI emits only configured rules. Customization requires Pro for custom-domain publishing, while unchanged defaults and staging remain available on Free plans. The server checks the saved production snapshot against the project owner's plan. Companion Cloud worker PR: https://github.com/webstudio-is/webstudio-saas/pull/664. Deploy its dispatcher support before exposing these settings in the Builder. Other hosts need an adapter that applies the generated rules; Webstudio Cloud dispatcher defaults do not apply automatically elsewhere. Static exports do not apply headers automatically. ## Validation - SDK, CLI, Builder browser, publish-warning, and production-build tests pass. - Builder, SDK, and CLI typechecks and lint pass. - The companion Cloud worker tests, typecheck, and lint pass. Replaces https://github.com/webstudio-is/webstudio/pull/6428 to use `headers.staging`. Closes https://github.com/webstudio-is/webstudio/issues/4748 |
||
|
|
30b4f994dc |
fix: restore publish countdown (#6443)
## Summary - Keep the publish countdown visible while the publish action is in progress. - Show the pending spinner after the 60-second countdown expires. The refactor in `804cd39bc` applied the design system's pending button state immediately. That state hides the button text, including the countdown label. Progress still disables the action throughout publishing, while the pending visual state now waits until the countdown ends. ## Verification - `git diff --check` |
||
|
|
cd64a6627e |
fix: Load unbound resource previews in the variable dialog (#6432)
New resources can fail to show data in the **New variable** dialog because a page-plan refresh cancels their preview request before it finishes. This change keeps explicitly requested previews alive until the dialog releases them. Changing inputs, changing resource type, or closing the dialog cancels obsolete work and prevents old data from showing. Unused page resources remain lazy; a preview still makes an on-demand request when **Load data** is clicked. The dialog stays usable while unrelated page resources are loading. Follow-up to #6030. ### Checklist - [x] Reproduce the cancellation with a regression test that fails before the fix. - [x] Keep dialog previews independent of page resource discovery, using the existing loader, cache, and request versions. - [x] Clear old previews on input changes and release requests on dialog close. - [x] Cover new Current date, Sitemap, HTTP, and existing unbound resources, plus repeated loads and stale responses. - [x] Keep tests for obsolete page-request cancellation and async resource dependencies passing. - [x] Test the unsaved dialog with an unrelated page request pending and a page-plan recalculation. - [x] Clear the old preview when switching resource types or starting an asynchronous body edit. - [x] Review documentation impact: no update needed; this restores the documented preview behavior. - [ ] Confirm GitHub CI passes. ### Verification - The dialog loading, type-switch, and body-edit regression tests failed before their fixes and passed afterward. - 82 focused tests and the settings-panel suite (588 tests) passed. - Builder typecheck and repository lint passed. - With preview retention temporarily disabled, all nine new loader regression cases failed as expected. |
||
|
|
9845517029 |
fix: hydrate published Markdown assets (#6422)
Migrated from #6421 to the short .staging branch name. |
||
|
|
3d0a0657aa |
feat: Support async resource dependencies (#6030)
## Summary Make `Resource<Document>` the lazy document-resolution abstraction shared by Content Engine graphs, generated sites, and Builder previews. Expressions use one async computation interface: referenced resource documents resolve first, independent requests run concurrently, and unused resources stay unloaded. Ref #6029 Ref #6031 ## Implementation checklist - [x] Define one resource contract for synchronous or asynchronous document resolution. - [x] Resolve explicit roots lazily with memoization, bounded concurrency, cancellation, and structured errors. - [x] Preserve cycle, duplicate, and missing-resource diagnostics. - [x] Extract resource dependencies with the existing expression AST. - [x] Discover consumed resource roots from the current page tree and page metadata. - [x] Generate a lazy request graph for published page data, including independent requests. - [x] Resolve dependency documents before evaluating dependent request expressions. - [x] Integrate dependency-first loading with Builder preview caching and invalidation. - [x] Expose safe Resource bindings in the editor and reject self/indirect cycles. - [x] Adapt REST, GraphQL, Assets, date, and sitemap requests through the same Resource contract. - [x] Cover laziness, chains, shared dependencies, concurrency, invalidation, cancellation, failures, and cycles with fail/pass tests. - [x] Review documentation impact and document dependent Resources in the Data variables guide. - [x] Track collection-item and component-parameter-dependent resources as follow-up #6031. - [x] Regenerate and review affected fixtures. - [x] Resolve action-resource request dependencies when an action is invoked. - [x] Reproduce and fix cached form submissions and multi-root dependency-cycle hangs. - [x] Document uncached form actions and regenerate affected fixtures. - [x] Preserve single and multi-selected content until a cut successfully writes to the clipboard. - [x] Preserve boolean expression values in the search-exclusion checkbox. - [x] Cancel cut deletion if project data changes while preparing or writing the clipboard; cover content/property edits and project switches for single and multi-selection, and document the retry behavior. - [x] Validate pending cuts after the final await, immediately before deletion, and reproduce the queued-update race for single and multi-selection. ## Technical direction The persisted, revisioned `DocumentGraph` remains the Content Engine artifact. `Resource<Document>` is the execution abstraction for obtaining a document; its resolver evaluates only the dependency closure reachable from requested roots. Static and remote documents therefore differ by Resource implementation, not by expression value type. Generated pages always emit a `ResourceRequestGraph`. Each node owns its output name, dependencies, and request factory. Roots come from resource variables actually referenced by the current page's metadata, props, actions, or expression children. Unused and off-page resources remain unresolved. The loader still accepts legacy request maps for compatibility. Builder preview uses the same page-root discovery as published generation. Its existing cache remains the lifecycle boundary: cached dependency documents unlock dependent requests, while invalidation removes downstream requests until their inputs resolve again. The separate canvas frame recomputes its local plan from the synchronized cache so rendered expressions receive those documents. Action requests and their dependencies resolve when a form is submitted. Each submission sends a new action request, bypassing Webstudio's resource cache. Dependency requests still use their configured cache lifetime. ## Review simplifications - Consolidated page resource-root discovery in the SDK and reused it in Builder. - Scoped root and action discovery to the current page tree. - Removed the redundant immediate-resource helper; `Resource.resolve` already accepts `Document | Promise<Document>`. - Moved output names onto graph nodes and removed the duplicate graph-level map. - Removed unused planner output and corrected transitive cycle discovery to include only Resource data sources. - Regenerated fixtures so independent resources also use lazy graph execution. - Reused one abort-aware concurrency limiter for document sessions and Resource resolution. - Collapsed duplicate generator action scans and removed redundant generated-resource bookkeeping. - Unified legacy request maps and request graphs through one resolution path. - Shared the 20-request concurrency limit between SDK, Builder preview, and the server batch boundary. - Preserved dependency failure paths and original causes, including the first cancellation reason. - Removed invalid-request logging that could expose Resource headers or request bodies. - Made editor cycle detection alias-safe by comparing underlying Resource IDs. - Memoized page settings values to prevent repeated async validation renders. ## Verification Latest local verification for `bbca6395e3`: - Both queued-update regression cases failed before the fix and passed afterward. Validation now runs synchronously immediately before deletion, after the final await, in both cut paths. - Passed: 255 copy/paste and command tests, Builder typecheck, lint, package boundaries, formatting, and diff checks. - Reviewed documentation: the existing copy/paste safety description remains accurate. Fixture inputs and outputs are unaffected; no fixture regeneration was needed. Agent evaluations were not run because separate approval is required. - CI for the new commit is pending. Previous local verification for `ffbc75b152`: - Six regression cases failed before the fix and passed afterward: content edits, property edits, and project switches during a pending cut, with both single and multiple selections. - Passed: 253 copy/paste and command tests, Builder typecheck, lint, package boundaries, source formatting, and diff checks. - An unchanged content-block test file initially failed to import in the browser. Its isolated rerun and the full 253-test rerun passed without code changes. - The guard conservatively treats any project-data change as a reason to keep the clipboard copy without deleting content. It shows a retry message. Copy/paste documentation now describes this behavior. - Fixture inputs and outputs are unaffected; fixtures were not regenerated. Agent evaluations were not run because separate approval is required. CI for the new commit is pending. Previous local verification for `3eb580697c`: - Reproduced both regressions with failing tests before fixing them: premature deletion during cut and false search exclusion appearing checked. - Passed: 203 copy/paste and page-settings tests, Builder typecheck, lint, package boundaries, formatting, and diff checks. - Cut coverage includes keyboard and programmatic entry points, single and multiple selections, delayed successful writes, rejected writes, and disabled copying. - Reviewed documentation impact: these fixes restore existing behavior; no documentation update is needed. Only Builder UI and clipboard files changed; fixture inputs and outputs are unaffected, so fixtures were not regenerated for this commit. - CI status for this older commit was recorded as pending at handoff. Agent evaluations were not run; they require separate approval. Previous local verification for `858b348ad`, rebased onto `cf606ca4c`: - Regression tests failed before each fix and passed afterward: repeated submissions in both generated route templates, plus three multi-root/branching cycle cases. - Passed: 590 SDK tests, 1,129 CLI tests, 72 focused Builder tests, SDK/CLI/Builder typechecks, lint, package boundaries, and fixture link/sync/build. - Initial concurrent runs hit timeouts. The complete CLI suite passed with one worker; the focused Builder suites passed without file parallelism. - Documentation and generated fixture changes reviewed. Agent evaluations were not run; they require separate approval. - CI for `858b348ad` passed: Main (including all six E2E shards), Visual Regression, Lint PR, and Check submodules. Earlier verification (before this update): TDD fail/pass evidence includes resolver creation, AST dependency discovery, published graph reachability, dependency-gated request generation, Builder dependency-first planning, Resource editor cycle filtering, page-tree root scoping, off-page action isolation, transitive Resource-only cycle discovery, abort/timeout precedence, server batch limits, and the rebased SSG fixture consuming its lazy Resource. - `pnpm checks` passed after rebasing onto `ce84ddcf12`; it covered workspace tests, typechecks, lint, package boundaries, generated API/docs validation, and fixture link/sync/build. - Earlier focused checks passed: Builder typecheck, 12 page-settings/pages unit tests, lint, formatting, and `git diff --check`. - Local generated-resource E2E passed for HTTP, GraphQL, and current-date resources (3 tests). - The page-actions and Marketplace page-settings persistence E2Es both pass locally. - CI for `6b8b08a70` passed: Main workflow (including all six Builder E2E shards), Visual Regression, Lint PR, and Check submodules. - Agent evaluations were not run because they require separate explicit approval. ## Current behavior and limitations - A failed dependency blocks its dependents and reports the resource path and cause. - One published resolution call is the memoization boundary; Builder maps dependency readiness onto its versioned request-cache lifecycle. - Scoped collection-item and component-parameter resources remain in #6031. - Builder skips cyclic dependency paths without blocking independent resources. |
||
|
|
d506525915 |
fix: allow re-uploading fonts with invalid metadata (#6423)
## Summary After #6419, a project with broken font metadata can load again, but uploading the same font still returns the broken asset. Deleting it first does not help: the upload reuses the deleted file. This lets a normal re-upload read the font again and create a valid asset. ## Changes - Reuse the existing font-metadata validation before restoring or creating a deduplicated asset. - Clear only the broken file's content hash so a fresh upload can proceed. Keep its bytes, metadata, and existing references unchanged. - Check that the metadata still matches before clearing the hash. If another request repaired it, reuse that valid file. - Keep normal deduplication for later uploads of the new valid font. No schema changes or migrations. Existing references are not automatically replaced, and the original font bytes must still be valid. ## Checklist - [x] Reproduce the bug before fixing it. - [x] Cover invalid JSON and invalid font metadata, with both active and deleted assets, using real WOFF2 bytes. - [x] Cover a concurrent metadata repair, including a failing run with the update guard removed. - [x] Pass all 306 asset-uploader tests, package typecheck, and lint/format checks for both changed files. - [x] Verify fixture impact: no fixture inputs, outputs, or bundle contracts changed; all 17 fixture checks pass. Regeneration is not needed. - [x] Review documentation impact: the custom-font and asset guides already describe normal uploading; no documentation changes needed. Agent evaluations and browser E2E were not run; both require separate approval. Ref #6419 |
||
|
|
804cd39bc2 |
fix: Stop slow diagnostics from blocking publishing and clarify publish status (#6416)
Closes #6406 ## What changes Publishing no longer waits for advisory content-database and MDX diagnostics. Those checks run alongside the publish request, so a slow diagnostic does not prevent publishing from starting. Permissions, pending content saves, and blocking project checks still run before publishing. The server continues to enforce publish authorization and build integrity. ### Publish dialog - Add a green **Validate** button beside the blue **Publish** button, with equal widths. - Show waiting states and disable the actions while their work is running. - Let users validate without publishing. Successful validation shows a persistent “Validation passed. Ready to publish.” toast. - Clear the button's **Validated** state when the popover closes. Reopening still reflects an active publish job. - Move **Add new domain**, **Export**, and **Publish settings** into the header's ellipsis menu. - Show yellow progress icons for publishing domains, green checkmarks for completed publishes, red icons for failures, and neutral icons for unpublished domains. Built-in and custom domains share the status mapping. ### CLI and MCP Add `check-publish-readiness` to check the saved project without starting a publish. It checks permissions, rejects empty or unusable domain selections, reuses the existing build-integrity checks, and returns content diagnostics. Broken resource references no longer produce a false `valid: true` result. ### Content checks Run independent collection reads with bounded concurrency instead of processing every collection sequentially. This reduces serial waiting, but does not eliminate the underlying storage reads or content processing. ## Checklist - [x] Keep authorization and blocking project checks in place. - [x] Run advisory content diagnostics alongside publishing. - [x] Add standalone validation, waiting states, and popover-local validation results. - [x] Consolidate secondary actions in the publish menu. - [x] Distinguish pending, completed, failed, and unpublished domain states. - [x] Add CLI/MCP readiness checks using existing integrity and verified-domain logic. - [x] Bound concurrent collection reads. - [x] Add regression tests, including invalid domains, missing resources, status transitions, and popover state. - [x] Demonstrate the latest regression tests failing without the fixes and passing with them. - [x] Review documentation impact: update CLI operation guidance and metadata, and document domain status colors in the publishing guide. - [x] Run focused Builder, CLI, and asset-uploader tests, Builder typechecking, lint, formatting, and the generated-API check. ## Verification and limits The latest UI check passed all 49 publish tests. The preceding readiness fix passed 98 focused Builder tests and 130 CLI tests; collection coverage passed 112 tests. Typechecking, lint, formatting, and generated-API checks passed. The latest fixes do not affect fixture inputs or generated site output. Storybook screenshots and agent evaluations were not run because approval was not given. A live production publish was not performed during the latest verification. Publish can finish before advisory diagnostics do. Returned warnings appear afterward and cannot stop a publish that has already started. Standalone validation still waits for diagnostics, and actual publishing still requires content synchronization, server checks, and build/deployment work. This does not promise that every publishing timeout is eliminated. |
||
|
|
cf606ca4c3 |
fix: tolerate invalid asset metadata on load (#6419)
Malformed persisted asset metadata can prevent an entire project from opening. This PR recovers safely from invalid stored metadata and prevents the same invalid font records from being written again. ## Summary - Safely parse persisted asset metadata; malformed assets load as generic files instead of breaking the project. - Log structured diagnostics for invalid persisted font metadata without exposing the metadata contents. - Detect font uploads by extension even when sent as generic files, and preserve parsed font metadata. - Reject invalid font metadata overrides and file/font schema combinations before persistence. - Add regression coverage for the reported empty metadata, upload parsing, validation, write rejection, and read fallback. Existing malformed rows are not rewritten. They remain identifiable as generic files and can be re-uploaded after the fix is deployed. Fixes #6418 ## Verification - `pnpm --filter @webstudio-is/asset-uploader test` (301 passed) - `pnpm --filter @webstudio-is/sdk test` (573 passed) - Relevant typechecks, generated API check, formatting, and `git diff --check` passed. |
||
|
|
ade7a30560 |
perf: prepare content collections concurrently (#6412)
Ref #6396 Publishing could spend the entire serverless request budget preparing content collections one folder at a time. Projects with several collections could therefore time out before the publish diagnostics or bundle response was ready. This change: - validates independent collection folders concurrently; - discovers reserved collection files concurrently; - removes collection configuration and template files from the content index concurrently; - reuses the existing bounded content-read limit, so storage and parsing work remains capped; - keeps validation rules and published project semantics unchanged. Todo: - [x] Reproduce the affected production project returning HTTP 504 after about 15.45 seconds. - [x] Confirm the diagnostics calculation is fast locally and isolate the delay to publication asset preparation. - [x] Add regression tests for concurrent validation, reserved-file discovery, and index preparation. - [x] Demonstrate the new tests fail against the previous serial implementation. - [x] Run the full asset-uploader test suite, typecheck, formatter, linter, and diff checks. - [x] Review documentation impact: no user-facing documentation changes are needed for this internal performance fix. Verification: - pnpm --filter @webstudio-is/asset-uploader test: 296 tests passed - pnpm --filter @webstudio-is/asset-uploader typecheck - pnpm exec oxfmt --check on changed files - pnpm exec oxlint --deny-warnings on changed files - git diff --check Known limitation: The affected production deployment must be retested after this PR is deployed. The local reproduction confirms the old behavior and the focused regression tests confirm the reduced serial work, but the remote project cannot execute new server code from this branch. |
||
|
|
2a389b878c |
fix: load embedded MDX documents in previews (#6415)
## What changed Published MDX Content Blocks could build with document bindings but fail at runtime when the content index did not include the MDX source text. Dynamic article routes then returned an asset-query 500 or crashed during SSR. This change: - hydrates missing local MDX source text during CLI prebuild; - resolves document-graph references from embedded content before making an HTTP request; - adds a regression test for embedded document loading. ## Verification - published runtime tests passed (17 tests) - prebuild tests passed (69 tests) - content-engine and CLI typechecks passed - exact imported marketplace project reproduced locally and verified: SSG generated 10 pages, `/posts/designing-with-intent` returned HTTP 200 with article content, and no `ReferenceError` or asset-query 500 occurred |
||
|
|
cd1881bde6 |
fix: upload asset tickets serially (#6414)
## Summary - Reserve and complete each asset upload before requesting the next upload ticket. - Prevent concurrent identical uploads from triggering the server's in-progress deduplication error. - Keep the upload result mapping keyed by the folder-scoped upload key. ## Verification - `pnpm --filter @webstudio-is/builder exec vitest run app/builder/shared/assets/upload-assets.test.ts app/builder/shared/assets/directory-drop.test.ts app/builder/shared/assets/asset-upload.test.tsx` - 41 tests passed. |
||
|
|
0e30263787 |
fix: Fix multi-file asset drops and folder-scoped deduplication (#6413)
## Summary - Preserve all files when dropping multiple local files into Assets. - Scope client-side duplicate detection by folder. - Allow the same underlying file to have asset entries in different folders. ## Validation - Focused asset upload and directory-drop tests passed locally. - `git diff --check` passed. |
||
|
|
d6c1a3c763 |
fix: Show one Alert styling target in Markdown Embed (#6411)
Markdown Embed currently adds one general Alert descendant plus five variant-specific descendants. This shows six Alert entries in the Navigator even though they represent one element type. This keeps one Alert descendant. Note, tip, important, warning, and caution still render normally and retain their state-specific default backgrounds. Ref #6278 ## Implementation - Remove the five variant-specific Alert descendants from the Markdown Embed template. - Keep the shared Alert descendant and its `data-state` style rules. - Add a regression test for the single Alert styling target. ## Checklist - [x] Reproduce the six Alert descendants in a failing test. - [x] Keep one Alert descendant. - [x] Preserve default styles for all five variants. - [x] Run the SDK components test suite. - [x] Run SDK components typecheck and declaration generation. - [x] Run repository lint. - [x] Review documentation impact: no documentation change is needed because Markdown syntax and rendered behavior are unchanged. - [x] Review fixture impact: no fixture inputs or generated fixture bundles are affected. |
||
|
|
e7181fffdc |
feat: Add GitHub-style Alert component (#6279)
## Summary - Add one official `Alert` component with a content-editable `variant` property for note, tip, important, warning, and caution. - Register Alert in the component catalog with a generated title descendant and Storybook story. - Render GitHub-style alerts in Markdown Embed using the same DOM, class, role, and variant contract. - Materialize connected Content Block MDX alerts as actual Alert instances and serialize content or variant edits back to `> [!TYPE]`. - Document the component and both Markdown workflows. ## Implementation Alert labels and variants live in Content Engine and are shared across the component, Markdown renderer, and MDX adapters. 1. The Alert React component owns the wrapper, generated title, stable classes, `role="note"`, and `data-variant`. 2. Markdown Embed transforms candidate micromark HTML before the existing sanitizer and emits the same markup contract. It remains sanitized HTML rather than a Builder instance tree. 3. Content Engine retains alert metadata on parsed Markdown blockquotes. Project Build maps those nodes to Alert instances, reconciles their authored children, and restores canonical GitHub syntax during MDX serialization. 4. The component registry exports one Alert insertion template with a styleable title descendant. Unsupported, lowercase, misplaced, and malformed markers remain ordinary blockquotes. There are no schema, migration, persisted-data, or sanitizer-policy changes. ## Checklist - [x] Add Alert as an official component with one Variant property. - [x] Support all five GitHub alert types. - [x] Share alert metadata and marker recognition. - [x] Preserve nested Markdown and ordinary blockquote behavior. - [x] Keep URL and HTML sanitization in the existing security boundary. - [x] Add shared, title, and type-specific Markdown Embed descendants. - [x] Materialize Content Block alerts as Alert instances. - [x] Preserve alert content and variant changes through MDX serialization. - [x] Regenerate component props and Storybook artifacts from source. - [x] Review documentation impact and update Alert, Markdown Embed, Content Block, and navigation docs. - [x] Verify fixture impact; no fixture inputs or generated fixture outputs are changed. ## Verification - [x] New tests demonstrated failure before implementation and pass afterward. - [x] `pnpm --filter @webstudio-is/content-engine test` — 417 passed. - [x] `pnpm --filter @webstudio-is/project-build test` — 2,282 passed. - [x] `pnpm --filter @webstudio-is/sdk-components-react test` — 144 passed, 1 skipped. - [x] SDK component registry tests. - [x] Relevant package typechecks, declaration builds, and production builds. - [x] Root lint, formatting, package-boundary, generated-doc, and diff checks. - [x] GitHub Actions main, E2E, lint, submodule, deployment, and approved visual-regression checks. ## Known limitations Alert identifiers must be uppercase and appear at the start of the blockquote's first paragraph, matching the documented syntax. Markdown Embed emits the component's markup contract but cannot create Builder instances inside sanitized HTML. Closes #6278 |
||
|
|
18d171212f |
feat: Resolve asset paths in HTML embeds (#6409)
## Description - Resolve root-relative script, stylesheet, image, and other asset attributes in HTML Embed markup. - Use the same asset-path map in Builder Canvas and generated published sites. - Keep SaaS asset proxy URLs deployment-relative instead of hard-coding the `p-….apps.webstudio.is` project origin. - Preserve canonical `/cgi/asset/` versus `/cgi/image/` routing and `?format=raw` behavior in Canvas. ## Regression coverage Added coverage for SaaS prebuild URLs, the real Builder asset-map-to-HTML-Embed integration, every supported asset attribute, HTML character references, and responsive-image `srcset` edge cases. ## Verification - [x] CLI prebuild suite: 69 passed - [x] HTML Embed suites: 63 passed - [x] Full Builder browser suite: 2,646 passed - [x] Asset URL map tests: 2 passed - [x] CLI, Builder, React SDK, and project-build typechecks - [x] Lint and package-boundary checks - [x] Previous PR CI: 29 successful, 1 skipped ## Code Review - [x] Self-reviewed - [x] Added regression and integration tests |
||
|
|
60c549c46f |
fix: preserve local styles and improve issue diagnostics (#6408)
Fixes #6386 ## Summary - Keep local `ws:style` declarations after `ws:tokens` so instance styles override token defaults. - Capture privacy-safe HTTP timing/status, exceptional session namespace states, preview freshness/version agreement, and validation paths in issue reports. - Derive reportable validation roots from the public operation catalog instead of maintaining a duplicate allowlist. - Keep captured failures current by clearing them after a successful tool call. ## Verification - Protocol issue-report tests: 3 passed - Project build MCP: 128 tests passed - CLI project session: 27 tests passed - Builder issue reporter: 5 tests passed - Relevant package typechecks passed - Generated API metadata is clean |
||
|
|
dd4bbabf79 |
fix: preserve text animation content during cleanup (#6383)
Updates the animation component to include webstudio-is/sdk-components-animation#35. On canvas, HTML Embed can replace its DOM before Text Animation cleanup runs. Cleanup now avoids detached sibling references and preserves the replacement content. This PR currently points to the reviewed branch commit from animation PR #35 and should merge after that PR. If #35 is squash-merged, the submodule pointer must be refreshed to its resulting main commit. Tests: - Focused browser tests pass in Chromium and Firefox: 14/14 assertions. |
||
|
|
fc15ebf81a |
perf: avoid repeated MDX parsing in publish diagnostics (#6407)
## Description The cold `build.contentDatabasePublishDiagnostics` path was parsing the same reachable MDX documents while the publication plan converged, then parsing them a third time to produce omission diagnostics. Content-heavy projects can approach or exceed the 15-second serverless limit on that first request. This change: - creates a request-scoped MDX dependency resolver that reuses parse results by asset revision while the publication plan converges; - carries the final template omissions out of the existing publication pass, so the diagnostics endpoint does not walk the artifact again; - keeps the existing sequential asset validation/preparation/stability checks unchanged; - does not use module-level caching or depend on a warm serverless instance; - leaves the timeout error handling from #6406 unchanged. ## Performance evidence An isolated cold-path benchmark used the same MDX payload (2,000 sections) and compared the previous three independent dependency-resolution walks with the new request-scoped convergence path: | path | time | | --- | ---: | | before | 1,178 ms | | after | 404 ms | That is a 66% reduction in the measured MDX resolution phase. The tests also assert the underlying work reduction directly: an unchanged revision is parsed once across convergence passes, while a changed revision is parsed again. For a stable 214-document candidate set, this removes up to 428 of the previous 642 parse operations. ## Verification - `pnpm --filter @webstudio-is/project-build test` — 2,420 tests passed - `pnpm --filter @webstudio-is/builder exec vitest run --project core-server` — 336 tests passed, including server-side e2e runner tests - `pnpm --filter @webstudio-is/project-build typecheck` - `pnpm --filter @webstudio-is/builder typecheck` - `pnpm lint` - `pnpm check:package-boundaries` - `pnpm check:generated-api` ## Code Review - [x] made a self-review - [x] added comments for the request-scoped cache and revision safety - [x] added tests for parse reuse, revision invalidation, and the optimized endpoint integration path ## Before merging - [ ] tested on a deployment preview with a production-sized content project ## Additional content-read optimization Successive compilation plans now share already-fetched, revision-keyed content bytes within one callback-scoped preparation session. The byte store: - is created inside one asset-stability attempt and discarded when that attempt finishes; - is not stored on the repository, in a module, or outside the request; - remains bounded by the existing 2 MiB hydration limit; - refetches changed revisions and starts clean on stability retries. Tests verify that two overlapping plans read unchanged content once, a revision change forces another read, a new session reads again, and a stability retry creates a new session. A fully overlapping two-pass workload therefore performs up to 50% fewer object-storage content reads. Additional verification: - `pnpm --filter @webstudio-is/asset-uploader test` — 292 tests passed - `pnpm --filter @webstudio-is/asset-uploader typecheck` ## Remaining optimization assessment The percentages below estimate whole-request improvement and are workload-dependent; they are not additive. | optimization | estimated improvement | complexity | decision | | --- | ---: | ---: | --- | | Request-local content-byte reuse | 10–35% | 3/10 | Implemented | | Stop when the initial dependency plan is already a fixed point | 5–15% for static/known MDX; ~0% for dynamic discovery | 2/10 | Implemented | | Reuse a canonical source snapshot/materialized entries across different plans | 15–30% | 8/10 | Deferred: large semantic and invalidation surface | | Reuse the bundle's initial asset-data snapshot | 1–5% | 5/10 | Not worthwhile | | Add a diagnostics-specific bundle loader | 2–8% | 6/10 | Not worthwhile for this PR | | Parallelize or skip unrelated user/project metadata | 0–3% | 2/10 | Not meaningful | | Combine collection validation and reserved-asset inspection | 0–5% normally | 4/10 | Only meaningful for projects with many collections | The fixed-point fast path is covered by a test asserting one artifact preparation and one dependency-resolution call when the original plan is already stable. |
||
|
|
ea17eaa3c4 |
docs: explain the complete Content Engine workflow (#6403)
## What changed - Add the complete Content Engine video tutorial to the main guide. - Explain the launch benefits before the step-by-step setup: file-based content, visual MDX editing, designed templates, collection entry forms, and MCP automation. - Document collection entry creation and editing in Content mode. - Explain content collection folders in the Assets guide. - Document that shared Slots cannot be used inside Content Block Templates. - Add missing links between Content Engine and Content Block documentation. ## Release documentation audit Reviewed the shipped MDX-backed Content Block, MDX template, structured collection entry, collection authoring, query diagnostic, publication warning, and asset-path changes. The detailed feature docs already cover their implementation-specific behavior. This PR fills the remaining discovery and workflow gaps across the main Content Engine, Assets, Modes, and Content Block pages. ## Todo - [x] Add the launch video to the Content Engine guide. - [x] Update the main launch value proposition and supported scale. - [x] Document collection workflows in Assets and Content mode. - [x] Document the shared-Slot limitation for Content Block Templates. - [x] Review documentation impact and navigation. - [x] Verify generated documentation remains clean. - [x] Verify changed relative links resolve. ## Verification - Content Engine documentation tests: 2 passed - Generated Content Engine and MCP documentation checks: passed - Documentation TypeScript check: passed - Relative link check: passed - Git diff whitespace check: passed The repository formatter excludes these GitBook Markdown files, so the pre-commit formatting task had no eligible targets. No fixture inputs or generated fixture outputs are affected. |
||
|
|
0d448313ab |
fix: harden MCP mutations and validation (#6402)
## Summary Fixes the reproducible MCP regressions reported today: - validate font upload metadata locally instead of surfacing an HTTP 500 - replace only the addressed child when `insertIndex` is supplied - support cross-parent duplication - bind data-variable assignments in actions - reject string-valued `style` bindings - include descriptions for every advertised MCP tool - preserve resource data-source exposure on full updates - render mixed expression/element children in the Builder canvas - preserve explicit outer Collection references in nested scopes - reject unsupported `update-page-settings` fields instead of dropping them - reject unavailable asset-query variables and log server error details Closes #6390 Closes #6391 Closes #6392 Closes #6393 Closes #6394 Closes #6395 Closes #6398 Closes #6399 Closes #6401 Closes #6404 Closes #6405 ## Verification - 484 project-build tests - 62 CLI tests - 35 Builder browser tests - 25 SDK tests - project-build, Builder, CLI, and SDK type checks - root lint and generated runtime contracts |
||
|
|
aa1587c100 |
fix: Clarify publish timeout errors (#6406)
## Summary - detect pre-publish HTTP timeouts from the response metadata already attached to `TRPCClientError` - show a clear publish-specific message instead of the JSON parser error - cover both HTTP 504 and Vercel timeout responses ## Why When `build.contentDatabasePublishDiagnostics` exceeds the serverless function duration, the proxy returns HTML or plain text. tRPC's JSON parser fails, but the resulting client error still contains the original HTTP response. The publish flow now uses that response to report: > Pre-publish checks timed out. Publishing was not started. Please try again. This PR intentionally does not change the shared tRPC transport or claim to solve the underlying diagnostics performance problem. ## Verification - `pnpm --filter @webstudio-is/builder exec vitest run --project core-browser-builder-features app/builder/features/publish/publish-error.test.ts` - `pnpm --filter @webstudio-is/builder typecheck` - `pnpm exec oxlint --deny-warnings <changed files>` - `pnpm exec oxfmt --check <changed files>` |
||
|
|
f23007457d |
fix(content-engine): normalize asset path filters (#6389)
## Description Fixes Assets path filters so authors can use visible folder and file names while canonical stored paths remain URL-encoded. - normalizes path filter operands segment by segment without double encoding - preserves already encoded filters and literal string matching behavior - covers equality, inequality, membership, contains, starts-with, and ends-with operators with spaces and URL-significant characters - verifies local/Preview database execution and published runtime return the same result - documents visible path input in the generated Content Engine reference Closes #6388 ## Steps for reproduction 1. Create an Assets folder named `Tutorial posts`. 2. Add an MDX file inside it. 3. Create an Assets system resource with `path starts with "Tutorial posts/"`. 4. Preview the query and expect the MDX file to match. 5. Change the value to `Tutorial%20posts/` and expect the same result for backward compatibility. ## Regression proof Before the implementation, the focused reproduction failed because the matcher returned no items: expected `["alpha"]`, received `[]`. With the fix, the expanded path-operator regression suite passes. ## Verification - [x] Content Engine test suite: 47 files, 577 tests passed - [x] Content Engine typecheck - [x] CLI typecheck - [x] Repository lint with warnings denied - [x] Formatting check for every changed source/test file - [x] Content Engine documentation test - [x] Content Engine and MCP documentation generation is idempotent - [x] Webstudio Features fixture generation is idempotent and typechecks - [x] No agent evaluations were run ## Documentation impact Updated the authoritative CLI Content Engine reference source and regenerated the Builder Content Engine and MCP documentation. The new guidance tells users to enter visible path names and notes that existing encoded filters remain supported. ## Code Review - [ ] hi @kof, I need you to do - conceptual review (architecture, feature-correctness) - detailed review (read every line) - test it on preview ## Before requesting a review - [x] made a self-review - [x] added inline comments where behavior is not obvious ## Before merging - [ ] tested on preview environment (preview dev login: 0000) - [ ] updated test cases document (not needed; automated regression and authoritative user docs were updated) - [x] added tests - [x] no new environment variables |
||
|
|
3531089965 |
fix: fall back to pnpm for generated previews (#6382)
## Description Fixes #6381. Generated preview previously defaulted to npm whenever launcher metadata was unavailable, even when npm was absent and pnpm was installed. Resolve npm from PATH first and fall back to pnpm, using the same resolver for dependency installation and preview commands. The React Router Vite plugin is already declared by the generated template, so no dependency duplication or compatibility wrapper is needed. ## Verification - 47 focused preview/package-manager tests pass - CLI typecheck passes - repository lint passes - formatting and generated CLI docs are current ## Code Review - [x] made a self-review - [x] added regression tests - [x] no new environment variables |
||
|
|
b7a11e4bc2 |
feat: Delay canvas scripts until resources render (#6380)
HTML Embed scripts in canvas and preview now wait until the complete
resource queue settles. Their markup remains rendered while loading;
only executable scripts are delayed, so scripts can read the committed
resource-backed DOM without requiring a custom event.
## Implementation
- Add an internal `$resourcesState` atom with `pending` and `settled`
states, driven by the complete resource queue.
- Synchronize the atom from the Builder to the canvas iframe.
- At the Builder component-render boundary, pass only HTML Embed the
private prop `$ws$executeScripts={isSafeMode !== true && resourcesState
=== "settled"}`.
- In the SDK HTML Embed component, default `$ws$executeScripts` to
`true`, keep markup inert while it is false, and execute scripts after
React commits the transition to true.
- Treat failed requests as settled so scripts cannot wait forever.
- Keep the private prop out of generated component arguments and
metadata through the existing `$`-prefixed prop convention.
- Keep published rendering unchanged because published sites do not pass
the private Builder prop.
- Keep the existing standard `DOMContentLoaded` / `load` compatibility
and sequential script queue.
- Remove the canvas wrapper and component-registry override.
## Todo
- [x] Track collective resource readiness in the Builder.
- [x] Synchronize readiness into the canvas.
- [x] Delay HTML Embed scripts in both canvas and preview.
- [x] Combine safe mode and resource readiness into one private
execution prop.
- [x] Preserve rendered HTML while scripts are delayed.
- [x] Preserve pages with no resources and failed-resource behavior.
- [x] Keep the private prop out of user-facing component metadata.
- [x] Add resource-state, sync, Builder-prop, and browser regression
tests.
- [x] Review documentation impact; no user-facing documentation changes
are needed.
- [x] Review fixture impact; no fixture inputs or generated outputs are
affected.
## Verification
- SDK HTML Embed browser tests — 44 passed
- Builder private-prop tests — 15 passed
- Resource tests — 28 passed
- Sync tests — 14 passed
- React SDK, SDK components, and Builder typechecks — passed
- Focused Oxlint and formatting — passed
Closes #6379
|
||
|
|
9963c95ef8 |
fix: Sync OAuth profile fields on login (#6376)
Closes #6375 ## Summary - Refresh username, avatar, and provider fields when an existing user logs in through OAuth. - Avoid unnecessary database writes when profile fields are unchanged. - Preserve existing development-login behavior. - Add regression coverage for changed GitHub profile data. ## Testing - `pnpm --filter @webstudio-is/builder exec vitest run --project core-server app/shared/db/user.server.test.ts` - `pnpm --filter @webstudio-is/builder typecheck` |
||
|
|
2aec79774e |
fix: focus spacing input when popover opens (#6374)
## Description Restore automatic focus to the CSS value input when the spacing popover opens. The property label became focusable after its migration to `ResettableLabel`, making it the first tabbable element in the popover and causing Radix to focus the label. Marking the intended value input with `autoFocus` makes React focus it as the popover content mounts; Radix then detects that focus is already inside its focus scope and preserves it. ## Steps for reproduction 1. Select an element. 2. Open the Style panel spacing section. 3. Click any margin or padding value. 4. Verify focus is placed in the CSS value input. ## Verification - [x] Builder typecheck - [x] Prettier check - [x] Oxlint - [x] `git diff --check` ## Code Review - [ ] conceptual review - [ ] detailed review - [ ] test on preview |
||
|
|
bd414eb53e |
fix: Fix text animation crash with leading HTML embed text (#6378)
Updates the animation component to include webstudio-is/sdk-components-animation#34. An HTML Embed that starts with raw text no longer crashes when placed inside Text Animation. The component now restores adjacent text nodes in a safe order during cleanup. Tests: - Focused browser test passes in Chromium and Firefox: 12/12 assertions. |
||
|
|
649ee3669d |
fix: Batch asset queries during project import (#6368)
## Problem Project import sent every asset filename in one database request. Large projects produced an oversized URL and failed before assets could upload. Closes #6367 ## Changes - [x] Reuse the existing encoded filename chunking rule for imports - [x] Batch imported file lookup and restore requests - [x] Add regression coverage for long filename lists - [x] Review documentation impact: no user-facing documentation changes are needed ## Verification - [x] Builder import tests: 21 passed - [x] Asset uploader tests: 50 passed - [x] Builder and asset-uploader typechecks - [x] Lint, formatting, and diff checks - [x] Real CLI import passed the original metadata lookup and began uploading 380 assets - [ ] Agent evaluations were not run; they require separate approval The real import later reached the target project's separate 350-asset limit. That limit is outside this fix. |
||
|
|
5d34b77fac |
feat: Improve collection entry authoring (#6361)
Collection authors and editors get clearer field help, direct entry navigation, and actionable validation instead of warnings that point at the wrong place. Closes #6360 ## Implementation - [x] Keep resettable help open after a click while the label remains hovered - [x] Stop repeating the property label inside resettable help - [x] Store JSON Schema field descriptions and show them in entry forms - [x] Add an optional dynamic collection entry page for explicit canvas navigation - [x] Rename entry file actions to **Edit file** - [x] Add **Open on canvas** to entry menus and Entry settings - [x] Put the entry filename in the Entry settings title - [x] Make collection validation banners explain the problem and open the first affected entry - [x] Remove false output-only `UNOBSERVED_FIELD` warnings while keeping filter and sort diagnostics - [x] Encourage useful field descriptions in general MCP collection guidance - [x] Update Content Engine documentation - [x] Confirm no database migration is required - [x] Regenerate the affected asset-query runtime fixture - [ ] Visually review the affected Storybook states in light and dark themes - [ ] Run the complete local agent evaluation suite - [x] Run broader package and Builder checks - [x] Complete final diff review ## Technical notes - `entryPageId` lives in `collection.json` under `x-webstudio`; no database schema changes are needed. - Entry creation still leaves the current canvas unchanged. Canvas navigation only happens after the user selects **Open on canvas**. - An entry page must contain exactly one URL parameter. The entry filename supplies that parameter, so the page can identify the selected entry. - Output projection fields are schemaless and may be produced after reference resolution, so catalog absence is no longer reported there. Filter and sort fields still report catalog diagnostics. - The structured-query runtime change affects the generated `webstudio-features` fixture, which is regenerated in this PR. ## Verification - 561 Content Engine tests - 2,413 Project Build tests - 253 Design System tests - 1,794 Builder tests - 67 focused Builder regression tests after the final navigation change - 11 ResettableLabel browser tests - 128 focused MCP tests - Builder, Content Engine, Design System, and Project Build typechecks - Repository lint and package-boundary checks - Generated documentation checks - Full workspace fixture build with `pnpm -r fixtures:build` - Formatting and diff checks - New regression tests were demonstrated failing before their fixes and passing afterward ## Documentation impact - [x] Updated the Content Engine guide for field descriptions, dynamic entry pages, actionable validation, **Edit file**, and **Open on canvas** - [x] Updated MCP guidance so collection fields include editor-facing descriptions |
||
|
|
d6375096ff |
fix: improve asset upload retries and diagnostics (#6364)
## Summary - retry only transient asset upload failures after a short backoff - return ASSET_UPLOAD_RETRY_EXHAUSTED with retryability and HTTP status for persistent failures - preserve successful batch uploads and support retrying the failed JPEG alone ## Verification - pnpm --filter @webstudio-is/http-client test -- src/index.test.ts - pnpm --filter @webstudio-is/http-client typecheck - pnpm --filter webstudio test -- src/error-codes.test.ts Fixes #6363 |
||
|
|
39c290bfa7 |
fix: resolve MCP-reported runtime and component issues (#6362)
## Summary - harden MCP runtime behavior around asset uploads and resources, HTTP responses, component and Content Block application, data reads, and Chromium screenshots - reject shared Slots inside Content Block templates and avoid unsafe unused-asset findings when Content Blocks can hide MDX dependencies - expand named grid-area values according to CSS shorthand fallback rules - add a consent-safe YouTube preconnect control and only warm origins that are actually used - add focused and end-to-end regression coverage for the reported paths ## Verification - project-build: 2,419 tests passed - css-data: 4,623 tests passed, 1 skipped - sdk-components-react: 134 tests passed, 1 skipped - high-impact CLI fixture: 7 tests passed - Builder asset REST service: 22 tests passed Closes #6336 Closes #6339 Closes #6353 Closes #6354 Closes #6355 Closes #6356 Closes #6357 Closes #6358 Closes #6359 |
||
|
|
eb61139e5a |
feat: Scale publishing allowance with workspace seats (#6352)
Builder already counts production builds for the project owner, including publishes created through MCP and CLI. This change scales the allowance used by Builder with the owner's paid seat capacity, so five seats at 100 publishes each give 500 publishes per day. Free stays at 10. Closes #6351 ## Implementation The existing `userPublishCount` endpoint still reads the owner-wide `user_publish_count` view. For a project, it now returns the project owner's base allowance multiplied by the owner, included member seats, and purchased extra seats. Builder uses that returned allowance in its existing publish UI. The count remains owner-wide. MCP and CLI publishes contribute to it because they create production build records, but their publish endpoints do not enforce this Builder-side limit. No database, server publish-path, dependency, fixture, or generated-file changes are included. ## Checklist - [x] Calculate the paid allowance from the owner, included seats, and purchased extra seats. - [x] Keep Free at 10 publishes per day. - [x] Reuse the existing owner-wide publish count. - [x] Use the calculated allowance in Builder. - [x] Review documentation impact; no Builder documentation changes are needed for this small allowance update. - [ ] Update the pricing page to explain the publishing allowance and how seats increase it. - [x] Review fixture impact; fixture inputs and outputs are unchanged. - [x] Review the final diff for unnecessary changes. ## Verification - The project router tests pass, including the five-seat 500-publish allowance. - The new assertion fails against the previous implementation and passes with this change. - Builder browser tests passed. - Project and Builder typechecks passed. - Formatting, lint, and package-boundary checks passed. - All GitHub Actions workflows passed. - Agent evaluations do not cover this flow and were not run. |
||
|
|
2c51bc9928 |
fix: Restore Cloudflare publishing with Wrangler 4 (#6350)
Publishing fails because Wrangler 3 cannot parse the JSON import attributes used by `html-tags@4`. Upgrade the CLI and Cloudflare template to Wrangler 4.130.0 and regenerate the fixture and lockfile used to package the publish artifact. Wrangler 4 also rejects Worker deployment when it finds the Pages configuration. Add a SaaS-only `wrangler.jsonc` that takes precedence over the Pages template's TOML configuration. Publish commands still supply the Worker name and compatibility date. Fix the staging smoke check's compatibility-date scope and shell expansion. - [x] Upgrade Wrangler and regenerate the publish fixture and lockfile. - [x] Reproduce the original parser failure and verify it passes with Wrangler 4. - [x] Build the packaged artifact and pass the staging smoke check and both SaaS publish dry runs, including dispatch-namespace arguments. - [x] Pass 383 existing template tests, CLI and fixture typechecks, repository lint, and all fixture generation from checked-in data. - [x] Review documentation impact: no user-facing documentation changes are required; the existing Node 22.12+ requirement remains sufficient. - [ ] Complete staging CI and manually test publishing. [Publish artifact build](https://github.com/webstudio-is/webstudio/actions/runs/34400149252) is running; [staging deployment](https://github.com/webstudio-is/webstudio/actions/runs/34400149301) is queued. Remix 2 still declares a Wrangler 3 peer dependency; the packaged production build and both publish dry runs passed with v4. Agent evaluations were not run. |
||
|
|
13952a7d34 |
fix: Preserve Global root tokens when importing templates (#6348)
Inserting the CMS Sitemap marketplace page could detach existing Global root tokens and break styles across existing pages. Preserve the root's existing style-source selections in their original order, then append mapped incoming sources without duplicates. Incoming local declarations continue to merge into the existing root local source. The MDX save fix is now included in main through `commitAssetContentUpdate`. This PR retains an E2E assertion that saved MDX revisions are not persisted again through `build.patch`. Closes #6347 Verification and delivery: - [x] Add four regression cases covering empty, local-only, token-only, and mixed incoming root selections, including repeated imports, token remapping, and local declaration merging. All four failed before the fix and pass after it. - [x] Rebase onto main and rerun style-copy and page-copy tests: 55 passed. Formatting and diff checks passed. - [x] Verify the cloned project locally: reproduce the broken Home canvas before the fix and restore it with Undo. After the fix, insert Sitemap and verify Home retains its logo sizing, typography, spacing, rounded corners, and both Global root tokens after reload. - [x] Verify the MDX E2E assertion fails with duplicate persistence and passes with the fix. Before rebase, all 13 shard 4 tests passed locally with four workers, along with relevant typecheck and lint checks. - [x] Resolve the rebase conflict using main's shared MDX implementation and remove the duplicate helper from this branch. - [x] Review documentation impact against marketplace, CSS-variable, and Content Block documentation: no documentation changes required. - [x] Review fixture impact: no fixture inputs, serialization formats, or generated contracts changed. No migrations are required. This prevents future imports from dropping root selections; it does not reconstruct selections already lost in previously saved projects. |
||
|
|
e69a3d2f8e |
feat: Create structured MDX entries from collection folders (#6317)
## Paragraph editing follow-up — |