206 Commits
Author SHA1 Message Date
ff4a081f80 fix: export text pages in static builds (#6513)
Fixes #6440

## Description

Static exports currently omit Text pages such as `/robots.txt`,
`/ads.txt`, and `/.well-known/security.txt`. This generates their
routes, evaluates content through the existing page-data loader, and
uses Vike's native `pageContext.content` to write the exact text at the
configured file path.

Internal route directories are separate from public URLs so dot-prefixed
paths work. No generated writer script, text-page manifest, HTML
wrapper, or post-build file rewrite is needed.

## Dependencies

- Pin Vike to `0.4.267-commit-feffb0f`: native non-HTML output is
published in this commit prerelease but is not yet in stable `0.4.267`.
- Use Vite `7.1.12` and the compatible React plugin for SSG. Build
through `vike build && vike prerender` so Vike uses its matching Vite
dependency.
- Update React Router's `vite-node` dependency to `3.2.4` for
compatibility with the CLI's Vite 7 test environment.

## Validation

- All 1,173 CLI tests pass locally across 72 files, including all 79
prebuild tests for normal HTML, dynamic SSG routes, and React Router
builds.
- Text export coverage checks exact output for `/robots.txt`,
resource-backed `/.well-known/security.txt`, empty text, Unicode, and
HTML-like content.
- CLI and SSG fixture type checks, lint, and formatting pass locally.
- SSG fixtures regenerated; the packaged SSG test passes locally.
- All executed GitHub CI checks pass at
`201fa971616bb607ca35ee24a970f107eddee754`, including all six browser
shards. Shard 4 passed on retry after an MDX template rename timeout.
Visual regression is skipped and preview deployment remains gated.
- Corrected the existing animation navigation test for fork CI: wait for
the rendered component with the public fallback and retain the animation
initialization assertion when the private module is present.

## Manual verification

1. Export a static project with Text pages at `/robots.txt` and
`/.well-known/security.txt`.
2. Run the generated project's build.
3. Confirm both files under `dist/client` contain exactly the configured
text, including resource expressions.
4. Confirm normal pages still render HTML.

- [ ] Original author tested the updated export and confirmed it works.
- [ ] Preview tested (deployment approval remains gated).

---------

Co-authored-by: Sviat Barbutsa <9897782+sviat-barbutsa@users.noreply.github.com>
Co-authored-by: Oleg Isonen <oleg008@gmail.com>
2026-10-12 11:41:04 +02:00
Oleg Isonen 2c51bc9928 fix: Restore Cloudflare publishing with Wrangler 4 (#6350)
Publishing fails because Wrangler 3 cannot parse the JSON import
attributes used by `html-tags@4`. Upgrade the CLI and Cloudflare
template to Wrangler 4.130.0 and regenerate the fixture and lockfile
used to package the publish artifact.

Wrangler 4 also rejects Worker deployment when it finds the Pages
configuration. Add a SaaS-only `wrangler.jsonc` that takes precedence
over the Pages template's TOML configuration. Publish commands still
supply the Worker name and compatibility date. Fix the staging smoke
check's compatibility-date scope and shell expansion.

- [x] Upgrade Wrangler and regenerate the publish fixture and lockfile.
- [x] Reproduce the original parser failure and verify it passes with
Wrangler 4.
- [x] Build the packaged artifact and pass the staging smoke check and
both SaaS publish dry runs, including dispatch-namespace arguments.
- [x] Pass 383 existing template tests, CLI and fixture typechecks,
repository lint, and all fixture generation from checked-in data.
- [x] Review documentation impact: no user-facing documentation changes
are required; the existing Node 22.12+ requirement remains sufficient.
- [ ] Complete staging CI and manually test publishing.

[Publish artifact
build](https://github.com/webstudio-is/webstudio/actions/runs/34400149252)
is running; [staging
deployment](https://github.com/webstudio-is/webstudio/actions/runs/34400149301)
is queued. Remix 2 still declares a Wrangler 3 peer dependency; the
packaged production build and both publish dry runs passed with v4.
Agent evaluations were not run.
2026-09-09 22:28:38 +02:00
Oleg Isonen 75840a119c fix: Start previews and diagnose runtime failures (#6321)
## Summary

Preview startup now binds loopback directly instead of scanning network
interfaces first. MCP no longer exposes or accepts a fixed preview host
or port: the CLI asks the operating system for an available loopback
port and returns the resulting URL.

The CLI also returns safe, structured diagnostics when the runtime
blocks preview networking or Chromium IPC, when generated IDs collide,
and when a listening preview fails its HTTP readiness probe. Preview
startup retries only a genuine automatic-port race; HTTP and connection
failures return immediately instead of repeating the full startup
timeout five times.

## Issue checklist

- [x] #6318 — reproduced the `uv_interface_addresses` failure, replaced
interface discovery with a direct TCP bind, and added a regression test
for the exact failure.
- [x] #6319 — reproduced Chromium aborting before DevTools startup when
the managed runtime blocks browser IPC/socket operations. The host
restriction cannot be bypassed by the CLI, but future reports now
include a safe `browser_ipc_permission_denied` issue without raw stderr,
paths, or tokens.
- [x] #6320 — ran four reported insert variants sequentially across two
pages; all generated unique IDs. Future collision errors now include the
affected namespace and insertion stage without exposing the generated
ID.
- [x] #6324 — reproduced the generic readiness timeout with a real
generated preview whose root probe returned HTTP 500 after the server
printed its Local URL. The MCP contract and documentation also allowed
agents to force a busy port; network binding is now runner-owned.
- [x] #6325 — confirmed the responsive screenshot uses the same
readiness path. Future reports distinguish HTTP, refused-connection,
timeout, and permission failures, non-port failures are no longer
retried, and screenshots cannot request a fixed preview port.
- [x] Documentation impact reviewed. Updated MCP examples and vision
guidance to omit runner-owned host and port fields.

## Technical notes

- Removes the CLI's direct `get-port` dependency. That package calls
`os.networkInterfaces()` even when a host is supplied.
- Binds `{ host: "127.0.0.1", port: 0 }`, reads the assigned TCP port,
then closes the temporary server.
- Removes `host` and `port` from MCP preview and screenshot input
schemas and rejects those fields at runtime.
- Returns the selected preview URL from `preview.start`; managed
screenshots reuse that active target.
- Returns `PREVIEW_NETWORK_RESTRICTED` with a stable
`network_permission_denied` issue when the OS rejects loopback binding.
- Reads at most the last 4 KB of Chromium startup stderr, maps only the
reproduced IPC/socket denial to a safe diagnostic, and discards the
buffer after startup.
- Preserves browser startup issues through CLI browser fallback
aggregation and the MCP screenshot error boundary.
- Reports generated record collisions with `generated_id_conflict`, the
namespace constraint, and the fragment insertion stage.
- Preserves structured readiness diagnostics when preview output is
appended.
- Reports HTTP 5xx and local connection failures without exposing raw
fetch errors.
- Retries with a newly allocated port only for `EADDRINUSE` /
`PREVIEW_PORT_IN_USE`.

## Verification

- [x] New regression tests were shown to fail before implementation and
pass afterward.
- [x] Reproduced the old generic timeout through the real preview
controller; after the fix, the same path returned `PREVIEW_HTTP_ERROR`
with `http_status:500`.
- [x] Verified MCP advertised and accepted fixed host/port fields before
the change, then rejected both fields after the change.
- [x] Preview readiness/controller tests: 2 files, 29 tests passed.
- [x] Vision tests: 13 files, 81 tests passed.
- [x] Project-build tests: 88 files, 2,282 tests passed.
- [x] CLI tests: 66 files, 1,038 tests passed.
- [x] Vision, project-build, and CLI typechecks passed.
- [x] Lint passed with warnings denied.
- [x] Package-boundary and MCP documentation checks passed.
- [x] Fixture impact reviewed; no fixture inputs or generated fixture
outputs are affected. Generated documentation was updated; the generated
runtime operation contract did not change.

Agent evaluations were not run because they require separate approval.

Closes #6318

Ref #6319

Ref #6320

Ref #6324

Ref #6325
2026-09-03 16:34:20 +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 bc8630f413 fix: Gate Builder releases on the published CLI contract (#6282)
Closes #6280

## Summary

- Expose the deployed Builder's CLI-facing bundle contract through a
non-cached, read-only endpoint.
- Resolve and execute the exact `webstudio@latest` registry artifact,
observe the bundle version sent by its real `sync` request, and require
an exact match before assigning the release staging alias.
- Include expected and received bundle versions in runtime and
release-gate errors.

## Technical choices

- The existing generated `bundleVersion` remains the single
compatibility boundary. Builder-only changes outside that project-bundle
contract do not require a CLI release.
- The CLI sync probe runs against a local fixture API and temporary
directory. It reads the deployed runtime contract but never reads or
modifies a Cloud project.
- Verification runs after Vercel creates the exact production-built
deployment and before the release staging alias is assigned. A mismatch
therefore leaves production domains untouched.
- Registry resolution requires version and integrity metadata, then
executes the resolved immutable version rather than source from the
checkout.
- The gate requires the deployed Builder origin and cannot fall back to
the checkout's contract.

## Todo

1. [x] Add the deployed Builder contract endpoint.
2. [x] Probe the exact published CLI through its real sync request.
3. [x] Gate the release staging alias on an exact contract match.
4. [x] Report expected and received versions for compatibility failures.
5. [x] Add regression tests and verify the production Builder build.
6. [x] Review documentation and fixture impact.

## Verification

- `pnpm --filter @webstudio-is/builder exec vitest run
app/services/build-router.server.test.ts
app/services/cli-compatibility-route.node.test.ts` — 12 passed.
- `pnpm --filter webstudio exec vitest run
scripts/builder-contract-gate.test.ts
scripts/release-smoke-registry.test.ts` — 7 passed.
- Rebased onto `main` at `9ec4c820e1`.
- Builder and CLI typechecks passed.
- `pnpm lint` and changed-file formatting passed.
- `pnpm --filter @webstudio-is/builder build` passed and emitted
`/rest/cli-compatibility`.
- The changed GitHub Action parses as valid YAML.
- Real registry probe passed for `webstudio@0.293.0` against
`bundle-kzb45v`.
- Real registry probe correctly blocked current Builder contract
`bundle-1mym82p` and reported expected `bundle-1mym82p`, received
`bundle-kzb45v`.
- Missing staged Builder origin fails closed before registry execution.
- GitHub CI passed all four workflows, including all six Builder E2E
shards.
- The formerly failing empty-MDX insertion workflow passed 8 repeated
runs with 4 workers locally, then passed in Builder E2E shard 4 in CI.
- Full browser-based release smoke was not run, per the request not to
use Chrome. Agent evaluations were not run because no evaluation
approval was requested or received.
- Documentation: no user-facing documentation changes are required.
- Fixtures/generated outputs: no fixture inputs or generated outputs are
affected.

## Operational boundary

The check needs the exact deployed runtime, so Vercel creates an
unaliased `--skip-domain` deployment before verification. A failed check
cannot affect production domains or the normal release alias. Repository
automation cannot prevent a Vercel administrator from manually promoting
an arbitrary deployment outside this release path.
2026-08-31 20:43:52 +02:00
Oleg Isonen f9681dc30f feat: MDX-backed Content Blocks (#6234)
## Summary

Supersede #6182 with a clean implementation of MDX-backed Content Blocks
on top of the unchanged `main` Content Block editing model. A connected
`.mdx` Asset changes where authored children are loaded and saved; it
must not change how Content mode inserts, edits, selects, moves, copies,
or deletes instances.

The previous implementation remains available in
`agent/mdx-content-block-6124` and
`agent/mdx-content-block-6124-review`. Reuse its independently tested
parsers, converters, schemas, Asset repository, template resolution,
publication, MCP, and UI work where those pieces fit the corrected
architecture. Do not port its per-operation storage routing, projected
editing stores, MDX undo/history, or atomic multi-root machinery.

Ref #6124
Ref #6182
Closes #6261

## Locked behavior

- `.md` keeps its existing Markdown behavior; `.mdx` enables MDX.
- Standard Markdown structures are stored as Markdown. JSX is used only
for structures Markdown cannot represent losslessly.
- Generic elements use `<ws.element ws:tag="…">`; template instances use
`<ws.element ws:name="…">`.
- Invalid, unsafe, or unsupported MDX never prevents editing the file or
publishing the project. Builder and publication use the same recovery
result: recoverable nodes are skipped with source-located warnings,
while an unrecoverable document renders no authored file content in
either environment.
- Connecting a source never serializes existing Content Block children
into the file. **Connect** removes ordinary persisted children,
preserves Templates, sets `src`, and uses file content.
- Disconnecting resets `src`, discards derived instances, leaves the
Content Block empty, and never changes the Asset.
- While connected, normal Content Block mutations update in-memory
instances synchronously. Asset persistence happens afterward and never
blocks rendering.
- Genuine external revision conflicts use the standard reload-required
flow. Rapid local edits are ordered/coalesced and must never conflict
with each other.
- Repeated scopes use Content Block ID plus Collection item identity.
- Multiple Content Blocks may intentionally share one MDX Asset. They
share one revisioned document session and edits propagate to every
connected occurrence.
- Missing templates show warnings/placeholders only in Builder and are
skipped on published sites.

## Reuse strategy

- [x] Audit all 62 original implementation commits and 5 later
review/fix commits
- [x] Reuse the shared Content Engine Markdown/MDX AST, parser,
serializer, diagnostics, reference discovery, and tests
- [x] Reuse SDK source schemas, instance-name utilities, unique template
naming, and source-integrity validation
- [x] Reuse template resolution/materialization and authored-tree
conversion after removing storage-operation coupling
- [x] Reuse revisioned Asset content repository, authorization, limits,
and browser/server transport
- [x] Reuse publication, document-graph, CLI, MCP, source-control UI,
frontmatter UI, and E2E work where contracts remain valid
- [x] Reuse tests as behavioral specifications; rewrite tests that
assert the rejected projection/routing architecture
- [x] Do not port per-operation MDX routing, alternate projected
mutation stores, semantic reconciliation after each command, MDX Builder
history/undo, atomic multi-file rollback, or canvas loading/saving UI


## Old-branch porting map — do not rewrite

Before implementing any checklist batch, inspect the named
implementation and tests on `agent/mdx-content-block-6124-review`. Move
the implementation and its tests first; change only the boundary that
conflicts with the rebuilt architecture. Do not create a second
implementation under a new name. When a test encodes the rejected
projected-store architecture, retain its behavioral assertion and
replace only its setup.

### Already ported

- `parseMarkdownAst`, `createMdxDocumentFromMarkdown`,
`parseMdxDocument`, `serializeMdxDocument`, `preferMarkdownSyntax`,
`discoverMdxBodyAssetReferences`, `discoverMdxAssetReferences`, and
`previewMarkdownToMdxConversion`
- Asset-reference, byte-stream, document-graph, Markdown, and MDX
helpers included in commit `76bc388ba9`
- Tests: the corresponding `packages/content-engine/src/**/*.test.ts`
files already on this branch

### Port with their existing tests

| Area | Functions to move or adapt | Tests to move with them |
| --- | --- | --- |
| Source contract and integrity | `parseContentBlockSourceProp`,
`getContentBlockSource`, `isEqualContentBlockSource`,
`formatContentBlockSourceIntegrityIssue`,
`getContentBlockSourceIntegrityIssues`,
`allocateUniqueContentBlockTemplateName` |
`packages/sdk/src/content-block.test.ts`,
`packages/sdk/src/schema/content-block.test.ts` |
| Existing instance/name utilities | `findChildReferenceIndex`,
`findParentInstanceReference`, `getInstanceName` |
`packages/sdk/src/instances-utils.test.tsx` |
| Template naming in mutations |
`assignUniqueBlockTemplateNamesMutable`,
`findBlockTemplateNameCollision`, `getSourceBackedBlockTemplateContext`,
`getBlockTemplateNameConfirmation`, `getBlockTemplateInsertionIndex` |
`packages/project-build/src/runtime/block.test.ts` |
| Content-mode property permissions | `getContentModePropEligibility`;
preserve its distinction between editable, design-only, incompatible,
and unknown props |
`packages/project-build/src/runtime/content-mode-permissions.test.ts` |
| Template resolution | `resolveMdxTemplates` |
`packages/project-build/src/runtime/mdx-template-resolution.test.ts` |
| Template materialization | `createMdxScopeIdGenerator`,
`materializeMdxTemplates` |
`packages/project-build/src/runtime/mdx-materialization.test.ts` |
| MDX → instances and instances → MDX |
`isMaterializedMdxAuthoredContentRoot`, `preserveMdxAuthoredContentIds`,
`materializeMdxAuthoredContent`, `reconcileMdxAuthoredContent`,
`omitTransientEmptyParagraphs`, `serializeMdxTemplateInsertion` |
`packages/project-build/src/runtime/mdx-authored-content.test.ts`;
retain the pure serialization cases from `mdx-storage-adapter.test.ts` |
| Revisioned Asset I/O | `createAssetContentRevision`,
`readAssetContentBytes`, the package-owned
`createHttpAssetContentRepository`, the thin Builder
`createBuilderHttpAssetContentRepository`, `createAssetContentBridge`,
`initAssetContentBridge`, `getAssetContentBridge`; keep one repository
implementation rather than copying the old Builder duplicate |
`packages/asset-uploader/src/content-repository.test.ts`,
`apps/builder/app/builder/shared/assets/mdx-content-repository.test.ts`,
`apps/builder/app/shared/asset-content-bridge.client.test.ts` |
| Source lifecycle planning | `createContentBlockBodyRemoval`,
`prepareContentBlockConnect`, `prepareContentBlockDisconnect`,
`prepareContentBlockSwitch`, `ContentBlockSourceRevisionConflictError` |
`packages/project-build/src/runtime/content-block-source-lifecycle.test.ts`
|
| Per-Asset revision/session behavior | `getContentBlockSessionSource`,
`isContentBlockSessionSourceCommitted`; reuse the loading,
authorization, revision, queue, conflict, retry, cancellation, and
source-replacement internals of `createMdxAssetEditingSession`, but key
the rebuilt session by Asset rather than Content Block/render root |
Port the applicable cases from
`packages/project-build/src/runtime/mdx-asset-session.test.ts`; replace
root-projection setup with in-memory snapshot setup |
| Template migrations | `validateMdxTemplateMigrationConfirmation`,
`planMdxTemplateMigration` |
`packages/project-build/src/runtime/mdx-template-migration.test.ts` |
| Publication | `createPublishedMdxMaterializationCache`,
`materializePublishedMdx`, `getPublishedMdxContentDatabaseMaxBytes`,
`getDynamicPublishedMdxSourceBlockIds`, `hasDynamicPublishedMdxSources`,
`createPublishedBuildContentCompilationPlan`,
`resolvePublishedMdxDependencyClosure`,
`resolvePublishedMdxAssetCandidates` |
`packages/project-build/src/runtime/published-mdx.test.ts`,
`packages/project-build/src/content-database.test.ts` |
| Build/import integrity | `assertContentBlockSourceIntegrity` and the
Content Block cases in
`getBuildIntegrityIssues`/`formatBuildIntegrityIssue` |
`packages/project-build/src/build-integrity.test.ts` |
| MDX paste/MCP insertion | `insertMdxText` and its input/result
schemas; retain parsing, confirmation, template-resolution, and
insertion-index logic, then invoke the normal mutation path |
`packages/project-build/src/runtime/mdx-paste.test.ts` |
| Builder source control | `createContentBlockSourceController`,
`createBuilderContentBlockSourceController` and the existing
source-control components | `content-block-source-controller.test.ts`,
`content-block-source.test.tsx` |
| Diagnostics | `formatContentBlockDiagnostic`,
`deduplicateContentBlockDiagnostics`, `takeNewContentBlockDiagnostics` |
Port only their focused cases from
`apps/builder/app/shared/content-block-content.test.ts` |

### Explicitly do not port

- `projectContentStorageChanges`, `createContentStorageProjection`,
`createContentStorageSelectorProjection`,
`executeContentStorageMutation`, `executeContentStorageTextReplacement`,
`executeContentStoragePropMutation`, and
`executeContentStorageStructuralMutation`
- `applyMdxContentStorageChanges` and `prepareMdxContentStorageWrites`;
replace them with one post-mutation snapshot serializer built from the
reusable pure `reconcileMdxAuthoredContent` converter
- `createContentBlockApplicationOperations` and the persistence-plan
wrappers that route individual editing commands
- Builder `$runtime*` projected stores, materialized mutation functions,
alternate selector/tree helpers, pending projected-change state, and
MDX-specific mutation sequences from `content-block-content.ts`
- Canvas loading/saving/open-file presentation state, MDX history/undo,
and atomic rollback machinery

## Implementation checklist

### 1. Preserve the `main` editing architecture

- [x] Keep normal synchronous insert, text, Enter, slash menu, property,
delete, move, wrap, copy/paste, selection, and focus mutations unchanged
- [x] Materialize connected content through the same runtime instance
interfaces used by ordinary Content Blocks
- [x] Keep connected authored children in memory and exclude them from
persisted build data
- [x] Route persistence only after a synchronous mutation has updated
the canvas
- [x] Never wait for Asset loading, conversion, or saving before
rendering an interaction
- [x] Add no MDX-specific implementation to individual editing commands

### 2. Shared Markdown and MDX conversion

- [x] Parse Markdown and the Markdown portion of MDX through one shared
AST and plugin configuration
- [x] Implement one shared MDX-to-instances converter and one shared
instances-to-MDX converter
- [x] Serialize headings, paragraphs, links, images, lists, tables, task
lists, blockquotes, thematic breaks, code, emphasis, strong,
strikethrough, and other supported GFM structures as Markdown
- [x] Serialize only non-lossless/custom structures as Webstudio JSX
- [x] Preserve nested Markdown in MDX elements, frontmatter, comments,
tight/loose list semantics, code whitespace, reference links, and Asset
references
- [x] Omit transient empty draft paragraphs instead of emitting
`<ws.element ws:tag="p" />`
- [x] Preserve unsupported source text and authored metadata whenever it
cannot be converted safely
- [x] Add deterministic round-trip and canonical-output coverage for
every supported Markdown structure

### 3. Invalid and unsafe MDX

- [x] Preserve file source exactly; never silently repair or rewrite
invalid source
- [x] Ignore imports, exports, expressions, executable JavaScript,
invalid properties, and other unsupported nodes when they can be
isolated
- [x] Continue rendering valid siblings and report every skipped subtree
once with filename, line, and column
- [x] Use the same recovery pipeline in Builder and publication so both
render the same authored result for the current file revision
- [x] When structural syntax prevents recovery, render no authored file
content in Builder or publication instead of retaining a stale
materialization
- [x] Skip an unrecoverable Content Block on published sites and
continue the build with a warning
- [x] Keep invalid and unsafe files editable and reconnectable
- [x] Enforce UTF-8, byte-size, depth, node-count, property-count, and
generated-output limits with source-located diagnostics where possible

### 4. File formats and Asset creation

- [x] Keep `.md` parsing and raw-HTML behavior unchanged
- [x] Support creating, opening, editing, deleting, and recreating
`.mdx` files through the normal text-file UI
- [x] Open `.mdx` in the same editor experience as `.md`
- [x] Always create an independent empty MDX Asset even when identical
empty files exist
- [x] Allow renaming `.md` to `.mdx` without converting or rewriting its
contents; after rename, handle invalid contents through the normal MDX
diagnostics and recovery pipeline
- [x] Update an already-open MDX editor immediately after canvas
persistence
- [x] Bound read/write buffering and verify the returned Asset identity
and revision

### 5. Source contracts and lifecycle

- [x] Support direct Asset bindings and dynamic expression bindings
- [x] Keep source mutation controls available only in Design mode; show
the connected filename and **Open** action read-only in Content mode
- [x] Reject duplicate source props, unsupported prop types, missing
Assets, non-MDX Assets, and unauthorized Assets
- [x] Analyze selected file diagnostics before confirmation without
modifying the block or file; MDX syntax diagnostics do not block
connection
- [x] For a non-empty block, show **Abort** and **Connect** and explain
that ordinary children will be replaced
- [x] On connect, remove every non-template child, preserve Templates,
set `src`, and materialize file content
- [x] Replace disconnect handoff with normal `src` reset; discard
derived content and leave the block empty
- [x] Remove disconnect confirmation and conversion; resetting a
repeated binding leaves every occurrence empty
- [x] Switching sources validates/loads the target before replacing the
usable binding and leaves both files unchanged
- [x] Revalidate Asset revision and project version when confirmation is
submitted
- [x] Make repeated connect/disconnect operations idempotent
- [x] Prevent disposed, stale, or out-of-order loads from replacing the
newest source
- [x] Keep loading, saving, conflict, empty-file, and open-file actions
off canvas

### 6. Asynchronous persistence and conflicts

- [x] Snapshot the current in-memory authored root after normal
mutations
- [x] Serialize/coalesce rapid edits per resolved Asset and always
prepare against the latest local snapshot
- [x] Allow independent Assets to save concurrently without scope
leakage
- [x] Use one revisioned document session and one ordered save queue per
Asset, even when multiple Content Blocks or render scopes reference it
- [x] After a shared Asset changes, rematerialize every connected
occurrence without persisting their generated instances to project data
- [x] Pin the resolved Asset and exact loaded revision for each write
- [x] Recheck authorization immediately before storage
- [x] Ensure local queued edits never produce stale-revision conflicts
with each other
- [x] On a genuine external revision conflict, preserve local content,
stop writes, and enter the standard reload-required state
- [x] Keep failed non-conflicting writes retryable without discarding
local content
- [x] Finish already accepted persistence writes after a Content Block
unmounts or switches source
- [x] Cancel obsolete loads, materializations, and UI updates after
unmount, reload, or source switch
- [x] Dispose project-scoped roots, queues, parse caches, failure state,
generations, and session subscriptions when the Asset session is
replaced
- [x] Invalidate Asset resources and synchronize open file editors after
successful writes
- [x] Keep multi-root persistence ordered, serial, and non-atomic;
report partial completion without rollback
- [x] Do not add Asset-history undo/redo; native text-editor undo
remains local to the open editor

### 7. Content mode parity

- [x] Empty connected blocks remain selectable and expose the normal
Content-mode `+` affordance
- [x] First insertion renders immediately
- [x] Enter creates and focuses the next paragraph immediately
- [x] Slash commands work in newly created empty paragraphs
- [x] Deleting one selected instance deletes exactly that instance
- [x] Mouse and keyboard moves use the same operation and permissions
- [x] Preserve sibling reorder, nested reparenting, and moves between
editable Content Blocks where `main` permits them
- [x] Preserve content-editable props such as Link `href`
- [x] Preserve copy, paste, cut, multi-cut, wrapping, unwrapping, grid
insertion, selection, Navigator order, and canvas order
- [x] Cover mutation routing centrally, retain the full unconnected
Builder suite, and exercise representative connected interactions in
real Builder E2E

### 8. Template names and permissions

- [x] Resolve only exact user-facing names from the direct flat
Templates list
- [x] Enforce unique names within each Templates list
- [x] Reject duplicate names during rename with inline validation
- [x] Allocate unique names during insert, paste, duplicate, move, wrap,
and unwrap
- [x] Apply valid template properties using the same permissions as
Content mode
- [x] Preserve and warn about ignored design-only, invalid, or stale
properties
- [x] Preserve template shell provenance without serializing expanded
template internals
- [x] Generate deterministic materialized IDs from source identity,
render scope, and authored usage path so focus/selection survives saves
- [x] Warn before renaming or deleting referenced templates; files
remain unchanged
- [x] Provide shared AST-based rename/remove migration operations for
MCP-assisted multi-file cleanup

### 9. Scope, frontmatter, and diagnostics

- [x] Scope materialized content by Content Block ID plus exact
Collection-item/render context
- [x] Prevent repeated instances and dynamic candidates from leaking
generated IDs, template resolution, or diagnostics across scopes while
sharing the underlying Asset source and revision where applicable
- [x] Remove frontmatter editing from Settings; edit the exact YAML
through the MDX Asset file editor
- [x] Preserve the exact frontmatter source byte-for-byte during canvas
body saves
- [x] Route canvas body changes and complete-file editor saves through
one revisioned per-Asset coordinator
- [x] Show a source warning indicator in Settings and precise
source-located diagnostics in the Asset editor
- [x] Deduplicate repeated diagnostics without losing distinct locations
- [x] Keep unresolved-template placeholders selectable and accessible
only in Builder

### 10. Asset references, transfer, and integrity

- [x] Discover and rewrite Asset references in frontmatter, Markdown
links/images, and MDX properties
- [x] Preserve Asset references while editing unrelated content
- [x] Include referenced Asset and template revisions in
dependency/cache identity
- [x] Route referenced Assets through published URL rewriting
- [x] Validate Content Block source integrity during project import,
fragment/page transfer, copy/paste, build integrity, and pre-publish
audit
- [x] Allow multiple Content Blocks and dynamic render scopes to
reference the same MDX Asset without treating the connection as an
integrity error
- [x] Preserve Templates when copying a connected Content Block
- [x] Preserve direct and dynamic Content Block source bindings when
copying or pasting within the same project
- [x] When copying only one rendered Collection item, resolve that
item’s current MDX Asset and replace the copied Content Block’s dynamic
source with a direct binding to that same Asset
- [x] When copying an entire Collection, preserve the Collection, its
instances, and its dynamic source bindings
- [x] Preserve the complete MDX source and frontmatter by reference;
copying a connected block must not rewrite the shared file
- [x] During cross-project transfer, copy every discoverable distinct
bound MDX Asset and rewrite transferred bindings to the destination
Assets
- [x] If some cross-project dynamic candidates cannot be discovered or
copied, continue with successful copies, preserve what can be
represented safely, and warn about skipped candidates
- [x] Revalidate source revisions and the destination project before
applying a cross-project transfer
- [x] If cross-project Asset creation or project insertion fails, leave
the source project unchanged and clean up any newly reserved destination
Asset
- [x] Use the same transfer operation through Builder and MCP

### 11. Dynamic sources and publication

- [x] Resolve dynamic bindings once per render/save scope
- [x] Require finite, discoverable candidate sets for publication and
load no unrelated MDX
- [x] Warn and skip unbounded, missing, unreadable, malformed, or unsafe
sources without failing the complete build
- [x] Materialize only rendered Content Blocks; ignore Templates
definitions and `src` on non-Content-Block instances
- [x] Skip unresolved template subtrees while keeping valid siblings
- [x] Include selected template styles, fonts, resources, unresolved
names, and referenced Asset revisions in generated dependency output
- [x] Keep draft-only MDX Assets out of publication retention

### 12. Builder, MCP, CLI, and shared operations

- [x] Use the same converters, source lifecycle, revision checks,
persistence service, diagnostics, and template migrations in Builder and
MCP
- [x] Keep frontmatter editing file-based; retain whole-frontmatter
runtime operations only where compatibility requires them
- [x] Avoid Builder-only or MCP-only mutation/conversion implementations
- [x] Regenerate runtime/API contracts from their source definitions
- [x] Update CLI Content Engine reference and generated MCP
documentation

### 13. Verification and delivery

- [x] Add regression tests that reproduce failures from the previous
implementation, including double deletion and blocked rendering
- [x] Cover two Content Blocks sharing one Asset: edits from either
block serialize once, update both canvases, preserve scope-specific
Templates, and cannot overwrite a newer local snapshot
- [x] Verify new tests fail against the broken implementation and pass
with the corrected behavior
- [x] Run SDK, Content Engine, Asset Uploader, Project Build, Builder,
React SDK, CLI, Protocol, and HTTP Client affected suites and typechecks
- [x] Run real Builder E2E for source lifecycle, live file refresh,
empty insertion, Enter/slash focus, Link props, delete, keyboard
reorder, switching, disconnect, conflicts, unresolved templates, dynamic
sources, and repeated scopes
- [x] Regenerate shared project fixture bundles and verify a second
generation leaves the tree clean
- [x] Run lint, package boundaries, `pnpm oxfmt --check`, and `git diff
--check`
- [x] Review and update authoritative `docs/` content and navigation
- [ ] Run the complete agent evaluation suite — not run because it
requires separate explicit approval

### 14. Content-mode parity and disconnect handoff

- [x] Allow keyboard reordering in Content mode through the normal move
command while keeping the editable Content Block boundary
- [x] Let already accepted Asset writes drain independently before
resetting the source; disconnect does not load, flush, or convert the
file
- [x] Remove MDX-to-instance copying from disconnect
- [x] Reset `src`, remove the derived tree, and leave the ordinary
Content Block empty
- [x] Preserve automatic text-editor focus after inserting editable
content from the template menu
- [x] Remove Builder frontmatter-save UI and report complete-file save
failures through the Asset editor
- [x] Add regression coverage for keyboard movement, disconnect
teardown, source switching, insertion focus, and paragraph deletion
focus restoration
- [x] Run the complete six-scenario MDX Content Block Builder E2E suite

### 15. Final architecture review fixes

- [x] Keep one canonical ordered pending document per Asset so shared
Content Block occurrences cannot conflict with one another
- [x] Merge ordered local edits from different occurrences while
preserving text changes, insertions, deletions, and sibling reordering;
keep external revisions on the strict reload-required path
- [x] Centralize typed render-scope parsing, repeated-occurrence
detection, scoped variable lookup, and dynamic Asset resolution across
Canvas, Settings, source lifecycle, and copy/paste
- [x] Capture the owning Asset session when a save is accepted so normal
unmount/source-switch teardown cannot redirect or lose it
- [x] Dispose project-owned roots, queues, caches, generations, failure
state, and subscriptions when replacing the project Asset session
- [x] Add regression coverage for same-Asset edits from two occurrences,
same-node last-write ordering, structural reorder, insertion
preservation, scoped source resolution, and project cleanup
- [x] Re-run affected full unit suites, typechecks, production build,
static checks, and all six MDX Content Block Builder E2E scenarios


### 16. Final persistence and transfer hardening

- [x] Drain every accepted per-Asset edit before project-session
teardown while retaining the owning authorization context
- [x] Drain canvas serialization queues and revisioned Asset writes
before pre-publish audit and publication
- [x] Block publication on a queued serialization failure or Asset
revision conflict
- [x] Copy actual Asset bytes during cross-project paste, preserve MDX
reference names, rewrite direct and Collection-backed Asset IDs, and
clean up newly created Assets when insertion fails
- [x] Include every resolved dynamic MDX source when copying an entire
Collection and warn while preserving successful copies when individual
Assets cannot be transferred
- [x] Keep MDX editor save failures visible with retry and route
conflicts through the standard reload-required flow
- [x] Give keyboard nested reparenting the same editable Content Block
boundary used by pointer movement
- [x] Add regression coverage and rerun the complete Content Engine and
Builder unit suites plus type, lint, formatting, package-boundary, and
diff checks

## Current rebuild status

- The connected Content Block now owns one complete MDX document:
frontmatter feeds designed-shell bindings and the explicit Body outlet
owns the authored MDX body.
- Builder and published output resolve the same frontmatter document
graph, including nested document references and Asset references.
- Direct frontmatter text/property edits use the existing ordered
per-Asset session; referenced-document values remain file-owned.
- Repeated Collection occurrences keep isolated runtime shell/Body
identities and occurrence-specific document values.
- The local blog article layout has been upgraded to the document/Body
model and its bindings validate cleanly.
- Full affected package suites and typechecks pass; every new regression
was demonstrated fail/pass.
- `pnpm lint`, package boundaries, `pnpm oxfmt --check`, generated
API/docs checks, fixture builds, and `git diff --check` pass.
- Full fixture synchronization is blocked by the development API
rejecting this local CLI version before fixture generation; existing
fixture bundles build successfully.
- Complete agent evaluations remain pending explicit approval.

### 17. Treat Content Block source as a property

- [x] Declare Content Block `src` in component metadata as a Design-mode
initial property labeled **Source**
- [x] Add the short property description: “Create an .mdx file in
Assets, then select or bind it here.”
- [x] Accept only a direct Asset or an expression resolving to an Asset
ID; reject URL/string sources, missing Assets, and non-MDX Assets
- [x] Extract and reuse the Image-style Asset picker and binding
presentation without duplicating source-control UI
- [x] Render Source through the normal properties section and remove the
separate source-section placement and special `src` filtering
- [x] Route Source changes through Content Block connect, switch, and
disconnect lifecycle operations instead of generic prop updates
- [x] Keep connect confirmation, Open, diagnostics, and persistence
state attached to Source; remove frontmatter and disconnect UI
- [x] Add regression coverage for direct Assets, dynamic Asset bindings,
invalid resolved values, lifecycle operations, and Design/Content mode
visibility
- [x] Re-review authoritative `docs/` content for the Source-property UI
change and update it if required

### 18. Source property UX

- [x] Show one full-width bindable Connect .mdx file button while
disconnected
- [x] Show equal-width filename and Open buttons while connected
- [x] Switch files from the filename button through the source lifecycle
- [x] Override PropertyLabel reset and Alt-click with the disconnect
lifecycle
- [x] Preserve confirmation, pending, failure, repeated-scope, and
dynamic-source behavior
- [x] Add regression coverage for connect, switch, binding, reset, and
disconnect
- [x] Update Content Block documentation
- [x] Run affected tests, typecheck, lint, formatting, package
boundaries, and diff checks


### 19. Reduced file-owned frontmatter follow-up

This checklist supersedes the earlier structured-frontmatter and
disconnect-copy behavior. Frontmatter remains file-owned and is edited
only in the MDX Asset editor.

#### A. Remove structured frontmatter UI

- [x] Remove the JSON frontmatter editor and unused Builder
controller/state
- [x] Keep source mutation Design-mode-only; show connected Source
read-only in Content mode and allow authorized editors to open the
complete file
- [x] Retain runtime frontmatter APIs only where compatibility requires
them

#### B. Preserve source and separate validation

- [x] Preserve the exact frontmatter envelope during every canvas body
save without parsing/stringifying YAML
- [x] Preserve comments, ordering, quoting, whitespace, BOM, newline
style, delimiters, and invalid but closed YAML
- [x] Keep the existing unsupported-node/property MDX recovery; do not
add an ad hoc partial parser
- [x] Parse body and frontmatter independently so either valid half
remains usable
- [x] Keep bounded Asset-query frontmatter extraction unchanged
- [x] Treat structurally malformed MDX as having no safe body tree

#### C. Share Asset state with the raw editor

- [x] Route canvas and complete-file changes through one ordered,
non-blocking per-Asset coordinator
- [x] Update canvas and clean raw editors immediately from shared
in-memory source
- [x] Reject stale dirty-editor saves, preserve unsaved text, and
require reload; never force-overwrite
- [x] Drain accepted writes after source replacement/disconnect and
report background failures globally
- [x] Dispose sessions only after they have no consumers and no queued
work

#### D. Connect, replace, and disconnect

- [x] Load and diagnose before connect; block only
unreadable/unauthorized/non-MDX Assets
- [x] Show **Abort / Connect** for non-empty blocks, including
diagnostics and the recoverable-content warning
- [x] Set `src` and delete persisted children through one runtime
mutation
- [x] Switch to a loaded source without waiting for the previous Asset's
network save
- [x] Remove disconnect confirmation and conversion
- [x] Reset `src` immediately, discard the derived tree, leave the block
empty, and preserve the Asset
- [x] Resetting a bound source leaves every repeated occurrence empty

#### E. Dynamic and shared sources

- [x] Keep one source/revision state per Asset and a separate derived
instances tree per occurrence
- [x] Resolve Templates independently per Content Block and preserve
Builder-only missing-template placeholders
- [x] Resolve bound `src` from the selected Collection occurrence
- [x] Make **Open** use the occurrence's resolved Asset; update the
filename and disable Open when unresolved
- [x] Add direct/bound tests including Collection item A opening `a.mdx`
and item B opening `b.mdx`

#### F. Diagnostics, MCP, and publication

- [x] Show an accessible warning icon beside Source with the first
diagnostic, line/column, and remaining count
- [x] Show precise YAML/MDX diagnostics in the Asset editor without
repetitive canvas/toast UI
- [x] Reuse parser/diagnostic/revision contracts in Builder, build,
publication, and MCP
- [x] Keep MCP frontmatter editing file-based and return structured
diagnostics for complete-source writes
- [x] Emit build warnings; published sites skip invalid/unsupported
content without diagnostic UI

#### G. Verification and documentation

- [x] Add fail/pass regressions for source preservation, independent
validation, stale raw saves, lifecycle, dynamic Open, shared Assets, and
cleanup
- [x] Run affected tests, typechecks, lint, formatting, package
boundaries, fixtures, and diff checks
- [x] Open Markdown and MDX editors at twice the default dialog size
with the right-side preview visible initially
- [x] Document canvas body editing, file-owned frontmatter, Content-mode
Asset access, and cloning an MDX Asset for a new post
- [x] Perform a final correctness, data-loss, DRY, simplification,
accessibility, and performance review
- [x] Keep this checklist synchronized with implementation status

### 20. Content-mode component properties

- [x] Show a connected Content Block Source read-only in Content mode
with an active **Open** action
- [x] Keep source switching, binding, reset, and disconnect available
only in Design mode
- [x] Expose HTML Embed code and preserve Code Text's code-editor
metadata on authored Text Content
- [x] Audit every registered component and expose authored payload while
keeping design, structure, and behavior controls in Design mode
- [x] Keep media dimensions and Code Text theme Design-only while
preserving adapter-owned intrinsic Image metadata during MDX round trips
- [x] Add exact component-permission and regression coverage
- [x] Update authoritative component documentation
- [x] Run affected full suites, typechecks, formatting, lint, package
boundaries, and generated contract/documentation checks


### 21. Designed document shell and Body outlet

- [x] Add one structural **Content Block Body** outlet and keep legacy
Content Blocks without it compatible
- [x] Materialize and persist only `document.body` children through the
Body outlet while preserving the surrounding designed shell and
Templates
- [x] Expose the connected document frontmatter through a Content Block
`document` parameter for shell text and property bindings
- [x] Write direct frontmatter-bound text and properties back through
the same ordered per-Asset session without blocking canvas mutations
- [x] Resolve document `$ref` dependencies and Asset references
consistently in Builder and published output
- [x] Keep referenced-document values read-only on canvas and direct
editors to the referenced file
- [x] Isolate repeated Collection occurrences while retaining
occurrence-specific source, frontmatter, shell, and Body content
- [x] Render the same designed shell, frontmatter values, and Body
substitution in generated/published output
- [x] Upgrade the local blog article layout to bind title, excerpt,
dates, author data, and images from frontmatter and render MDX through
Body
- [x] Add fail/pass regressions for nested Body discovery, lifecycle,
permissions, repeated values, document references, and generated shell
rendering
- [x] Update authoritative Content Block documentation
- [x] Run affected tests and typechecks, formatting, lint, package
boundaries, generated API/docs checks, and fixture builds


### 22. Final nested references and frontmatter editing

- [x] Keep direct frontmatter-bound text and property controls editable
in Content mode without exposing or replacing their bindings
- [x] Keep referenced-document values read-only and preserve legacy
instance-property name normalization
- [x] Render direct frontmatter text bindings through the plain-text
editing path
- [x] Resolve nested legacy and structured Asset references from
referenced Markdown/MDX frontmatter
- [x] Preserve missing Asset references, emit structured
`ASSET_NOT_FOUND` diagnostics, and keep them out of the document graph
- [x] Add fail/pass regressions for the real Settings control and
root/nested missing Asset-reference cases
- [x] Fix exact Content Block selection after the Body node appears in
Navigator
- [x] Run full affected suites/typechecks, all six MDX Content Block E2E
scenarios, deterministic fixture builds, generated checks, lint,
formatting, package boundaries, and diff checks

### Before merge

- [x] Resolve #6261: Nested Asset references in referenced Markdown
frontmatter work consistently in Assets queries, previews, publication,
and static export


### 23. Explicit writable expression bindings

- [x] Add an explicit `readwrite` mode to expression bindings; existing
expressions remain read-only by default
- [x] Accept `readwrite` only for direct static member paths and
centralize their parsing and validation
- [x] Require the expression root to provide a writable data source;
initially support the connected Content Block document frontmatter
- [x] Update Content Block permissions, canvas text editing, and
property controls to require a valid writable binding
- [x] Persist direct frontmatter edits through the existing ordered
per-Asset session
- [x] Create new direct frontmatter bindings with `readwrite` mode and
migrate existing compatible bindings
- [x] Preserve writable mode through schemas, serialization, loading,
copy/paste, transfer, and export
- [x] Add fail/pass regressions for valid paths, derived expressions,
unsupported sources, permissions, persistence, and compatibility
- [x] Review authoritative `docs/` content and update it if the
persisted binding contract affects user-facing documentation
- [x] Reject unsafe frontmatter paths and reject `readwrite` bindings
outside a connected Content Block document
- [x] Preserve expression binding mode through the public HTTP client
and document the MCP authoring contract
- [x] Limit frontmatter value write-back to Content mode so Design mode
retains normal binding replacement/reset behavior
- [x] Keep bindings inside Templates and across nested Content Block
ownership boundaries read-only
- [x] Upgrade compatible legacy bindings even when the Content Block is
disconnected during migration
- [x] Run affected tests, typechecks, formatting, lint, package
boundaries, fixture checks, and `git diff --check`

Verification: full SDK (567), Project Build (2,277), and Builder (2,695)
suites pass, along with affected Expression, Migration, Template, HTTP
Client, and MCP suites; typechecks, lint, formatting, package
boundaries, and diff checks pass. Generated contracts are refreshed.
Fixture synchronization remains blocked before generation because the
development API rejects this local CLI version as incompatible. The
checked-in bundles pass the current Protocol suite and every fixture
build with the current bundle version.
2026-08-29 20:15:20 +02:00
Oleg Isonen b1d23f69c0 fix: Report unsupported Node versions at CLI startup (#6201)
## Summary

- Reject unsupported Node.js versions before loading the CLI bundle.
- Report the declared engine range and detected version with an
install-and-retry instruction.
- Keep the runtime check aligned with `package.json#engines.node`.

## Root cause

The CLI declares Node.js 22.12+ but did not enforce that requirement at
startup. Package managers can warn and continue, allowing unsupported
runtimes to reach preview code. Execa 10 then initializes
`Set.prototype.union()`, which is unavailable in Node 20 and causes the
delayed `screenshot.responsive` failure.

## Technical choices

- Validate the runtime directly at the published executable boundary.
- Parse the declared engine range with `semver`.
- Dynamically import the CLI only after the runtime passes validation.
- Report the exact engine range rather than assuming every valid range
means “or newer.”
- Test the published `bin.js` in a subprocess with an injected
unsupported runtime version.
- Write the actionable startup failure to stderr and exit nonzero.
- No migrations or public API changes.

## Checklist

- [x] Add the startup runtime guard.
- [x] Add executable-level regression coverage for unsupported Node.js.
- [x] Verify the supported runtime still loads the CLI.
- [x] Review fixture impact; no fixture inputs or outputs are affected.
- [x] Review authoritative documentation; `docs/university/cli.md`
already requires Node.js 22.12+, so no update is needed.
- [ ] Run agent evaluations — not run because the requester declined
them.

## Verification

- Published and local launcher tests: 4 passed.
- CLI typecheck: passed.
- Targeted lint and formatting: passed.
- CLI production build: passed.
- Node.js 18.16.1 and 20.12.2 executable checks: exited 1 before loading
the CLI, reported the `>=22.12.0` requirement, and wrote no stdout.
- Node.js 22 executable check: CLI loaded successfully.
- Package dry run: includes the guarded `bin.js` and no separate runtime
helper.
- `git diff --check`: passed.
- The executable-level regression test was confirmed to fail against the
previous message/implementation and pass after the direct guard was
applied.

## Known limitation

An MCP client may wrap a subprocess startup failure in its own UI, but
the CLI now provides the actionable requirement and installation
instruction on stderr before any tool runs.

Closes #6190
2026-08-20 00:17:52 +02:00
Oleg Isonen 5a57234c75 revert: Store Content Block content in MDX assets
Revert the accidental merge of #6125 so the implementation can continue in draft PR #6181.
2026-08-18 13:23:32 +01:00
Oleg Isonen 86b6310fff feat: Store Content Block content in MDX assets 2026-08-17 15:22:20 +01:00
Oleg Isonen 21ca567686 fix: Stop owned preview process trees (#6111)
## Summary

Supervise generated preview processes so the CLI terminates the complete
owned process tree when an MCP session disconnects, a command finishes,
or the owner receives a termination signal. Record owned PIDs and report
actionable locked-path recovery when cleanup still fails.

Closes #6019

## Technical choices

- Start generated previews through a dedicated supervisor process
connected to its CLI/MCP owner over IPC.
- Disconnect the supervisor to stop a preview; the supervisor owns all
descendant cleanup.
- Use Execa `killDescendants` for cross-platform process-tree
termination instead of maintaining separate Windows and POSIX kill
implementations.
- Force-stop the owned tree so a descendant that ignores SIGTERM cannot
survive its launcher.
- Record supervisor and preview PIDs beside the generated preview
directory.
- Include the supervisor in the CLI build output.

## Implementation checklist

- [x] Add owned preview process-tree supervision.
- [x] Dispose previews on MCP completion, failure, disconnect, and
signals.
- [x] Add scoped locked-path diagnostics and recovery instructions.
- [x] Add lifecycle and command regression coverage.
- [x] Run the CLI typecheck and broader test suite.
- [x] Review authoritative `docs/` content; no user-facing documentation
changes are needed.
- [ ] Run the complete agent evaluation suite after explicit approval.

## Verification

- Preview server and supervisor tests: 42 passed.
- Full CLI test suite: passed.
- CLI typecheck: passed.
- CLI production build: passed.
- Package-boundary check: passed.
- Targeted lint and formatting: passed.
- `git diff --check`: passed.
- The supervisor-disconnect regression was verified to fail without the
new behavior and pass with it restored.
- Agent evaluations were not run because repository policy requires
separate explicit approval.
2026-08-12 22:09:03 +02:00
Oleg Isonen db2d092268 ci: replace Lost Pixel with self-hosted visual regression (#6086)
## Summary

Replace the defunct Lost Pixel service and the interim Chromatic
workflow with a fast, self-hosted visual comparison pipeline.

The workflow indexes the existing CSF stories without building
Storybook, builds and serves a lightweight browser app with Vite,
renders the merge base and current revision through Webstudio's shared
browser tooling, and compares screenshots with Webstudio's pixel-diff
and OCR engine. It uses GitHub Actions cache and artifacts only—no R2
bucket or external visual-testing service.

Closes #6064

## Implementation

- [x] Remove the Lost Pixel workflow, configuration, acknowledgement,
and global two-second wait.
- [x] Remove the interim Chromatic workflow and settings.
- [x] Extract source-agnostic capture, diff, OCR, audit, cache, and
report tooling into `@webstudio-is/vision`; rename the
Webstudio-specific preview boundary to
`@webstudio-is/project-build/preview`.
- [x] Expose the reusable browser capture session through the shared
vision boundary.
- [x] Make OCR and diff-artifact generation conditional on detected
pixel changes.
- [x] Render existing CSF stories through a typed, lightweight browser
harness built with Vite.
- [x] Replace the embedded HTML and handwritten HTTP/MIME server with a
real HTML entry, Vite production build, and Vite preview server; isolate
declarative build configuration in `story-build.ts`.
- [x] Apply Storybook preview annotations, decorators, global CSS,
backgrounds, and story metadata.
- [x] Store story scopes as shared data and load each revision's own
configuration.
- [x] Discover changed, added, and removed stories from both revisions.
- [x] Populate private story sources symmetrically in the baseline
worktree.
- [x] Isolate every story with a fresh React root and deterministic
time, randomness, intervals, focus, animation, and layout readiness.
- [x] Preserve story-owned visual options for masking, settling, and
interval control.
- [x] Reuse Vite preview servers, one Chromium process, grouped browser
pages, production bundles, and a bounded CPU worker pool for image
comparison.
- [x] Recheck initial pixel differences with serial captures, then
recapture persistent baseline/current pairs on the same browser page so
renderer variance cannot create false failures.
- [x] Report individual story render failures without discarding
successful captures.
- [x] Enforce a 0.1 per-pixel threshold and 0.001% total mismatch
tolerance.
- [x] Run OCR only for changed comparisons and include text-change
evidence.
- [x] Move the generic report model, writer, static viewer, and opener
into the shared Vision package for reuse by CI and future CLI
comparisons.
- [x] Bundle report HTML, styling, and browser behavior as static Vision
assets without runtime source-file lookups.
- [x] Copy external screenshot inputs into self-contained report
artifacts for CLI reuse.
- [x] Handle cached removed-only comparisons without rendering the
removed story on the current server.
- [x] Support focused local reproduction and opening the report with one
command.
- [x] Pin CI to the lockfile's Playwright Chromium, cache complete
revision screenshots with matching restore/save paths and automatically
derived runtime invalidation, and render both revisions on a miss.
- [x] Keep cache archives bounded to one revision instead of
accumulating the cache history.
- [x] Run the complete visual suite in one CI job and upload one report
as a 14-day artifact.
- [x] Fail PR checks on visual differences, empty runs, missing
screenshots, missing or empty report artifacts, and infrastructure
failures.
- [x] Rerun fork checks when `safe-to-deploy` is added.
- [x] Allow reviewed visual-only differences through
`visual-change-approved` and invalidate approval after new commits.
- [x] Keep capture, pixel diff, OCR, and report generation
source-agnostic for future draft-versus-published project comparisons.
- [x] Use Vite for the complete story HTML, module, asset,
production-build, and preview-server lifecycle; inline the selected
stories and skip ineffective tree-shaking to keep the cached run under
one minute.
- [x] Review Builder product documentation impact: no user-facing
Builder documentation is affected; contributor usage is documented in
`scripts/visual-regression/README.md`.
- [x] Review fixture impact: no fixture inputs or generated fixture
outputs are affected.

## Verification

- [x] Project-build Vision tests, including the reusable report test,
and entrypoint contract tests pass.
- [x] CLI screenshot, preview, and browser-session tests pass.
- [x] Project-build, CLI, Builder, design-system, and visual-runner
typechecks pass.
- [x] Visual runner tests pass (10), and the complete Vision package
passes (79), including demonstrated fail-before/pass-after coverage.
- [x] Full Storybook production build passes.
- [x] Full local Vite run completes all 238 stories in 69.9s cold and
50.3s with a cached baseline plus two same-page serial verifications,
with zero differences; identical-image comparison remains sub-second.
- [x] The report writer passes a bundled-output smoke test and
materializes external screenshot assets.
- [x] The generated report validates all 238 entries and referenced
images.
- [x] Hosted cached-baseline comparison completes all 238 stories in
52.9s with zero differences; the cache-miss fallback completes in
101.3s.
- [x] Cache-miss fallback renders both Git revisions on demand.
- [x] Visual differences produce baseline, current, diff, OCR, JSON, and
HTML evidence and fail without approval.
- [x] Hosted single-job visual workflow restores both the pinned browser
and baseline cache, validates all 238 public and private stories with
zero differences, and uploads the report.
- [x] The final Vite production build renders all 238 stories without
dependency invalidation or duplicate React runtimes, and restores
`NODE_ENV` so cached serial fallback installs the baseline's dev
dependencies.
- [x] Root lint, package-boundary validation, and relevant formatting
checks pass.
- [x] Workflow YAML parses successfully.
- [x] `git diff --check`, staged-diff review, and final worktree review
pass.

## Usage

Run the complete local comparison and open the visual report:

```sh
pnpm visual-regression:ui
```

Focus one component while iterating:

```sh
pnpm visual-regression:ui -- --grep "Design system/Button"
```

Reopen the latest report without rerunning:

```sh
pnpm visual-regression:report
```

The CI report is available as the `visual-regression-report` artifact.

## Tradeoffs

- Baseline screenshots are a disposable acceleration cache, not source
of truth. A missing or invalid cache renders the merge base directly
from Git.
- GitHub artifact storage provides downloadable one-click reports;
permanently hosted browser links would require another hosting surface.
- OCR runs after pixel triage because invoking Tesseract for every
unchanged story would make the common path unnecessarily slow.
- Vite production builds add Rollup's module graph and HTML/asset
pipeline. The runner emits one bundle because every selected story is
rendered, and skips tree-shaking because it removed little while
increasing build time.
- The verified local path is 50.3s cached and 69.9s cold. The hosted
path is 52.9s cached and 101.3s cold. A new browser/runtime cache must
render its baseline once; the pinned browser keeps later runners on the
reusable path.
- The complete suite stays in one Actions job; browser-page concurrency
is internal and bounded.
2026-08-12 10:55:52 +02:00
Oleg Isonen 93fa799cb8 fix: Preserve SSG exports with Assets queries (#6102)
## What changed

- Preserve the SSG asset-resource template as a package-relative file
URL in the bundled CLI.
- Ignore Assets queries that do not bind any parameters from the current
dynamic SSG route, while retaining the error for partial or split
multi-parameter bindings.
- Recognize the persisted `$ws$system.params.*` expression form when
enumerating dynamic SSG paths.
- Add a required package smoke test that deploys the release-shaped SSG
package, runs the packaged CLI, runs Vite and Vike, and verifies
rendered Assets data.

## Why

Two gaps caused the staging export failures:

1. Vite inlined the template URL as a `data:` URL, which Node could not
pass to `readFile`.
2. Dynamic-route validation treated an unrelated Assets query as an
incomplete route enumerator.

The initial smoke test only checked that an HTML file existed and could
pass while resource loading logged a `400`. The replacement test
verifies the rendered query result and fails on resource-loading errors.

## Technical choices

- The package smoke uses `createPublishedProjectBundleFixture`, so
fixture data stays checked against the published bundle contract.
- Persisted expressions use `encodeDataSourceVariable`; the generated
query now receives the real route parameter instead of compiling to
`undefined`.
- Temporary deployment, cleanup, subprocess execution, and assertions
live in `test:ssg-package`. The workflow invokes one repository command.
- Asset downloads are disabled to keep the smoke deterministic. It still
covers CLI packaging, the embedded Assets index, dynamic path
enumeration, generated resource execution, Vite compilation, and Vike
prerender.
- The test asserts the queried title in `/posts/hello-world`, rejects
any resource-load error, and verifies that an unrelated query does not
invent a dynamic path.

## Todo

- [x] Reproduce the invalid URL scheme through a bundled template
reader.
- [x] Preserve the package-relative template URL in the production CLI
bundle.
- [x] Ignore Assets queries unrelated to the current dynamic route.
- [x] Preserve rejection of incomplete multi-parameter route queries.
- [x] Support persisted system-variable expressions during route
enumeration.
- [x] Add a production-shaped packaged CLI and Vike smoke test.
- [x] Make the packaged SSG smoke test required on `main`.
- [x] Run CLI tests, typecheck, lint, build, and the packaged smoke
test.
- [x] Rerun the previously failing `WEBSTUDIO-LANDING` SaaS SSG
workflow.
- [x] Review documentation impact; no user-facing documentation changes
are needed.
- [x] Review fixture impact; synced fixture inputs and generated outputs
are unaffected because smoke data exists only in a temporary deployment.

## Verification

- `pnpm --filter webstudio test` — 61 files, 977 tests passed before the
final test addition
- `pnpm --filter webstudio test -- prebuild.test.ts
ssg-asset-resource-fetch-template.test.ts` — 57 tests passed
- `pnpm --filter webstudio test:ssg-package`
- `pnpm --filter webstudio typecheck`
- `pnpm lint`
- `pnpm --filter webstudio build`
- Package regression proof: the smoke failed on the original
unrelated-query implementation with `Dynamic SSG route parameters must
be completely enumerated by one Assets query`, then passed with the fix
restored.
- Persisted-expression regression proof: the focused test returned no
prerender path before encoded-system support, then passed with the
support restored.
- Template regression proof: the focused bundle test failed with
`ERR_INVALID_URL_SCHEME` before the fix and passed after it.
- Exact SaaS E2E rerun passed: project sync, CLI build, Vike build,
archive upload, and database update ([run
31519515809](https://github.com/webstudio-is/webstudio-saas/actions/runs/31519515809)).

Closes #6100

Supersedes #6101 after moving the change to the staging branch.
2026-08-11 20:56:12 +02:00
Oleg Isonen e4983b0d1d fix: Report unsupported Node versions (#6058)
Closes #6057

## Outcome

Generated projects now reject Node.js versions older than 22.12 before
React Router, Remix, or Vite evaluates SDK components. Users see the
package-manager engine error with the current and required versions
instead of the indirect `sanitize-html` / `htmlparser2`
`ERR_REQUIRE_ESM` stack trace.

## Root cause

`sanitize-html@2.17.6` synchronously loads the ESM-only
`htmlparser2@12`. That dependency combination relies on synchronous
`require(ESM)` support, which Node.js enabled by default in 22.12.
Generated projects incorrectly declared the broader `>=22` range,
allowing an unsupported runtime to reach SSR evaluation.

## Implementation

- Set the CLI and all generated base templates to `engines.node:
>=22.12.0`.
- Add npm `devEngines.runtime` with `onFail: error`, which runs before
install, CI, and run commands.
- Enable `engine-strict` in generated npm configuration so pnpm also
rejects an unsupported runtime.
- Regenerate every tracked CLI fixture package manifest.
- Update CLI documentation and the release-smoke manifest contract.
- Remove the earlier sanitizer-bundling workaround from the branch;
sanitizer code and packaging are unchanged from `main`.

## Checklist

- [x] Declare the exact Node.js compatibility floor
- [x] Fail before generated development, build, and start commands
- [x] Cover the generated engine contract with a fail/pass regression
- [x] Regenerate and inspect all affected fixtures
- [x] Review documentation impact and update the CLI guide
- [x] Keep sanitizer behavior and SDK packaging unchanged

## Verification

- Regression demonstrated failing before the template metadata change
and passing afterward
- `pnpm --filter webstudio test` — 946 passed
- `pnpm --filter webstudio typecheck`
- `pnpm --filter webstudio build`
- `pnpm fixtures`
- `pnpm lint`
- `pnpm exec oxfmt --check` on changed source, template, fixture, and
documentation files
- `git diff --check`

Agent evaluations were not run because they require separate approval.
2026-08-09 01:53:31 +02:00
Oleg Isonen 1fe087ed26 fix: Improve MCP preview and mutation reliability (#6073)
## Summary

Fix the second MCP reliability batch across tool discovery, runtime
mutations, preview/screenshot setup, Windows process launching, and
stdio recovery.

## Implementation

- [x] #6071 Accept canonical dotted/kebab tool names and MCP underscore
names in `mcp run`; return near matches and `meta.index` guidance for
unknown tools.
- [x] #6067 Parse JSON-stringified `tools` arrays in
`meta.get-more-tools`.
- [x] #6069 Preserve resource-backed variables when renaming without a
replacement value.
- [x] #6068 Parse CSS declaration strings consistently in design-token
style updates.
- [x] #6065 Fail immediately for occupied explicit screenshot ports and
discover Chromium from the Playwright browser cache.
- [x] #6066 Recover the stdio MCP transport after an abandoned partial
newline-delimited frame.
- [x] #6072 Launch managed Windows previews through Node plus
`npm-cli.js`, avoiding `spawn EINVAL`.
- [x] #6061 Reuse `npm-cli.js` when launched through `npx`, fall back to
the Node-adjacent npm CLI on Windows, forward `npm_config_cache`, and
include sanitized package-manager diagnostics.
- [x] Address review findings: preserve rebinding on resource scope
changes and discover default Playwright caches on Linux, macOS, and
Windows.
- [x] Complete the DRY pass: remove the dead npm command selector,
centralize accepted MCP tool-name lookup, simplify stdio frame recovery,
and share Levenshtein distance across MCP suggestions and screenshot
text matching.
- [x] Complete the follow-up review: centralize preview URL port
resolution, use `get-port` instead of custom TCP probing, use named
resolver dependencies, and correctly reuse owned previews on default
HTTP/HTTPS ports.
- [x] Complete the final review: use non-reserving `detect-port` checks
for explicit ports and repair the generated-app guidance regression
coverage.
- [x] Audit new utility code against maintained libraries: use
`fastest-levenshtein` for edit distance; retain custom stdio recovery,
Playwright cache discovery, and npm launching where no supported library
API preserves the required behavior.
- [x] Audit Windows/macOS/Linux compatibility helpers: use `path-key`
for environment PATH casing and `which` for executable discovery; retain
explicit Playwright layouts, browser application paths, npm CLI
resolution, symlink types, and process-tree shutdown where behavior is
platform- or product-specific.
- [x] Add fail/pass regression coverage for every fix.
- [x] Review documentation impact and update the CLI MCP sources plus
generated GitBook output.
- [x] Review fixture impact: no fixture inputs or generated fixture
bundles are affected.
- [x] Run targeted tests, package type checks, lint, package-boundary
checks, generated API checks, and generated documentation checks.
- [ ] Agent evaluations — not run because repository policy requires
separate explicit approval.

## Verification

- Complete CLI suite: 60 files, 968 tests passed.
- Project-build affected tests: 4 files, 382 tests passed.
- `pnpm --filter webstudio typecheck`
- `pnpm --filter @webstudio-is/project-build typecheck`
- `pnpm lint`
- `pnpm check:package-boundaries`
- `pnpm check:generated-api`
- `pnpm check:generated-docs`

Each new regression test was run against the unfixed behavior to confirm
the expected failure, then rerun after its fix.

## Compatibility note

The stdio recovery layer discards only an unterminated frame that
remains idle for five seconds. Complete newline-delimited JSON-RPC
frames continue through the SDK transport unchanged.

Closes #6072
Closes #6071
Closes #6069
Closes #6065
Closes #6066
Closes #6067
Closes #6068
Closes #6061
2026-08-09 01:04:01 +02:00
Oleg Isonen 2ec78c183d feat: Add single-result modes to Assets queries (#6040)
## Summary

- Add `many`, `one`, `first`, and `last` result modes to Assets queries
while keeping `many` as the backward-compatible default.
- Return direct items for single-result modes, validate deterministic
ordering, and report duplicate `one` matches as a structured
`MULTIPLE_RESULTS` error.
- Update Builder controls, preview/published runtime handling, SDK
resource encoding, MCP/CLI guidance, generated contracts, and fixtures.

## Implementation TODOs

- [x] Add result-mode schemas and core execution behavior.
- [x] Select single results before content hydration and preserve
deterministic ID tie-breaking.
- [x] Add structured duplicate-match transport errors.
- [x] Update Builder controls and hide/reset pagination for
single-result modes.
- [x] Keep existing settings first, then Output and Result, without a
duplicate Return label.
- [x] Preserve legacy saved resources with an implicit `many` default.
- [x] Update preview, published runtime, SDK, protocol, MCP, and CLI
behavior.
- [x] Regenerate runtime contracts, server metadata, CLI docs, and
fixtures.
- [x] Review documentation impact and update the authoritative MCP/CLI
guidance.
- [x] Add regression coverage and verify the new tests fail without the
implementation.
- [ ] Run the agent evaluation suite (not run; requires explicit user
approval).

## Compatibility and behavior

- Existing queries without `result` continue to behave as `many` and
retain the ID-keyed collection shape.
- `one` returns an item or `null`, but fails when more than one asset
matches.
- `first` and `last` require explicit sorting; the existing asset-ID
tie-breaker makes equal sort values deterministic.
- Single-result modes ignore and do not persist pagination controls.
Materialized collection queries remain collection-only; single-result
queries execute dynamically.

## Verification

- Content engine typecheck and full test suite (291 tests).
- Query builder, query-builder React, SDK, protocol, asset uploader,
project build, Builder, and CLI targeted typechecks/tests.
- Root lint.
- MCP documentation tests, typecheck, sync check, and generated-doc
checks.
- Generated API contract checks.
- Fixture generation pipeline.
- Final focused content-engine regression run (53 tests).
- Final DRY review: affected typechecks, focused tests, lint, package
boundaries, generated checks, and fixtures.

Closes #6039
2026-08-07 19:13:19 +02:00
Oleg Isonen 6385e290c6 feat: Add syntax highlighting to Code Text (#6007)
Closes #4119

Supersedes #5999 after GitHub closed it during the head-branch rename.

## Approach

Code Text uses one optional public highlighting boundary:

- `@webstudio-is/sdk-components-react/code-text` → `src/code-text.tsx`

The ordinary `components` entry remains Shiki-free. Canvas loading,
metadata options, theme variables, and the plain semantic `<code>`
component remain private implementation details.

**Code** uses the code editor. **Language** and **Theme** use normal
bindable selects. Fixed selections generate direct imports for only the
per-page language/theme union; plaintext imports no grammar. Bound
selections generate Shiki's lazy language/theme registries.

SSR and client rendering share the same factory. Missing bound assets
suspend the first render while SSR resolves the selected modules. SSG
now waits for Suspense before serializing HTML. During hydration the
completed server markup stays in place while the browser fetches only
the selected language and theme. Later client-side binding changes load
only the new selections and keep the same `<code>` node and focus.

Highlighted output preserves the semantic root, ref, author
classes/styles, whitespace, escaped source, and legacy children/native
`lang` behavior. Shiki's implicit tab stop is disabled. A color-only
transformer strips theme typography so asynchronous highlighting cannot
change text geometry.

## Bundle impact

Measured from same-commit production React Router + Cloudflare builds
containing one JavaScript / GitHub Light Code Text instance. Sizes are
the sum of emitted JavaScript files; gzip is the sum of each file
compressed independently.

| Worker output | Files | Raw | Sum gzip |
| --- | ---: | ---: | ---: |
| Fixed selections | 3 | 1,341,851 B | 288,342 B |
| Bound selections | 310 | 10,372,112 B | 1,872,273 B |
| Increase | +307 | +9,030,261 B (8.61 MiB) | +1,583,931 B (1.51 MiB) |

The bound browser build also emits the catalog as lazy chunks:
+9,012,594 raw bytes / +1,578,779 sum-gzip bytes across the complete
deployed output. Those chunks are not all delivered on page load. The
production SSG regression verifies 100+ catalog chunks are emitted while
the HTML directly module-preloads only one shared runtime chunk; the
browser fetches the runtime-selected language/theme modules on demand.

## Tradeoffs and compatibility

- Instances with both highlighting properties unset keep the legacy
plain renderer.
- Static highlighting still requires both **Language** and **Theme**.
- Binding either selection includes that catalog in deploy output
because its runtime value is not known at publish time.
- The syntax-highlighting property is `language`; legacy native HTML
`lang` remains preserved.
- Invalid or unavailable runtime selections render as plain code.
- Fixed selections retain the smallest publish output; bound selections
trade deploy/worker size for runtime flexibility.

## Todo

- [x] Restore the specialized Code Text component and semantic plain
fallback
- [x] Use a code editor for Code and bindable selects for Language and
Theme
- [x] Persist JavaScript / GitHub Light template defaults
- [x] Collapse highlighting to one public `./code-text` entry
- [x] Keep canvas loaders and option/theme helpers private
- [x] Generate direct imports for fixed selections and omit plaintext
grammar
- [x] Generate lazy catalogs when Language or Theme is bound
- [x] Preserve highlighted SSR markup during hydration without
node/focus movement
- [x] Support Suspense-aware highlighted SSG output
- [x] Preserve escaping, accessibility, legacy children, and native
`lang`
- [x] Measure fixed versus bound Cloudflare worker output
- [x] Deep-review correctness, DRYness, package surface, and obsolete
binding infrastructure
- [x] Review documentation impact and update Code Text documentation
- [x] Run focused tests, typechecks, production builds, formatting, and
staged diff review
- [ ] Fixture pipeline — blocked during sync because the current API
rejects this local CLI version as incompatible; no fixture output
changed

## Verification

- [x] New/changed regressions were demonstrated failing without their
behavior and passing after restoration
- [x] SDK Code Text metadata, rendering, hydration, and bundle tests: 17
passed
- [x] Component registry tests: 3 passed
- [x] CLI asset collection and full prebuild suite: 59 passed
- [x] SDK components, component registry, SDK, and CLI typechecks
- [x] SDK components declaration and production builds
- [x] Component registry production build
- [x] Production Vite + Vike prerender emits highlighted bound SSG HTML
with one doctype
- [x] Dynamic catalog chunks remain outside the SSG page's direct
preload set
- [x] Documentation reviewed and updated
- [x] Formatting and staged diff checks
2026-08-04 18:25:36 +02:00
Oleg Isonen 56a22fde8a feat: Add storage-backed document graph resolution (#5966)
## Summary

Introduce a document graph architecture for Assets resources so
structured documents can reference one another while keeping full
document payloads on CDN-backed storage.

The content database will retain the searchable index and dependency
graph. At runtime, the server will select a root document, determine its
complete dependency set before performing I/O, fetch each unique
document concurrently, and assemble the final result server-side.

## Implementation todos

### Document graph foundation

- [x] Add normalized internal reference contracts for whole documents,
JSON paths, Markdown body, and Markdown frontmatter.
- [x] Add an immutable graph abstraction with deterministic ordering,
dependency traversal, revision validation, and cycle detection.
- [x] Add a storage-independent resolver with dependency closure,
bounded parallel loading, shared-content deduplication, representation
selection, assembly hooks, cancellation, and structured errors.
- [x] Add focused unit coverage for the isolated document-graph
abstraction.
- [x] Define and validate the external remote-document reference syntax.
- [x] Add a pure graph compiler that resolves canonical document URLs
into IDs and revisions and validates missing, duplicate, and cyclic
dependencies.

### Build-time graph

- [x] Add a storage-independent source-catalog compiler for bounded
parallel reference discovery and deterministic graph compilation.

- [x] Add a versioned deterministic document graph artifact with
canonical serialization and integrity verification.

- [x] Discover and normalize statically declared references while Assets
resources are processed.
- [x] Resolve document identities and revisions and report missing,
stale, or cyclic dependencies with document context.
- [x] Persist document nodes and dependency edges alongside searchable
resource metadata.
- [x] Include persisted graph data in artifact integrity and size
validation.

### Document representations

- [x] Add a standalone JSON document adapter for exact reference
markers, compiler occurrences, JSON path selection, and immutable
assembly.
- [x] Add a standalone Markdown document adapter for bounded decoding,
frontmatter references, immutable assembly, and source, body, and
frontmatter selection.

- [x] Parse fetched JSON and Markdown documents through format-specific
adapters.
- [x] Select complete documents, JSON fragments, Markdown body, and
Markdown frontmatter through the shared reference model.
- [x] Assemble nested and shared references into the final server-side
value.

### Runtime resolution

- [x] Enforce reachable-document, per-document byte, and aggregate-byte
limits before parsing and assembly.

- [x] Add a revision-keyed bounded source-cache wrapper with replayable
bytes, stale-entry fallback, and in-flight deduplication.

- [x] Add a storage-neutral loaded-source contract that rejects revision
mismatches before parsing.

- [x] Resolve graph-backed property paths before filtering, sorting,
pagination, and projection; skip graph loading for unrelated queries.
- [x] Add an injected HTTP/CDN document loader with revision metadata
validation.
- [x] Apply runtime payload limits, bounded concurrency, caching, and
structured failure mapping.
- [x] Ensure shared documents are fetched and parsed once per
resolution.

### Product integration

- [x] Integrate equivalent behavior in local preview, SSR, SSG, and
published runtime paths.
- [x] Preserve existing embedded Assets resource behavior without
requiring migration.
- [x] Add observability for graph loading, document fetching, caching,
and resolution failures.
- [x] Document the public reference and resolution behavior.

### Review hardening

- [x] Enforce graph, artifact, cache, and published-storage identity
consistency.
- [x] Compile only graph sources reachable from selected build entries.
- [x] Resolve graph-backed fields before query evaluation and avoid
unnecessary graph loading.
- [x] Consolidate duplicated graph schemas, utilities, and document
content-type detection.
- [x] Correct runtime documentation and use structural evaluation
validation.

### Verification

- [x] Keep a deterministic high-impact agent evaluation for
Markdown-to-JSON references across the dynamic blog overview and article
routes.
- [x] Add a separate discoverability evaluation that must learn the
reference workflow from MCP guidance without prompt-supplied syntax,
queries, bindings, or call order.
- [ ] Re-run the complete local agent evaluation suite after the
discoverability fixture change and compare every fixture with its
accepted baseline.

- [x] Add integration coverage for CDN-backed hydration, parallel
fetching, caching, and shared dependencies.
- [x] Add integration coverage for missing references, cycles, revision
changes, limits, and cancellation.
- [x] Verify equivalent behavior across preview, SSR, SSG, and published
deployments.
- [x] Verify that existing embedded Assets resources retain their
current behavior.

## Intended outcome

- Storage-backed documents do not require their complete payloads to be
embedded in the content database.
- The server knows the complete statically discoverable dependency set
before fetching document content.
- Shared dependencies are fetched once per resolution and independent
resources can be fetched in parallel.
- JSON fragments and Markdown body/frontmatter representations use the
same document-resolution system.
- Reference and payload revisions cannot be mixed silently.
- Existing Assets resources continue to work without migration.

## Verification results

- `@webstudio-is/content-engine`: 37 files / 244 tests passed; typecheck
passed.
- `@webstudio-is/asset-uploader`: 22 files / 182 tests passed; typecheck
passed.
- CLI: 57 files / 925 tests passed, including generated SSR and SSG
build/prerender coverage; typecheck passed.
- Repository-wide `pnpm oxfmt --check` passed across 2,757 files.
- Package-boundary validation passed.
- Previous `pnpm evaluations` run: all 4 original high-impact fixtures
passed. The complete 5-fixture rerun is pending explicit approval after
adding the discoverability fixture.
2026-08-02 10:39:06 +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 c3c0e32204 fix: make MCP font assets editable and deterministic (#5944)
Closes #5943
Closes #5942

## User impact

MCP-managed font assets now keep their identity, metadata, and generated
CSS behavior predictable across upload, editing, synchronization, and
rendering.

## Changes

- Preserve explicit font metadata overrides while validating supported
fields and rejecting unsupported metadata instead of silently dropping
it.
- Expose font metadata through `update-asset`, with partial updates
merged into the existing metadata and validated before the mutation is
committed.
- Prefer the typographic family name when reading font files, so
Fontsource and Google font files resolve to the same logical family
where the file provides that information.
- Deduplicate generated font sources by URL and format, choose a
deterministic source when legacy assets collide, and derive the CSS
format hint from the filename when historical metadata is stale.
- Add MCP and CLI examples explaining font metadata upload and
correction.
- Add regression coverage for metadata persistence, invalid overrides,
family-name extraction, duplicate source handling, stale format
metadata, and generated runtime contracts.

## Verification

- `pnpm checks`
- 46 workspace packages tested, including 2,355 Builder tests, 809 CLI
tests, 2,019 project-build tests, and 97 asset-uploader tests.
- All workspace typechecks, Oxlint, package-boundary checks, generated
API/docs checks, and fixture link/sync/build checks passed.
2026-07-22 19:04:53 +02:00
Oleg Isonen 12ad74584a feat: Improve MCP authoring, auditing, and verification (#5886)
## Summary

This improves how coding agents discover, author, verify, and audit
Webstudio projects through the CLI and MCP. The work focuses on making
agents more reliable with less context, while keeping edits semantic and
Builder-editable.

## What changes for users

- Agents can verify dynamic bindings after authoring and receive
actionable diagnostics when expressions, resources, scopes, or component
props do not line up.
- Agents can create complete resource-backed runtime UI through a
semantic operation instead of coordinating fragile low-level edits.
- MCP discovery and command output are compact by default, with
pagination and focused verbose detail when an agent needs more context.
- Asset, style, token, font, page, and component inspection provides
stronger usage context so agents can preserve the existing design
system.
- Rendered audits provide better evidence for responsive behavior,
geometry, contrast, generated-build size, and large-project runs.
- Cross-project MCP workflows can run from a manifest with explicit
mutation approval, isolated failures, resumable progress, and persistent
checkpoints.
- Project-specific agent onboarding is clearer and does not add
telemetry.
- Packaged CLI releases gain stronger smoke verification for install,
MCP startup, authoring, preview, screenshots, and audits.

## Reliability and architecture

- Runtime operation output schemas are generated from the runtime
registry and remain client-compatible.
- Project-build exports are consolidated around architectural boundaries
instead of feature-by-feature convenience entry points.
- HTTP, preview, screenshot, and project-session paths are hardened for
longer autonomous workflows.
- Craft compatibility work is read-only and provenance-aware; it does
not silently opt ordinary projects into Craft behavior.
- A minimal-context evaluation harness exercises key workflows with a
weaker model and stores bounded, privacy-safe evidence.

## Validation

- Rebased on the latest `origin/main`.
- `pnpm lint`
- Repository-wide `oxfmt --check`
- CLI typecheck and full test suite: 773 tests passed.
- Project-build typecheck and full test suite: 1,866 tests passed.
- Protocol typecheck and full test suite: 83 tests passed.
- HTTP client tests: 23 passed.
- CSS data tests: 3,620 passed, 1 skipped.
- Focused Builder tests: 67 passed.
- Package-boundary, generated API, and generated documentation checks
passed.
- Minimal-context agent evaluations passed for authenticated
resource-backed UI and design-system-aware responsive authoring.
2026-07-16 17:53:16 +02:00
Oleg Isonen d186d24501 feat: Improve MCP project audits, visual verification, and dynamic content authoring (#5874)
This update helps AI agents understand, audit, and visually verify
Webstudio projects more reliably. It also adds clearer guidance for
expressions, Collections, screenshots, and responsive rendered audits.

### Audit complete projects

- Run one `audit` command across accessibility, SEO, security, assets,
styles, and performance.
- Audit the whole project or focus on a specific page, scope, or
severity.
- Receive stable findings with locations, explanations, and recommended
fixes.
- Continue large result sets through pagination without repeating
general guidance.

### Audit the rendered website

- Build and inspect the generated website, rather than relying only on
stored project data.
- Check every static page at representative mobile, tablet, and desktop
widths.
- Use one suitable viewport inside each configured breakpoint range.
- Reuse the same browser and resize pages between captures for
substantially faster audits.
- Process multiple pages concurrently while keeping resource use
bounded.
- Supply concrete examples for dynamic routes such as blog posts.
- Review and confirm unusually large screenshot plans before they run.

### Find visual and performance problems

Rendered audits can detect:

- Horizontal page overflow.
- Broken images.
- Images loaded eagerly below the fold.
- Images that are much larger than their rendered size.
- Render-blocking resources.
- Legacy font formats.
- Pages that fail to load or redirect somewhere unexpected.
- Pages captured before their layout becomes stable.

Detailed screenshots, measurements, failures, and timing evidence are
saved locally for further inspection.

### Capture generated pages directly

- Capture a project route with `webstudio screenshot --path /route`.
- Automatically generate and start a temporary production-style preview.
- Stop the temporary preview after the screenshot is captured.
- Return navigation, responsive layout, and page-size evidence with JSON
output.
- Allow external image domains needed by the generated preview.

### Reuse generated previews

- Cache generated preview builds when the project has not changed.
- Reuse preview dependencies across regenerations.
- Keep preview dependencies isolated from the user’s project
dependencies.
- Surface preview build and startup failures with useful diagnostic
output.
- Include local project assets in generated previews.

### Author Collections correctly

- Explain when Collection is required for arrays and objects.
- Guide agents to bind the complete iterable instead of one item or the
response wrapper.
- Explain how Collection repeats its children for every entry.
- Explain current-item and current-key scope.
- Preserve Webstudio’s generated Collection parameters.
- Guide agents to use stable values for repeated interactive components.

### Write expressions with fewer mistakes

- Add a dedicated `webstudio://project/expressions` reference.
- Document expression scope, supported syntax, and supported methods.
- Explain how resources, variables, Collections, actions, and `system`
values are accessed.
- Distinguish fixed values from runtime expressions.
- Provide valid examples for text, props, resource URLs, headers, query
parameters, and bodies.
- Warn agents that valid syntax does not guarantee that runtime data has
the expected shape.

### Improve agent discovery

- Make Collection and expression workflows discoverable through
`meta.guide`.
- Return Collection-specific instructions through `components.get`.
- Point relevant command schemas to the expression reference.
- Keep detailed guidance available without placing it in every tool
response.

### Improve audit reliability

- Report which rendered captures passed, found issues, failed, or were
skipped.
- Distinguish planning, preview, capture, and cleanup failures.
- Include actionable retry instructions with rendered failures.
- Preserve completed evidence when part of an audit fails.
- Detect stale or conflicting preview servers more clearly.
- Support cancellation and bounded capture timeouts.

### Improve packaged CLI verification

- Add a release-shaped CLI smoke test.
- Install the packed CLI in an isolated temporary project.
- Fail on peer-dependency warning floods.
- Verify preview, screenshots, MCP calls, rendered audits, and generated
assets.
- Confirm that generic React Router previews do not include Docker-only
image dependencies.
- Keep CLI and MCP stdout machine-readable while progress remains on
stderr.

## User Impact

Agents can now audit a real rendered Webstudio site, inspect responsive
behavior, find concrete visual and performance problems, and provide
evidence for their conclusions. They also receive much clearer
instructions when turning API data into repeated content or writing
dynamic expressions.
2026-07-14 13:52:09 +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 6e10ae3809 fix: Fix Builder paste transfer data handling and publish sync edge cases (#5861)
- Fix publish sync for empty JSON data variables
- Retry transient asset downloads once with shared sync-client backoff
- Fix Builder paste handling for Webstudio transfer data
- Add transfer/data-envelope terminology and colocated runtime
data-format modules
- Rename page clipboard runtime operation to page transfer semantics
- Report malformed Webstudio/Webflow paste data through paste results
instead of inserting it as text
- Add browser-level E2E coverage for instance, page, folder, template,
generic plugin, malformed data, native input, and content-mode paste
flows

## Details

- Allows empty JSON data variables to sync/publish correctly.
- Adds asset download retry coverage and uses shared backoff logic.
- Introduces runtime `data-formats` modules for data envelopes, instance
transfer data, and page transfer data.
- Removes stale clipboard aliases and `validateTemplateStructure`.
- Keeps clipboard as a Builder UI transport concern while
runtime/protocol use transfer-data terminology.
- Changes paste plugins to return expressive success/error results so
callers can show toast errors and stop fallback insertion.
- Prevents malformed Webstudio transfer payloads from falling through to
text/HTML/markdown insertion.
- Handles malformed Webflow-owned paste data without throwing.
- Adds shared copy-paste fragment insertion helpers to reduce duplicated
breakpoint-warning/fragment-data logic.
2026-07-10 13:51:55 +02:00
Oleg Isonen da13e301c9 chore: Post merge fixes (#5860) 2026-07-10 12:55:20 +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 b1a3eed1f8 feat: guide agents through webstudio cli (#5847) 2026-07-03 01:06:47 +02:00
Oleg Isonen 9b0cedf9c2 fix: keep project-build out of cli runtime deps (#5844) 2026-07-01 17:07:30 +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 64717a71d9 fix: Packages publishing (#5830)
Internal packages publishing issue.
2026-06-23 12:13:22 +02:00
Oleg Isonen b194d3e0b3 feat: Import project via CLI (#5828) 2026-06-23 02:54:55 +02:00
Oleg Isonen 16fa5ab0e3 feat: Basic authentication (#5779)
Closes https://github.com/webstudio-is/webstudio/issues/3991


Adds HTTP Basic Authentication support for published pages and
project-level `.wsauth` rules.

This introduces a new `@webstudio-is/wsauth` package that owns the
generic authentication format logic: parsing, validation, serialization,
route matching, resource generation, and request authentication. The
current supported method is `basic`, with the package structured so
additional auth methods can be added later.

Builder changes include:
- Page Settings now has an `Authentication` section for per-page Basic
Auth credentials.
- Project Settings now has an `Authentication` section for editing
`.wsauth` route rules.
- Page Settings was split into section-specific files with focused
tests.
- Auth UI shows Pro badges/info tooltips but remains editable.
- Publishing to custom domains is blocked on plans without `allowAuth`
when either page auth or project auth is configured.
- ProBadge now renders as a real pricing link and uses improved text
alignment.

Build/publish changes include:
- CLI prebuild generates and merges `.wsauth` entries.
- Published app templates enforce auth for HTML/XML routes.
- Generated auth resources are shared between build output and runtime.
2026-05-27 18:42:08 +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 2bf52cf0c1 chore: upgrade to Node 22 (#5603)
- Update engines.node in all package.json files
- Update .nvmrc to 22
- Update GitHub Actions workflows to node-version: 22
2026-02-05 10:25:17 +01:00
Oleg Isonen fdee339de0 chore: Migrate to tsgo (#5578) 2026-01-20 17:25:12 +01:00
Oleg Isonenandzehjotkah 0116966822 feat: Updated asset manager: new file types, asset resource, filters, sorting (#5539)
## Description

- [x] new file types support
- [x] categories filter
- [x] sorting filter
- [x] asset resource for access from custom code


## Steps for reproduction

1. click button
3. 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: zehjotkah <111518041+zehjotkah@users.noreply.github.com>
2025-12-24 18:25:46 +01:00
Bogdan Chadkin 59b6471c4f experimental: support paste html (#5185)
Ref https://github.com/webstudio-is/webstudio/issues/4404

Slightly reworked paste story. Now minimal API to insert html looks like
this

```js
const fragment = generateFragmentFromHtml(html);
insertWebstudioFragmentAt(fragment);
```

- attributes are casted to string, number and boolean types
- text is wrapped with spans when outside of rich text
- unsupported tags are ignored in result



https://github.com/user-attachments/assets/c8072d86-72bd-4446-a26a-e678b193f93e
2025-05-06 13:31:13 +04:00
Bogdan Chadkin a9c9573977 experimental: add react-router + cloudflare template (#5179)
Added react-router + cloudflare template to migrate our cloud
publishing.

This template does not support image optimization and intended only for
internal usage.
2025-05-02 19:17:49 +04:00
Bogdan Chadkin 63c54fcad6 refactor: upgrade remix and react-router (#5177)
This should fix a few vulnerabilities we get from react-router and vite
2025-05-02 00:35:20 +04:00
Bogdan Chadkin c8cbf482bf refactor: upgrade to vite 6 (#5172)
Got rid of "module" export condition everywhere.
Seems like it has very poor usage everywhere.
2025-05-01 10:32:18 +04:00
Bogdan Chadkin 452c50a41a refactor: upgrade vite for vitest and storybook (#5165)
Tough cookie. There is a problem with resolving react-remove-scroll,
figured it by reducing allowed amount of server conditions.
2025-04-29 14:17:42 +04: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 b1e373975d build: upgrade react-router and remix (#5106)
- security fixes
https://github.com/remix-run/remix/blob/main/CHANGELOG.md#v2164
- cloudflare support fixes
https://github.com/remix-run/react-router/blob/main/CHANGELOG.md#v750
2025-04-08 21:35:50 +07:00
Bogdan Chadkin 7a73f40889 refactor: upgrade react-router and remix (#5067)
Ref
https://github.com/remix-run/react-router/blob/main/CHANGELOG.md#v740
2025-03-28 18:16:31 +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
Ivan Starkov 35d0d7c8ac experimental: Breakpoint support for the Animation component (#5012)
## Description

https://animations.wstd.work/
Breakpoints Example

See on narrow screen animation is disabled.

<img width="699" alt="image"
src="https://github.com/user-attachments/assets/f464fdf3-f57a-4cf7-91a1-beb355f8a5bd"
/>



## 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-03-18 23:30:17 +05:00
Bogdan Chadkin 935983b543 build: upgrade checks (#4982)
- vitest
- testing-library (got much lighter)
- eslint and plugins (@types/eslint__js no longer necessary)
- storybook
- esbuild
2025-03-11 15:22:57 +07:00
Bogdan Chadkin 16258bb9b5 refactor: bump remix (#4972)
Upgraded legacy remix. The new version got vite 6 support so we could
upgrade it later.
2025-03-10 16:41:01 +07:00