Repository navigation
Conversation
This was referenced Oct 3, 2026
Draft
Copies @decocms/blocks/protocol (unpublished v8) into packages/shared/src/vendor/blocks-protocol with a sync script and a SYNC.md note, and exposes it as @decocms/shared/blocks-protocol*. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01WNwbSEePYNcY5YCgqZURig
Default off. Gates the content-protocol editing path for next-major Blocks sites. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01WNwbSEePYNcY5YCgqZURig
Adds a ContentStorage over RepoContentClient (one repo, app root and branch; blob shas as versions, the branch head as the revision) behind the vendored createContentHandler, at POST /api/:org/decofile/:virtualMcpId/:branch/rpc GET /api/:org/decofile/:virtualMcpId/:branch/draft-grant Both sit under the existing scope middleware (session, cms plan, repository binding) and answer 404 unless the org has the site_editor_content_protocol flag. They don't need a preview server. A missing branch reads as the default branch until the first write creates it. The tracked blocks.gen.json regeneration moves to gen-artifact.ts, shared with the commit coalescer. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01WNwbSEePYNcY5YCgqZURig
Runs the protocol's black-box conformance suite against the new endpoint over the GitHub stub, plus the flag gate, session auth, the bound branch, branch creation on first write and the tracked blocks.gen.json. The stub now hashes blobs the way git does, so versions computed from content agree with its tree. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01WNwbSEePYNcY5YCgqZURig
useContentBackend decides, per project and branch, whether the editor reads and writes the legacy way or through the Blocks content protocol: a connected deco serve, or Studio's GitHub backend when a Fast Preview session's branch has a committed schema. Behind the org flag; pending while the flag or the probe loads, so a project never switches backends mid-read. On the protocol, useDecofile and useLiveMeta poll blocks.list and schema.get with ifNoneMatch at describe.pollIntervalMs and on focus, the write hooks send one blocks.apply each and adopt its revision, and a poll keeps entries still being saved. On GitHub the draft pointer comes from the new draft-grant route plus the list revision. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01WNwbSEePYNcY5YCgqZURig
/connect#endpoint=…&token=… (the link deco serve prints) takes the connection out of the fragment, keeps it for the tab across the login redirect and hands over to /$org/connect, which calls describe (Chrome's Local Network Access prompt), lets the editor pick the project and opens its site editor. The connection is stored per project in this browser. The site editor shows a Local server chip with Disconnect, says when the server restarted with a new token or isn't running, and hides the publish and terminal surfaces: the developer commits. Image and file uploads go to PUT <server>/assets/<name> when describe.assets allows. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01WNwbSEePYNcY5YCgqZURig
- A key in the manifest is a block type, so short names like `hero` aren't read as saved blocks, are offered in block pickers, and can't be taken by a new saved block. Without the manifest, the module-path heuristic is unchanged. - Lazy<T> fields render the form of T and store the lazy block around the value; `lazy` is never offered as a pick. The built-in `multivariate` keeps each variant's value in a lazy block; the legacy names keep plain values. - Redirects list and edit the flat `redirect` shape next to the nested one, keep the shape they were read in, and edit its optional status (301/302/307/308). New redirects stay nested. - On the protocol, Secret fields are write-only: what an editor types is encrypted in the browser with describe.secrets.publicKey and only the secret block with its ciphertext is saved. v7 secrets say they can't be edited there. The content protocol never runs site code, so on it: - the preview is the real app (the draft on GitHub, the dev app for a connected deco serve) with no in-place /live/previews renders; - the add-section gallery shows each block's name, description and schema @image instead of rendered thumbnails; - loader-backed pickers fall back to the schema's options or free text; - Run, runnable loaders and actions, and app install are hidden. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01WNwbSEePYNcY5YCgqZURig
A stand-in deco serve (the protocol's handler over an in-memory working tree, on 127.0.0.1 with a token) is connected through /connect; the spec edits a field, a Lazy<T> field (stored wrapped) and a Secret field, and checks the stored ciphertext decrypts with the test's private key while the plaintext appears in no stored file and no request. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01WNwbSEePYNcY5YCgqZURig
Documents the site_editor_content_protocol flag, when a project uses the content protocol (a Fast Preview branch with a committed schema, or a connected deco serve), connecting deco serve, and what works differently because the site's code never runs. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01WNwbSEePYNcY5YCgqZURig
The SEO autosave read the latest page block from a hard-coded cache key, which a connected deco serve doesn't use. Also drops exports nothing imports any more. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01WNwbSEePYNcY5YCgqZURig
Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01WNwbSEePYNcY5YCgqZURig
…ew server The content-protocol storage and the commit coalescer share the commit message builder. Only the rpc route skips the preview-server check: a draft grant has nothing to point at without one. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01WNwbSEePYNcY5YCgqZURig
Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01WNwbSEePYNcY5YCgqZURig
Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01WNwbSEePYNcY5YCgqZURig
/connect is now a root route (the deco serve connect link), so an org with that slug would be shadowed. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01WNwbSEePYNcY5YCgqZURig
Fixes: - Pages come from the manifest's pages group (the built-in page and route blocks like post), and new pages use the built-in page type. - Connect links accept only a server on this machine, and the connect screen shows the server and folder before a project is picked. - The legacy secret field (which posts plaintext to the site) renders only on the legacy backend; undecided or unreachable shows a message. - A failed GitHub probe makes the backend unavailable and retries, instead of routing a protocol site to the legacy path for good. - A deco serve that restarted or stopped is detected on the next read or write, so the chip says why. - Uploads respect describe.assets.maxBytes; /assets thumbnails load from the dev app on a deco serve connection. Cuts: - One batched blocks.list + schema.get per poll, shared by the decofile and schema hooks (as the protocol docs describe), replacing two pollers and the probe's schema reuse. - The draft grant is a cached query; saves no longer fetch it. - ContentCapabilities becomes isProtocolProject; the git-status invalidation, cache-key choice, unavailable error and localStorage mirroring each live in one place; the connect routes share the default org resolution and layout with the home route. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01WNwbSEePYNcY5YCgqZURig
/site-editor is now a root route (the account-less site editor over deco serve), so an org with that slug would be shadowed. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01WNwbSEePYNcY5YCgqZURig
The link deco serve prints becomes /site-editor#endpoint=…&token=…: just the site editor, talking the content protocol to the server on this machine, with no sign-in, org, project or GitHub. The connection leaves the URL at once and is kept for the tab (sessionStorage); only loopback servers are accepted. /connect redirects there for older CLIs, and the signed-in /$org/connect project picker is gone. The editor gets a placeholder project whose org has no id: useVirtualMCP and the org-settings read skip themselves without one, and TabDecoServeConnectionContext hands every surface the tab's connection. The header shows a v8/v7 badge (ContentVersionBadge). Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01WNwbSEePYNcY5YCgqZURig
Pasting a deco serve link into Advanced → Local checks the server answers describe, then edits the project over the content protocol (v8); any other URL keeps today's tunnel behaviour (v7). The local path no longer needs the site_editor_content_protocol flag: a connection exists only once its link was pasted, so v7 sites are untouched. The GitHub backend stays behind the flag. The logged-in editor header shows the v8/v7 badge. The e2e spec covers the account-less /site-editor (through a /connect link) and the signed-in Local option. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01WNwbSEePYNcY5YCgqZURig
Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01WNwbSEePYNcY5YCgqZURig
PostHog captures the first pageview before the router strips the fragment, so /connect#…&token=… reached $current_url. Drop token from the hash in sanitizeAnalyticsUrl. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01WNwbSEePYNcY5YCgqZURig
Signed in, the user pastes the link rather than opening it. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01WNwbSEePYNcY5YCgqZURig
Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01WNwbSEePYNcY5YCgqZURig
Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01WNwbSEePYNcY5YCgqZURig
Docs say the site editor reconnects on its own and remembers the server; the analytics token= redaction and the storage-key comment go; connect links must be loopback hosts deco serve accepts (no *.localhost) and the /rpc path; the waiting screen tells a non-default origin to pass --allow-origin. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01WNwbSEePYNcY5YCgqZURig
A "Settings" row in the Content sidebar opens the form of the site's `CMS` block (type `cms-settings`: preview hosts, telemetry, analytics), from the schema. With no block yet the form shows the defaults and the first change creates CMS.json through blocks.apply. Offered only on content-protocol sites whose schema describes the type (published 8.1.0-next.3 does not); v7 sites are unchanged. A block named CMS of another type is not edited. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01WNwbSEePYNcY5YCgqZURig
The first save of the CMS settings block while it's absent sends
blocks.apply with ifMatch { CMS: null }, so a CMS block created meanwhile
(of any type) is never replaced. A refused save re-reads the content once the
branch's writes settle, so the editor shows the saved block or explains one
of another type; after a guarded save lands, saves are unguarded like any
other block. The guard threads through useSaveBlock / useDebouncedSaveBlock
(SaveGuard, decided when the save runs) to applyProtocolPatch; only the
content-protocol backend sends it.
e2e: the first save's request carries the guard and the second doesn't; a
CMS of another type written behind the editor's back survives the first save
and the editor explains it.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01WNwbSEePYNcY5YCgqZURig
/site-editor with no link now shows a guide inside the app shell instead of "This site editor link is incomplete": what the editor is, the command to copy (with --allow-origin only off the official Studio origins), a status line while Studio looks for deco serve on its own (remembered server, then 127.0.0.1:4545; one probe at a time, 3s timeout, 1s->15s backoff, paused while the tab is hidden, asks first where Chrome would prompt for local network access), and a "Using another port?" field that takes the printed link, an address or a port. Docs links come from one constant (BLOCKS_DOCS_URL). Probe failures are classified (not answering, out of date, version mismatch, another program on the port, server error) and every connection, schema, read-only, save and upload state says what happened and what to do next, in en and pt-br. Disconnect keeps that server out of discovery for the session. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01WNwbSEePYNcY5YCgqZURig
- Show the guide inside the same framed Site Editor panel as the editor. - Command box: copy button sits inside it and the command wraps only between words (it broke mid-flag and squeezed into a column on phones). - Keep inline code on one line; shorten the --allow-origin note. - Show a found-but-unusable server inside step 2, where detection lives, so step 1 stays first. - Steps: number beside the heading, full-width body on phones. - Docs links: label above, links on one row. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01WNwbSEePYNcY5YCgqZURig
/site-editor looks for deco serve at the link's endpoint, or else the last one used and the default port. If it answers, the editor opens; if not, the guide shows and keeps looking (backing off, paused while the tab is hidden) and opens the editor as soon as it answers. When the server stops answering while editing, the guide comes back until it does. Removed: the chip's Disconnect, the session list of disconnected servers, the disconnected/Reconnect notice, the "Using another port?" field, the gate's "Try now"/"Use a different server" and its not-answering guidance, and the "paste another address to switch" copy. Guidance stays only for a server that answered but can't be used (out of date, version mismatch, another program, error, no schema, read-only). The Chrome local-network button is a single plain button, shown only where Chrome would ask first. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01WNwbSEePYNcY5YCgqZURig
The redesigned blocks editor is on for every content-protocol (v8) site: `deco serve` on /site-editor, the signed-in Local draft option and the GitHub-backed protocol. v7 sites keep following the org's `new_blocks_editor` flag. One rule decides (`newBlocksEditorEnabled` in content-backend): protocol or unavailable-protocol backend -> on; legacy -> the org flag; no site (org settings) -> the org flag; no org (/site-editor) -> no flag to read, so v8 is on and nothing waits on org settings. While the backend is still being detected it is undecided (unless the flag is on), and the Blocks panel, the Content browser and the page JSON panel keep their loading state instead of flashing the old editor and swapping. `NewBlocksEditorProvider`, mounted by the Content and Preview tabs, probes the site's backend once for everything below it; `useNewBlocksEditor()` reads it with the flag. The org settings switch reads the flag itself and now says it applies to v7 sites. Forms carry `data-blocks-editor` so the deco serve e2e asserts the new editor with no org and with the flag off; its selectors follow the guided-first-run copy. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01WNwbSEePYNcY5YCgqZURig
deco serve now answers every origin, so the guided empty state shows plain `npx @decocms/blocks serve` on any Studio origin. Removed the --allow-origin command variant, the "You're using Studio at…" paragraph and its en/pt-br strings, and the official-origin check (needsAllowOrigin/serveCommand). The e2e deco serve stub reflects any Origin like deco serve does, instead of taking an allowed one. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01WNwbSEePYNcY5YCgqZURig
…ard patch next.4 ships the legacy website/loaders/secret.ts exemption, so the bun patch for next.3 is gone; legacy-secret-guard.test.ts passes without it. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01WNwbSEePYNcY5YCgqZURig
The default endpoint is http://localhost:4545/rpc and every label shows localhost:<port>. Links and remembered endpoints on 127.0.0.1 or [::1] still open and are read as localhost, so a stored 127.0.0.1 server and a new localhost link are the same server. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01WNwbSEePYNcY5YCgqZURig
With no .deco/schema.gen.json yet, the v8 site editor (/site-editor and the Local draft) no longer stops at a "forms haven't been generated" gate or a "Blocks unavailable" error: - The poll reads "no schema" (schema.get's schema: null, or NotFound from an older deco serve) as an empty, marked schema, so the blocks still load and the next poll asks again until the real schema replaces it. - Content lists every saved block, grouped by __resolveType and sorted by name, with a search. A block opens as plain fields inferred from its JSON (text, numbers, switches, nested groups and lists) plus the existing raw JSON editor. An edit replaces only the value it touched, so a save keeps every other value, its type and the key order. Autosave as usual; pending edits are saved when the schema arrives and the regular editor takes over. - Preview's Blocks panel shows the current page the same way. - One calm banner on top: forms get proper fields once the schema exists, `npx @decocms/blocks schema` with a copy button, and a docs link. It goes away on its own once the schema appears. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01WNwbSEePYNcY5YCgqZURig
The docs moved from decocms/blocks to deco-sites/docs-tanstack (published at docs.decocms.com/storefront/blocks). Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01WNwbSEePYNcY5YCgqZURig
Drop the overlay preview protocol (POST /preview, revisionOnBranch,
site-connection, overlay uploads, /api/_delivery, overlay grants and site
tokens, the "Preparing preview" state). v8 drafts use v7's Fast Preview
pointer; the only change is what it answers:
- GET .../:branch/changes (draft token or session, org flag) returns
{format: 1, set, delete}: what the branch changed against production
since their merge base, computed from Git per request (draft wins per
file). A branch that doesn't exist yet changed nothing; over 8 MiB is 413.
- GET .../:branch/draft-token (session only) mints the pointer's token,
since saves over /rpc carry none. A token can't mint another.
- The legacy GET/PATCH are back to main: v7 sites are unchanged.
- The editor builds <apiHost>/api/<org>/decofile/<vmcp>/<branch>/changes
?token=…@<revision>; a failed token fetch shows "Preview unavailable".
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01WNwbSEePYNcY5YCgqZURig
Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01WNwbSEePYNcY5YCgqZURig
- Read only the merge base (compare?per_page=1 on GitHub, merge_base on GitLab/Bitbucket) instead of the full compare payload, which a branch far from production could time out on. - Reuse a computed answer for up to a minute per branch head. - A saved block that isn't valid JSON answers 422 naming its file. - Refresh the draft token an hour before it expires instead of every 30 minutes, so the preview iframe doesn't reload on every refresh. - Tests: delete-only branch, rename, deleting the winning spelling, malformed block, reuse. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01WNwbSEePYNcY5YCgqZURig
…Major
- api: @decocms/blocks is a devDependency (the server bundle inlines it), so
`bun add decocms` no longer links the Blocks CLI as `.bin/deco`; the Docker
image runs Studio's CLI by path. smoke-tarball checks the bin resolves to
Studio's cli.js and boots the Dockerfile command; deco-bin.test.ts guards
the package.json/Dockerfile.
- Pin @decocms/blocks to exactly 8.1.0-next.4 (api, web, e2e). bun.lock is
origin/main's plus only @decocms/blocks and its nested zod (bun 1.3.14).
- resolve-schema: a self-referencing type keeps its fields for 3 levels
(MenuItem.children: MenuItem[]) instead of none; still bounded for Product.
- v8 detection: a site is v8 only when its committed schema says
"blocksMajor": 8 (isV8Schema). A meta.gen.json/schema.gen.json without it,
a failed GitHub probe, or a form with no project id are v7 (legacy); the
probe retries quietly. No more "unavailable" GitHub state.
- Content-protocol routes read the org flag before anything else; a failed
read is off (404), never an error after a commit.
- Local option: a localhost/127.0.0.1/port whose deco serve probe fails is
saved as the v7 tunnel URL, as on main.
- v7-visible changes reverted: no v7 badge (v8 only), main's Local picker and
blocks-editor-setting copy, preview toolbar only for a deco serve preview,
visual edit unchanged on v7, recent apps as on main for projects,
async-render controls shown unless v8, no "backend unavailable" text while
the backend is being decided.
- e2e: GitHub protocol specs use a v8 schema ("blocksMajor": 8); new specs
show a flag-on org keeps meta.gen.json sites on the v7 editor, a
blocksMajor 8 site gets the v8 badge, and v7 decofile read/save still mint
draft tokens.
- Unexport 5 in-file-only symbols knip flagged; document the pre-deploy
`site-editor` org slug check at the route.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01WNwbSEePYNcY5YCgqZURig
…e rebase - Image field: main moved uploads into useImageUpload; the deco serve upload (v8 only) now goes through it as an optional serveUpload, and the /assets thumbnail retry sits on main's safeImageSrc. With no deco serve connection the field is main's, unchanged. - Delete/move keep main's Local-tunnel cache key and no-op persistence; the content-protocol path still runs first. - Drop the deno.json/package.json query keys main removed with use-blog-support. - bun.lock: main's lockfile plus only @decocms/[email protected] and its nested zod (bun 1.3.14, --frozen-lockfile passes). Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01WNwbSEePYNcY5YCgqZURig
The branch's "keep key-utils at the merge base" commit removed main's .avif content type once replayed on top of main; fs-bytes.test failed. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01WNwbSEePYNcY5YCgqZURig
The fields now ask useContentBackend (deco serve uploads, protocol secrets), which reads useProjectContext(); the bare CT mount has no provider. The stub answers legacy, which is what v7 sites see. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01WNwbSEePYNcY5YCgqZURig
tlgimenes
force-pushed
the
feat/blocks-v8-support
branch
from
October 6, 2026 18:50
24a7219 to
47ead55
Compare
Studio's CORS reflects its own and localhost origins with credentials, so the shared localhost API context never saw the pointer's `*`. A storefront on its own origin does, which is what the test means to check. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01WNwbSEePYNcY5YCgqZURig
…olved - repo-content-storage: serve the schema only when it says "blocksMajor": 8, and refuse any commit to a site whose schema at the base isn't v8, so a flag-on org can't write a v7 site over /rpc. - resolve-schema: array items whose $ref is a union (a matcher inside Multi) stay resolved as on main, so nested matchers keep their branch schema and defaults. resolveSchema over two real v7 metas now matches main on every block (76/76, 226/226). - e2e: a v7 schema over /rpc with the flag on is neither served nor written. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01WNwbSEePYNcY5YCgqZURig
…tions - /rpc answers carry the draft token and API host (X-Deco-Draft-Token, X-Deco-Api-Host), as v7's decofile read/save do; the separate GET .../draft-token route, its client and the failed-token preview card go. - The GitHub content storage no longer advertises refs or idempotency and ignores ref, matching the protocol that dropped them (the two description fields stay only for 8.1.0-next.4's types until the next bump). - e2e: describe without refs, tokens read from the rpc answers. Co-Authored-By: Claude Opus 5.5 <[email protected]>
…nce passes 8.1.0-next.4's conformance requires resolvedRef null without refs; the field is only a shim until the next @decocms/blocks bump. Co-Authored-By: Claude Opus 5.5 <[email protected]>
…urce Co-Authored-By: Claude Opus 5.5 <[email protected]>
A content-protocol (v8) project on GitHub now gets its draft token and API host exactly as v7 does: from the body of the session-authenticated GET /api/:org/decofile/:vmcp/:branch read, made on load and again after each save. The /rpc answers no longer carry X-Deco-Draft-Token / X-Deco-Api-Host, and the protocolDraftGrant cache with its 5-hour refresh rule is gone. Co-Authored-By: Claude Opus 5.5 <[email protected]>
…e shim - apps/api (dev), apps/web and packages/e2e pin 8.1.0-next.6 exactly; bun.lock changes only the @decocms/blocks entries (frozen install passes). - The GitHub content storage no longer describes refs/idempotency, which next.6 removed from the protocol. - e2e: a `ref` param on blocks.list is rejected again (Invalid params, an unknown parameter in next.6). Co-Authored-By: Claude Opus 5.5 <[email protected]>
8.1.0-next.6 answers schema.get without a schema as a result, not NotFound; the check is that it never reads as a v8 schema. Co-Authored-By: Claude Opus 5.5 <[email protected]>
- Accept main's retirement of the docs workspace (#7763): drop this branch's "Next-major Blocks sites" section in agentic-cms.mdx (en, pt-br); the Blocks/site-editor docs live in deco-sites/docs-tanstack. - bun.lock: main's lockfile plus only @decocms/[email protected] (and its nested [email protected]) for apps/api, apps/web and packages/e2e; every other package resolves exactly as on main. Co-Authored-By: Claude Opus 5.5 <[email protected]>
The merge staged main's bun.lock verbatim; add back only the @decocms/[email protected] entries (apps/api, apps/web, packages/e2e) and its nested [email protected]. `bun install --frozen-lockfile` accepts it unchanged; every other package resolves exactly as on main. Co-Authored-By: Claude Opus 5.5 <[email protected]>
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What is this contribution about?
The Studio site editor can now edit sites built on next-major Blocks (
@decocms/blocks@8) through the Blocks content protocol. Editing a localdeco serve(the account-less/site-editorroute, and the Local draft environment when signed in) needs no org flag; the GitHub-backed protocol is behind the org flag below. The editor reads the committed schema and.deco/blocksand never runs the site's code. All of it sits behind the default-off org flagsite_editor_content_protocol. With the flag off, Studio behaves as it does today.What's in
Protocol from
@decocms/blocks. Studio depends on the published@decocms/blocks, pinned exactly at8.1.0-next.6, and imports its public@decocms/blocks/protocol,/protocol/server,/protocol/conformance,/protocol/storage/fsand/secretssubpaths. See "How Studio gets the protocol" below.GitHub backend (API). It serves the protocol over a project's repository:
POST /api/:org/decofile/:virtualMcpId/:branch/rpcrunscreateContentHandlerfrom@decocms/blocks/protocol/serverover a storage built onRepoContentClient(apps/api/src/decofile/repo-content-storage.ts).schema.gen.json, thenmeta.gen.json, then the default branch. It is served only when it says"blocksMajor": 8; a v7 site reads as schemaless and any write to it is refused (Unsupported), so even a direct API call can't write a v7 site.blocks.gen.jsonis regenerated in the same commit (gen-artifact.ts, shared with the existing commit coalescer).GET .../changesanswers what the draft branch changed against production, for the site's?__draft=pointer. Like v7's read and save, every/rpcanswer carries the pointer's token (X-Deco-Draft-Token,X-Deco-Api-Hostheaders, since the body is the protocol's). See "Draft previews" below.Which backend a project uses (web). One selector decides:
deco serveconnection, which is always v8);deco serve→ protocol on the local server;cms) session whose branch has a committed schema → protocol on GitHub;Sandbox sessions stay legacy. A failed GitHub check is never read as "no schema": the project shows as unavailable and the check retries.
Reading and writing (web).
blocks.list+schema.getper poll, usingifNoneMatch, atdescribe.pollIntervalMsand on window focus.blocks.apply, and the client adopts the returned revision.?__draft=link is the v7 Fast Preview pointer, naming the branch'schanges(see "Draft previews" below). "Exit preview" still uses?__draft=off.Connecting to
deco serve. No token anywhere: Studio never sends one, ignorestoken=in old links, remembers the endpoint per browser, reconnects on its own, accepts only127.0.0.1/localhost/[::1]/rpcendpoints.7d1a2c79c:deco servenow answers every origin (blocks#619), so the empty state shows plainnpx @decocms/blocks serveon any Studio origin; the--allow-originguidance, its en/pt-br strings and the official-origin check are gone, and the e2e stub reflects anyOrigin.c97b68ba3:deco serveis onlocalhost(blocks#619): the default endpoint ishttp://localhost:4545/rpcand every label showslocalhost:<port>; links and remembered endpoints on127.0.0.1or[::1]still open and are read aslocalhost, so a returning user's stored server matches a new link.<studio>/site-editor#endpoint=…&token=…./site-editortakes the token out of the URL and keeps it for this tab only, so a reload keeps the connection. Signed in, the same link pasted into the draft selector's Local option connects a project.127.0.0.1,localhost,[::1],*.localhost).deco serve --read-only). There is no Disconnect: on/site-editorthe connection follows one rule (see "Guided site editor empty state"); in a project, choosing a draft in the selector leaves Local.PUT <server>/assets/<name>and respectdescribe.assets.maxBytes. On adeco serveconnection,/assets/…thumbnails load from the dev app.v8 content shapes.
pagesgroup, so the built-inpageand route blocks such aspostappear.Lazy<T>fields editTand save the{"__resolveType":"lazy","value":…}wrapper;lazyis never offered as a pick.multivariatewraps each variant's value inlazy; the legacy multivariate names keep plain values.status(301/302/307/308) anddiscardQueryParameters, and keep fields the editor doesn't know.Secret widget. Write-only:
describe.secrets.publicKey(RSA-OAEP/SHA-256 + AES-256-GCM, the protocol's ciphertext format). Only{"__resolveType":"secret","ciphertext":…}is sent..deco/secrets.pub.What isn't available on the protocol. Nothing renders in place, and the add-section gallery shows each block's name, description and schema
@image. Loader-backed pickers fall back to the schema's options or free text. Run, runnable loaders and actions, and app install are hidden.Settings (CMS settings block, v8). A "Settings" row in the Content sidebar opens the form of the site's well-known
CMSblock (typecms-settings: preview hosts, telemetry, analytics), from the schema. It knows only that name and type. It's offered only when the schema describes the type, so not on v7 sites or on8.1.0-next.3, and aCMSblock of another type gets an explanation instead of a form.CMS.jsonwith oneblocks.applyguarded byifMatch: { CMS: null }(b4bfc9124), so aCMScreated meanwhile, of any type, is never replaced.useSaveBlock/useDebouncedSaveBlock(SaveGuard, decided when the save runs) toapplyProtocolPatch. Only the content-protocol backend sends it.Other.
site-editoris now a reserved organization slug.agentic-cms.mdxwas dropped in the merge; see "Merged main" below for what still needs a home.Flag:
site_editor_content_protocol, off by default. It gates the GitHub-backed protocol only;/site-editorand the Local draft environment work without it. It is not inDEFAULT_ON_FLAGSand has no settings UI. Turn it on for an org withORGANIZATION_SETTINGS_UPDATE, passing{ "flags": { "site_editor_content_protocol": true } }.How Studio gets the protocol
From npm:
@decocms/[email protected](exact pin, dist-tagnext) is a dependency ofapps/api,apps/webandpackages/e2e. Nothing is vendored: the oldpackages/shared/src/vendor/blocks-protocol, itsSYNC.mdandscripts/sync-blocks-protocol.tsare gone. Every import maps to a public export:@decocms/blocks/protocolcreateContentHandler(GitHub endpoint, deco-serve e2e stub)@decocms/blocks/protocol/serverrunConformance(GitHub e2e)@decocms/blocks/protocol/conformancecreateFsStorage(deco-serve e2e stub)@decocms/blocks/protocol/storage/fsencryptSecret(secret field)@decocms/blocks/secretsThree pieces the vendored copy exposed have no public export, and the framework wasn't widened for them:
ciphertext,secrets):@decocms/shared/secret-ciphertextis a small reading of the documentedv1.<wrappedKey>.<iv>.<ciphertext>format. It checks that aSecretfield holds a well-formed ciphertext, and gives tests what they need to decrypt one. Encryption itself usesencryptSecret.storage/memory): the deco-serve e2e stub now runs the public filesystem storage in a temp working tree, likedeco serve, and reads the saved files from disk.server/assets): dropped from the stub, since no spec uploads.@decocms/blocksships TypeScript sources. Bun (API) and Vite (web) load them as they are. Playwright runs on Node, which won't strip types undernode_modules, so e2e imports the runtime pieces throughpackages/e2e/fixtures/blocks-protocol.ts. That file registers tsx first, the same way the package's owndecobin does.@decocms/blocksandtsxare on the e2e import allowlist.Async rendering is off on v8. v8 has no async rendering out of the box, so on v8 sites the site editor offers no async-render control on section rows or page SEO, and never writes a Lazy wrapper. The v7→v8 migration strips Lazy wrappers, so v8 shows no async-render UI at all. The controls appear only once Studio knows the site is v7, not while the backend is still being detected. v7 is unchanged.
Out of scope
ifSchemaMatch,ref/refsand read limits: removed from the protocol (v8 N-16: drafts are the fast-preview pointer, with only the branch's changes over the local release blocks#619). The GitHub storage is bound to the branch in the URL; since 8.1.0-next.6 itsdescribe()no longer returnsrefs/idempotency, and arefparam is rejected as an unknown parameter (Invalid params).ifMatchon ordinary saves (autosave is last writer wins). The one exception is Settings' first save, which is create-only.deco serveinside sandbox pods.Production safety
Verdict: safe to merge with
site_editor_content_protocoloff everywhere. An independent re-audit at7bd82f5b0found nothing that changes v7 sites; its two remaining code items are fixed ina01bb071f(see below). v7 behaviour equalsmain.Which sites are v8 (the
blocksMajorrule). The schema's file name (schema.gen.json/meta.gen.json) does not tell the version.deco schemawrites an explicit top-level"blocksMajor": 8, anddeco checkrejects a v8 schema without it. Studio treats a site as v8 only when its committed schema hasblocksMajor === 8(strict equality). Everything else is v7: a missing field,7,"8",9,null, a schema that doesn't parse, no schema file, or a failed GitHub read (retried every 5 s; a site already known to be v8 stays v8). The web (isV8Schema) and the API's/rpcstorage apply the same rule: on a v7 site/rpcreads as schemaless and refuses every write.Gating matrix
/rpc,/changessite_editor_content_protocol(a failed settings read answers 404)/rpcwith the flag on, v7 siteUnsupported)blocksMajor === 8at the branch headnew_blocks_editorflag as today, no badgeblocksMajor === 8mainresolve-schema)mainon every block of two real v7 metas (76 and 226 blocks)deco servediscovery, no-schema editor/site-editorroute and the protocol path onlymain; localhost probed asdeco serve(3 s) then saved as the tunnel/site-editorsite-editoris a reserved org slugdeco@decocms/blocksis a devDependency only;.bin/decois Studio's CLI8.1.0-next.6in api, web and e2eFixed after the re-audit (
a01bb071f)/rpcnow enforcesblocksMajorserver-side (repo-content-storage.ts):readSchemareturns no schema unless it is v8, andcommitthrowsUnsupported: not a Blocks v8 site. New e2e: a v7 schema over/rpcwith the flag on is not served and not written.resolve-schema.ts: array items whose$refis a union (a matcher inside Multi) stay resolved as onmain, so nested matchers keep their branch schema and defaults. Re-run over the two real v7 metas: 0 of 76 and 0 of 226 blocks differ frommain(previouslymulti.ts/negate.tsdiffered).Release order
docker buildthe API image and confirm/healthanswers (CI'sdocker-smokebuilds the sandbox image, not the API image).@decocms/blockswithBLOCKS_MAJOR(deco schemawriting"blocksMajor": 8), bump Studio's exact pin, and re-rundeco schemaand commit in each v8 site (storefront-tanstack, blog-tanstack, faststore). Until then no site is recognized as v8 (the safe failure: they stay v7)./rpc,/changes) and GitHub API usage / rate limiting for that org.How did you verify your code works?
Run on the final tree (
5d1756b52):bun run fmt:checkbun run lint(oxlint)bun run knippackages/runtime, a package this PR doesn't touch)bun run check(typecheck of every workspace)bun run testtsc --noEmitfor web, api, shared and e2e on every commit of the branchNew or updated unit tests:
pagetype for new pages;Lazy<T>and multivariate values;Upstream (Blocks protocol) tests:
vitest packages/blocks/src/protocol, 492 pass, plus a new test that a legacy secret loader block passes the secret guard.E2E.
content-protocol-deco-serve.spec.tspasses locally against the published package (4/4, and 8/8 with--repeat-each=2). With the Settings tests (b4bfc9124): 7/7 against the local framework link. Under a heavily loaded machine,refuses a link to a server off this machineonce missed its 5 s wait; it passed on every rerun.content-protocol-github.spec.tsloads and runs, but it needs the e2e API environment (the GitHub stub and its env). Against a plain dev server it fails on sign-up rate limits and on the missing stub, so CI is the signal for it.content-protocol-github.spec.ts:blocks.gen.jsonis regenerated;content-protocol-deco-serve.spec.ts:CMS.jsonwithifMatch: { CMS: null }; the second save carries no guard;CMSof another type written behind the editor's back survives the first save, and the editor explains it;/site-editorlink flow, including that the server address is shown;Lazy<T>field (stored wrapped) and a secret: the stored ciphertext decrypts with the test's key, and the plaintext never appears in storage or in a request.Run them with
bun run --cwd=packages/e2e test:e2e content-protocol. The existingdecofile-api.spec.tsandfast-preview-git-sync.spec.tsare unchanged.Screenshots/Demonstration
To add: the
/site-editorscreen (server address and folder), the "Local server" chip, the secret widget, and the page list on a v8 site.How to Test
site_editor_content_protocolfor a test org..deco/schema.gen.json.?__draft=….npx @decocms/blocks serve --preview localhost:<app port>(with the app's dev server running) and open the/site-editor#endpoint=…link it prints (no token:deco servehas none)./site-editor#endpoint=https://example.com/rpc&token=x: you should see "This site editor link is incomplete", in the New Layout whatever the preference says./rpcand/changesreturn 404.Migration Notes
site-editoris now a reserved org slug. Before deploying, confirm no existing organization uses it (SELECT id, slug FROM organization WHERE slug = 'site-editor';must return no rows); I couldn't check production data. The check is also documented next to the route inapps/web/src/router.tsx.Follow-ups
8.1.0-next.6to the stable@decocms/blocks@8once it's released.ifMatchon every save, with managed drafts.deco servein sandbox pods, so sandbox sessions on v8 sites can use the protocol.Review Checklist
/site-editoris reachable only by URL; the Local option keeps today's tunnel behaviour for any non-deco serveURL)🤖 Generated with Claude Code
https://claude.ai/code/session_01WNwbSEePYNcY5YCgqZURig
Draft previews: the Fast Preview pointer, changes only
v8 keeps v7's Fast Preview protocol: the site gets a
?__draft=pointer and fetches it. The only change is what the pointer answers: what the draft branch changed against production, not the whole decofile. The site'scms.forDraft(pointer)layers it over the production content it already has (blocks docs:/next/content-delivery#draft-previews; SDK side: decocms/blocks#619).Pointer (same shape as v7, with a
/changessuffix)<apiHost>/api/<org>/decofile/<vmcp>/<branch>/changes?token=<draft token>@<revision>.signDraftToken): HMAC-signed, scoped to org, project and branch, 6 hours./rpcanswer (session only, so a draft token can never mint another) carries it in theX-Deco-Draft-TokenandX-Deco-Api-Hostheaders. The editor's protocol client stashes it, and replaces it only an hour before its 6-hour expiry, so polling doesn't reload the preview iframe. There is no separate token route.Answer (
GET .../changes,apps/api/src/decofile/draft-changes.ts){format: 1, set: {name: block JSON}, delete: [names]}, computed from Git on every request. Nothing is prepared or stored.RepoContentClient.mergeBase(GitHub:compare?per_page=1, reading onlymerge_base_commit; GitLab/Bitbucket: their merge-base endpoints), never the full compare payload, so a branch far from production doesn't time out:getBranchcall. A new save is a new head.{format: 1, set: {}, delete: []}), so a pointer minted before the first save works.Cache-Control: no-store,Access-Control-Allow-Origin: *.{error, file}names it), 502 for the Git provider./changesthe way the v7 anonymous read projects them (projectPlanningPostsForPreview), so they don't show in v8 previews yet. Documented; blog-tanstack doesn't use drafts today.v7 unchanged
GET .../:branchandPATCHbehave exactly as on main: whole decofile for the anonymous?token=read, and a fresh token on every editor read and write.Editor
useProtocolDraftbuilds the pointer from the stashed token and the current revision. There is no readiness state: until the first/rpcanswer there is no pointer, as with v7 before its first read.Tests
draft-changes.test.ts: merge base, aliases,__proto__, app roots, missing branch, size limit, delete-only branch, rename (delete + set), deleting the winning spelling of an aliased name, malformed block JSON, per-head reuse.content-protocol-github.spec.ts): flag off and anonymous access,/rpcanswers carry the token and a token can't call/rpc, a save shows only its changes in/changes, the token is scoped to its branch, and the v7 read of the same branch still returns the whole decofile.decofile-api.spec.ts(v7) is unchanged.Replaced the overlay delivery with the changes pointer
POST .../preview,revisionOnBranch,GET .../site-connection, the/rpcpost-commit overlay hook, overlay uploads to object storage,/api/_delivery(draft-delivery.ts), overlay grants and site tokens, the "Preparing preview" state anddraft-preview-loop.test.ts(it ran the overlay SDK; the changes SDK isn't published yet).draft-token.ts,paths.ts,key-utils.tsandorg-fs.tsare back to main.Testing v8 locally
/site-editor(no account): a top-level route that is not gated: no org flag and no preference. It always renders in the New Layout (the project-first app takeover), even when the user's New Layout preference is off; a route-scoped override (ForceProjectFirstNav, set only byroutes/site-editor.tsx) does that without a second copy of the layout. It opens the same Site Editor app a project launches (its Preview and Content tabs; Preview has the page picker; Content edits blocks and saves throughdeco serve), full screen with no sidebar. Hosted features are hidden: no chat, GitHub, drafts, publishing/releases or Code tab. It talks to a localdeco serveover the content protocol. The connection arrives in the URL (/site-editor#endpoint=…&token=…); Studio removes the token from the address bar, keeps it for that tab only, and strips it from analytics. Only servers on this machine are accepted./:org/:project/site-editor(and its Content and Code tabs) and at/site-editor. Signed in on/site-editor, the rail lists the user's orgs, then the Site Editor entry, highlighted (aria-current="page", linking to/site-editor); signed out there is no rail. There is no org there, so no recent app is recorded.storefront-tanstack(feat/next-major,@decocms/[email protected]) withdeco serve --preview localhost:5190, driven with Playwright, signed out at/site-editorand signed in through a project's Local environment: the schema loads (recursive commerceProducttypes no longer freeze the tab), the preview frames the real storefront, a text edit lands in.deco/blocks/pages-home.jsonand shows in the preview about 2s later, and Replace image uploads throughdeco serve(/assets/<name>). Site-side fixes that made this work: frame loads getframe-ancestorsfor Studio instead ofX-Frame-Options: SAMEORIGIN,vite devskips the edge cache, and the dev server reloads open pages when the content module changes.deco servereports the app URL in the content protocol's describe (describe.preview.url). Set it withdeco serve --preview localhost:8001(host:port or a full URL); by default it readsserver.portfrom the Vite config, elsehttp://localhost:5173. Studio loads it in the Preview tab only if it is a loopback URL. The signed-in Local draft environment uses the same value.deco servelink and Studio checks the server answers, then switches the project to v8 (inline errors when the server stopped or restarted with a new token). Any other URL is a tunnel, handled exactly as today (v7). Works for every org without a flag; the GitHub-backed protocol stays behindsite_editor_content_protocol.x-deco-matchers-override, so a variant tab forces its variant in the preview's?__draft=pointer instead. It adds one reserved__variant=<block>@<path>=<index>parameter per forced variant, andcms.forDraftapplies them (v8 N-15: preview a forced variant through the draft pointer; dev reload recipes blocks#618). For localdeco serveit is a pointer to the serve endpoint carrying only the forced variants, never the token. On the GitHub backend they go into the Fast Preview pointer. v7 projects keep the header. Verified live against storefront-tanstack: variant 2 shows on its tab, variant 1 comes back on its tab, and a forced variant survives the reload after a save.v8badge with a tooltip in the header of/site-editorand the signed-in site editor, on v8 sites only. v7 sites show nothing new./site-editor(no org) and signed in, whatever the org'snew_blocks_editorflag; v7 sites keep following the flag. While the site's version is detected the editor stays in its loading state instead of flashing the old one (bbf06e2).Guided site editor empty state
/site-editorfollows one rule, with no way to disconnect:#endpoint=…, which wins), or else the last one used in this browser, then the default127.0.0.1:4545.The empty state explains the site editor, shows the
deco servecommand to copy (with--allow-origin <origin>when Studio isn't on an official address), the "Looking for deco serve on …" line, and docs links.deco serveon another port prints a link with#endpoint=…; opening it is how you reach that port (there is no address field). On a deployed Studio that doesn't have Chrome's local-network permission yet, a single "Look for deco serve on this computer" button starts the search, so Chrome's prompt comes after a click; a denied permission is explained.Guided messages remain only where the server answered but can't be used: out of date (asks for a token), version mismatch, another program on the port, an error, and read-only (chip). Verified headless with Playwright: a fresh context with nothing on 4545 shows the empty state;
/site-editor#endpoint=http%3A%2F%2F127.0.0.1%3A4547%2Frpcopens the storefront editor; stopping the server returns to the empty state and restarting it reopens the editor; no disconnect control anywhere.No schema yet (
72ce0c33c): without.deco/schema.gen.json, the editor (/site-editorand the Local draft) still opens. Content lists every saved block grouped by__resolveType; a block opens as plain fields inferred from its JSON plus the raw JSON editor, and a save keeps every untouched value exactly; Preview's Blocks panel shows the current page the same way. One banner (npx @decocms/blocks schemawith copy, docs link) goes away on its own when the schema appears. Readsschema.get's newschema: null(decocms/blocks#619766b0ff7) and an older server's NotFound alike. Verified headless with Playwright on a storefront-tanstack copy with the schema removed: list, open, edit and save round-trip, thendeco schemaand the banner left.Framework side: decocms/blocks v8 stack #602–#614 (spec: decocms/blocks#585). Studio consumes it as
@decocms/[email protected]from npm.🤖 Generated with Claude Code
https://claude.ai/code/session_01WNwbSEePYNcY5YCgqZURig
Summary by cubic
Adds editing Blocks v8 sites through the Blocks content protocol, from published
@decocms/[email protected]. A site is v8 only when its committed schema says"blocksMajor": 8; legacy projects are unchanged. A localdeco serveneeds no org flag; the GitHub-backed protocol sits behind the default-offsite_editor_content_protocolflag.What changes
POST /api/:org/decofile/:virtualMcpId/:branch/rpcserves the protocol over the repository (git blob shas as versions, branch head as revision), regeneratesblocks.gen.jsonin the same commit, and refuses any read or write on a v7 site.GET .../changes, which answers{format:1, set, delete}— what the branch changed against production since their merge base, computed per request and cached briefly per head. The token comes from the v7 decofile read body, fetched on load and again after each save./site-editorand the signed-in Local draft connect to a loopbackdeco servewith no token; the GitHub-backed protocol needs the flag.blocks.list+schema.getwithifNoneMatch; each save is oneblocks.applyadopting the returned revision.Lazy<T>wrappers, the built-inmultivariate, flat redirects with optionalstatus/discardQueryParameters, and write-onlySecretfields encrypted in the browser.cms-settingsblock; the first save is create-only, guarded withifMatch {CMS: null}. With no schema yet, blocks open in plain fields inferred from their JSON plus the raw JSON editor.?__draft=pointer through reserved__variantparameters.PUT <server>/assets/<name>withindescribe.assets.maxBytes; the preview loadsdescribe.preview.url(loopback only); the add-section gallery shows schema images since site code never runs.@decocms/blocksis a devDependency in the API, so the Docker image runs Studio's CLI by path and the Blocksdecobin never shadows it. Before deploying, confirm no existing org uses the now-reservedsite-editorslug.Since the merge with main, the studio docs moved to
deco-sites/docs-tanstack(main retired the docs workspace) and thebun.lockis main's plus only the pinned@decocms/[email protected]and its nested zod.Written for commit 55f6063. Summary will update on new commits.
Moved to published @decocms/[email protected]
apps/api,apps/webandpackages/e2enow depend on@decocms/blocks@^8.1.0-next.3from npm (compiled dist);bun.lockhas no local paths.Dropped the tsx raw-
.tsloader (packages/e2e/fixtures/blocks-protocol.ts) andtsxfrom e2e devDependencies; e2e fixtures import@decocms/blocks/protocol/{server,storage/fs,conformance}directly.Typecheck, lint, fmt, knip, unit tests (1391 pass) and both builds pass. Two GitHub content-protocol e2e failures predate this bump (spec expects
preview.originwhere the protocol returnspreview.url; the legacy-secret fixtureencrypted: "0a1b2c3d"is rejected as malformed ciphertext) and are tracked separately.Fixed both GitHub content-protocol e2e failures (3332863): the spec now expects
preview.url, and a bun patch carries the dropped upstream legacywebsite/loaders/secret.tsexemption (blocks ccdf6c25) into @decocms/[email protected] until a release includes it; v8 secrets stay strict.Removed the v8 unwrap-only "Disable async rendering" control (2f3f994): the v7→v8 migration strips async-render wrappers, so v8 sites show no async-render UI; v7 is unchanged.
On published @decocms/[email protected]
apps/api,apps/webandpackages/e2enow depend on@decocms/blocks@^8.1.0-next.4(bc5b85e).website/loaders/secret.tsexemption upstream, sopatches/@decocms%[email protected]and itspatchedDependenciesentry are removed.legacy-secret-guard.test.tspasses without it; v8Secretfields stay strict.On published @decocms/[email protected]
apps/api(devDependency),apps/webandpackages/e2epin@decocms/blocksexactly at8.1.0-next.6(b163a2d).bun.lockchanges only the@decocms/blocksentries (version + integrity; its deps and peers are identical to next.4), andbun install --frozen-lockfilepasses, so every other package resolves as before.repo-content-storage.ts(refs,idempotency: nullindescribe()) is gone; the e2e check thatblocks.listrejects arefparam is back (now-32602Invalid params: an unknown parameter).schema.getwithout a schema as a result instead of NotFound; the v7-site e2e check now asserts it never reads as a v8 schema (4a1e921). next.6 also ships the SDK side of the draftchangespointer.Merged main (a702910, 55f6063)
origin/main(no rebase;feat/blocks-v8-hostedstays stacked on this branch).apps/docs, includingagentic-cms.mdx(en and pt-br), which this branch had extended. The Blocks site-editor docs live indeco-sites/docs-tanstack(storefront/blocks/next/site-editor.mdx), which already coversdeco serve,/site-editor, uploads topublic/assets/, write-only secrets via.deco/secrets.pub, schema-only pickers and gallery cards. These Studio-side details from the dropped section have no home yet:"blocksMajor": 8; any other site keeps the v7 editor, and v8 sites show a v8 badge.deco servelink, checks the server answers before switching, shows a Local server chip, reconnects on restart, and leaves Local when a draft is chosen. A tunnel URL there still works for v7 sites.127.0.0.1and[::1]links open aslocalhost."blocksMajor": 8and the org hassite_editor_content_protocol(off by default): each save is one commit on the draft branch, the schema comes from that branch (or the default branch), and the preview gets a?__draft=link. Sessions with a sandbox stay on the existing path.@decocms/[email protected](apps/api, apps/web, packages/e2e) and its nested[email protected]: a 7-line diff against main.bun install --frozen-lockfileaccepts it unchanged, so every other package resolves exactly as on main.apps/api/package.json,apps/web/src/router.tsx,query-keys.tsandtool-io.tsmerged cleanly. v7 behaviour is main's.