Commit Graph
422 Commits
Author SHA1 Message Date
Oleg Isonen 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.
2026-09-10 18:39:54 +02:00
Oleg Isonen e69a3d2f8e feat: Create structured MDX entries from collection folders (#6317)
## Paragraph editing follow-up — 42a16db02c (September 9)

Nested formatted paragraphs now retain their text, links, styling
identity, and existing labels during editing and saving. No database
migration.

- [x] Review all four changed text-editor files.
- [x] Preserve text before and after nested links inside emphasis,
strong text, and spans.
- [x] Preserve existing instance labels on save and keep inherited
formatting from overwriting a link's styling identifier.
- [x] Demonstrate regression failures without each fix, then pass all 41
focused text-editor and MDX synchronization tests.
- [x] Pass Builder typecheck, lint, formatting, and diff checks.
- [x] Verify the reported paragraph in Design and Content modes: edits
reach MDX and survive reload; original text restored. Verify matching
link color and underline inside and outside editing.
- [x] Review documentation and fixture impact: this restores existing
documented behavior; no fixture inputs, generated output, or
documentation changes are needed.
- [x] Commit and push the reviewed fixes.
- [ ] Confirm CI on this commit before merging.

Full E2E and agent evaluations were not rerun for this focused
follow-up. Earlier CI and suite results below apply to their recorded
commits, not this new head.

---

## Final verification — 50093ed2b7 (September 9)

Article edits now retain inline formatting and save newly inserted
custom components reliably. Saving a file no longer sends a second
project-sync write that could restore an older revision. No database
migration.

- [x] Fix iframe-blur saves, inherited template defaults, unused
resolved assets, and stale template tag metadata.
- [x] Remove duplicate server writes for already saved file revisions;
share the result with the canvas using the existing external-content
sync channel.
- [x] Demonstrate new regression tests fail without their fixes and pass
with them. Keep E2E file-write, content-order, and reload assertions;
remove the obsolete duplicate metadata-write wait.
- [x] Pass all 2,955 Builder tests, all 2,409 Project Build tests, and
all 8 focused MDX E2E checks.
- [x] Pass Builder and Project Build typechecks, lint, formatting, and
diff checks.
- [x] Run the complete fixture pipeline with no generated changes. The
later Builder-only save-acknowledgment changes affect no fixture inputs
or outputs.
- [x] Verify live article fields, hero replacement/save/reload/restore,
Accordion text edits, and YouTube URL edits. Verify UI edits reach MDX
and MDX edits persist after reload. Restore original article content.
- [x] Review documentation impact: these fixes restore the documented
Content Block editing behavior; no further documentation change is
needed.
- [x] Apply `visual-change-approved` after the user's explicit approval
of the 24 reviewed intended visual changes.
- [x] Commit and push the reviewed changes; worktree is clean.
- [x] Confirm CI and mergeability on this final commit: all 19 Main
workflow jobs passed, including all six E2E shards; PR lint and
submodule checks passed. Visual approval run 34383497017 passed. Its
predecessor reported the 24 intended differences; all 24 current images
were byte-identical to the reviewed report, with zero capture errors.
GitHub reports no merge conflict.

Agent evaluations were explicitly skipped for these final runtime fixes,
as requested. Earlier evaluation results below apply to their recorded
commits, not this final commit. This summary supersedes historical
pending-check notes below. The PR has not been merged.

---

## Final merge check — 9bc31ca679 (September 9)

- [x] Merge main without rewriting branch history. Preserve main's
image-picker fix and description-list validation.
- [x] Reset inherited HTML parent context at template boundaries. All
four new regressions fail without the fix and pass with it.
- [x] Fix shared navigation style composition and alignment; verify the
browser regression fails before and passes after. Review focused
screenshots.
- [x] Pass 2,408 Project Build tests, 251 design-system tests, and 3
image-picker tests; Builder, Project Build, and design-system
typechecks; lint, formatting, and diff checks.
- [x] Run the complete fixture pipeline with no generated changes.
- [x] Rerun all six agent evaluation scenarios on the merged code with
GPT-5.5. All functional checks pass; incompatible/missing token-baseline
comparison remains explicitly disabled.
- [x] Review documentation impact: this merge preserves documented
behavior; the image-editing guidance was already updated in f90e39cfcc.
- [x] Commit and push; worktree is clean and GitHub reports no merge
conflict.
- [x] Confirm Main CI on 9bc31ca679: all 19 jobs passed, including all
six E2E shards.
- [x] Review final visual artifact 10110845203 from run 34367911826: 24
added/changed stories, zero capture errors. Reviewed collection dialogs
and icons, light/dark login gradients, dashboard and project-settings
navigation, panel spacing, button variants, inset lists, and resettable
labels. Fourteen captures are byte-identical to the previously inspected
CI images. Updated navigation and collection-settings captures were
inspected; the formerly blank story renders normally. Pixel measurements
confirm the columns story retains its intended column positions (second
column x=261, third around x=388).
- [x] Apply visual approval after renewed explicit user approval.
Final-head CI is tracked above.

The live hero replacement and article/custom-component checks below are
now complete. The PR has not been merged.

---

## Merge-readiness follow-up — September 9

- [x] Remove contradictory image guidance and add an executable
writable-source/read-only-alt binding recipe. Regenerate CLI/MCP docs.
- [x] Verify the recipe regression fails with the old guidance and
passes with the new guidance. All 10 focused documentation tests, 2
content-reference tests, CLI/docs typechecks, lint, formatting, and
generated-documentation checks passed.
- [x] Rerun all six agent evaluation scenarios with GPT-5.5: all
functional checks passed. The incompatible/missing token-baseline gate
was explicitly disabled; existing baselines are unchanged.
- [x] Commit the documentation follow-up as f90e39cfcc.
- [x] Review existing CI screenshots and identify unintended shared-list
alignment changes. Implement a local shared-style composition/alignment
fix with a regression test demonstrated failing before and passing
after; all 251 design-system tests and its typecheck passed.
- [x] Visually verify and push the shared list fix in 9bc31ca679. The
focused run compared 28 stories; navigation is left aligned, column
layouts remain intact, and the previously blank collection-settings
story rendered normally. No product fix was inferred from that one blank
capture.
- [x] Review and approve the intended visual differences. See the
current final-head CI status above.
- [x] Verify these changes affect no fixture inputs or generated fixture
output. No database migration.

The previously pending live hero-swap and article/custom-component
checks are now complete. See the current verification summary above.

---

## Article editing follow-up — d307c8ba3d (September 9)

The target blog's hero source was incorrectly marked read-only. It now
uses the existing writable image picker. Reading time and the author URL
also use direct writable values. Time properties now have native
date/date-time controls. No database migration.

- [x] Fix the target's hero source, reading-time structure, and author
URL bindings while preserving the current content and link destination.
- [x] Verify Content-mode category, title, excerpt, date, reading-time,
shared image Description, author name/URL, MDX heading, and list-item
edits reach their source files. Check reloads and restore test values.
- [x] Add date-only, local timestamp, UTC timestamp, empty-value, and
legacy-value regression coverage; demonstrate failure without the date
control and passing results with it.
- [x] Fix the macOS Bash runner's empty-argument failure. Demonstrate
default invocation and argument-forwarding regressions fail without
their behavior and pass afterward.
- [x] Update authoritative Content Block/Time docs and generated CLI/MCP
guidance: inventory every article field, use direct writable bindings
and appropriate controls, check saved source and reload, and never infer
full editability from one heading.
- [x] Pass 291 date/text/Time/design-system tests (one existing skip), 2
runner tests, and 9 documentation tests; relevant typechecks, lint,
package boundaries, formatting, and diff checks.
- [x] Run the complete fixture pipeline: no generated fixture changes.
The later runner/docs-only edits do not affect fixture inputs or
outputs.
- [x] Run the full Builder E2E suite: 82 passed. This used an explicit
reporter; the default invocation correction was then covered by the
runner tests.
- [x] Run all six agent evaluation scenarios on gpt-5.5 after the final
image guidance correction. All functional checks passed. The older-model
token-baseline gate was disabled explicitly; accepted baselines were not
changed.
- [x] Review, commit, and push code and generated documentation.
- [x] With explicit approval, replace the live hero image through
Content mode, verify the MDX reference and reload, then restore and
verify the original image.
- [x] Complete the article-field checks listed above. Insert Accordion
and YouTube from templates; verify UI edits reach MDX and MDX edits
persist after reload. Restore the original article content.
- [x] Inspect CI for 7834d90a61: formatting, lint, typechecks, generated
docs, package/Builder tests, build checks, and five E2E shards passed.
The long MDX lifecycle exhausted its total 120-second budget at its
final assertion; the trace showed completed edits and reloads, not a
stalled save.
- [x] Give only that lifecycle a 180-second total budget; leave
individual save waits and assertions unchanged. Both local repeats
passed (plus setup). Push d307c8ba3d; this test-timeout-only follow-up
affects no fixture inputs or generated output.
- [x] Verify Main CI for d307c8ba3d: all 19 jobs passed, including all
six E2E shards. Visual approval remains separate.
- [x] Finish visual review and approval after correcting navigation
alignment and verifying the collection-settings story renders. The user
approved the reviewed 24 intended differences.
- [x] Recheck target publication preparation: seven documents included,
zero omitted, zero missing-template omissions. No deployment.
- Deferred: manual Storybook/screenshots; not authorized for this pass.

These results supersede the earlier pending image-product decisions and
live-check notes. Evaluation status for the latest fixes is recorded
above.

---

## Blog authoring fixes — 6359f979a3 (September 9)

This review fixes failed UI-to-MDX saves, missing source Undo/Redo,
editor recovery and focus, and publication preparation for the migrated
blog. No database migration.

- [x] Stop treating template-record ordering as a style edit; still
reject actual style changes that cannot be saved in MDX.
- [x] Share save-preparation errors with property controls across the
canvas frame.
- [x] Keep malformed MDX as an unsaved draft, with repair and discard
paths; focus the source editor when opened from the Navigator.
- [x] Enable supported Content-mode Move actions using the existing
central permission rules.
- [x] Keep source Undo/Redo separate from transient rendering history.
Serialize rapid commands, wait for pending canvas edits, reject
stale-source conflicts, and retain the last 20 edits per project
session.
- [x] Fix publication candidate discovery for projected documents and
unrelated author references; keep rejecting unsupported references used
as the actual MDX source.
- [x] Demonstrate regression tests failing without their fixes and
passing afterward.
- [x] Run the complete Builder (2,938), Content Engine (559), and
Project Build (2,395) suites: 5,892 tests passed.
- [x] Pass relevant package typechecks, root lint, formatting, package
boundaries, and diff checks.
- [x] Run the full fixture pipeline; no generated fixture changes.
- [x] Review documentation impact and document draft recovery and source
Undo/Redo.
- [x] Verify live heading edits, author-file edits, malformed-draft
recovery, and immediate delete/Undo/Redo; restore test content and
confirm persisted source.
- [x] Verify target publication preparation: seven documents included,
zero omitted, no missing-template omissions. This did not deploy the
site.
- [x] Review, commit, and push.

### Remaining verification and decisions

- [x] Correct the target's read-only Image source binding. The existing
Content-mode picker replaces the article reference; shared Description
edits use Asset settings. No new image-editing API or data model is
needed. See the latest verification limits above.
- [x] Repeat the full E2E and agent evaluation suites after these
changes: 82 E2E tests and all six evaluation scenarios passed.
- [x] Repeat the live Accordion/YouTube insertion and editing flow after
the save fixes, including UI-to-MDX saves and MDX edits surviving
reload.
- Historical note: this round did not run CI or Storybook checks; later
results are recorded above.

Unknown JSX already has source-range lint diagnostics; it remains an
editable missing-template placeholder, not an unconditionally blocked
save. The target author's binding was also repaired through the UI so
Content mode can edit its referenced author file. Shared resolved URLs
remain read-only text; the image picker changes the article reference,
and Asset settings edits the shared Description.

This section supersedes earlier claims of complete verification for the
latest code; historical results below remain records of earlier runs.

---

## Sync and import verification — a2a567551c (September 9)

Ordinary `link` → `sync` → `import` now exports the current saved
Builder project with its current assets. It no longer mixes an older
published build with current files. Import uploads assets before
assigning their source folders, then restores those assignments when
importing the bundle.

- [x] Fix foldered asset imports without a database migration.
- [x] Preserve file formats, folder assignments, build metadata, and
stable repeat-sync output.
- [x] Keep explicit `--buildId` export behavior unchanged; default sync
does not require publishing.
- [x] Review implementation and demonstrate regression tests failing
before the fixes and passing afterward.
- [x] Update protocol test servers for the current Builder data
endpoint.
- [x] Review documentation impact and update CLI documentation and
README.
- [x] Run all 1,121 CLI tests and 43 HTTP-client tests, both package
typechecks, root lint, package boundaries, formatting, and diff checks.
- [x] Run the full fixture pipeline and include expected current-build
fixture changes.
- [x] Verify the real source through the local CLI: repeated sync gives
identical output; import into the supplied target succeeds. Blog listing
and article rendering were also checked during the import investigation.
- [x] Commit and push the fix.
- Deferred at user request: agent evaluations for this round. Later CI
results are recorded above.

Sync still downloads the project and missing asset files and builds the
content index locally. This is not a transfer-free operation. Default
sync exports editable-build metadata rather than published deployment
metadata; use the explicit build option when selecting a particular
build.

---

## Final review and verification — ab3a6b7c55 (September 9)

Existing entries now use the same field controls as New entry. The
author-name permission fix, field-level validation, publishing warnings,
and final cache fixes are included. No database migration.

### Completed

- [x] Review all 38 local files, including entry autosave, revision
conflicts, permissions, shared fields, collection discovery, and
publishing diagnostics.
- [x] Allow existing-folder setup without rewriting entries or rejecting
unconfigured frontmatter.
- [x] Add Entry settings with autosave, repairable invalid fields,
immutable filename slugs, and preserved MDX body/unknown properties.
- [x] Warn before publication when missing or ambiguous custom templates
omit content, including discovered dynamic sources.
- [x] Allow authorized frontmatter writes to referenced Markdown author
files and preserve error messages across the canvas-frame boundary.
- [x] Reject impossible integer limits, slugless generated-filename
patterns, and slug maximum length zero. Existing raw configurations
remain readable for repairs.
- [x] Share collection discovery across Assets, file editors, and
property controls. Builder first synchronizes project asset metadata
into the browser. The browser then groups that metadata once per update
and shares configuration/template reads, instead of repeating them for
each control. This does not remove initial synchronization or
entry-frontmatter reads. Preserve project/access isolation, refresh
retries, stale-response protection, and duplicate-filename invalidation.
- [x] Demonstrate new regressions fail before fixes and pass afterward.
- [x] Correct the folder-drag E2E's obsolete root-folder assumption and
verify remembered-folder persistence.
- [x] Review and update authoritative Content Engine and Content Block
documentation.
- [x] Merge current main and regenerate the conflicting CLI
documentation from its source.
- [x] Fix generated previews with shared development dependencies:
invoke React Router binaries through Node, isolate each preview's Vite
cache, and forward script options correctly through npm and pnpm.
- [x] Fix a false MDX conflict when a new edit arrives immediately after
the previous save is acknowledged. Advance the local revision before
asynchronous parsing and ignore stale refresh results.
- [x] Run the full fixture link/sync/build pipeline. Generated changes
contain only the expected React Router scripts and Vite cache location.
No database migration.
- [x] Review the final diff and scan added lines for credential
patterns.

### Verification results

- Builder: **2,934 tests passed**. CLI: **1,120 tests passed**.
- Content Engine: **559 passed**; Asset Uploader: **291 passed**;
Project Build: **2,394 passed**; Design system: **250 passed**.
- The clean full workspace run passed all 35 non-CLI packages. Its two
CLI failures exposed pnpm argument forwarding; the complete CLI rerun
passed after that fix. Earlier load-related test timeouts did not recur
in the clean run.
- All workspace typechecks passed. Builder and CLI typechecks and
repository lint were repeated after their final changes. Package
boundaries, generated API checks, and the complete
generated-documentation gate passed. Documentation was regenerated from
source; the post-commit clean-file check passed.
- Full Builder E2E: **82 passed** from a fresh build, including
generated previews, collection creation/reload, MDX editing, stale
revisions, and permission checks. The isolated disposable test database
was cleaned up afterward; development data was untouched.
- Full agent evaluations: **all six scenarios passed on gpt-5.5**,
including every functional check for Markdown blogs, reference
discovery, MDX article editing, authentication, fonts, and design input.
The account cannot use the old **gpt-5.4-mini** baseline model. Five
baseline comparisons are incompatible and the MDX scenario has no
accepted baseline; token-baseline gating was disabled explicitly.
Accepted baselines are unchanged.
- New preview and MDX regressions were demonstrated failing before their
fixes and passing afterward.
- Working-tree/diff checks passed. Main was merged without rewriting
branch history. CI was not checked, as requested.

### Final delivery checklist

- [x] Finish the full Builder E2E rerun.
- [x] Finish the full agent evaluation rerun with the authorized
accessible model.
- [x] Commit, verify the clean generated-documentation gate, and push.
GitHub reports the branch mergeable with current main.

No known code or functional-test blocker remains from this review. CI
was not checked at the user's request. Manual Storybook/screen-reader
checks remain deferred; the automated E2E and agent visual checks above
passed.

The historical review sections below retain their original run results.
This section supersedes earlier claims about strict entry validation,
entry editing, browsing reads, and evaluation authorization.

## Outcome

Content editors can create structured MDX entries from a collection
folder without writing frontmatter. Designers configure flat fields,
limits, optional slug behavior, and the Markdown template in the
Builder.

## High-level goals

- [x] Keep folders ordinary in the database and derive collection
behavior from a direct **collection.json**.
- [x] Add **Use as content collection** to folder creation.
- [x] Give designers a visual configurator for the JSON Schema and MDX
template.
- [x] Show a collection badge and a generic **New entry** action.
- [x] Generate independent MDX entries from the configured schema and
template.
- [x] Keep the current page unchanged after creating an entry; no
automatic preview navigation.
- [x] Select direct MDX entries with URLPattern filename rules; keep
ignored files as ordinary supporting assets.
- [x] Keep reserved collection files out of collection query results and
generated content indexes.
- [x] Preserve broken collections as visible, repairable collection
folders.
- [x] Restore normal folder behavior when **collection.json** is
removed.

## Implementation todos

- [x] Add the Content Engine collection contract, default
schema/template, slug normalization, validation, serialization, and
entry generation.
- [x] Discover collections from Assets files without a database folder
type or migration.
- [x] Create **template.mdx** and **collection.json** when the folder
checkbox is selected.
- [x] Add basic field controls for text, long text, slug, number,
integer, and Boolean values.
- [x] Support required fields, string length limits, numeric limits,
template defaults, and generated slugs.
- [x] Add designer collection settings and template editing.
- [x] Remove dynamic preview-page configuration and ignore its legacy
metadata.
- [x] Add the schema-generated **New entry** form and creation endpoint.
- [x] Preserve reserved-file portability in authenticated export/import
while excluding it from content query and generated-index results.
- [x] Document the feature in the authoritative Content Engine guide.

## Deep review checklist

A checked item means the area was inspected and evidence was recorded.
It does not mean the behavior passed. Unresolved defects and product
decisions remain listed in **Review findings**.

### 1. Product contract

- [x] Decide whether the collection checkbox creates defaults
immediately or opens the configurator first.
- [x] Decide whether existing folders can be converted through the UI.
- [x] Define collection activation when **collection.json** exists but
is invalid.
- [x] Define an entry: every valid direct MDX child or only files
created through **New entry**.
- [x] Confirm collection membership is direct-child only and nested
folders can define their own collections.
- [x] Define designer, content editor, viewer, service, CLI/MCP,
old-client, and direct-API authority.
- [x] Decide whether content mode is simplified UI or a server
authorization boundary.
- [x] Decide whether slugs are permanently immutable.
- [x] Decide whether schema changes may invalidate existing entries or
must migrate them.
- [x] Decide whether invalid unused collections block unrelated queries
or whole-project publication.
- [x] Decide what happens to the preserved template after collection
removal.
- [x] Define the promised JSON Schema dialect and supported subset.
- [x] Decide whether temporary invalid collection states are admitted
for repair.
- [x] Define duplicate-request semantics: no duplicates, exactly one
success, and retry behavior.
- [x] Decide whether entries require valid frontmatter only or valid
complete MDX.

### 2. State machine

- [x] Review ordinary folders and root-level **collection.json**.
- [x] Review empty-folder, template-only, config-uploading, and
config-loading initialization states.
- [x] Review ready collections.
- [x] Review invalid JSON, UTF-8, size, schema, and duplicate-config
states.
- [x] Review missing, duplicate, wrong-type, oversized,
invalid-frontmatter, and invalid-MDX template states.
- [x] Review forbidden direct files, invalid entries, and slug/filename
mismatches.
- [x] Distinguish transient read/network failures from persistent
invalid content.
- [x] Review removing, removed, moved, renamed, restored, duplicated,
and deleted collection states.
- [x] For every state, inspect visibility, allowed actions, server
admission, query/publish behavior, recovery, and concurrent-client
behavior; record recovery behavior.

### 3. Activation and deactivation paths

- [x] Review checkbox creation.
- [x] Review create/upload/rename/move/paste/duplicate of
**collection.json**.
- [x] Review restore, import, project duplication, and sync behavior.
- [x] Review delete/rename/move/replace of **collection.json**.
- [x] Verify all activation paths produce the same state and validation.
- [x] Verify all deactivation paths restore ordinary-folder behavior
without accidental data loss.

### 4. Folder membership and nested collections

- [x] Verify only direct children are collection entries or reserved
files.
- [x] Verify a nested folder with its own direct config becomes its own
collection.
- [x] Verify parent rules do not leak into nested folders.
- [x] Define filename and extension case sensitivity.
- [x] Define duplicate logical-name behavior over generated storage
names.
- [x] Define how uploading, deleted, and stale assets affect folder
state.
- [x] Review moving entries out and between collections with different
schemas.
- [x] Review ordinary subfolders with arbitrary files inside a
collection.
- [x] Review template behavior after collection removal.

### 5. Roles and authorization

- [x] Review config/template listing and download for every role.
- [x] Review config/template content edits for every role.
- [x] Review config/template rename, move, restore, and deletion for
every role.
- [x] Review entry create/edit/rename/move/delete/restore for every
role.
- [x] Review generic upload and subfolder operations for every role.
- [x] Review collection removal and repair for every role.
- [x] Verify server enforcement separately from hidden or disabled
controls.
- [x] Recheck permission changes while operations are in flight.

### 6. Mutation surfaces

- [x] Review REST upload-ticket creation and upload completion.
- [x] Review asset-content replacement and asset metadata changes.
- [x] Review runtime add/update/duplicate operations.
- [x] Review sync patches and direct persistence helpers.
- [x] Review clipboard, drag/drop, move, rename, and duplicate paths.
- [x] Review import/export, restore, and project/folder duplication
paths.
- [x] Review delete-unused-assets and recursive folder deletion.
- [x] Verify invariants at the final persistence boundary, not only in
UI preflight.

### 7. Concurrent operations

- [x] Review create entry against schema save, template save, raw config
edit, and collection removal.
- [x] Review edit/delete/restore entry against schema and template
changes.
- [x] Review two collection-settings editors and raw editor versus
configurator.
- [x] Review schema writer A interleaved with template writer B.
- [x] Review upload/move/rename against collection activation and
removal.
- [x] Review template/config deletion against creation and publication.
- [x] Review folder deletion/move and project switch against all async
operations.
- [x] Review final validity, conflict detection, cleanup, user outcome,
cache invalidation, and publish behavior across the implemented
intersections; record conflict and recovery behavior.
- [x] Review retry after the server commits but the HTTP response is
lost.

### 8. Collection initialization and recovery

- [x] Review project switch, permission revocation, dialog close, folder
rename/move/delete, and conflicting uploads during initialization.
- [x] Verify retry is idempotent and does not duplicate reserved files.
- [x] Verify partial setup has a visible finish, retry, or cleanup path.
- [x] Verify generic actions cannot corrupt the initialization window.
- [x] Verify project and folder identities are captured for the whole
operation.
- [x] Review asset-count, storage, filename, and folder limits with
cleanup.

### 9. JSON Schema conformance

- [x] Confirm the exact draft and validate configs against its
meta-schema.
- [x] Review unknown dialects, boolean schemas, malformed keyword types,
and duplicate JSON keys.
- [x] Review refs/defs, recursion, composition, conditionals,
dependencies, and nullable/multiple types.
- [x] Review enum, const, format, pattern, patternProperties, and
additionalProperties.
- [x] Review min/max properties, array constraints, contains, and
uniqueItems.
- [x] Review exclusive numeric bounds and all string/number/integer
limits.
- [x] Differential-test validation against an independent draft 2020-12
implementation.
- [x] Verify unsupported keywords are rejected or explicitly documented,
never silently ignored.

### 10. Schema resource limits and hostile input

- [x] Bound schema bytes, depth, field count, enum size, and reference
depth.
- [x] Bound validator compilation and validation time.
- [x] Review recursive references and excessive composition branches.
- [x] Review catastrophic patterns and regex denial of service.
- [x] Review huge labels, keys, defaults, and values.
- [x] Review prototype-sensitive and structurally awkward field names.
- [x] Review memory and CPU amplification across many collections.

### 11. Configurator ownership and round trips

- [x] Define owned, preserved, read-only, and rejected schema paths.
- [x] Verify parse/save/parse semantic equivalence and repeated-save
idempotence.
- [x] Verify a UI edit changes only explicitly owned schema paths.
- [x] Review property/form order and required-array order.
- [x] Review unknown root, property, and Webstudio extension metadata.
- [x] Review editable primitive fields that also contain enum, const,
format, composition, readOnly, or custom constraints.
- [x] Review type changes for incompatible preserved or removed
keywords.
- [x] Review rename/removal collisions with unsupported properties and
requirements.
- [x] Surface hidden preserved rules that can cause unexplained
validation errors.
- [x] Review field ordering/reordering.
- [x] Review choosing/changing slug field, slug source, and template
filename.
- [x] Review turning newly added fields into slug or slug-source fields.

### 12. Required/default/unset semantics

- [x] Review absent, empty string, false, zero, null, default, and
user-cleared values for every field type.
- [x] Define required-property versus non-empty-value behavior.
- [x] Verify required Boolean false remains valid and understandable.
- [x] Review optional Boolean absence versus explicit false.
- [x] Review explicitly clearing template-backed values.
- [x] Review JSON Schema default as annotation versus persisted entry
value.
- [x] Verify precedence among template values, schema defaults,
generated slug, and user values.
- [x] Review hidden/non-renderable required fields and template
requirements.
- [x] Verify a collection cannot be ready when every entry form must
fail.

### 13. Schema evolution and migration

- [x] Review add/remove optional and required fields.
- [x] Review field rename and label-only changes.
- [x] Review type changes and tightened/relaxed limits.
- [x] Review enum option, default, slug field/source, template name, and
additionalProperties changes.
- [x] Verify compatible save ordering and identify impossible two-write
migrations.
- [x] Decide whether entries are rewritten and whether migration is
atomic.
- [x] Review entry changes after validation but before schema commit.
- [x] Ensure designers see all incompatible entries or an actionable
summary.

### 14. Template, YAML, and MDX

- [x] Review absent/empty frontmatter and empty YAML.
- [x] Review BOM, CRLF, final-newline, and alternate YAML delimiter
behavior.
- [x] Review duplicate keys, anchors, aliases, tags, comments, quoting,
and multiline strings.
- [x] Review Unicode and byte limits.
- [x] Verify frontmatter and starter-body preservation.
- [x] Review invalid MDX bodies, imports, exports, expressions, and
unsafe nodes.
- [x] Review missing, renamed, duplicate, wrong-type, and oversized
templates.
- [x] Verify template changes affect future entries only.
- [x] Review reserved template exposure through direct asset URLs and
build copying.

### 15. New-entry form and creation

- [x] Verify every required field is renderable or supplied safely.
- [x] Verify deterministic field order and correct controls/constraints.
- [x] Compare client and authoritative server validation.
- [x] Prevent submitted values from overwriting protected hidden fields.
- [x] Preserve values and focus after failed creation.
- [x] Review per-field errors, error summary, and first-error focus.
- [x] Prevent duplicate submission and define lost-response recovery.
- [x] Verify local sync, reload persistence, and project-switch
handling.
- [x] Review no/stale preview page, query delay, and draft-filtered
entries.
- [x] Review large forms and narrow/mobile layouts.

### 16. Entry editing and lifecycle

- [x] Review body-only, frontmatter-only, and combined edits.
- [x] Review invalid intermediate frontmatter and invalid complete MDX.
- [x] Review slug change, filename rename, and reference consequences.
- [x] Review delete, restore, move out, move between collections,
duplicate, paste, and undo.
- [x] Review slug reuse after delete and restore collision.
- [x] Review edits concurrent with schema/template changes.
- [x] Review repair of legacy invalid entries and blocked intermediate
saves.
- [x] Decide whether existing entries receive a generated settings form
or raw MDX editing.

### 17. Slug and filename identity

- [x] Review slug source selection, same slug/source field, manual
override, and visible final normalization.
- [x] Enforce lowercase-dash identity independently of editable schema
metadata.
- [x] Review empty normalized slugs and template/schema slug defaults.
- [x] Review diacritics, non-Latin scripts, and emoji-only sources.
- [x] Use locale-independent case comparison and Unicode normalization.
- [x] Review character/byte limits and case-insensitive filesystems.
- [x] Review collisions with reserved config/template filenames.
- [x] Review concurrent creation, stale reservations, deletion, reuse,
restoration, and URL encoding.

### 18. Collection-root restrictions

- [x] Review upload, external drop, internal drag, generic text
creation, paste, duplicate, move, rename, and extension changes.
- [x] Review runtime add, sync patch, import, and restore bypasses.
- [x] Review upload tickets completed after activation.
- [x] Review moving or renaming **collection.json** through metadata
changes.
- [x] Review dedicated entry creation, initialization, repair, body
editing, and collection removal exceptions.
- [x] Verify subfolder creation and arbitrary files inside subfolders
remain allowed.

### 19. Storage, database, idempotency, and cleanup

- [x] Review object-without-File, File-without-Asset, stale UPLOADING,
and soft-deleted states.
- [x] Review storage success/database failure and database
success/storage failure.
- [x] Review postcheck failure, object cleanup, row cleanup, and cleanup
failure.
- [x] Verify cleanup preserves the original error and cannot delete
another request's asset.
- [x] Review timeout/lost response after commit and safe retries.
- [x] Review reservation lookup/cleanup failure and expiration.
- [x] Review failed creation cleanup and distinguish incomplete uploads
from existing entries with repairable field errors. Existing field
errors do not hide entries or block publication.
- [x] Verify orphan reclamation and project-scoped cleanup.

### 20. Query, build, and publication

- [x] Verify config/template exclusion only for an identified
collection.
- [x] Verify ordinary root-level **collection.json** remains ordinary
content.
- [x] Review template queryability after collection removal.
- [x] Validate actual entry frontmatter and decide complete-MDX
requirements.
- [x] Review invalid content versus transient read failure.
- [x] Decide invalid-collection blast radius across queries, field
catalog, build, and publish.
- [x] Review direct asset IDs, document references, build copying, and
public URLs for reserved-file leakage.
- [x] Verify preview and publish use the same collection rules.

### 21. Cache and snapshot consistency

- [x] Verify config, template, entries, filenames, folder movement,
activation, and removal affect source revision.
- [x] Verify immutable/revision-pinned reads under concurrent swaps.
- [x] Verify config and template come from one logical version.
- [x] Review revision consistency between entry reads and indexing.
Queries do not require entry-schema validation.
- [x] Review rejected-promise caching and retry after repair.
- [x] Verify no cross-project cache collision.

### 22. Performance and availability

- [x] Review sequential versus bounded parallel reads.
- [x] Review request cancellation and repeated preview-query work.
- [x] Review rate limits and resource-exhaustion protection.
- [x] Review progress/cancellation and actionable limit errors.

### 23. Invalid-state repair

- [x] Review repair for every config, template, forbidden-file, entry,
and slug mismatch state.
- [x] Show exact folder, file, field, and rule.
- [x] Distinguish retryable transport errors from content errors.
- [x] Provide missing-template creation despite normal root
restrictions.
- [x] Provide duplicate-file deletion and forbidden-file move recovery.
- [x] Preserve raw repair when the configurator cannot parse the schema.
- [x] Show collection health after repair.
- [x] Prevent custom-template leakage to content editors when config
cannot identify it.

### 24. Entry navigation

- [x] Remove dynamic preview configuration and automatic navigation
after entry creation.
- [x] Verify entry creation leaves the selected page unchanged, with or
without a slug field.

### 25. Accessibility and responsive behavior

- [x] Review native form submission and required semantics beyond an
asterisk.
- [x] Review linked errors, error summary, live announcements, and busy
state.
- [x] Review focus after errors, add/remove field, key edits,
confirmation transitions, and dialog close.
- [x] Review dirty-close warning, explicit cancel/retry, and durable
feedback beyond toasts.

### 26. Portability, compatibility, and rollback

- [x] Review export/import, folder/project duplication, and restore
ordering.
- [x] Verify logical filenames, not storage names, define the portable
contract.
- [x] Review case-insensitive filesystem behavior.
- [x] Review rollback after collection files already exist.
- [x] Verify removal or rollback leaves content recoverable.
- [x] Confirm database/migration assumptions.

### 27. Observability and supportability

- [x] Review state-transition and validation diagnostics.
- [x] Track cleanup failures and orphaned reservations.
- [x] Make publish errors actionable without logging private content.
- [x] Ensure client errors do not expose stack traces or sensitive
internals.

### 28. Verification strategy

- [x] Unit-test schema, slug, merge, serialization, and validators.
- [x] Demonstrate each new regression test fails without its fix.
- [x] Run affected unit suites, typechecks, lint, docs checks, E2E,
fixture-impact review, and final diff review.
- [x] Review authoritative documentation impact.

## Persistence and recovery

No database migration is needed. Folders remain ordinary database rows;
their direct **collection.json** activates collection behavior. This PR
adds no table, column, index, RPC, folder type, or backfill.

- Setup writes the template first and **collection.json** last.
Interrupted setup leaves an ordinary folder and can be retried.
- Existing immutable File revisions, conditional Asset updates, and
upload reservations provide conflict detection and retry-safe entry
creation.
- Settings saves validate the intended template and schema together,
then write only the files that changed. Existing entry field errors stay
repairable and do not block unrelated saves, queries, or publication.
New entry creation remains strict.
- Invalid or interrupted collections remain visible and repairable.
Configuration/template structure errors remain distinct from entry-field
errors; entry-field errors do not invalidate the entire collection.
- Public/service publication excludes configuration and template files.
Authenticated CLI exports retain them for lossless import.

## Review findings

The implementation review is complete. Confirmed defects were fixed and
the following tradeoffs remain explicit.

### Fixed

- Enforced collection structure and permissions across REST, runtime
patches, import, query, and publication, while keeping existing
entry-field errors non-blocking for queries and publication.
- Preserved Undo/Redo, including restoring shared File revisions in
cloned projects.
- Rejected forged shared-file metadata while preserving metadata edits
on legacy files with null uploader provenance.
- Added retry and recovery behavior for setup, settings saves, lost
responses, and transient reads.
- Moved collection setup into one retry-safe server operation and kept
the local Builder update as one Undoable transaction.
- Centralized collection inspection and limited schemas to the flat
fields the configurator can represent. Opening a collection still reads
its entries in the background to report field errors.
- Guarded stale dialogs and deferred saves against permission changes,
protected files, project switches, and replaced revisions.
- Kept Asset settings open while choosing nested folders; the existing
browser regression fails before the fix and passes afterward.
- Preserved required Boolean false values, field-level errors,
dirty-close prompts, and inline Markdown editing.
- Separated authenticated portable exports from public runtime assets.
- Updated the authoritative Content Engine guide.

### Known tradeoffs

- A failure after template content saves but before configuration saves
can temporarily leave an invalid collection. Retrying the settings save
completes it; otherwise the visible files allow repair. The
template/config rename endpoint remains retry-safe and rolls back a
rename when its config write fails.
- Cloned-project Undo can retain an unused prior File revision. Separate
read-then-delete cleanup could race with another restore, so this path
retains the revision.
- Build/asset persistence and import already use multiple calls. This PR
validates before writes and provides retry/conflict handling; it does
not provide a transaction spanning every resource or a global collection
lock.
- Opening a collection loads its configuration and template through
shared Builder discovery, then checks entry frontmatter in the
background for field errors. Unchanged configuration/template content is
reused across controls and entry edits. Frontmatter checks still require
entry reads; ordinary folder browsing does not discover every
collection’s file content.

## Latest unstaged-change review — 2026-09-07

- [x] Review collection settings, validation, autosave/error recovery,
entry creation, reserved-file actions, and conversion flows.
- [x] Review shared labels, list keyboard handling, dialog focus/Escape,
buttons, and panel spacing migrations.
- [x] Fix Enter/Space list activation lost when arrow navigation
replaced the existing press handler.
- [x] Recognize historical generated ASCII/Unicode slug patterns, use
the bundled Unicode slug schema, and save a locally resolved $ref
without changing existing filenames.
- [x] Prevent duplicate slugless entries after a lost response: New
entry sends a stable UUID per attempt, reused by the repository's
existing filename/content retry checks. No database migration. Callers
omitting the optional requestId retain the previous behavior.
- [x] Preserve Content Block template validation independently of page
HTML placement, without accepting invalid rendered nesting.
- [x] Demonstrate the new review regressions fail without their fixes
and pass afterward.
- [x] Review authoritative documentation and update legacy slug
behavior.
- [x] Run fixtures and inspect generated changes: none.
- Deferred manual verification: Storybook screenshots were not
authorized for this pass.
- Historical evaluation status: not run in this pass; superseded by the
final verification section above.

## Verification

Local checks for commit **2b8195692e**:

- Builder app: 1,739 tests; Builder core: 1,150 tests. After the final
fixes, entry/settings tests and shared asset REST checks also passed,
including the added stable-retry test.
- Content Engine: 535 tests.
- Asset Uploader: 279 tests.
- Design system: 249 tests.
- Project Build: 2,392 tests.
- All five affected package typechecks, changed-file lint/formatting,
package boundaries, and Content Engine documentation tests passed.
- Complete fixture link/sync/build pipeline passed with no tracked
fixture changes.
- Staged diff and credential-pattern checks passed. No database schema,
migration, or generated database type changes. The lockfile includes the
collection validator and filename matcher dependencies.
- CI for this commit is pending. Builder E2E, manual
screen-reader/mobile checks, Storybook screenshots, and agent
evaluations were not run in this pass.

## MDX editing review — commit c3702a7238

- [x] Review all 36 local changed files: MDX parsing/materialization,
template enforcement, mutation commits, persistence, Assets refresh,
Navigator, source binding, editor diagnostics, dialogs, and query menus.
- [x] Validate new custom components at the shared Builder mutation
commit before applying tree changes. Cover move, reparent, paste, nested
paste, duplicate, and batched operations; preserve unchanged authored
content.
- [x] Match template names and component structure, including renamed
templates, instead of accepting any component type found in Templates.
- [x] Remove the registered-component fallback from MDX materialization
and completion; report untemplated JSX in the editor.
- [x] Preserve unresolved JSX until its placeholder is deleted, then
persist its removal without clearing the Assets resource during refresh.
- [x] Keep custom designer content outside the MDX body; omit the extra
body for fresh unconnected Content Blocks.
- [x] Resolve Navigator's MDX-file action from the active content root
for dynamic sources.
- [x] Fix the first dialog drag jump while honoring subsequent explicit
size changes; contain long query menus and prevent editor Backspace from
deleting instances.
- [x] Demonstrate new review regression failures before the fixes and
passing results afterward.
- [x] Review and update authoritative Content Block documentation.
- [x] Run the complete fixture pipeline; no generated fixture changes.
- Historical evaluation status: deferred in this pass; superseded by the
final verification section above.
- Historical verification limits: no Storybook screenshots, Builder E2E,
or manual accessibility checks in this pass. See the final verification
section for the current E2E result; manual checks remain deferred.

### Latest verification

- Builder affected suites: **624 tests passed**.
- Project Build full suite: **2,394 tests passed**.
- Design system full suite: **250 tests passed**.
- Query Builder React full suite: **14 tests passed**.
- Component Registry full suite: **7 tests passed**.
- All five affected package typechecks, repository lint, changed-source
formatting, staged diff checks, and credential-pattern scan passed.
- Fixture link/sync/build passed without generated changes. No database
migration.
- CI for this commit has not yet been verified.

The new mutation-commit check covers Builder operations affecting loaded
external content roots. It is not a claim that every remote API mutation
is now guarded by this client-side check.

Closes #6316


## Local-change review — 2026-09-08

- [x] Review all 47 changed files and trace collection setup, filename
filters, public metadata/upload APIs, sync patches, Content-mode write
targets, local folder persistence, and MCP downloads.
- [x] Fix ignored MDX files being renamed into entries through the
metadata API. Selected filenames require New entry.
- [x] Fix supporting-asset moves/renames being blocked by unrelated
invalid entries. Configuration/template checks still run. The later
entry-repair work also removed entry-field validation as a blocker for
unrelated writes and publication.
- [x] Validate frontmatter directly with Ajv, resolve the bundled slug
$ref without network fetching, preserve the flat schema contract, and
avoid retaining old validator instances.
- [x] Verify Unicode generation, legacy-pattern upgrades, sibling
constraints, field error paths, optional binding paths, referenced-file
permissions, and independent queued edits.
- [x] Review authoritative documentation, correct contradictory
referenced-write guidance, and regenerate CLI/MCP documentation.
- [x] Demonstrate new review regression failures with the fixes
disabled, then restore and pass them.
- [x] Pass Content Engine (553), asset uploader (284), SDK (570),
project-build (2,394), MCP command (61), and collection/Content-mode
browser tests (279), plus expression tests and documentation checks.
- [x] Pass seven affected package typechecks, repository lint,
formatting, package boundaries, and fixture link/sync/build. No
generated fixture changes or database migration.
- Historical evaluation status: deferred in this pass; the user
subsequently authorized the full suite. See the final verification
section above.
- Historical verification limits: no Builder E2E or manual
visual/accessibility checks in this pass. See the final verification
section for the current E2E result; manual checks remain deferred.
2026-09-09 21:31:04 +02:00
Oleg Isonen 55920c57c4 fix: Show all Markdown and Assets query diagnostics (#6308)
Ref #6305

## Outcome

Show actionable Markdown, MDX, and Assets query problems in the editor,
query Diagnostics, API, and MCP.

The current implementation substantially improves source diagnostics,
query error aggregation, query scoping, exact paths, MCP feedback, and
loading states. The exhaustive audit below also records what is not
complete yet.

## Completion rule

An error state is complete only when all applicable checks pass:

- [x] The editor uses the production validator and shows every issue for
the open file.
- [x] Query execution uses the same validation and returns every issue
for every file that matches the query, not only the returned page.
- [ ] MCP can reproduce the state through a real tool call and returns
the same code, severity, message, file, and location.
- [x] Diagnostics shows fatal errors and nonfatal warnings in the
correct place.
- [x] Exact file is always present; line and column are present whenever
the parser can determine them.
- [x] Multiple issues in the same file, multiple files, and multiple
validation phases are returned together.
- [ ] A regression test proves failure without the behavior and success
with it.

## Cross-surface contract

### Required validator parity

- [x] Editor, query execution, and MCP file operations invoke the same
exported production file-validation pipeline for byte decoding,
source/frontmatter, Markdown/MDX, Content Block semantics, and
references. Copied schemas, adapter-only checks, or reimplementations do
not count as parity.
- [x] Query builder, query execution, `validate-asset-query`, and
`preview-asset-query` invoke the same exported structural and
catalog-aware semantic query validator with the same project snapshot
and context.
- [x] Every surface preserves the same complete, deterministically
ordered diagnostic array: severity, code, message, phase/scope, asset
ID, file path, line/column/range, query path, and
fatal-versus-warning/result behavior. UI, API, and MCP serializers must
not drop or remap fields.
- [ ] A table-driven contract suite calls the real editor, query, API,
and MCP entry points—including MCP upload, update, download, validate,
and preview—and compares full normalized arrays for multiple errors,
multiple warnings, multiple files, and pre-pagination matches.

- [x] Markdown and MDX source syntax/frontmatter use
validateTextAssetSource in editor, query compilation, and MCP file
tools.
- [x] Query request execution and MCP local parsing use
assetQueryRequest.
- [x] Fatal query setup errors retain all detected semantic errors and
accompanying warnings.
- [x] Nonfatal query warnings retain a stable code and exact query path.
- [x] Source diagnostics retain severity, phase, code, asset ID, path,
and available source position.
- [x] Query Diagnostics excludes diagnostics produced only by unrelated
published queries.
- [x] Query, Preview, and Diagnostics tabs show loading states.
- [x] Authenticated diagnostics can show a sanitized internal message;
public/pre-auth errors remain redacted.
- [x] Share byte-level UTF-8 validation instead of decoding separately
in query and MCP.
- [x] Make the query editor and MCP call one literal shared
query-validation function before execution.
- [x] Share cross-file reference validation across editor, query, and
MCP file operations.
- [x] Share contextual Content Block/template validation across all
applicable surfaces.
- [x] Preserve an invalid stored query in the editor and explain it
instead of replacing it with defaults.
- [x] Define and enforce whether “matches the query” includes every
pre-pagination match; current source validation follows
returned/paginated IDs.
- [x] Continue through source, reference, and runtime phases where safe
so one phase does not hide later issues.
- [x] Map every user-triggerable graph/storage/runtime failure to a
structured public error instead of INTERNAL_ERROR.
- [ ] Label candidate-file warnings separately from returned-file
diagnostics.

## File transport and encoding

- [x] Empty Markdown and MDX are accepted.
- [x] UTF-8 BOM and CRLF are accepted.
- [x] Whole Markdown/MDX file over 1 MiB is detected.
- [x] Missing or unavailable selected content is reported.
- [x] Invalid UTF-8 frontmatter returns the same structured diagnostic
in query and MCP.
- [x] Invalid UTF-8 body returns the same structured diagnostic in query
and MCP.
- [x] MCP download must use fatal UTF-8 decoding rather than replacement
characters.
- [x] Validate bytes before committing an upload, or return the
committed Asset ID and explicit cleanup state when post-commit feedback
fails.
- [x] Reject filename/format mismatches instead of allowing either hint
to bypass Markdown/MDX validation.
- [x] Storage status, missing body, invalid metadata, revision mismatch,
format mismatch, short read, and excess read each return structured file
context.
- [x] Content changing during validation has a clear retryable conflict
diagnostic.

## Frontmatter

- [x] No frontmatter.
- [x] Empty frontmatter.
- [x] Opening delimiter without a closing delimiter.
- [x] Frontmatter over 64 KiB.
- [x] Invalid YAML grammar.
- [x] Multiple YAML parser errors.
- [x] Duplicate keys.
- [x] YAML aliases.
- [x] Unsupported YAML tags.
- [x] Scalar or array root instead of an object.
- [x] Non-JSON values, NaN, Infinity, and unsafe integers.
- [x] Nesting deeper than 8.
- [x] More than 256 fields/array entries.
- [x] One string over 16 KiB.
- [x] Normalized indexed properties over 64 KiB.
- [x] Frontmatter warnings remain nonfatal and visible.
- [x] Collect all post-parse normalization/limit errors; this phase
currently stops at the first.
- [ ] Prove every state above through real MCP upload, update, download,
query, and Diagnostics paths.

## Markdown body

- [x] Treat ordinary CommonMark/GFM as permissive; malformed-looking
Markdown and raw HTML are not automatically syntax errors.
- [x] Preserve and validate the body when frontmatter is invalid.
- [x] Detect the 1 MiB body/file limit.
- [x] Handle body extraction and bounded excerpts.
- [x] Return a shared structured invalid-UTF-8 body error from every
byte-reading surface.
- [ ] Distinguish author errors from internal
excerpt-limit/configuration errors.
- [ ] Prove body-size and decoding states through real MCP and
Diagnostics.

## MDX grammar and safety

- [x] Malformed MDX/JSX grammar.
- [x] Imports.
- [x] Exports.
- [x] Executable flow expressions.
- [x] Executable text expressions.
- [x] JSX expression attributes.
- [x] JSX spread attributes.
- [x] Arbitrary components.
- [x] HTML-looking JSX outside ws.element.
- [x] Unsupported/raw MDX node types.
- [x] Duplicate attributes and normalized alias collisions.
- [x] Event-handler attributes.
- [x] srcdoc, srcset, and dangerouslySetInnerHTML.
- [x] Unsafe URL protocols in link/source/action-like props.
- [x] Forbidden tags: base, link, meta, noscript, script, style,
template, title.
- [x] Conflicting, empty, or non-static ws:name and ws:tag.
- [x] More than 20,000 nodes.
- [x] Nesting deeper than 100.
- [x] More than 4,000 props.
- [x] Multiple recoverable unsafe-mdx warnings are collected.
- [ ] Collect multiple fatal grammar/structural errors when parser
recovery can do so; unrecoverable parsing currently stops at the first
fatal error.
- [x] Preserve sibling expression warnings when unsupported JSX is also
present; {first()}, <Card />, {second()} currently reports only the Card
warning.
- [ ] Prove every state above through real MCP and Diagnostics, not only
validator unit tests.

## Content Block semantics

- [x] Unresolved template warning exists.
- [x] Unknown template prop warning exists.
- [x] Incompatible template prop warning exists.
- [x] Design-only template prop warning exists.
- [x] Stale template prop warning exists.
- [x] Invalid materialized HTML content model error exists.
- [x] Run these checks for an MDX file even when no active editor
Content Block root has materialized it.
- [x] Run applicable semantic checks in query Diagnostics.
- [x] Run applicable semantic checks for MCP upload as well as
contextual update/download.
- [x] Return all Content Block frontmatter diagnostics; one path still
throws only diagnostics[0].
- [ ] Add real MCP and UI coverage for every semantic state.

## Cross-file references

- [x] Non-string $ref marker.
- [x] Invalid reference URL.
- [x] Invalid fragment encoding.
- [x] Invalid fragment.
- [x] Invalid JSON Pointer.
- [x] Missing referenced document.
- [x] Missing referenced JSON path.
- [x] Missing referenced local Asset warning.
- [x] Unsupported target representation.
- [x] Reference cycle.
- [x] Duplicate document ID or URL.
- [x] Missing graph source or target.
- [x] Root not found.
- [x] Duplicate/unused/unresolved reference.
- [x] Invalid resolved value.
- [x] Content identity conflict.
- [x] Target revision mismatch.
- [x] Representation selector required/invalid.
- [ ] Diagnose {$ref: value, extraKey: value} as an invalid marker or
explicitly document it as ordinary data.
- [x] Collect all bad references and targets instead of stopping at the
first graph failure.
- [x] Validate references from the editor and MCP file tools, not only
query compilation.
- [x] Map graph compilation/resolution, Markdown-document, and
JSON-document errors to exact structured Diagnostics rows.
- [x] Prevent an unrelated file's graph error or duplicate canonical URL
from blocking an exact-file query.
- [ ] Prove missing targets, cycles, bad representations, and bad JSON
paths through real MCP.

## Query request and structure

- [x] Invalid JSON, invalid request UTF-8, empty/non-object request, and
request over 512 KiB.
- [x] Missing query and unknown request/query keys.
- [x] Invalid result mode.
- [x] Malformed where/all/any/filter shape.
- [x] More than 32 filters or children.
- [x] Filter nesting deeper than 8.
- [x] Empty field path or segment.
- [x] Field path deeper than 9.
- [x] Bare properties path.
- [x] Unknown or nested standard field.
- [x] Missing or unknown operator.
- [x] Non-JSON operator value.
- [x] Invalid in value or more than 1,000 in values.
- [x] Non-boolean exists/isEmpty value.
- [x] More than 8 sort entries.
- [x] Invalid sort field or direction.
- [x] first/last without a sort.
- [x] Invalid output mode or includeMetadata.
- [x] Duplicate output fields or more than 256 fields.
- [x] No selected output.
- [x] Negative, fractional, or over-1,000 limit.
- [x] Negative, fractional, or over-1,000 offset.
- [x] Invalid content mode.
- [x] Invalid full/markdown-body-ref maxBytes outside 1..1 MiB.
- [x] Invalid range offset/length or range over 256 KiB.
- [x] Empty or over-255-character index revision.
- [x] Multiple simultaneous schema issues retain exact query paths.
- [x] Make content option objects strict; unknown keys are currently
stripped.
- [x] Show an invalid persisted resource body rather than silently
loading the default query.
- [x] Aggregate unknown-key errors with every other structural issue;
MCP currently stops at the first unsupported key.
- [x] Add field-value type validation, for example reject size gt
"large" and id contains {}.
- [x] Warn about unobserved dynamic fields selected only as output.
- [ ] Prove the full structural matrix through the MCP server/API end to
end; the current broad matrix tests the local adapter.

## Query semantic states

- [x] INCOMPATIBLE_OPERATOR is fatal for standard fields.
- [x] UNOBSERVED_FIELD is a nonfatal warning.
- [x] INCOMPATIBLE_OBSERVED_TYPES is a nonfatal warning.
- [x] STRUCTURED_SORT_ORDER is a nonfatal warning.
- [x] Every incompatible standard-field operator is collected.
- [x] Fatal semantic errors retain nonfatal warnings.
- [x] Successful warnings appear with exact query paths.
- [ ] Reproduce every catalog-dependent semantic state through real MCP.
- [x] Test repeated warnings at distinct query paths without accidental
deduplication.

## Query execution and hydration

- [x] Stale index revision.
- [x] result one matching multiple files, including matchedCount.
- [x] Candidate document limit of 1,000.
- [x] Result payload limit of 16 MiB.
- [x] Hydrated file count limit of 20.
- [x] Per-file hydration limit of 1 MiB.
- [x] Total hydration limit of 2 MiB.
- [x] Range limit of 256 KiB.
- [x] Binary content requested as text.
- [x] Invalid UTF-8 during hydration.
- [x] Missing, stale, or conflicting content identity.
- [x] Canonical metadata/byte-count mismatch.
- [x] Storage returning more bytes than requested.
- [x] Missing content reader.
- [x] Selected content not returned.
- [x] Runtime Asset URL unavailable.
- [x] Document graph document-count/per-file/total limits.
- [x] Classify candidate-document and result-byte limits as
CONTENT_LIMIT_EXCEEDED instead of INVALID_REQUEST.
- [x] Give unavailable URL, missing reader/content, storage, selection,
and assembly failures stable codes and exact asset/file details instead
of INTERNAL_ERROR.
- [x] Never silently turn an exact-file unavailable-content failure into
an empty successful result.
- [x] Add direct regression tests for duplicate identity, excess bytes,
and canonical byte mismatch.
- [ ] Reproduce every runtime/hydration state through real MCP.

## Scoping and aggregation

- [x] Errors and warnings from multiple loaded result files are returned
together.
- [x] Nonfatal errors do not suppress successful query results.
- [x] Unrelated published-query diagnostics do not replace current-query
diagnostics.
- [x] File path and available line/column are shown.
- [x] Exact nested query paths are shown.
- [x] Validate and report every pre-pagination matching file if that is
the product definition.
- [ ] Explain candidate metadata warnings when invalid metadata prevents
deciding whether a file matches.
- [ ] Stop including METADATA_PREPARATION_FAILED globally unless the UI
labels its candidate scope.
- [x] Aggregate reference errors instead of stopping at the first.
- [x] Aggregate across validation phases where safe.
- [x] Add a matrix for same-file multiple errors, multiple files,
outside-page errors, filter-only candidate files, and unrelated queries.

## Transport, authorization, cancellation, and internal failures

- [x] UNAUTHORIZED and FORBIDDEN.
- [x] REQUEST_CANCELLED in query HTTP paths.
- [x] Sanitized authenticated internal message.
- [x] Generic unauthenticated/public internal message.
- [x] Preserve structured causes for document-load HTTP
status/body/metadata failures.
- [x] Preserve structured causes for object-storage read failures.
- [x] Preserve structured causes for graph selection/assembly failures.
- [ ] Test MCP/API cancellation directly.
- [ ] Reproduce authorization, cancellation, storage, and
sanitized-internal states through real MCP where safe.

## MCP reproduction

- [x] Real MCP reproduction: multiple Markdown YAML errors.
- [x] Real MCP reproduction: multiple simultaneous structural query
errors.
- [x] MCP update returns Markdown and MDX source diagnostics.
- [x] MCP upload returns Markdown and MDX source diagnostics.
- [x] MCP download returns Markdown and MDX source diagnostics.
- [x] Temporary remote fixtures are removed after reproduction.
- [ ] Real MCP reproduction for every frontmatter code.
- [ ] Real MCP reproduction for every MDX fatal/warning class.
- [ ] Real MCP reproduction for every Content Block semantic diagnostic.
- [ ] Real MCP reproduction for every reference/graph error.
- [ ] Real MCP reproduction for every semantic query warning/error.
- [ ] Real MCP reproduction for every hydration/runtime/limit error.
- [ ] Real MCP reproduction for auth, cancellation, storage, and
internal errors where safe.
- [ ] A durable table-driven test proves code/severity/message/path
parity between editor, query, Diagnostics, and MCP.
- [x] Preserve stable top-level error identity and structured details
through MCP instead of flattening known errors to MCP_TOOL_FAILED.
- [x] Prove failed post-commit MCP feedback reports whether a mutation
committed and returns enough identity for cleanup.

## Real MCP recheck and follow-up fixes (2026-09-03)

Ran the branch CLI against the PR preview backend. The first run exposed
that the saved CLI origin pointed to a different backend, so those
results were discarded. Every MCP result below came from the PR preview.
All temporary remote and local fixtures were removed afterward. The
failures found in that run were then fixed and covered by regression
tests.

- [x] Exact broken Markdown query returns FRONTMATTER_INVALID with
severity, filename, message, line, and column.
- [x] Exact MDX query returns unsafe-mdx with severity, filename,
message, line, and column.
- [x] A no-extension query returns warnings from both matching Markdown
and MDX files.
- [x] A Markdown-only query excludes the unrelated MDX warning.
- [x] Two fatal MDX files inside the returned page are both reported;
matching warnings remain attached.
- [x] Structural query validation returns three independent errors with
exact paths in one call.
- [x] Semantic query validation returns three fatal operator errors and
two warnings with exact paths in one call.
- [x] MCP upload, update, download, and exact-file query return multiple
source diagnostics for the same MDX source.
- [x] Query preview reports a missing Asset reference as ASSET_NOT_FOUND
with the source file and reference.
- [x] All temporary MCP fixtures were deleted and the saved CLI
connection was restored.
- [x] Fixed after recheck: validate every matching file before
pagination, including broken files outside the returned page.
- [x] Fixed after recheck: unrelated graph failures no longer block an
exact-file query.
- [x] Fixed after recheck: update, download, editor, and query paths use
shared reference validation.
- [x] Fixed after recheck: graph failures map to structured diagnostics
with the exact file.
- [x] Fixed after recheck: shared fatal UTF-8 validation runs before
upload writes and preserves structured error identity.
- [x] Fixed after recheck: MCP rejects filename/format mismatches.
- [x] Fixed after recheck: MDX validation keeps sibling and nested
warnings around unsupported components.
- [x] Fixed after recheck: MCP preserves stable top-level error codes
and structured details.
- [x] Fixed after recheck: query and MCP serializers preserve full
normalized diagnostic fields.
- [x] Fixed after recheck: unknown keys are aggregated with all other
structural query errors.
- [x] Fixed after recheck: shared query validation covers literal types,
output-only fields, and strict content options.
- [x] Fixed after recheck: unavailable selected content returns an
exact-file diagnostic instead of a silent empty result.

## Tests and delivery

- [x] Full Builder suite: 2,707 tests.
- [x] Content Engine suite: 445 tests.
- [x] Asset uploader suite: 211 tests.
- [x] Project runtime/MCP targeted suite: 128 tests.
- [x] CLI/MCP suite: 1,051 tests.
- [x] Relevant package typechecks, lint, generated docs, and diff
checks.
- [x] Documentation impact reviewed and generated Content Engine/MCP
reference updated.
- [x] Add the missing cross-surface error matrix described above.
- [ ] Demonstrate red/green behavior for every new matrix case.
- [ ] Run the complete agent evaluation suite after explicit approval.
- [ ] Re-run all checks after the remaining checklist is implemented.

## Compatibility and risk

Normal query result and expression-binding shapes remain unchanged.
Diagnostics add optional fields. Existing public/pre-auth error
redaction remains intact. The remaining unchecked items are broader
exhaustive real-MCP coverage, parser-recovery limits, candidate-warning
labeling, cancellation coverage, and agent evaluations.
2026-09-04 16:00:28 +02:00
Oleg Isonen b832a8e808 refactor: Centralize Builder ID generation (#6323)
## Outcome

Builder-owned code now routes standard ID generation through
`@webstudio-is/sdk/createId` while preserving existing NanoID and UUID
formats.

Closes #6322

## Technical choices

- Use `createId("nano")` for Builder records, assets, transaction IDs,
and other existing NanoID-backed values.
- Use `createId()` for UUID-backed database records and browser-side
client IDs.
- Keep `BuilderRuntimeContext.createId` as an injectable dependency.
Runtime operations, copy/paste, and deterministic tests rely on that
injection.
- Keep Node's `randomUUID` in CLI paths that explicitly support running
without the Web Crypto global.
- Keep specialized generators for custom-alphabet project domains and
actual hash generation.
- Remove direct `nanoid` dependencies from packages where no specialized
use remains.
- Do not migrate existing data or change database schemas.

## Todo

- [x] Migrate Builder app ID creation.
- [x] Migrate project runtime and template defaults.
- [x] Migrate asset, project, domain, and authorization-token IDs.
- [x] Preserve runtime ID injection.
- [x] Review remaining direct generators as explicit exceptions.
- [x] Add NanoID-format regression coverage for the default runtime
context.
- [x] Review documentation impact: no user-facing documentation changes
are needed.
- [x] Review fixture impact: no fixture input or generated output format
changes are needed.
- [x] Run targeted tests, typechecks, lint, and package-boundary checks.

## Verification

- Targeted Builder tests: 153 passed after preserving runtime-context
injection.
- Project-build runtime tests: 270 passed.
- Asset uploader tests: 61 passed.
- Authorization-token tests: 17 passed.
- Project tests: 52 passed.
- Domain tests: 18 passed.
- CLI tests: 32 passed.
- Typechecks passed for Builder, project-build, asset-uploader,
authorization-token, project, and domain.
- `pnpm lint` passed.
- `pnpm check:package-boundaries` passed.
- The runtime-context format test was demonstrated to fail with a UUID
default and pass with the NanoID default.
- Agent evaluations were not run because they require separate explicit
approval.
2026-09-03 15:56:23 +02:00
Oleg Isonen 0d5c2f6ee8 fix: Allow folder index page paths (#6147)
## Summary

Fix the dry-run/commit mismatch for folder index pages. Page mutations
could plan an empty local path inside a folder, but persistence rejected
the same page because the shared Pages schema treated every non-home
empty path as invalid.

## Technical choices

- Derive valid folder-index page IDs from non-root folder children in
the shared SDK schema.
- Continue rejecting empty paths for non-home pages at the root.
- Keep the existing home-page and root-folder invariants unchanged.
- Cover both an existing page update and the transaction shape used when
duplicating a folder index page.

The other reports from this batch were verified against current main and
closed against their existing fixes: browser process failures are
covered by #6135, and fragment conflict options are covered by #6122.

## Checklist

- [x] Reproduce the persistence failure
- [x] Add regressions that fail before the schema fix and pass after it
- [x] Allow empty local paths only for pages parented by non-root
folders
- [x] Verify update and duplicate persistence paths
- [x] Run the fixture sync/build pipeline and inspect generated output
- [x] Review documentation impact — no documentation change is needed
because this restores the existing folder-index behavior
- [x] Review the final diff for duplicated logic, edge cases, and
unrelated changes

## Verification

- `pnpm --filter @webstudio-is/sdk test` — 513 tests passed
- SDK typecheck passed
- `pnpm --filter @webstudio-is/project test` — 85 tests passed
- Project typecheck passed
- `pnpm --filter @webstudio-is/project-build test` — 2,094 tests passed
- Project-build typecheck passed
- `pnpm --filter ./packages/cli test` — 980 tests passed
- CLI typecheck passed
- `pnpm lint`
- `pnpm check:generated-api`
- `pnpm fixtures` — completed with no tracked fixture changes
- Real local Chrome and auto-browser screenshot reproductions passed,
including parallel captures

Agent evaluations were not run because they require separate explicit
approval.

Closes #6142
2026-08-14 23:31:27 +02:00
Oleg Isonen 11d76eb43d perf: Diagnose and reduce Assets resource latency (#6095)
## Summary

Adds Builder-only resource performance metrics to grouped Diagnostics
tables, removes duplicate object-store reads from the Assets query path,
scopes compiled-artifact reuse to one repository request, and compiles
unpinned Builder previews from their concrete query values instead of
hydrating the complete saved dynamic deployment plan. Nothing is
precomputed or retained in a warm serverless process after the request
finishes.

Ref #6092

## Technical choices

- Keep `__performance__` as internal response metadata and strip it
before resource values enter expression-visible caches.
- Record Builder round-trip, server duration, response size, Assets
phases, document work, completed storage reads, and cumulative
compiler/document-graph storage-read durations.
- Present Diagnostics as collapsible sections ordered Database and
sizes, Timing, Query work, then detailed database/result inspectors.
Open only the first available section by default. Every metric keeps an
explanatory tooltip, with info icons revealed only when the label cell
is hovered or keyboard-focused.
- Add a copy action to every section header. It copies that section's
raw structured data as formatted JSON without opening a collapsed
section.
- Keep Index preparation as an inclusive parent duration and explain
that relationship in Diagnostics.
- Compile ordinary unpinned Builder preview requests from a union of
their concrete query values. A detail route therefore hydrates only
documents that can satisfy that request.
- Continue using the saved artifact-producing plan for revision-pinned
requests.
- Keep publication and prepublication preparation unchanged.
- Load only `props`, `dataSources`, and `resources` when constructing
the single-query Builder preview plan, matching the already-narrow batch
path instead of downloading and parsing the complete dev Build row.
- Build the deployment-wide saved plan only when detailed Diagnostics
requests its Published database statistics. Report that work as the
separate inclusive `Published diagnostics` timing and exclude its child
phases and fetch counters from the normal query measurements.
- Reuse successfully read content bytes across compiler preparation,
document graph construction, and runtime resolution within one query or
batch. Graph-fetched bytes are size-validated before entering the
revision-keyed request map, and graph additions stop when the request
cache reaches the 2 MiB hydrated-content limit.
- Before repairing canonical metadata, load candidate metadata once and
prove its revision, base document, and prepared metadata tier match the
open source snapshot. Skip synchronization when it is already current;
retain recovery and repair for stale, missing, insufficient-tier, or
inconsistent rows.
- Key request-local bytes by content reference and revision so
source-change retries cannot reuse stale data.
- Instantiate compiled-artifact reuse per `PostgresAssetRepository`;
repeated preparations inside one request can reuse or coalesce work, but
later requests and other serverless instances cannot.
- Remove the module-level 32-entry compiled-artifact cache introduced in
#5946.
- Introduce no precomputed, persisted, process-local, or cross-request
content cache.

## Findings and measurements

The supplied production post resource was bimodal before removing the
process cache:

- Warm process: approximately 1.0–1.5 seconds.
- Cold process: approximately 5.7–6.7 seconds.
- Ordinary response: approximately 4.6 kB.

The earlier development capture was a process-cache hit: 542.6 ms server
time and 932.5 ms Builder round trip. A later hit measured 491.5 ms
server time and 739.1 ms round trip. Those results demonstrated the old
module cache's nondeterministic serverless behavior rather than
cold-path performance.

After request-scoped reuse replaced the process cache, the supplied cold
capture measured 3,848.5 ms server time. Index preparation was 3,259.7
ms. The saved dynamic plan caused 25 compiler content fetches and 301 kB
of compiler input even though the concrete post query resolved only two
documents. The published database contained 28 documents and used 45.4
kB bounded / 512 kB unbounded.

Tracing compilation also exposed duplicate request-time I/O: selected
Markdown was fetched for compiler input, document graph construction,
and runtime document resolution. Request-local byte reuse changes that
representative path from three object-store reads to one.

The remaining dominant issue was therefore query breadth, not response
serialization or runtime result resolution. The Builder was compiling
the deployment-wide dynamic plan to answer a concrete post request. The
new preview path compiles the concrete values; regression coverage
demonstrates that a saved two-post dynamic plan reads only `post-a` when
previewing `post-a`.

The next cold capture confirmed that change: Builder round trip fell
from 4,391.4 ms to 2,245.2 ms, server duration from 3,848.5 ms to
1,601.8 ms, and index preparation from 3,259.7 ms to 1,044.9 ms.
Compiler content fetches fell from 25 to 1 and document-graph content
fetches from 3 to 1. Canonical metadata remained 239.2 ms because an
unchanged request still performed a repair synchronization round and
then loaded the same stored metadata again. The new fast path reduces
that normal case to one recovery-safe candidate metadata read.

A subsequent capture confirmed the canonical metadata fast path: server
duration fell from 1,601.8 ms to 1,401.0 ms, index preparation from
1,044.9 ms to 684.8 ms, and canonical metadata from 239.2 ms to 74.7 ms.
The post query remained narrow at one compiler fetch and one
document-graph fetch. Builder round trip rose from 2,245.2 ms to 2,411.1
ms while the server improved, so that difference is outside the measured
server work and is consistent with
browser/network/development-environment variance.

At that point `buildPlan` was the largest remaining isolated phase at
242.8 ms. Single-query preview was still loading every dev Build column
and parsing pages, styles, instances, deployment data, and other fields
that are not inputs to the Assets compilation plan. The narrow loader
now requests and parses only the three content-engine fields used by
plan construction.

The next capture confirmed that optimization: build plan fell from 242.8
ms to 99.0 ms, server duration from 1,401.0 ms to 1,056.8 ms, and the
concrete post query remained at one compiler fetch and one
document-graph fetch. Index preparation stayed effectively flat at 679.7
ms, making compiler entries (142.3 ms), source snapshot (119.2 ms),
source validation (119.1 ms), and document graph (114.0 ms) the next
candidates. The new child timings separate cumulative storage waiting
from the remaining compiler/document-graph work before choosing another
behavioral optimization.

The storage timing capture then showed that I/O dominated the remaining
compiler and graph phases: compiler storage was 114.6 ms of 125.9 ms,
while document-graph storage was 114.0 ms of 147.6 ms. The graph path
consulted compiler-cached bytes but did not retain newly fetched graph
documents, so runtime reference resolution fetched the same two-document
chain again. Retaining validated graph bytes in the same request reduces
the regression fixture from four physical object-store reads to two
without changing its resolved result.

Final three-run measurements after same-request graph-byte reuse were
stable: median Builder round trip was 926.2 ms, median server duration
was 681.9 ms, median index preparation was 407.9 ms, and median document
resolution was 3.7 ms. Compared with the uncached 3,848.5 ms server /
3,259.7 ms index baseline, that is approximately 82% less server time
and 87% less index-preparation time for this post query.

A final DRY/correctness review centralized request-local byte-cache
keying and its 2 MiB accounting, removed repeated Diagnostics size rows
and SDK metadata assembly, typed phase keys, and corrected response-size
measurement so internal performance metadata is excluded as the UI
promises.

The module cache was also only bounded for completed entries. Many
simultaneous unique-project compilations in one process could exceed 32
pending entries until they settled. Scoping reuse to one repository
request removes cross-user retention and tenant cache competition while
preserving duplicate-work elimination inside the request.

## Todo

- [x] Add generic resource timing and response-size metrics.
- [x] Add Assets phase, document graph, source validation, storage-read
count/byte metrics, and compiler/document-graph storage-read durations.
- [x] Render ordered collapsible Diagnostics sections with only the
first open by default, per-metric explanations, interaction-only info
icons, and per-section JSON copy actions.
- [x] Reuse compiler and document-graph content bytes through runtime
resolution within the current request, without precomputation.
- [x] Remove cross-request process caching and retain request-scoped
compilation reuse.
- [x] Compile unpinned previews from concrete query values.
- [x] Separate deployment-wide diagnostic preparation from normal query
phase counters.
- [x] Skip redundant canonical metadata synchronization when stored
candidates already match the source snapshot and requested tier.
- [x] Narrow single-query Build reads to the three fields required by
Assets plan construction.
- [x] Expose cumulative compiler and document-graph storage-read timing
as explained child rows.
- [x] Add regression coverage, including red/green verification.
- [x] Review the final diff for correctness, duplication, and
unnecessary complexity.
- [x] Verify concrete-query compilation against the supplied post
resource: compiler fetches fell from 25 to 1.
- [x] Remeasure the canonical metadata fast path: canonical metadata
fell from 239.2 ms to 74.7 ms and index preparation from 1,044.9 ms to
684.8 ms.
- [x] Review documentation impact: no authoritative `docs/` page covers
this internal Diagnostics tooling, so no documentation update is
required.
- [x] Run focused tests, affected package typechecks, lint, formatting,
and the fixture pipeline.

## Verification

- Content engine tests: 23 passed.
- Asset uploader tests: 195 passed, including repository, canonical
synchronization, request-cache, and storage-timing coverage.
- Builder focused Diagnostics tests: 10 passed in the latest
storage-timing pass; 15 passed in the preceding final pass and 35 across
the earlier instrumentation scope. The collapsible view test verifies
section order, default state, and deferred content interaction.
- Project tests: 84 passed, including 5 focused preview tests. The
focused regression failed against the full-Build loader and passed after
switching the single-query path to the narrow content-engine loader.
- SDK resource loader tests: 24 passed.
- Current canonical metadata regressions failed under the old
always-synchronize expectations and pass with one metadata load and no
synchronization; stale metadata still exercises and passes the repair
fallback.
- The Timing clipboard test failed with an empty payload and passed with
the complete raw duration/phase JSON; copying a collapsed section is
also verified not to open it.
- The collapsible default-state test failed when Timing was temporarily
opened alongside Database and sizes, then passed after restoring the
first-section-only behavior.
- The concrete-preview regression failed before the optimization by
reading both `post-a` and `post-b`, then passed by reading only
`post-a`.
- A repository-reuse regression failed without the request cache and
passed when reuse became the repository default.
- The content-read regression failed before the original compiler reuse
optimization with three storage calls and passed afterward with one.
- The two-document graph regression failed with four physical storage
calls and passed with two after graph reads populated the request-local
runtime cache.
- The response-size regression failed at 127 bytes when internal
performance metadata was included and passed at the actual 66-byte
payload after separating that metadata.
- Builder, content engine, asset uploader, project, and SDK typechecks
passed.
- Oxfmt, oxlint, and `git diff --check` passed.
- The full fixture link/sync/build pipeline passed with no tracked
fixture changes after each runtime change.

## Known limitations

- Detailed Diagnostics intentionally prepares both the concrete query
database and the deployment-wide Published database. `Published
diagnostics` reports the latter separately; normal resource loads do not
perform it.
- Builder round-trip and server duration cover the complete resource
batch and therefore include Published diagnostics when the detailed view
requests it.
- Phase durations are aggregated when a batch contains multiple Assets
queries.
- Compiler and document-graph storage-read timings sum completed fetch
durations. They exclude request-local byte-cache hits and can exceed
wall-clock parent phases when reads run concurrently.
- Content-read counters report completed normal-query reads;
deployment-wide diagnostic reads are excluded, and failed storage reads
are represented by the enclosing phase timing and error.
- Request-local byte reuse retains selected content only until the
current query or batch finishes. Document-graph additions are capped by
the existing 2 MiB hydrated-content limit; content beyond the cap is
still streamed and can be fetched again at runtime.
- Source snapshot and final source validation remain separate reads. The
metadata fast path removes redundant repair work without weakening that
concurrent-change check.

## Measurement gate

PR deployments use the development backend. The supplied production
project returns 500 on both the branch deployment and
`main.development.webstudio.is`, while the production host returns 200.
Final phase timings for the exact project require its corresponding
development project/session or an explicitly authorized
production-backed deployment. An unrelated fixture will not be used to
claim the production improvement.
2026-08-11 12:31:23 +02:00
Kathir Eswaran 7b7ab69d4e chore: remove stale authz todo comments in project-router (#6036)
## Description

1. What is this PR about (link the issue and add a short description)
The rename and delete mutations already thread ctx into authorization
(edit and own permits respectively). Drops the leftover `@todo pass ctx
for authorization` comments. No behavior change.

## Code Review

- [x] hi @kof, I need you to do
  - conceptual review (architecture, feature-correctness)
  - detailed review (read every line)

## Before requesting a review

- [x] made a self-review
2026-08-07 12:30:44 +02:00
Oleg Isonen c44ef705cf perf: Speed up Builder resource loading (#6011)
## Problem

Assets-backed Builder pages can take 6–7 seconds to become usable even
when their Assets resources only request metadata. On the
production-derived Blog project, a single Assets query measured 8,703 ms
and an immediate repeat measured 8,110 ms. Four sibling Assets resources
repeated the same authorization, development-build load/parse,
compilation, canonical-asset preparation, runtime metadata load, and
document work.

## Architecture

The loader now treats remote resources holistically while preserving
provider boundaries:

- The client scheduler is resource-provider neutral. It versions logical
requests, frees capacity when obsolete requests are replaced, ignores
stale results, and aborts physical batches only when every member is
obsolete.
- Ordinary Assets requests in one server resource-loader call use a
deferred Assets provider and execute as one repository batch.
Independent HTTP, GraphQL, and other resources start immediately instead
of waiting for Assets preparation.
- Arbitrary remote responses are **not** coalesced or persistently
cached. Their auth headers, cookies, upstream freshness, and `Vary`
semantics remain isolated.
- The Assets provider authorizes and creates its API context once per
batch, then loads only `props`, `dataSources`, and `resources` from the
development Build.
- Queries covered by the saved Build compilation plan reuse that exact
plan/artifact, preserving published byte limits, truncation, and
pinned-revision behavior. Uncovered unpinned queries use a deterministic
literal union and safely fall back to their existing individual path if
shared preparation cannot preserve behavior.
- Request-scoped document loading uses npm's byte-bounded `lru-cache` so
sibling queries do not reread the same referenced author/content files.
- Sibling dynamic queries with the same filter, sort, output, and
content shape stitch into one document-graph resolution while keeping
filter values, pagination windows, results, and failures independent.
Aggregate document/byte-limit failures fall back to isolated execution.
- Provider-neutral batching lives in the SDK runtime, and project
asset-query preview orchestration lives in the shared project package so
Builder and MCP paths can reuse the same behavior.
- Cancellation flows from the client batch through the
SDK/server/build/query path, with checkpoints between expensive phases.
- Runtime asset metadata remains conservatively artifact-wide because
URL/size filters, structured references, markdown hydration,
materialized rows, and saved plans have different reachability rules. To
make 1,000-asset artifacts safe, PostgREST `.in(...)` lookups are
deduplicated and split into 100-ID chunks with bounded concurrency.

## Implementation checklist

- [x] Trace the production Blog resource path and identify repeated work
- [x] Copy the production Blog project into an ignored disposable local
project
- [x] Record production and local baselines
- [x] Add provider-neutral client scheduling, stale-result protection,
and cancellation
- [x] Batch ordinary Assets queries without coupling or caching
HTTP/GraphQL responses
- [x] Load only Build fields required to create the saved content
compilation plan
- [x] Preserve saved-plan, truncation, fallback, diagnostics, and
revision semantics
- [x] Share Assets artifacts, runtime metadata, and revision-keyed
document reads per request
- [x] Stitch compatible query shapes into one graph resolution with
isolated fallback
- [x] Extract reusable SDK batching and project preview orchestration
for MCP/runtime consumers
- [x] Bound large runtime asset metadata lookups for the 1,000-asset
project limit
- [x] Add regression coverage and demonstrate new tests failing before
their fixes
- [x] Run focused and broad tests, type checks, lint, format,
package-boundary, and diff checks
- [x] Review documentation impact; no authoritative `docs/` content
changes are required
- [x] Regenerate and verify the affected asset-query runtime fixture; no
production data is changed
- [x] Address all actionable PR review comments
- [x] Rerun the final parity-preserving implementation against the
copied Blog project

## Measurements

Production trace before the change:

- Updates Assets query: 8,703 ms
- Immediate identical repeat: 8,110 ms
- Query artifact: 9,344 bytes / 7 documents
- Saved source database: 42,086 bytes / 28 documents

Copied-project local baseline:

- Builder navigation until resource loading: 5,111 ms
- Exact four-resource batches: 1,448 / 797 / 1,377 / 774 / 3,018 ms

During implementation, before the final saved-plan parity tightening:

- Exact four-resource batch: 174 ms first run, then 51–80 ms
- Actual Builder resource-loader requests: 234–246 ms

Final parity-preserving copied-project rerun:

- Preflight: 10 ms
- Exact four-resource batch: 435 ms cold, then 119 / 97 / 90 / 79 ms
warm
- Every response returned HTTP 200 with the same 16,884-byte payload

The final cold batch is 70% faster than the best copied-project cold
baseline, and the fastest warm batch is 90% faster than the best warm
baseline. The production trace remains the authoritative production
baseline; these before/after comparisons use the same disposable local
project and captured request payload.

## Verification

Passed:

- Full package suites: Builder (212 files / 2,496 tests), asset-uploader
(22 / 193), content-engine (40 / 274), project (7 / 84), SDK (29 / 508),
and project-build (82 / 2,070)
- Final focused regressions: Builder preview/API/resource integration (3
files / 42 tests), SDK resource loader (23 tests), and document-graph
resolution (6 tests)
- Builder, asset-uploader, content-engine, project, SDK, and
project-build type checks
- Fixture regeneration is deterministic; the generated vendor exactly
matches the source runtime bundle
- Fixture typecheck and production build
- Changed-file Oxfmt, repository Oxlint, and package-boundary checks
- `git diff --check`
- `git diff --name-only HEAD --exit-code`

New behavioral tests were demonstrated to fail before implementation and
pass afterward, including Assets batch coordination, saved-plan wiring,
truncation and pinned revisions, shared document reads, cancellation
checkpoints, stale/replaced client requests, and large PostgREST ID
filters.

Agent evaluations were not run because they require separate explicit
approval.

## Compatibility and remaining work

The public resource result/error shape and on-demand diagnostics
contract stay compatible. Generic HTTP/GraphQL caching semantics are
unchanged. Compilation already in progress is not force-cancelled
because safely interrupting shared compilation requires
ownership/reference tracking; cancellation prevents later phases from
starting.

Closes #6003
2026-08-04 18:39:41 +02:00
Oleg Isonen efbc3098c4 feat: add queryable Assets resources (#5946)
Closes #5919
Ref #5920

## Outcome

Extend the existing Assets system resource with optional queries for
Markdown, JSON, and standard file metadata. Unconfigured Assets
resources retain the existing fetch-all behavior and activate none of
the content-query infrastructure.

Files are the authoring model. A standalone content engine converts an
immutable snapshot of only the files required by configured queries into
one bounded, deterministic runtime database. Builder preview, SSR, and
SSG use the same query semantics without requiring a database service
for a published site.

## Final architecture

```text
Markdown / JSON files
        │
        ▼
ContentSource adapter
(FS or Webstudio Assets)
        │ immutable snapshot
        ▼
ContentCompilationPlan
(union of configured query requirements)
        │
        ▼
ContentCompiler
(parse, normalize, discover fields, enforce budget)
        │
        ▼
ContentArtifact
(bounded, deterministic, immutable JSON)
        │
        ▼
ContentDatabase
(filter, OR groups, sort, paginate, project, read content)
        │
        ├── Builder preview
        ├── SSR runtime
        └── SSG build only
```

The authoring/storage layer owns mutable files. The content engine
consumes immutable snapshots and produces immutable, disposable
artifacts.


Query authoring is a separate OpenAPI-driven path:

```text
Assets REST OpenAPI operation
+ standard request JSON Schema
+ dynamic field paths
        │
        ▼
Generic OpenAPI adapter
        │ resolved schemas, controls, paths, and transport mapping
        ▼
Generic query-builder core and React renderer
        │ arbitrary provider-defined value
        ▼
Assets REST request adapter
        │
        ▼
{ query: value }
```

The selected standard OpenAPI operation is the only source of query UI
semantics. Request parameters and JSON Schema describe the editable
data; the generic renderer derives controls and owns layout.

### Activation and compilation

- The compiler does not index every asset. It combines all reachable
configured Assets-resource queries into one `ContentCompilationPlan`.
- Static constraints such as folder, path, and file type select
candidate files. Dynamic values such as a route-bound slug cannot reduce
the build-time candidate set.
- The plan contains the union of fields used by filtering, sorting,
routing, projection, excerpts, and requested full content.
- Documents shared by multiple resources are stored once in one
deployment-wide runtime database.
- Markdown/frontmatter, JSON properties, excerpts, and full bodies are
prepared only when required.
- No configured content query means no parsing, artifact, or shipped
runtime dependency. Fresh generated apps need no content-runtime
cleanup; incremental generation removes stale integration if a
previously configured query is deleted.

### Runtime database limit

- `CONTENT_DATABASE_MAX_BYTES` limits the complete serialized runtime
database, not source files, images, or unrelated assets.
- The default is `500 * 1024` bytes and is presented as 500 KiB.
- Counted data includes indexed metadata, frontmatter/JSON properties,
excerpts, the field catalog, serialization overhead, and full Markdown
bodies only when requested.
- Prepublish validation builds and serializes the exact database that
will be attached to the immutable build, so it knows the unbounded size,
bounded size, included documents, omitted documents, and affected
resources.
- Overflow never stores partial documents. Candidates are ordered by
`createdAt` descending, canonical path ascending, and stable document ID
ascending. Missing dates follow dated documents. A document that does
not fit is skipped while smaller later documents are still considered.
- Exceeding the limit warns but does not block publishing.
- Builder preview can report exact bounded versus unbounded results when
dynamic expressions have concrete preview values. Prepublish warnings
remain conservative for future route values.

### Snapshot consistency

The source contract guarantees a consistent compilation, while adapters
provide the mechanism:

- Webstudio Assets captures asset metadata and immutable content
references.
- Filesystem sources capture file identity and verify files did not
change before accepting the artifact.
- A changed source retries once, then fails clearly instead of producing
a mixed-revision database.
- This requires no universal snapshot service, source-tree copy, or new
versioned-asset infrastructure.

### Package ownership

- `@webstudio-is/content-engine`: runtime artifact schema, query
execution, field catalog, compact runtime statistics.
- `@webstudio-is/content-engine/compiler`: source snapshots, compilation
plans, Markdown/JSON parsing, deterministic compilation, byte
accounting, and compiler diagnostics. This entry exists to keep
Remark/YAML/future MDX dependencies out of runtime bundles.
- `@webstudio-is/query-builder`: resolves standard OpenAPI operation
schemas into an internal provider-neutral editor model, validation,
mutations, and source serialization. It owns no Assets,
provider-authored UI contract, or fixed REST-query semantics.
- `@webstudio-is/query-builder/react`: container-neutral schema renderer
whose layout is renderer policy. It remains separate from the content
engine.
- SDK: Webstudio Assets/Resource domain models and mapping Webstudio
expressions into generic content requirements.
- Protocol: external Assets REST/OpenAPI transport contracts.
- Asset uploader/repository: asset and folder mutations, generic
metadata, immutable byte references, and storage access. Its hosted
adapter supplies Webstudio Assets snapshots and parsed-metadata cache
persistence to the content engine; parsing, artifact creation, and query
semantics remain engine-owned.
- Builder and generated-app integrations decide when to compile, cache,
embed, load, or discard a database.

### Runtime lifecycle

- Builder caches immutable `ContentDatabase` instances by source
revision plus compilation-plan hash and coalesces concurrent
compilation. Matching operations reuse the same instance; field
discovery uses a dedicated minimal all-properties plan that excludes
excerpts and bodies.
- SSR attaches the validated bounded database to the build and includes
the small runtime only when required.
- SSG uses the database only while generating pages and omits it and the
runtime from final output unless a future runtime-query feature requires
them.
- Local development compiles from the filesystem and uses identical
query semantics.
- Published pages query their local artifact; they do not call Builder
REST endpoints.
- Published artifacts need no external index store, invalidation,
garbage collection, SaaS content proxy, new bucket, or new environment
variable.

## Implemented foundation

These existing parts remain useful and should be moved behind the final
ownership boundaries rather than reimplemented.

- [x] Upgrade the existing Assets system resource in place and preserve
unconfigured fetch-all behavior.
- [x] Implement typed filtering, nested boolean groups, deterministic
sorting, pagination, projections, dynamic values, and content hydration.
- [x] Add Markdown frontmatter, excerpt, JSON-property, and
field-catalog extraction.
- [x] Add reusable query-control implementations and a separately
imported React UI as a foundation for the final OpenAPI-driven contract.
- [x] Add Assets query authoring and dynamic field discovery as existing
behavior to migrate into the Assets OpenAPI operation.
- [x] Add synchronized visual and editable expression authoring.
- [x] Unify Assets REST operations under `/rest/assets/*`.
- [x] Define authenticated collection, item, content, upload, folder,
query, field-catalog, and OpenAPI operations.
- [x] Support Builder cookie authentication and public API token
authentication.
- [x] Add Builder preview, MCP/CLI operations, SSR execution, SSG path
generation, and conditional activation.
- [x] Add revision-keyed parsed metadata persistence for the hosted
Builder.
- [x] Add focused query, API, authorization, Builder, CLI, SSR, SSG,
migration, and fixture coverage.

## Remaining implementation plan

### 1. Establish the content engine

- [x] Rename the generic `@webstudio-is/asset-resource` implementation
to `@webstudio-is/content-engine`.
- [x] Move existing behavior instead of creating a parallel
implementation.
- [x] Keep the primary entry runtime-only and add only the compiler
entry needed for bundle separation.
- [x] Remove the old package after all consumers migrate.
- [x] Ensure the engine has no Builder, SDK, asset-uploader, PostgreSQL,
R2, or deployment-target dependency.

### 2. Define source snapshots and compilation plans

- [x] Introduce `ContentSource.openSnapshot()` and a revision-bearing
`ContentSourceSnapshot`.
- [x] Include canonical path, stable document ID, content type,
immutable content reference, size, and optional `createdAt`.
- [x] Implement Webstudio Assets and filesystem snapshot guarantees
using their adapter-specific mechanisms.
- [x] Introduce `ContentCompilationPlan` for the union of reachable
configured resource requirements.
- [x] Separate statically selectable candidates from dynamic runtime
predicates.
- [x] Add mutation-during-compilation tests for replacement, deletion,
folder movement, and filesystem changes.

### 3. Separate storage from content processing

- [x] Keep upload, replacement, folders, byte storage, revisions, and
generic metadata in the Assets repository/uploader.
- [x] Move parsing, excerpts, field discovery, query execution, and
artifact creation into the content engine.
- [x] Remove content-index coordination from asset mutation business
logic.
- [x] Preserve original source `createdAt` across content replacement
and expose it as optional queryable metadata.
- [x] Keep hosted parsed-document persistence behind the content
compiler's optional cache interface.

### 4. Build deterministic compilation

- [x] Move the existing Markdown, frontmatter, JSON, canonicalization,
hashing, document-building, and tests into the compiler.
- [x] Keep frontmatter behind a dedicated module and continue using the
existing Remark/Micromark pipeline.
- [x] Parse only candidate files and only the tiers required by the
compilation plan.
- [x] Deduplicate documents and fields required by multiple resources.
- [x] Define a versioned, deterministic `ContentArtifact` with integrity
information.
- [x] Keep verbose parse and omission diagnostics outside the runtime
artifact.
- [x] Reject incompatible artifact versions cleanly.

### 5. Enforce the deployment-wide database budget

- [x] Replace the old asset-index limit with
`CONTENT_DATABASE_MAX_BYTES`, defaulting to 500 KiB.
- [x] Have applications read configuration and pass the byte limit into
the compiler.
- [x] Measure the exact serialized database, including selected bodies
and overhead.
- [x] Implement deterministic skip-and-continue packing of complete
documents.
- [x] Return compiler diagnostics with unbounded/bounded bytes,
included/omitted counts, omitted identities, largest contributors, and
affected resources.
- [x] Expose only compact artifact statistics at runtime through
`ContentDatabase.getStats()`.
- [x] Add exact boundary, deterministic ordering, deduplication, and
oversized-document tests.

### 6. Finalize the runtime database

- [x] Define `ContentDatabase` over an immutable artifact.
- [x] Preserve filtering, nested AND/OR groups, sorting, offset/limit,
projection, field references, and content retrieval.
- [x] Expose `getFieldCatalog()` and compact `getStats()`.
- [x] Keep Markdown/YAML/compiler dependencies out of the runtime entry.
- [x] Add execution guards and maximum-size runtime benchmarks.

### 7. Make query authoring OpenAPI-driven

The selected standard OpenAPI operation is the complete query-authoring
contract. The query builder resolves parameters and request-body JSON
Schema, derives its internal editor model, and applies renderer-owned
layout policy. It must not embed or fetch a second capabilities/UI
language through `x-webstudio-query` or another side channel.

- [x] Remove `x-webstudio-query` and all vendor query-definition
metadata from the Assets OpenAPI operation.
- [x] Resolve local OpenAPI references and derive the editable request
value, defaults, validation, labels, choices, arrays, objects, and
unions solely from standard operation parameters and request-body JSON
Schema.
- [x] Represent dynamic Assets field paths with standard JSON Schema
vocabulary in the `queryAssets` request schema.
- [x] Keep the normalized editor representation internal to
query-builder; do not expose another provider-authored capabilities
contract.
- [x] Remove provider-controlled layout metadata such as `group`; make
compact scalar packing and all other layout renderer policy.
- [x] Keep Webstudio expression binding as a consumer/editor concern
layered over schema values, not part of the OpenAPI contract.
- [x] Preserve the existing Assets filter, sort, output selection,
full-content/range selection, limit/offset, editable source, and
configured-field behavior.
- [x] Keep the Assets resource adapter responsible for serializing the
edited query into its request body.
- [x] Remove the obsolete Assets query-capabilities endpoint, URL, and
UI-side capability parsing.
- [x] Add a non-Assets OpenAPI proof with differently named parameters
and no vendor metadata.
- [x] Verify the generic packages contain no Assets imports, fixed
Assets property contract, or provider-authored layout model.
- [x] Update focused core, React, SDK, protocol/OpenAPI, Builder, and
source round-trip tests.

### 8. Manage ContentDatabase lifecycle in Builder

- [x] Cache databases by source revision plus normalized
compilation-plan hash.
- [x] Coalesce concurrent compilation requests.
- [x] Reuse cached database instances across field discovery,
autocomplete, query preview, and response preview when their normalized
compilation plans match.
- [x] Replace it when source revision or query requirements change.
- [x] Preserve the optional revision-keyed hosted parsed-document cache
without making it a source of truth.
- [x] Show exact preview warnings when concrete values reveal missing
bounded results.

### 9. Materialize and verify immutable builds

- [x] Compile and serialize the exact deployment-wide database during
prepublish validation.
- [x] Attach that validated bounded database to the immutable build
without rebuilding it from later asset state.
- [x] Show non-blocking prepublish warnings with database bytes,
omissions, and potentially affected resources.
- [x] Avoid claiming exact future route matches when dynamic values are
unknown.
- [x] Include the database/runtime only when a reachable configured
query requires them.
- [x] Ensure detail resources requesting Markdown content include all
statically eligible bodies needed by dynamic routes.

### 10. Integrate all targets

- [x] SSR: load the build's bounded database and conditionally include
the small runtime.
- [x] SSG: query the same database during generation, then omit
database/runtime output when no runtime query is needed.
- [x] Local/CLI: compile from the filesystem source with the same
semantics.
- [x] Preserve overview pagination, alternative route fields,
draft-as-user-data behavior, and full article rendering.
- [x] Verify ordinary Assets and fresh query-free sites perform no
parser, artifact, content-runtime dependency install, or cleanup work.

### 11. Correct API and package ownership

- [x] Move external Assets REST/OpenAPI contracts to
`@webstudio-is/protocol`.
- [x] Keep Webstudio domain models and Assets system-resource
configuration in the SDK.
- [x] Keep both cookie and token authentication behavior on the unified
Assets REST surface.
- [x] Remove pass-through route wrappers/reexports that add no transport
behavior.
- [x] Keep published runtime queries local to the artifact rather than
routing them through Builder REST.

### 12. Remove superseded deployment infrastructure

- [x] Remove external deployment-index upload, fetch, invalidation,
cleanup, and garbage-collection code.
- [x] Remove the SaaS asset-origin adapter requirement; close
webstudio-is/webstudio-saas#652 as superseded because it has no
independent purpose.
- [x] Remove index-bucket compatibility configuration and avoid adding
Infisical variables.
- [x] Remove obsolete external-index paths, package dependencies,
routes, scripts, and tests.
- [x] Consolidate unreleased intermediate migrations where safe and
retain only schema required by the final hosted cache/API design.

### 13. Verification and release readiness

- [x] Move and preserve existing tests while changing ownership; add new
tests only for changed contracts and behavior.
- [x] Run content-engine compiler/runtime tests, query-builder tests,
SDK/protocol/API tests, Builder tests, CLI tests, and affected
typechecks.
- [x] Run formatting, generated-file idempotence, fixtures, clean
Supabase-compatible migrations, E2E shards, and complete agent
evaluations.
- [x] Verify SSR and SSG conditional inclusion and query-free generated
package manifests.
- [x] Run the five-article MCP blog workflow: authoring, field
discovery, overview, dynamic detail routes, full Markdown rendering,
publishing, and published-site verification.
- [x] Run a maximum-budget database test and a
mutation-during-compilation test.
- [x] Perform a final architecture, security, API compatibility,
migration, bundle, correctness, and DRY review.
- [x] Reconcile every checkbox and replace the verification section with
results from the final architecture before release.

## Future MDX work

MDX is intentionally separate from this release.

- The compiler contract should allow a future build-only MDX parser.
- MDX compilation must not enter the published runtime.
- Embedded JSX must use an explicit compiled representation rather than
runtime source evaluation.
- Webstudio components, tokens, styles, and component allowlists remain
Webstudio integration concerns.
- The future MDX work should reuse `ContentArtifact` and
`ContentDatabase` where practical.

## Superseded design

The following earlier design choices are no longer the target
architecture:

- GROQ or GraphQL as the Assets query language.
- One external or long-lived index object per resource/query.
- A deployment index fetched by the Worker from SaaS/CDN infrastructure.
- Lazy production reads of source Markdown bodies.
- A separate index bucket, asset origin, invalidation service, or
garbage collector.
- A 4 MiB published index limit.
- Rebuilding an old build's database from the current mutable asset set.
- Bundling query infrastructure into projects without a configured
content query.

## Verification baseline

The embedded runtime-database architecture previously passed the checks
below. The OpenAPI-driven query-authoring change additionally passed:

- Query-builder core: 4 files / 19 tests.
- Query-builder React: 1 file / 7 tests.
- SDK Assets source/config: 1 file / 7 tests.
- Protocol Assets OpenAPI: 1 file / 9 tests, including independent
OpenAPI validation.
- Builder Assets OpenAPI description: 1 file / 5 tests.
- Query-builder, React, SDK, protocol, and Builder typechecks.
- Package-boundary validation and formatting of every affected file.

Local verification baseline:

- Content engine: 15 files / 104 tests.
- Asset uploader: 24 files / 175 tests.
- Builder: 204 files / 2,423 tests.
- CLI: 54 files / 866 tests.
- Complete workspace typecheck, formatting, lint, package boundaries,
generated fixtures, and fixture builds.
- The complete migration history applied successfully to a fresh
Supabase-compatible database, including every migration after the
consolidated Assets migration.
- Builder production build and full local E2E suite passed.
- Complete agent evaluations passed: authenticated page (170,859 ms),
design input (207,101 ms), and font assets (67,050 ms).
- Final review additionally verified correct REST edit/view/build
permits, cookie and public-token read paths, immutable snapshot retries,
exact database budgeting, query-free dependency omission, and SSR/SSG
conditional runtime inclusion.

Final staging verification passed against the embedded runtime-database
architecture: MCP uploaded and updated five Markdown articles,
discovered dynamic frontmatter fields, previewed a five-item sorted
overview and one full-body slug query, updated both Assets resources,
found zero binding issues, rendered `/blog` and `/blog/dynamic-routes`
at HTTP 200, published build version 266, and verified both published
routes at HTTP 200 with the expected article metadata and Markdown body.
The workflow also found and fixed offset-form asset timestamps failing
canonical datetime validation and made MCP `preview.start({ port: 0 })`
correctly select an available local port.

## Release constraints

- No new SaaS content service, bucket, or environment variable.
- No published-site database dependency.
- No parser/compiler dependency in query-free sites or runtime-only
bundles.
- The validated content database is immutable build output.
- Publishing warnings do not block deployment.
- The selected standard OpenAPI operation and its request JSON Schema
are the only source of query UI semantics.
2026-07-31 00:17:46 +02:00
Oleg Isonen 878d6f1de1 feat: Add asset folders to asset manager and improve asset manager UX (#5892)
Closes https://github.com/webstudio-is/webstudio/issues/5877
Closes https://github.com/webstudio-is/webstudio/issues/4775


- Organize assets into nested folders.
- Navigate folders with breadcrumbs and Back controls.
- Select and manage multiple assets and folders at once.
- Drag, copy, cut, paste, duplicate, move, and delete items.
- Use context menus and familiar keyboard shortcuts for common actions.
- Search and sort assets and folders, with folders grouped first.
- Upload files directly into the active folder.
- Manage folder placement from asset and folder settings.
- Automate asset and folder management through MCP.
2026-07-17 23:39:14 +02:00
Oleg Isonen d440e02990 feat: Add safer MCP authoring and draft-page verification (#5905)
- **Restore points for agent work**: Create named restore points before
major edits, review changes with a dry run, and safely revert project
content if needed.

- **Shared Slot authoring**: Agents can turn existing sections into
shared Slots and insert linked copies across pages, including valid
nested Slots.

- **DTCG and Figma token imports**: Import design tokens and CSS
variables through CLI, MCP, or direct paste, with aliases, modes,
composite values, and mappings supported.

- **Consistent token conflict handling**: Every paste workflow now
offers the same preserve, rename, or merge choices instead of silently
overwriting existing design tokens.

- **Draft-page previews**: Agents can generate and inspect previews of
draft pages without publishing them or exposing drafts in production
builds.

- **Safer MCP mutations**: Destructive operations require explicit
confirmation, invalid raw patches and invented record IDs are rejected,
and restore operations commit atomically.

- **More dependable agent contracts**: New tools have complete runtime
schemas, clearer validation errors, and consistent behavior across CLI,
MCP, Builder, and server APIs.
2026-07-17 23:16:39 +02:00
Oleg Isonen dde30ffb54 feat: Improve MCP authoring, compact output, and agent onboarding (#5883)
## Summary

This improves how agents discover, author, inspect, and verify Webstudio
projects while reducing unnecessary MCP context usage.

## What changed

- Adds an **Agents** section to Project Settings with ready-to-run setup
commands and client configuration for Claude Code, Codex, Cursor, and VS
Code.
- Makes large list and schema responses compact and paginated by
default, with **verbose** available when complete records or diagnostics
are needed.
- Applies consistent compact output to assets, instances, styles, design
tokens, CLI schemas, and project-session metadata.
- Returns actionable expression warnings for props, resources, and
Collection bindings, including unknown variables and risky render-time
mutation resources.
- Improves Collection expression guidance so agents can bind array items
with the correct scoped variables.
- Reports rendered audit outcomes explicitly as complete, partial,
confirmation-required, or failed.
- Expands runtime output schemas so MCP clients can validate responses
reliably.
- Strengthens the packaged CLI smoke workflow with a realistic
seven-page stdio MCP scenario.

## Architecture

- Consolidates `project-build` from 65 file-oriented entrypoints to 11
architecture-owned surfaces.
- Separates the core model, contracts, runtime authoring, transfer,
state, project sessions, MCP, visual tooling, persistence codecs, and
authenticated server services.
- Isolates Node-only JSX evaluation from browser-safe transfer utilities
and authenticated server modules.
- Keeps persistence codecs independent from authenticated database
services, preventing unrelated module initialization.
- Defines shared instance-path types once and reuses them across runtime
modules.
- Preserves Immer initialization through explicit package side-effect
metadata.
- Adds package tests that prevent a return to source-file entrypoints or
generic exposure of Node-only surfaces.

## Validation

- Full repository checks, tests, typechecks, generated-file checks, and
fixtures
- All 163 Builder test files and 2,141 tests
- All 71 project-build test files and 1,794 tests
- Lint and package-boundary validation
- Full packed CLI release smoke test, including install, preview, agent
setup, seven-page stdio MCP workflow, rendered audit, and structured
commands
2026-07-15 18:11:28 +02:00
Oleg IsonenandClaude Fable 5 071a4d9a85 feat: MCP update 3 (#5864)
## Summary

This update adds new MCP and CLI capabilities for project auditing,
structured data, project-specific agent instructions, focused project
search, safer bulk editing, image descriptions, font discovery, visual
verification, and external registry inspection.

## New Capabilities

### Audit projects

- Run a single `audit` command across accessibility, SEO, security,
assets, styles, and performance.
- Limit an audit to selected scopes, pages, or severity levels.
- Receive stable findings with locations and suggested fixes.
- Run rendered audits across desktop, mobile, and Builder breakpoint
widths.
- Detect horizontal overflow, broken images, oversized images, eager
below-fold images, render-blocking resources, and legacy font formats.
- Identify unused assets, tokens, CSS variables, local styles, and
breakpoints.
- Identify duplicate token declarations.
- Detect accessibility issues involving names, labels, headings,
landmarks, IDs, keyboard focus, ARIA, iframes, and autoplaying media.
- Detect SEO issues involving titles, descriptions, language, social
images, and structured data.
- Detect unsafe new-tab links and write resources exposed during page
rendering.

### Search an entire project

- Search project text, labels, props, resources, assets, and styles
through `search-project`.
- Find relevant records without downloading and reparsing the full
project snapshot.
- Scope searches to the relevant project-data areas.

### Add validated JSON-LD

- Add structured data with a dedicated JSON-LD component.
- Place JSON-LD inside the page Head Slot.
- Edit JSON in a purpose-built code editor.
- Prevent structurally invalid JSON-LD from being saved.
- Validate Schema.org types, properties, and values.
- Find invalid, missing, unknown, deprecated, or incompatible structured
data through the SEO audit.
- Let agents discover the correct JSON-LD workflow without using page
custom metadata or a generic HTML embed.

### Configure project-specific agent instructions

- Add AI-agent instructions from the new **Agents** section in Project
Settings.
- Synchronize those instructions into a managed root `AGENTS.md`.
- Update or remove the managed file automatically during project sync.
- Protect existing user-owned `AGENTS.md` files from being overwritten.
- Share the instructions with authenticated CLI and MCP agents.
- Keep agent instructions out of publicly readable production bundles.

### Generate and manage image descriptions

- Audit image assets for missing descriptions.
- Let a vision-capable agent inspect each image in its rendered context.
- Save generated descriptions to multiple image assets in one operation.
- Mark images as intentionally decorative.
- Reuse the saved asset description wherever the image is used.
- Re-run the audit to verify that missing-description findings are
resolved.

### Perform bounded bulk replacements

- Replace matching literal text across selected pages with
`replace-text`.
- Replace matching fixed prop text with `replace-prop-text`.
- Replace matching resource names or URLs with `replace-resource-text`.
- Restrict replacements by page, instance, prop, resource, field, match
mode, and maximum change count.
- Leave dynamic expressions unchanged.

### Inspect element ancestry

- Return an element’s direct parent in instance listings.
- Request the complete ancestor chain when inspecting an element.
- Understand tree placement without rebuilding the instance hierarchy
from raw project data.

### Discover available fonts

- List uploaded font families through `list-fonts`.
- Discover available system font stacks.
- Inspect font family, style, weight, format, and associated asset
information before applying typography.

### Inspect external component registries

- Inspect a local or remote shadcn-style registry item.
- Read its description, files, dependencies, targets, and documentation.
- Receive an explicit Webstudio compatibility report.
- Inspect registry metadata without installing or executing external
code.

### Capture generated project routes directly

- Run `webstudio screenshot --path /route` against the configured
project.
- Generate a temporary production-style preview automatically.
- Capture the requested route.
- Stop the temporary preview after capture.
- Avoid manually building and starting a preview for a single
screenshot.

### Assert visual changes

- Add expected text to screenshot comparisons.
- Set maximum pixel mismatch limits.
- Set minimum or maximum changed-region counts.
- Assert whether overall brightness or a color channel moved in the
expected direction.
- Use these assertions as pass/fail evidence for visual changes.

### Require compatible CLI versions

- Send the project-bundle contract version with CLI synchronization
requests.
- Stop incompatible CLI versions before they receive incomplete project
data.
- Tell users exactly how to update the CLI or run the latest version
once.
- Prevent older clients from silently dropping project settings.

## Upgrade Note

This branch introduces a new synchronized project-bundle contract. Older
CLI versions must update before synchronizing against the new API.

```sh
npm install -g webstudio@latest
```

Or run the latest version once:

```sh
npx webstudio@latest <command>
```

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-12 11:27:58 +02:00
Oleg IsonenandClaude Fable 5 de23e2a888 chore: migrate toolchain to oxc (oxfmt, oxlint, rolldown-vite) and typeScript 7 (#5868)
## prettier -> oxfmt (0.58.0)

- .oxfmtrc.json generated with `oxfmt --migrate=prettier`: trailingComma
es5, printWidth 80 (oxfmt defaults to 100), sortPackageJson disabled,
.prettierignore patterns folded in (file deleted).
- ignorePatterns additionally exclude yml/yaml/toml/jsonc and
packages/cli/templates/** so oxfmt covers exactly the file set prettier
used to format (ts,tsx,js,json,css,md) and never touches user-facing
scaffolding artifacts.
- root `format` script, nano-staged pre-commit hook and the CI check
(`pnpm oxfmt --check`, replacing `prettier --cache --check` and its
actions/cache step — oxfmt checks the whole repo in ~0.7s) now run
oxfmt.
- every generator script that ran `prettier --write` on __generated__
output now runs `oxfmt` (css-data, icons, html-data, postgrest, sdk,
sdk-components-*, apps/builder tailwind preflight).
- the four scripts that used prettier's JS `format()` API write raw
source instead and their package.json scripts pipe the generated file
through the oxfmt CLI: project-build generate-docs +
generate-runtime-operation-contracts, cli generate-docs, apps/builder
generate-server-only-api-metadata. oxfmt rejects paths containing "..",
so cross-package generated files are formatted via a subshell cd into
the owning package.
- one-time reformat: oxfmt's canonical output differs from prettier on 8
repo source files (binary-operator continuation indent, import() call
wrapping, sub-pixel spacing of empty for-clauses); oxfmt honors existing
`// prettier-ignore` comments so intentional layouts are kept.
- prettier remains ONLY as a cli devDependency for the
prettier/standalone HTML normalizer inside html-to-jsx.test.ts, and
inside fixtures/ + packages/cli/templates/ (ships to scaffolded user
projects; out of scope here).
- editor config switched from esbenp.prettier-vscode to oxc.oxc-vscode
(devcontainer extension list, .vscode editor.defaultFormatter).

## oxlint 1.56 -> 1.73

- oxlint 1.73 rules-of-hooks special-cases hooks NAMED useEffectEvent:
their results may only be called from effects. Our
app/shared/hook-utils/effect-event.ts is a stable-callback helper
(useEvent pattern), intentionally called from event handlers and passed
as props. The rule is disabled via .oxlintrc.json overrides for the five
files doing this (product code untouched); note those files lose
hook-order linting entirely until the rule becomes configurable.

## TypeScript 5.8.2 -> 7.0.2 (native compiler)

- `tsc` is now the Go-based native binary; all `tsgo` script usages
(workspace packages and fixtures) renamed back to `tsc` and
@typescript/native-preview removed (the package is being phased out).
- fixes for TS7 changed defaults and stricter checks:
- `types` now defaults to [] -> base tsconfig sets "types": ["node"]
(restores the implicit-@types/node behavior of TS5).
- `rootDir` now defaults to ./ -> every tsconfig.dts.json sets
"rootDir": "./src" (TS5011 otherwise).
- import assertions removed -> cli/src/cli.ts uses `with { type: "json"
}` (TS2880).
- stricter isolatedDeclarations inference -> explicit annotations in
css-data bin/property-filter.ts (TS9010) and image image-dev.stories.tsx
(TS9013).
- declaration serialization limit -> project-build builder-runtime.ts
runtimeOperationContracts gets an explicit type (TS7056); the annotation
preserves the narrow RuntimeOperationId union.
- TS7 ships no stable programmatic API:
- react-sdk (component-generator tests drive the compiler API) aliases
its typescript devDependency to @typescript/typescript6@^6.0.2; its bin
is `tsc6`, so the package's typecheck still runs native TS7 tsc from the
workspace root.
- generate-arg-types keeps typescript 5.8.2 for react-docgen-typescript.
- fixtures/ and packages/cli/templates/ keep typescript 5.8.2
(user-facing); fixture scripts still work because plain `tsc` resolves
to their local dependency.

## vite -> rolldown-vite 7.3.1 (oxc bundler)

- global pnpm override `"vite": "npm:rolldown-vite@^7.3.1"`: the builder
app (remix v2 vite plugin works unmodified), every package vite build
and the storybook build now bundle on rolldown/oxc.
- vitest is scoped BACK to vanilla vite via `vitest>vite`,
`vite-node>vite` and `@vitest/mocker>vite` overrides because vitest
3.1's runner does not understand rolldown's SSR transform
(__vite_ssr_exportName__ ReferenceError in every suite).
- those overrides pin vite EXACTLY to 6.3.4: letting ^6.3.4 float to
6.4.3 breaks cli prebuild tests (dynamic import of a generated
app/routes/$.tsx fails to resolve under 6.4.3's loader).

## unrelated cleanup requested during review

- apps/builder commands.ts imports duplicate-tokens-group statically
instead of via dynamic import. The circular dependency the dynamic
import guarded against only exists through the command-panel barrel
(command-panel.tsx > groups/index.ts > commands-group.tsx >
commands.ts); importing the group module directly is cycle-free
(verified with madge), matching the neighboring wrap-group and
convert-group imports.

## verification

- pnpm lint, oxfmt --check: clean.
- pnpm -r typecheck (TS7 native) and pnpm dts: clean.
- pnpm -r test: all suites pass (builder 2093 tests, cli 630, react-sdk
45, project-build 11, ...).
- builder app build, full workspace build, cli build and storybook build
all succeed on rolldown-vite.

## 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

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-12 01:03:36 +02:00
Oleg Isonen d291e4b671 feat: Builder api runtime contracts guardrails for MCP (#5857)
This PR expands Webstudio MCP and CLI into a more complete agent
authoring interface. Agents can discover project capabilities, edit real
Webstudio content, use data/resources, verify visual output, and report
useful issues when workflows fail.

## MCP User Capabilities

- Create, update, duplicate, reorder, and delete pages.
- Create pages from templates and manage reusable page templates.
- Inspect project pages, instances, props, styles, assets, variables,
resources, and metadata.
- Insert Webstudio components and authored JSX fragments into pages.
- Edit text, props, styles, breakpoints, design tokens, and CSS
variables.
- Update page metadata, SEO fields, redirects, marketplace metadata, and
project settings.
- Create and use static data variables.
- Create and use dynamic resources fetched over HTTP.
- Use REST, GraphQL, and built-in system resources in authored pages.
- Bind data variables and resources to visible page content.
- Create resource-backed pages such as sitemap XML, structured SEO data,
and API-driven content sections.
- Preview current project state without requiring a publish step.
- Capture screenshots for visual verification.
- Verify responsive designs across desktop, tablet, and mobile
breakpoints.
- Use screenshot diff and OCR-style checks to inspect rendered output.
- Reset and refresh local MCP project state when needed.
- Discover available CLI/MCP commands from generated manuals.
- Use clearer examples for resources, data variables, JSX authoring,
previewing, and visual checks.
- Read marketplace product metadata without requiring a full project
snapshot.
- Get safer guidance when using low-level patch tools.
- Get a ready-to-copy Discord report template when MCP/CLI behavior is
confusing or broken.
2026-07-10 02:13:22 +02:00
Oleg Isonen 1ddf6b02c9 feat: API and CLI for everything (#5838)
Closes #5287
2026-07-01 01:20:50 +02:00
Oleg Isonen 82c3d83fd1 fix: optimize CLI import for large data amount (#5831)
## 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.
2026-06-23 18:50:01 +02:00
Oleg Isonen e7b7faeca5 fix: performance optimizations (#5827) 2026-06-19 12:23:44 +02:00
Oleg Isonen 8764b57a49 fix: prevent data variable creation crash (#5815) 2026-06-13 12:22:25 +02:00
Oleg Isonen d49582bcf5 feat: Copy-paste pages, folders and page templates (#5798)
Closes https://github.com/webstudio-is/webstudio/issues/5797
## Summary

- Add page, page template, and folder copy/paste support, including
cross-project paste.
- Reuse a shared page item actions menu for page headers and context
menus with Copy, Duplicate, Delete, and shortcut hints.
- Add Paste to the pages context menu.
- Preserve template semantics when copying/pasting templates.
- Support folder copy with nested folders/pages.
- Add Backspace/Delete page deletion shortcuts and focus destructive
dialog actions for Enter confirmation.
- Rename `init-copy-paste.ts` to `copy-paste.ts`.

## Testing

- `pnpm --filter @webstudio-is/builder typecheck`
- `pnpm --filter @webstudio-is/builder test
app/shared/copy-paste/copy-paste.test.ts
app/shared/copy-paste/plugin-page.test.ts app/shared/page-utils.test.tsx
app/builder/features/pages/page-utils.test.ts`
- `git diff --check`
- E2E copy/delete flows were added in
`apps/builder/e2e/tests/pages-actions.e2e.ts`
2026-06-09 15:10:52 +02:00
Oleg Isonen 392c9089be fix: content mode permissions (#5795)
**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`
2026-06-09 01:48:23 +02:00
Oleg Isonen cc26648519 fix: Fix page template editor permissions (#5793)
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.
2026-06-04 22:34:56 +02:00
Oleg Isonen 833db3ad2e fix: Allow editor links to save content block edits (#5754) 2026-05-10 20:26:55 +02:00
Oleg Isonen 9c2116ade2 fix: Use project owner plan limits when project is shared via workspace (#5751) 2026-05-09 13:12:47 +02:00
Oleg Isonen 6b09e91324 build: Release 29 04 26.staging (#5742) 2026-04-29 19:31:17 +02:00
Oleg Isonen 9ea5f70a73 chore: Pages.staging (#5736)
## 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
2026-04-28 19:43:21 +02:00
Oleg Isonen a2cfcbb7be feat: WIP Multiplayer (#5733) 2026-04-28 03:38:12 +02:00
Oleg Isonen b006947a85 feat: WIP realtime collaboration to builder (#5726)
https://github.com/webstudio-is/webstudio/issues/46
2026-04-27 23:19:21 +02:00
Oleg Isonen 70a1a5d6be chore: show over-capacity warning when members exceed paid seats (#5708) 2026-04-20 00:11:44 +02:00
Oleg Isonen d8157f3cb6 chore: seats management (#5707) 2026-04-19 12:35:47 +02:00
Oleg Isonen 09c89376fb chore: fix workspaces seats counter (#5693) 2026-04-13 20:49:13 +02:00
Oleg Isonen 4748fa5f1e fix: restore short --variable label in CSS value input (#5694)
## Problem

Commit cc20991b accidentally changed `itemToString` for `var` type
values to use `toValue(item)`, which produces `var(--variable,
fallback)` instead of the intended short `--variable` label.

This meant the CSS value input (when unfocused, and in the autocomplete
dropdown) showed the full `var(--variable, fallback)` string, which is
too long for small inputs and not how it previously displayed.

## Fix

- Restored `itemToString` to return `--${item.value}` for var types
(short label)
- Updated the `onFocus` handler to explicitly call `toValue(value)` for
var types, so the full `var(--variable, fallback)` is shown when the
user focuses the input to edit it
2026-04-13 20:07:14 +02:00
Oleg Isonen ce3c82b582 chore: Decouple plans from the builder as much as possible (#5687) 2026-04-12 14:53:23 +02:00
Oleg Isonen 8b5fa7ef15 chore: msw testing helpers (#5683)
## 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
2026-04-10 19:11:27 +02:00
Oleg Isonen 90f92c58d3 feat: workspace seat billing at invite time, persist pending invites (#5680)
- Add minSeats/maxSeats to PlanFeatures schema
- listMembers returns DB-backed pending invites (no more client-side
state)
- countAllMembers includes pending invites (billed at invite time, Figma
model)
- Builder-level workspace-router calls payment worker on
addMember/removeMember
- Removed client-side invitedEmails state from manage-members-dialog
- getSeatSuspendedMessage now accepts optional workspace name
- notification-router simplified (accept no longer syncs seats)

## 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
2026-04-09 02:07:53 +02:00
Oleg Isonen b8a194c011 feat: Workspaces (#5641) 2026-04-08 21:58:20 +02:00
Oleg Isonen 348d049ed2 fix: add authorization checks (#5622)
closes https://github.com/webstudio-is/webstudio/issues/5621

to publishedBuilds and findManyByIds en…dpoints

- Add getProjectPermit check to publishedBuilds endpoint to verify user
has access
- Add userId filtering to findManyByIds to only return user's own
projects or approved marketplace templates
- Maintain belt-and-suspenders approach with both authType check and
permit verification

## 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
2026-02-21 03:18:56 +01:00
Oleg Isonen 4f27152c38 feat: Unpublish (#5579)
## 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
2026-01-22 10:17:42 +01:00
Oleg Isonen fdee339de0 chore: Migrate to tsgo (#5578) 2026-01-20 17:25:12 +01:00
Oleg Isonen f63b5cae8d feat: Resizable left-side panels like navigator (#5503)
## 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
2025-12-11 19:06:58 +01:00
Bogdan Chadkin 02ca084a0c refactor: upgrade to csstree v3 (#5455)
The new version is aware of modern colors and other new css features.
2025-11-23 14:32:12 +03:00
Bogdan ChadkinandOleg Isonen 801181c8b6 feat: add project tags in dashboard (#5399)
Ref https://github.com/webstudio-is/webstudio/issues/860





https://github.com/user-attachments/assets/a85b525a-d43b-4361-aa5f-f2158b3c0211

---------

Co-authored-by: Oleg Isonen <oleg008@gmail.com>
2025-11-07 11:33:05 +01:00
Bogdan ChadkinandOleg Isonen 5632a40940 feat: allow restore from published backup (#5320)
Ref https://github.com/webstudio-is/webstudio/issues/5276

---------

Co-authored-by: Oleg Isonen <oleg008@gmail.com>
2025-07-11 19:05:31 +02:00
Bogdan Chadkin 395a6b9e72 refactor: move embed template into ai (#5148)
To not bloat cli and remove embed template together with legacy ai
eventually.
2025-04-21 12:47:51 +07:00
Bogdan Chadkin 5b3144d656 refactor: bump zod (#5035)
All three have minor feature updates

- zod
- zod-validation-error
- zod-to-json-schema
2025-03-25 00:17:05 +07:00
Bogdan Chadkin 5c3a6e5fcd refactor: restrict publish count per account (#5030) 2025-03-22 19:29:22 +07:00
Bogdan Chadkin dd08852d43 build: upgrade typescript (#4991)
Upgraded to 5.8 and bumped all type definitions.
Enabled erasable syntax only flag and got rid from one case in
expression editor.
2025-03-13 11:21:00 +07:00
Bogdan Chadkin 5acb458a68 build: upgrade dev dependencies (#4764)
Nothing critical, all not related to production

storybook 8.5
eslint 9.18
vitest 3
typescript 5.7.3
@types/node 22.10.7
type-fest 4.32
2025-01-21 00:14:56 +07:00
Bogdan Chadkin 4f026a0acf refactor: bump CLI dependencies (#4728)
All minor

- https://github.com/bombshell-dev/clack/releases - configurable key
bindings
- https://github.com/sindresorhus/p-limit/releases/tag/v5.0.0 - node
bump
- https://github.com/sindresorhus/p-limit/releases/tag/v6.0.0 - better
scheduling
- https://github.com/inikulin/parse5/releases/tag/v7.2.0 - search
element support
- https://github.com/ai/nanoid/releases/tag/5.0.9 - security fix
- https://github.com/alexeyraspopov/picocolors/releases/tag/v1.1.1 -
bundlers support
2025-01-07 16:32:42 +07:00
Bogdan Chadkin 425788f545 build: upgrade dev dependencies (#4658)
- storybook
- eslint
- types/node
- type-fest
- esbuild
2024-12-27 02:11:48 +07:00