Commit Graph
6821 Commits
Author SHA1 Message Date
Oleg Isonen efda26ed99 refactor: simplify advanced style editor setup 2026-11-02 09:15:49 +00:00
Oleg Isonen dce1cedc69 fix: Restore autocomplete in new Advanced style rows 2026-11-02 08:58:48 +00:00
Oleg Isonen a121e100e3 style: Make inline Advanced code editor transparent 2026-11-01 20:41:20 +00:00
Oleg Isonen cb6217e0c0 fix: Preserve Advanced style drafts and variable fallbacks 2026-11-01 15:33:30 +00:00
Oleg Isonen 53f6c4493f fix: Scope Advanced add draft to selected style block 2026-11-01 15:19:52 +00:00
Oleg Isonen 6b3dc57cd2 fix: Close Advanced declaration draft after save 2026-11-01 15:08:37 +00:00
Oleg Isonen 8b864856ed fix: Keep Advanced editing drafts and validation consistent 2026-11-01 14:50:26 +00:00
Oleg Isonen 3d9194280f fix: Align Advanced menu items 2026-11-01 14:28:37 +00:00
Oleg Isonen ec24571859 Scope section background to Style Panel 2026-11-01 14:11:55 +00:00
Oleg Isonen 22e8a36add Add sticky Advanced styles option 2026-11-01 14:06:42 +00:00
Oleg Isonen 36b3a39979 Remove Navigator CSS preview 2026-11-01 13:54:08 +00:00
Oleg Isonen 7ce09a5d32 Add saved inline code editing mode for Advanced styles 2026-11-01 13:41:00 +00:00
Oleg Isonen 6172f9b6d6 Add Advanced styles actions menu 2026-11-01 13:35:40 +00:00
Oleg Isonen 04bdaa955c fix: Delete advanced declaration from empty property name 2026-11-01 13:20:52 +00:00
Oleg Isonen f3f8302691 fix: Validate Firefox font smoothing in style blocks 2026-11-01 13:07:53 +00:00
Oleg Isonen 01a2bdc429 fix: Match Advanced add button to section buttons 2026-11-01 13:04:36 +00:00
Oleg Isonen db8d3c799a test: Use current style entry flow across browser checks 2026-11-01 12:32:07 +00:00
Oleg Isonen 5977b3462e test: Focus the new style property field 2026-11-01 12:20:45 +00:00
Oleg Isonen b99c965e5f fix: Keep style block checks aligned with inline entry 2026-11-01 12:12:03 +00:00
Oleg Isonen 8b7e934de3 test: Check inline CSS submission when leaving editor 2026-11-01 12:01:40 +00:00
Oleg Isonen 3f8b57ca1f feat: Edit selected style block in a centered CSS editor 2026-11-01 11:56:53 +00:00
Oleg Isonen eb5f6fb152 feat: Add styles from their insertion line 2026-11-01 11:46:49 +00:00
Oleg Isonen c2c6316026 docs: Explain expanded advanced CSS editing 2026-11-01 11:37:29 +00:00
Oleg Isonen fa1bda2327 feat: Expand advanced CSS editors in place 2026-11-01 11:34:42 +00:00
Oleg Isonen b8a5e89085 fix: Disable unavailable style menu actions 2026-11-01 11:15:43 +00:00
Oleg Isonen 87a2538bee fix: Start inline CSS property row on Tab 2026-11-01 11:00:13 +00:00
Oleg Isonen cc76e6f126 fix: Keep property name hover corners rounded 2026-11-01 10:56:31 +00:00
Oleg Isonen 32221deba8 Keep advanced CSS drafts on their selected instance 2026-11-01 10:42:46 +00:00
Oleg Isonen f8657bf7c4 Open multiline CSS editor beside its field 2026-11-01 10:35:01 +00:00
Oleg Isonen fc63ac5502 Open multiline CSS editing in maximized dialog 2026-10-31 15:24:49 +00:00
Oleg Isonen 4f6de89482 Refresh search and preserve multiline draft focus 2026-10-31 15:08:09 +00:00
Oleg Isonen 34262b8a0d Update Add styles blur submission expectation 2026-10-31 14:54:35 +00:00
Oleg Isonen ced1388d85 Preserve numeric units and focus on multiline submission 2026-10-31 14:50:09 +00:00
Oleg Isonen 2b797a2911 Guard renames of disabled CSS values 2026-10-31 14:39:05 +00:00
Oleg Isonen c538ef16ef Preserve CSS variables in multiline value editing 2026-10-31 14:21:57 +00:00
Oleg Isonen b877b44a7c fix: Preserve uploaded images during value editing 2026-10-31 14:08:47 +00:00
Oleg Isonen 819f4bfe6b fix: Keep unfinished styles visible after property changes 2026-10-31 13:56:56 +00:00
Oleg Isonen 76e725a5f2 fix: Start new styles in an inline declaration row 2026-10-31 13:42:42 +00:00
Oleg Isonen a166c4fd4f fix: Preserve values when editing advanced styles 2026-10-31 13:29:28 +00:00
Oleg Isonen b0d3a67127 fix: Show full advanced property names 2026-10-31 13:13:02 +00:00
Oleg Isonen a633a41e95 feat: Edit advanced CSS declarations inline 2026-10-31 13:07:40 +00:00
Oleg Isonen 7cab28b633 fix: Allow Form Resources to reach sibling API hosts (#6623)
A Form on `site.example.com` can now send a Resource request to
`api.example.com`. Cloudflare fetches use public routing, while requests
back into the same app are stopped even when they arrive through a
different hostname.

## Checklist

- [x] Enable public `fetch()` routing in the self-hosted Cloudflare
Worker and Pages templates.
- [x] Narrow Cloudflare Form Resource hostname checks to site hostnames,
including published aliases; keep the Node transport policy intact.
- [x] Explain the routing and recursion boundary in code comments.
- [x] Add focused regression tests and verify they fail before the fix
and pass afterward.
- [x] Reject Cloudflare Resource requests that re-enter the app through
an alias, and verify both Worker and Pages paths.
- [x] Run relevant package tests, typechecks, lint, and fixture builds.
- [x] Review the authoritative `docs/` content. No user guidance
currently describes this hostname policy, so no docs change is needed.

The `global_fetch_strictly_public` flag affects all Cloudflare `fetch()`
calls in the generated app. It routes same-zone requests through the
public front door. The known site hostnames are blocked before fetch; a
reserved request marker carrying the originating project ID stops direct
reentry through any additional self-hosted alias while allowing other
projects. The marker is set on every redirect hop.

Verification: SDK suite (914 tests), CLI prebuild suite (143 tests), SDK
and CLI typechecks, published types, lint, package boundaries,
formatting, full fixture pipeline, and both Cloudflare fixture
typechecks/builds passed. The new marker test failed before the fix and
passed afterward. Local Pages returned 508 for a marked request and 200
for an ordinary request. Local Worker returned 508 for a marked request;
an ordinary local request hit a fixture-only `assets/process` module
error. The optional local fixture-size check lacked the unrelated React
Router Netlify built client artifact; the prior PR CI fixture-size check
passed.

Staging test: moved from #6621 to `frm.staging`. The Builder deployed at
https://frm.staging.webstudio.is/ and the Cloudflare template artifact
build and validation passed.

- [x] Publish the test site from staging and verify a Resource call to a
sibling API hostname, plus recursive-call protection.

Live staging verification: Published `ee-trpc-test-ivan.wstd.work` from
Builder commit `35d22fc8a`. A temporary Resource to `api.wstd.work`
produced that host's HTTP 401 response in published page data,
confirming the request reached the sibling host. A marked request
initially returned 200 because the SaaS publish Worker uses a separate
entrypoint. The matching guard is in webstudio-is/webstudio-saas#673;
deploying that branch made the marked request return 508 while an
ordinary request returned 200. The temporary Resource and binding were
removed and the clean build was republished with the SaaS fix.

## Resource response limit follow-up

- [x] Enforce 1 MiB (1,048,576 decoded bytes) for all HTTP Resource
responses, including page Resources, dependencies, Form actions, and
cache hits; reject before cache writes.
- [x] Cancel oversized responses and report `RESPONSE_TOO_LARGE` without
retrying. Show: “Resource response exceeds 1 MiB. Request fewer fields
or use pagination.”
- [x] Verify exact boundaries, streamed overflow, compressed responses,
cache behavior, and Form/loader error propagation with regression tests.
- [x] Update Resource and Form documentation to explain the limit and
recovery.
- [x] Monitor CI after pushing the verified implementation. All checks
passed for `f59b770d45112581514eaa8bc42f57b7f27d290b`, including all ten
browser E2E jobs, visual regression, Linux/Windows fixtures, and staging
builds/deployments.

Verified locally: all 926 SDK tests, SDK typecheck and published types,
lint, package boundaries, Form browser boundary, formatting, full
fixture pipeline, and Cloudflare React Router fixture typecheck/build
passed. All 12 new tests and the updated transport test failed against
the previous implementation; disabling only the retry guard also
reproduced a duplicate attempt. A local Cloudflare runtime test with
gzip accepted exactly 1 MiB of decoded data and rejected one byte over.
The full fixture sync pulled an unrelated saved-project text change; the
original fixture source was restored and regenerated, leaving no fixture
diff.

The response limit is enforced before JSON parsing and before Resource
cache writes, and checked again when loading cache hits. Oversized
responses return `RESPONSE_TOO_LARGE` with `retryable: false`; the graph
honors that flag. System and Email Resources retain their own limits.
The implementation adds 59 net non-test code lines plus 5 documentation
lines, below the 70–100 estimate. Browser E2E passed in CI. Agent
evaluations were not run; they require separate permission and were not
needed for this transport change.


## Simplification follow-up

- [x] Reuse Content Engine's bounded byte reader for Resource bodies and
Form uploads; remove duplicate accumulation and cancellation loops
(estimate: about 40 fewer production lines).
- [x] Preserve response limits, request limits, cancellation, error
messages, and retry behavior; run existing SDK and Content Engine
coverage plus package/build checks.
- [x] Review documentation impact; behavior and approved copy should
remain unchanged.
- [x] Push the simplification and verify CI. All checks passed for
`755ec4210a7858fe298ad4d3a725a0167fb5bb26`, including all ten browser
E2E jobs and staging deployment checks.

The simplification removes 37 net non-test lines, reducing the
response-limit implementation from 59 added lines to 22. Content Engine
now exposes its existing byte-stream module directly and accepts a
caller-provided limit error. Resource bodies and Form uploads reuse that
reader. Native Response construction also replaces redundant
status/header copying. All existing tests remain.

Verification: 926 SDK tests and 655 Content Engine tests passed, along
with both packages' typechecks/builds, published types, lint, package
boundaries, Form browser boundary, formatting, the full fixture
pipeline, and a Cloudflare fixture build. Local Cloudflare runtime
checks passed for gzip at/over the limit and empty 204/205/304
responses. The generated fixture vendor change is limited to the shared
reader's optional error argument. Documentation and approved copy remain
accurate and unchanged.

## Response handling cleanup

- [x] Share bounded response reconstruction between protected fetches
and the cache; remove stale encoding/length headers after decoding
(estimate: 5–10 fewer non-test lines).
- [x] Reproduce the protected-response header bug, then verify the fix,
limits, empty responses, and existing SDK coverage.
- [x] Review documentation and comments for accurate scope; preserve
approved user-facing copy.
- [x] Run relevant checks, regenerate fixtures, push, and monitor CI.

The shared response reader fixes stale compression and length headers in
protected fetches and removes four net production lines (slightly below
the 5–10 estimate). All 927 SDK tests, types, published types, lint,
package boundaries, and Form browser boundary passed. The new regression
test failed on the old code and passed after the fix. Cloudflare runtime
checks passed for decoded bodies and empty 204/205/304 responses. The
existing Resource/Form documentation remains accurate; approved copy is
unchanged.

The reentry marker now carries the originating project ID. A different
project can serve the request; the same project rejects direct reentry
through any hostname. This is cooperative loop detection, not a sandbox
for arbitrary code.

- [x] Reproduce and fix overflow and redirect hangs when a response has
an unread clone; preserve stream cancellation and error handling for all
shared-reader callers.

The clone regressions failed before the fixes and passed afterward.
Cancellation still starts immediately and releases the reader lock, but
no longer waits for an unread tee branch. Both overflow rejection and
redirect following are covered. All 929 SDK tests and 655 Content Engine
tests passed, along with both typechecks and lint. A local Cloudflare
runtime also rejected a cloned oversized response promptly. Combined
with response reconstruction reuse, this cleanup removes five net
production lines. Fixture regeneration changes only the bundled
cancellation logic.

Final verification for `7761f67d6d1e0a853a6ef239f482ebaf9d70c1ae`: all
CI checks passed, including all ten browser E2E shards, visual
regression, package/Builder/CLI tests, size checks, Linux and Windows
fixtures, and staging deployment workflows. Full fixture regeneration
and the Cloudflare fixture build also passed locally. No agent
evaluations were run; they require separate permission and were not
needed for these fixes.

## Scope reentry protection to the project

- [x] Replace the global marker with the originating project ID and
compare it with generated project metadata before handling requests,
including cached requests.
- [x] Cover unrelated sites, same-project aliases, and redirects with
regression tests; demonstrate failure before the fix.
- [x] Review documentation and clarify that this is cooperative loop
detection, not a sandbox for untrusted code.
- [x] Regenerate fixtures, run relevant checks, push, and monitor CI.
Estimate: 20–30 implementation lines across both repositories, plus
generated metadata and tests.

Implementation: reuse the project ID already exported by the generated
home-page module; no new metadata file or package. The generated
Cloudflare Resource adapter passes the same ID to the SDK factory, which
now requires it. Guards compare that ID before rendering or cache
lookup. SDK and generated-adapter regression tests cover another project
returning 200 and an unknown same-project alias returning 508. Hosted
Worker tests verify the guard runs before the cache and permits another
project's cached response. The original guard and a blanket-guard
mutation fail the regressions. A local Cloudflare runtime reproduced the
expected 200/508 behavior. No user-facing copy or documentation changes
are needed; code comments state the cooperative boundary. The fix adds
19 implementation lines across both repos, below the 20–30 estimate,
plus tests/configuration and regenerated fixtures. Existing deployments
require republishing with the updated sender and guard to use
project-specific markers.

Final project-specific reentry verification: 930 SDK tests, 143 CLI
prebuild tests, and 41 hosted-template tests passed. SDK/CLI types,
published SDK types, lint, package boundaries, full fixture
regeneration, both Cloudflare fixture builds, and the Pages function
bundle passed. The actual Pages function returned 200 for another
project's marker and 508 for its own marker through an unknown alias in
a local Cloudflare runtime. All CI checks passed for Builder
`433f9a359d469ca3669e383c4516c3e805ea22a1`, including all ten E2E shards
and staging workflows; companion SaaS
`3e28e7e33813dd968f33caac35dbbba52a3847d3` checks and preview deployment
also passed. Agent evaluations were not run because they require
separate approval; no evaluation changes were needed.
2026-10-30 22:42:27 +01:00
Oleg Isonen c94e5a94c1 fix: stop evaluating page settings for sitemaps (#6614)
## Problem

A saved page setting could run as code when the Builder or CLI generated
a sitemap.

## Change

Read the sitemap setting as a literal value instead of executing it.
This PR does not change how expressions are compiled for published
sites.

## Tasks

- [x] Reproduce sitemap execution on the unpatched code
- [x] Reproduce page metadata execution during static prerendering on
the unpatched code
- [x] Stop evaluating sitemap settings
- [x] Remove the publish-time expression guard and its tests
- [x] Run the relevant checks and review the diff
- [x] Review Builder documentation impact: no documentation change
needed
- [x] Push the simplified fix
- [x] Confirm required CI checks pass on the final commit

## Verification

On the unpatched code, a saved `excludePageFromSearch` expression ran in
the CLI process during sitemap generation. A separate saved
page-description expression ran during static prerendering. This PR
addresses the sitemap path only; the static prerendering path remains a
separate issue. The hosted service was not tested.

On this commit, 19 sitemap tests and 141 CLI prebuild tests passed. SDK
and CLI typechecks, root lint, formatting, package boundary checks, and
`git diff --check` passed. All 23 main-workflow jobs passed, along with
visual regression, PR lint, and submodule checks.

The final diff has two files: the sitemap helper and its regression
test.
2026-10-29 00:49:44 +01:00
Oleg Isonen 6bfc8a80a7 feat: Allow owners to use Content mode (#6619)
A Free project owner could not switch to Content mode directly, but
could open a free Builder share link and use Content mode there. Owners
can now use the switch on any plan. Share-link visitors can use it only
when the project plan includes Content mode.

## Changes

- Keep Content visible in the mode menu. When it is unavailable, disable
it and show a Pro badge instead of the shortcut.
- Let project owners use Content mode on any plan.
- On Free projects, disable Content mode for every share-link
permission. A Content-only link opens in Preview; a Builder link still
opens in Design.

## Checklist

- [x] Keep the Content menu row visible and test its badge and shortcut.
- [x] Update the permission rule and tests for Free owners, Free share
links, and Pro share links.
- [x] Verify a Free Content-only link falls back to Preview mode.
- [x] Review Builder docs. The Modes guide already says owners can try
Content mode, and the Share links guide says Content-only links require
Pro. No copy change is needed.
- [x] Run focused tests, Builder typecheck, and lint after the
permission change.
- [x] Review the non-test diff for redundant code.
- [x] Set a paid plan only in E2E tests that open Content mode through
an Editor share link. Keep unrelated fixtures on their original plan.
- [x] Fix the Design-mode fallback for Free Content-only links and add a
regression test.
- [x] Confirm required CI checks pass on the latest commit.

## Verification

- Builder typecheck: passed.
- Oxlint on changed code: passed.
- Focused tests: 66 passed across mode, permission, and state suites.
The two new Design-entry cases failed before the fix.
- Latest-commit CI: Main workflow, Visual regression, Check submodules,
and Lint PR passed. Every E2E shard passed.
- Manual Storybook screenshots were not run because approval was not
received.

## Known limit

The Share dialog blocks Content-only links on Free plans. Token creation
and update do not enforce that plan limit on the server. This PR
controls which Builder mode a share-link visitor can enter; it does not
change token issuance.

Closes #6618
2026-10-28 23:36:18 +01:00
Oleg Isonen 283929bb49 fix: Make Form progress text editable (#6617)
A new Form’s Progress message shows “Submitting…”, but Builder cannot
edit that text because it sits directly beside the nested byte summary.
The template now gives the message its own Span. Adding an element to an
existing text container also wraps its existing text, using the same
guard for Builder and MCP insertion and Builder moves.

Closes #6616
Ref #6605
Ref #5992

## Plan

- [x] Reproduce the new Form structure through template, Builder, and
MCP insertion.
- [x] Give the submission text its own editable element while preserving
the bound summary.
- [x] Add Form regression tests, update docs, and verify the first
change.
- [x] Reproduce insertion into an existing text container through the
shared runtime and MCP.
- [x] Share destination-parent normalization across insertion and move,
preserving authored fragment internals and replace behavior.
- [x] Add regression coverage for editable text, rich text, undo, and
insertion results.
- [x] Review documentation impact of the shared guard.
- [x] Run targeted tests, typecheck, lint, and applicable broader
checks.
- [x] Confirm required CI for the final commit.

## Scope and compatibility

The guard acts on existing content in the destination parent when
inserting an element. It does not rewrite descendants inside the
inserted fragment, so intentionally mixed rich text remains as authored.
Indexed replacement wraps surviving text; full replacement leaves no old
wrappers. Generated spans and the parent rewrite are committed together,
so undo and redo restore the original structure. Existing saved Forms
keep their structure; no migration is included. The submission wording
and bound byte summary stay the same.

The shared runtime change adds 88 net non-test lines, above the 45–65
line estimate. The extra lines cover the two position formats used by
moves and insertions, atomic parent patching, indexed replacement,
generated ID checks, and insertion results. No schema, package, or
production data changes.

## Verification

Local: project-build 2,667 tests passed; Builder insertion 45 tests
passed; project-build and Builder typechecks passed; targeted oxlint,
oxfmt, and git diff checks passed. An independent Astra review found no
blocking defects. Agent evaluations require separate approval and were
not run. Required CI for the final commit passed: 35 successful checks
and one skipped check. Builder end-to-end shard 8 failed once during
generated Preview submission with status “unknown”; its targeted rerun
passed without source changes.
2026-10-28 19:26:29 +01:00
Oleg Isonen c9f6435aba fix: Allow ECMAScript module asset uploads (#6613)
A `.mjs` file currently fails to upload with HTTP 500, so the CLI
retries the same unsupported format and reports a retry-exhausted error.
This PR lets people upload ECMAScript modules as JavaScript assets.
Files with unsupported extensions now get HTTP 400 and the CLI does not
retry them.

Closes #6612

The existing asset-type registry now includes `.mjs` with the same MIME
type and editor as `.js`. Filename validation uses a typed error so the
Assets API can return 400 without inspecting error text. Transient
server failures still retain the existing retry. The upload still
transfers the file and checks its size and content; this change does not
remove those costs.

- [x] Reproduce the `.mjs` rejection locally and show new tests fail
before the fix.
- [x] Accept `.mjs` in upload detection, serving MIME lookup, and the
Assets panel Code filter.
- [x] Return HTTP 400 for unsupported extensions.
- [x] Stop the CLI after a non-retryable upload response. The regression
test failed with two requests before the fix and passes with one
afterward; HTTP 500 still retries.
- [x] Review documentation impact and add `.mjs` to the authoritative
Assets guide. The retry behavior needs no further docs change.
- [x] Verify fixture impact: no fixture asset has format `mjs`; no
generated fixture input or output changes.
- [x] Run focused tests (SDK 133, asset uploader 8, Builder Assets API
23), then full SDK (910) and asset-uploader (313) suites.
- [x] Run SDK, asset-uploader, Builder, project-build, and HTTP-client
typechecks; lint, package-boundary check, formatting, and diff check.
- [x] Verify required CI checks after the retry fix: main workflow
(including all ten Builder E2E shards), visual regression, staging
build, lint, and submodule checks passed.

The reporter’s exact package file was not available. The regression uses
a small valid `.mjs` file and verifies the same upload-validation path.
The full agent evaluation suite was not run, as requested; focused tests
were used instead.
2026-10-27 14:32:28 +01:00
Oleg Isonen 9a8ae2dc8f feat: Customize Form progress feedback (#6606)
Closes #6605

New Forms show editable feedback while Resource actions run. The
`formProgress` variable starts with `status: "idle"`, `loaded: 0`,
`total: 0`, and `files: []`. It becomes pending during submission, then
returns to idle. The existing `formState` still reports only initial,
success, or error.

The Progress container says “Submitting…” and adds measured
whole-request bytes when the total is known. Files include ID, field
name, name, size, and type. The browser cannot measure reliable per-file
transfer bytes in the single multipart request. The binding editor
suggests one example file to reveal those fields; the example never
enters the actual Form value. Saved Forms retain their existing bindings
and submission message.

## Checklist

- [x] Keep the existing Form outcome variable and add upload activity,
byte counts, and file details.
- [x] Show zero byte defaults on insertion, new submissions,
cancellation, and Preview reset without fake runtime files.
- [x] Suggest file fields in Form and Resource bindings while
evaluation, reset, rendering, and stored values use real data.
- [x] Preserve Builder Preview headers, authentication, response checks,
and cancellation.
- [x] Keep existing success/error feedback and saved-Form fallback.
- [x] Reset external progress when an active published Form unmounts.
- [x] Update Form, Variables, and MCP/CLI guides; clarify the older
screenshot and final-only simulation. Generated MCP docs check passes.
- [x] Audit Form and Variables docs against final progress behavior;
clarify the older Variables screenshot.
- [x] Cover lifecycle, transport, repeated submission, cancellation,
unmount, Preview, template, MCP binding/style, and editor completion
with focused tests.
- [x] Run relevant typechecks, lint, formatting, fixture generation, and
independent review.
- [x] Required CI checks pass on the latest commit.

## Verification

Local focused Form browser tests (25), Form template tests (12), Builder
Preview and Form context tests (14), and mounted editor example/reset
tests (6) pass. Builder, SDK React, SDK registry, and project-build
typechecks pass, as do lint, formatting, and fixture generation. The
fixture sync regenerated two unrelated linked-project site paths; those
outputs were restored before commit. Independent review found no
remaining issues. All latest-commit checks passed; E2E shard 9 passed on
a targeted rerun after its two Form tests also passed locally with 11
related tests.

This follow-up adds 162 net non-test lines, more than the initial
estimate. The extra code identifies the actual callback-bound variable
by ID, even when renamed, and gives autocomplete a separate example
scope so it cannot affect actual values. One provider covers Form fields
and Resource editors. No schema or package was added.

The existing Variables screenshot predates `formProgress`; its
explanatory text is current. The React Router fixture's built browser
client grew by 4 KiB on Linux CI (376 → 380 KiB), and its checked limit
matches that measured output. Multipart transfer remains one whole
request.

Browser submission supplies live progress. MCP can discover
`formProgress`, bind the Progress container, and style it; server
simulation reports final outcomes and does not measure browser uploads.
2026-10-26 14:38:12 +01:00
Oleg Isonen de166827bc fix: Build existing previews from the isolated directory (#6609)
`webstudio preview --generate false` now rebuilds the generated app from
`.webstudio/preview`. A linked project does not need a root
`package.json`, and the command still skips regeneration.

Closes #6608

The fix changes the working directory returned by the existing preview
preparation path. It adds no new state or fallback path. The regression
test creates a linked project without a root package file, then runs a
real build script from the isolated preview directory. It failed before
the fix and passes after it.

- [x] Reproduce the reported failure on current `main`.
- [x] Fix the preview directory with one production-line change.
- [x] Add a red/green regression test that builds without a root package
file.
- [x] Run focused preview and preview-server tests (48 passed), CLI
typecheck, lint, and formatting.
- [x] Review docs impact: existing help and `docs/` already say
generated preview files and dependencies live in `.webstudio/preview`;
no docs change needed.
- [x] Review fixture impact: no fixture inputs or outputs are changed.
- [x] Run full Luna/low agent evaluations: 6/9 fixtures passed; three
form fixtures missed goals unrelated to this path.
- [x] Verify required CI on the final commit (all workflows passed).

Full Luna/low agent evaluations failed overall:
`managed-form-authoring-v1` missed `contactPage`,
`managed-form-runtime-v1` missed `runtimeFormAction`, and
`form-modes-authoring-v1` missed three form-mode checks. The changed
`--generate false` branch is not used by these MCP fixtures;
`mcp-preview` always generates. Accepted baselines use another model, so
no compatible baseline comparison or baseline update was made.
2026-10-26 13:06:51 +01:00
Oleg Isonen 59e0e1111f fix: Publish uploaded fonts used through CSS variables (#6604)
## What changes

Uploaded fonts used through CSS variables now reach the published site.
Previously Builder could render them, but publishing filtered them out
and emitted no `@font-face` rules. This fixes root font variables used
by body and heading tokens with either quote style. The asset manager
also protects those uploaded fonts from being deleted as unused.

Closes #6603

## Implementation

The published bundle follows variables used by `font-family`, parses
their values as font stacks, and handles nested variables without
looping on cycles. Asset usage now uses the same lookup, records each
referring style, and counts every uploaded weight in a family. Replacing
a font used through a variable is blocked because the variable value
cannot be rewritten by the current asset replacement path. Visitors
still download each font file that the page uses; this change makes
those files available rather than falling back to system fonts.

## Checklist

- [x] Reproduce missing font assets in a published project bundle.
- [x] Keep uploaded fonts referenced by root CSS variables and heading
tokens.
- [x] Verify both single and double quotes; exclude unrelated fonts.
- [x] Verify regression tests fail before the publishing fix and pass
afterward.
- [x] Keep fonts referenced through CSS variables out of the
unused-assets list and block deletion.
- [x] Protect every uploaded weight in a used family and block unsafe
font replacement.
- [x] Verify the asset-usage regression tests fail before each fix and
pass afterward.
- [x] Run targeted Builder, project-build, SDK CSS, and CLI prebuild
tests.
- [x] Run Builder, project-build, and CLI typechecks, lint, formatting,
and diff checks.
- [x] Review `docs/`: existing custom-font and CSS-variable guides
already describe the supported behavior; no text change is needed.
- [x] Check fixture inputs and outputs: no fixture contains font
variables, so regeneration is not needed.
- [x] Push the tested changes.
- [x] Monitor required CI checks and fix any failures.

- [x] Simplify font family collection and asset usage without changing
behavior.
- [x] Re-run focused tests, typechecks, and CI after the cleanup.

The cleanup removes a second per-style deduplication map. The collector
now reports each family once per declaration. Production code shrank by
four net lines; the remaining callback and variable map preserve each
style's usage and protect asset deletion and replacement.

- [x] Fix the fixtures diff check after submodule setup moves to current
main.
- [x] Verify the check still catches generated files and edits inside
the submodule.
- [x] Push the CI fix and monitor both PR and push workflows.

## Verification

- Before the publishing fix, both quote variants produced an empty font
asset list in the published bundle. Afterward, both include Inter and
Playfair Display while excluding an unused uploaded font.
- Asset usage tests failed before the follow-up fix for both quote
styles, repeated references, multiple uploaded faces in one family, and
unsafe replacement. They now pass.
- Project-build asset and style utility tests: 95 passed.
- Builder bundle tests: 11 passed.
- CLI prebuild tests: 141 passed.
- Builder, project-build, and CLI typechecks: passed.
- Changed-file lint, formatting, and `git diff --check`: passed.
- Local agent evaluations were not run because they require separate
approval.
- CI: Lint PR, Check submodules, Visual regression, and Main workflow
passed. One unrelated Form E2E test failed on its first run; shard 10
passed on rerun.
- Cleanup checks: 95 project-build tests, 11 Builder bundle tests, and
141 CLI prebuild tests passed. Project-build, Builder, and CLI
typechecks, changed-file lint, formatting, and diff checks passed.
- Cleanup CI: Lint PR, Check submodules, Visual regression, and Main
workflow passed; all ten Builder E2E shards passed.
- CI fix: a local Git reproducer confirmed pointer movement passes while
tracked changes in the parent or submodule fail. YAML parsing and `git
diff --check` passed. The staging push workflow, Linux and Windows
fixture jobs, and all PR checks passed.
2026-10-25 19:46:53 +01:00
Oleg Isonen 659e953869 fix: Preserve transitions and animation preview behavior (#6602)
Transition variables no longer get copied into unrelated timing fields.
Generated Text/Stagger animations use the saved `slidingWindow` prop,
while older `charWindow` configurations still work. Easing moves in the
expected direction. Windows preview-install reports include the process
failure code when available.

Closes #6598
Ref #6593
Ref #6599
Ref #6594

The animation runtime lives in [sdk-components-animation
#38](https://github.com/webstudio-is/sdk-components-animation/pull/38).
The private PR is merged; this PR points to its merged commit. #6593 was
tested on its exact saved project in headless Chromium and closed as not
reproducible; the confirmed prop leak is fixed here. #6594 was closed
after a documented local repro attempt; this PR improves the next
report.

## Work

- [x] Reproduce the transition bug; add regression coverage in parsing
and generated CSS.
- [x] Preserve unresolved `transition` shorthands for the browser to
resolve.
- [x] Keep old `charWindow` values working in Text and Stagger
animations, with a red/green regression test in the linked private PR.
- [x] Reproduce and fix the saved animation prop mismatch in generated
helpers.
- [x] Verify text/stagger easing in unit tests and Chromium/Firefox.
- [x] Add safe preview-install process details for future Windows
reports.
- [x] Update Builder property help and both animation docs pages.
- [x] Run focused animation tests, typecheck, lint, package build, and
animation fixture build after the compatibility fix.
- [x] Point the animation submodule to the merged #38 commit.
- [x] Verify required CI on the final commit (all workflows passed; one
unrelated E2E shard passed on rerun).
- [x] Find the production share token and build #6593’s exact project
with its reported 0.307.0 packages.
- [x] Compare intermediate scroll styles on #6593’s exact project.
Visible targets animate in both builds; the leaked attributes disappear
with this fix.

Known limit: the reported static-target symptom in #6593 and the Windows
environment in #6594 were not reproduced. The confirmed animation prop
leak and reporting gap are fixed, without claiming the unreproduced
symptoms are solved.
2026-10-25 19:12:25 +01:00