## Summary
- Add CLI project import support from synced `.webstudio/data.json` into
another project via a destination share link.
- Move project bundle import/export contract into
`@webstudio-is/protocol`, including bundle versioning, staged upload
constants, schema validation, and fixture coverage.
- Upload project bundle data through staged TUS upload before calling
the import RPC to avoid request body limits.
- Upload referenced assets as binary files through the existing asset
upload route before importing asset rows.
- Add `--skip-assets` and `--ignore-version-check` import options.
- Add retry handling for transient missing imported asset files by
re-uploading only the reported missing assets.
- Share missing-asset import error formatting/parsing through protocol
to avoid duplicated string contracts.
- Preserve browser asset upload behavior while adding API upload
support.
- Normalize schema naming across the branch to lower-case names without
`Schema` suffix.
Closes https://github.com/webstudio-is/webstudio/issues/4586
Closes https://github.com/webstudio-is/webstudio/issues/4619
## Summary
Fixes shared Slot editing so linked Slot occurrences stay consistent
across structural edits and labels.
## Changes
- Fixed moving a direct Slot child out of a Slot so the child is removed
from all linked Slot occurrences.
- Fixed unwrapping a direct Slot child so the child is removed from all
linked Slot occurrences.
- Added linked Slot label sync when renaming from Navigator or Settings
panel.
- Added/updated tests for canonical Slots, legacy Slots, nested Slot
children, keyboard moves, unwrap, reparent, and label sync.
- Simplified stale Slot detach logic that was incorrectly cloning only
the selected Slot occurrence.
## Testing
- `pnpm --filter @webstudio-is/builder test --
app/shared/instance-utils/...`
- `pnpm --filter @webstudio-is/builder test --
app/builder/shared/commands.test.ts`
- `pnpm --filter @webstudio-is/builder typecheck`
- `pnpm lint`
- `git diff --check`
## Summary
Fixes insertion into legacy Slot instances whose children are stored
directly under the Slot instead of under the newer hidden Fragment
wrapper.
Previously, adding an element to an old Slot could insert the new
element into the first existing Slot child. The insertion path assumed
the first Slot child was always a Fragment.
## Changes
- Normalize legacy Slot children during insertion by wrapping direct
Slot children in a Fragment.
- Preserve the existing behavior for valid `Slot -> Fragment ->
children` structures.
- Add regression tests for:
- low-level `insertInstanceChildrenMutable`
- UI-facing `insertWebstudioElementAt`
## Validation
```bash
pnpm --filter @webstudio-is/builder test -- app/shared/instance-utils.test.tsx
pnpm --filter @webstudio-is/builder typecheck
```
Originally we made the token color purple to make it more distinct from
local style source, but now local style source is visually different and
having both blue makes sense because when its blue, active style values
are matching the blue color and it makes it more clear what that blue
color on values means.
## Summary
Adds timezone selection support to the Time component.
Users can now choose:
- `UTC` for deterministic server/client rendering
- `visitor` to render UTC during SSR, then update to the browser
timezone after hydration
- an IANA timezone such as `Europe/Berlin`
Also adds a timezone combobox control in the settings panel with common
timezone options, supported IANA timezone values, typed input, and
preview descriptions.
## Changes
- Added `timeZone` prop to the Time component, defaulting to `UTC`
- Updated standard and custom-format date rendering to use the selected
timezone
- Added visitor timezone mode with hydration-safe UTC fallback
- Added `timeZone` prop metadata and settings-panel control support
- Added timezone combobox control with previews
- Added tests for:
- explicit timezone rendering
- custom format timezone rendering
- date rollover in another timezone
- invalid timezone fallback
- trimmed timezone values
- visitor timezone hydration behavior
## Verification
- `pnpm --filter @webstudio-is/sdk-components-react test --
time.test.ts`
- `pnpm --filter @webstudio-is/sdk-components-react typecheck`
- `pnpm --filter @webstudio-is/builder typecheck`
- `pnpm exec prettier --check ...`
**Summary**
Fixes content-mode edit permissions so editor-only users can perform
allowed content workflows without backend “build permission” failures.
**Changes**
- Added shared content-mode permission validation used by backend
authorization.
- Aligned content-mode capabilities around editable props, editable
instances, content roots, pages, assets, and template insertion.
- Allowed content-safe instance/text/page/template/style changes while
keeping design/data/resource changes build-only.
- Updated template insertion to preserve content-safe local styles and
reuse tokens by id.
- Added accessible `SyncStatusDot` for e2e-visible sync state without
replacing the existing sync status UI.
- Added builder e2e setup with Postgres/PostgREST and a first
content-mode browser test:
- edit existing text as an editor-only user
- wait for saved state via the sync status dot
- reload and verify persistence
**Verification**
- `pnpm --filter=@webstudio-is/builder test -- sync-status.test.tsx`
- `pnpm --filter=@webstudio-is/builder typecheck`
- `git diff --check`
- `pnpm e2e:builder`
Adds permission protection around page templates so content editors can
create pages from templates without being able to open, edit, or patch
template pages directly.
## Description
1. Issue: https://github.com/webstudio-is/webstudio/issues/4931
2. Adds V1 of Page Templates for designers:
- stores project-local page templates separately from published pages
- adds a designer-only Page Templates section in the Pages panel
- supports creating, editing, duplicating, deleting, and reordering
templates
- supports creating a regular page from a template through a prefilled
page settings dialog
- makes canvas/page awareness, asset usage, asset replacement, and
page-copy utilities template-aware while keeping templates out of normal
public page lookup paths
## Steps for reproduction
1. Open the builder in Design mode and open the Pages panel.
2. Click the New Template button in the Page Templates section.
3. Fill in template settings, including name, title, description, search
toggle, social image, and custom metadata.
4. Click Create template and expect the new template to appear under
Page Templates and load on the canvas with an editable blank body.
5. Add content to the template canvas, reopen template settings, change
metadata, close/reopen settings, and expect the changes to persist.
6. Click the `+` action on the template row and expect a Create Page
from Template dialog prefilled from the template with a unique page
path.
7. Change page settings, click Create page, and expect a normal page to
be created in the root folder with copied content and metadata while the
template remains unchanged.
8. Right-click a template row, choose Duplicate, and expect a new
independent template copy with a deduplicated name.
9. Drag templates within the Page Templates section and expect the order
to persist.
10. Right-click a template row, choose Delete, confirm deletion, and
expect the template and its canvas tree to be removed. If the deleted
template was selected, expect the builder to navigate back to the home
page.
11. Switch to Content mode and expect template management UI to be
hidden.
12. Use a template social image from Assets, check asset usages, replace
the asset, and expect the template social image reference to update.
## 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 things may be not obvious (the "why",
not "what")
## Before merging
- [x] tested locally and on preview environment (preview dev login:
0000)
- [ ] updated [test
cases](https://github.com/webstudio-is/webstudio/blob/main/apps/builder/docs/test-cases.md)
document
- [ ] added tests
- [ ] if any new env variables are added, added them to `.env` file
---------
Co-authored-by: shreyanshkotak <sk7739@nyu.edu>
**Summary**
Fixes slot occurrence mutations so operations on one rendered slot
instance do not leak into other slot instances sharing the same slot
content.
**Changes**
- Unwrap now skips the hidden slot `Fragment` and unwraps the visible
slot occurrence on the first command.
- Added shared slot content detachment before path-sensitive mutations:
- delete
- reparent
- wrap
- duplicate
- convert `Slot` to non-slot component
- Added regression tests for two slot instances sharing `fragment ->
div` content.
**Validation**
```bash
pnpm --filter @webstudio-is/builder test -- app/shared/instance-utils.test.tsx
pnpm --filter @webstudio-is/builder typecheck
```
**Summary**
Validates CSS custom property values as raw CSS token streams before
saving/parsing them.
This prevents malformed values like `#sd'` from being normalized into
`sd` or serialized into broken canvas CSS that invalidates the whole
generated rule.
**Changes**
- Added tokenizer-based validation for custom property values.
- Rejects malformed strings, URLs, comments, unmatched blocks, and
trailing backslashes.
- Preserves raw custom property declaration values before `css-tree` can
repair/normalize them.
- Prevents custom property value editing from coercing invalid input
through fallback parsing like `kebabCase()` or color recovery.
- Added regression tests for advanced panel input and CSS data parsing.
**Verification**
- `pnpm --filter @webstudio-is/css-data test -- parse-css-value.test.ts
parse-css.test.ts`
- `pnpm --filter @webstudio-is/builder test --
parse-intermediate-or-invalid-value.test.ts parse-style-input.test.ts`
## Description
Adds support for plain text pages. Related to
https://github.com/webstudio-is/webstudio/issues/4257
This PR introduces `text` as a supported document type, stores plain
text page content in page metadata, and generates `text/plain` route
handlers for Remix and React Router templates.
It also limits HTML-specific Builder actions on text pages, excludes
XML/text pages from the generated static sitemap, and adds SDK coverage
for text document schema and sitemap behavior.
## Steps for reproduction
1. Create or edit a page in Builder.
2. Set the document type to `TEXT`.
3. Enter plain text content in page settings.
4. Build with a Remix or React Router template.
5. Open the generated text page URL, for example `/robots.txt`.
6. Expect the response body to contain the configured text content with
`Content-Type: text/plain; charset=utf-8`.
7. In Builder, expect HTML insert/wrap/convert/tag actions to be
unavailable for text pages.
## 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
- [ ] added inline comments where things may be not obvious (the "why",
not "what")
## Before merging
- [x] tested locally and on preview environment (preview dev login:
0000)
- [ ] updated [test
cases](https://github.com/webstudio-is/webstudio/blob/main/apps/builder/docs/test-cases.md)
document
- [x] added tests
- [ ] if any new env variables are added, added them to `.env` file
---------
Co-authored-by: shreyanshkotak <sk7739@nyu.edu>
Co-authored-by: Shrek <122366903+shreyanshkotak@users.noreply.github.com>
Closes https://github.com/webstudio-is/webstudio/issues/3991
Adds HTTP Basic Authentication support for published pages and
project-level `.wsauth` rules.
This introduces a new `@webstudio-is/wsauth` package that owns the
generic authentication format logic: parsing, validation, serialization,
route matching, resource generation, and request authentication. The
current supported method is `basic`, with the package structured so
additional auth methods can be added later.
Builder changes include:
- Page Settings now has an `Authentication` section for per-page Basic
Auth credentials.
- Project Settings now has an `Authentication` section for editing
`.wsauth` route rules.
- Page Settings was split into section-specific files with focused
tests.
- Auth UI shows Pro badges/info tooltips but remains editable.
- Publishing to custom domains is blocked on plans without `allowAuth`
when either page auth or project auth is configured.
- ProBadge now renders as a real pricing link and uses improved text
alignment.
Build/publish changes include:
- CLI prebuild generates and merges `.wsauth` entries.
- Published app templates enforce auth for HTML/XML routes.
- Generated auth resources are shared between build output and runtime.
Closes https://github.com/webstudio-is/webstudio/issues/5336
Adds a tooltip to the Transforms section `+` button when transforms are
unavailable for the selected element.
The Transforms section now stays visible but inactive for unsupported
elements, and the tooltip explains that transforms do not work with
`display: inline` and suggests changing display to `inline-block` or
`block`.
Also adds shared CSS data helpers for HTML replaced elements so the
transform availability check can distinguish regular inline elements
from replaced inline elements like `img`.
Limits projects to 8 editable breakpoints, with a toast warning when
users try to add more. Pasted/imported styles that exceed the limit are
merged into the closest existing breakpoint instead of creating new
ones.
Also updates the breakpoint editor UI with required names, hover-only
trash actions, scrolling, and tighter layout polish.
Closes https://github.com/webstudio-is/webstudio/issues/4209
Adds a Cmd+\ / Ctrl+\ shortcut to toggle hidden UI mode in the builder.
In hidden UI mode, the sidebars, footer, and topbar are hidden so the
canvas gets the full workspace. The topbar stays mounted and can be
temporarily revealed by moving the pointer to the top edge, with a short
slide animation. Open topbar menus/popovers keep it visible until they
close.
Closes https://github.com/webstudio-is/webstudio/issues/3895
Fixes the Transition dialog Easing field so valid CSS timing functions
are accepted when typed directly:
cubic-bezier(...)
steps(...)
linear(...)
The parser already accepted these values, but the Transition UI only
committed keyword and var values, so parsed function/unparsed timing
values were dropped and the input reverted.
Closes https://github.com/webstudio-is/webstudio/issues/5376
## Description
1. What is this PR about (link the issue and add a short description)
## Steps for reproduction
1. click button
2. expect xyz
## 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
- [ ] made a self-review
- [ ] added inline comments where things may be not obvious (the "why",
not "what")
## Before merging
- [ ] tested locally and on preview environment (preview dev login:
0000)
- [ ] updated [test
cases](https://github.com/webstudio-is/webstudio/blob/main/apps/builder/docs/test-cases.md)
document
- [ ] added tests
- [ ] if any new env variables are added, added them to `.env` file
**Summary**
Migrates Builder bootstrap data loading from the legacy
`/rest/data/:projectId` endpoint to `build.loadData` tRPC, while keeping
the old REST route as a no-store compatibility shim.
Hardens authenticated Builder/dashboard responses by explicitly sending:
- `Cache-Control: private, no-store, max-age=0`
- `Pragma: no-cache`
- `Expires: 0`
- `Vary: Cookie`
**Details**
- Added `build.loadData` tRPC query for full Builder state.
- Switched Builder client bootstrap loading to tRPC.
- Added shared cache-control helpers for private no-store responses.
- Made tRPC responses private/no-store by default unless anonymous and
explicitly public-cacheable.
- Added no-store headers to
Builder/dashboard/auth/resource/asset-related responses.
- Updated redirect handling to preserve headers while enforcing
no-store.
- Prevented stale dashboard account data from flashing by applying
user-scoped loader data before paint and clearing stores on teardown.
- Added tests for cache headers, tRPC response metadata, and no-store
redirects.
**Validation**
- `pnpm --filter @webstudio-is/builder test --
app/services/cache-control.server.test.ts
app/services/trpc-response-meta.server.test.ts
app/services/no-store-redirect.test.ts app/routes/rest.assets.test.ts
app/shared/sync/project-queue.test.ts app/dashboard/dashboard.test.ts`
- `pnpm exec oxlint ...` on touched files
- `git diff --check`
`pnpm --filter @webstudio-is/builder typecheck` still fails on existing
unrelated Tailwind/css-engine errors.
## Summary
- Preserve browser-valid CSS math values during CSS value parsing when
`css-tree` can parse the value but cannot fully validate the property
syntax.
- Fix pasted HTML/imported inline styles like nested `clamp()` +
`calc()` font sizes being marked invalid.
- Keep malformed math values and numeric functions in non-numeric
properties invalid.
- Add regression coverage for CSS value parsing and HTML paste/import
behavior.
## Testing
- `pnpm --filter @webstudio-is/css-data test
src/parse-css-value.test.ts`
- `pnpm --filter @webstudio-is/builder test app/shared/html.test.tsx
app/shared/tailwind/tailwind.test.tsx`
## Notes
This prevents valid pasted CSS math expressions from becoming invalid
style values and crashing the builder on import.