Repository navigation
Conversation
…ent, the router and decoTanstack() Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WNwbSEePYNcY5YCgqZURig
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WNwbSEePYNcY5YCgqZURig
…only on its Deco hosts, as in v7 The worker deferred to cms.draftPointer whenever previewHosts was unset, so a site with no preview hosts in its CMS block previewed drafts on every host (blocks' default). v7's allowlist had no such default: without a declared list a site previewed only on <site>.deco.site and <site>.deco-cx.workers.dev. declaresPreviewHosts() tells a declared list (including an explicit "*") from blocks' default; blocks' own behaviour is unchanged. The smoke app declares 127.0.0.1 in its CMS block. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WNwbSEePYNcY5YCgqZURig
Brings in the PO review of P1-P3: @decocms/blocks no longer exports the draft names, draftResponseHeaders() or Studio's origins, /image is platform-neutral, and StudioBridge takes trustedOrigins from the binding. CLAUDE.md conflict: both sides' tests/ and examples/ lines kept. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WNwbSEePYNcY5YCgqZURig
…ponse headers and Studio's origins Moved from @decocms/blocks, unchanged values (PO review of #693): a new browser-safe root export with DRAFT_PARAM, DRAFT_COOKIE, DRAFT_HEADER, draftResponseHeaders (src/draft.ts) and STUDIO_ORIGINS, STUDIO_FRAME_ANCESTORS, isStudioOrigin (src/studio.ts). The worker, /server and the frame-ancestors use them; DecoDocument passes STUDIO_ORIGINS to StudioBridge's now required trustedOrigins, the list the bridge answered before. Tests moved with them, plus one that the bridge gets Studio's origins and one that the package depends on no @decocms/apps-* package. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WNwbSEePYNcY5YCgqZURig
tlgimenes
added a commit
that referenced
this pull request
Oct 14, 2026
…draft names and Studio's origins Brings in the PO review: @decocms/blocks no longer exports the draft names, draftResponseHeaders or Studio's origins (#693), @decocms/blocks/image is platform-neutral with the VTEX and Shopify helpers in @decocms/apps-vtex/image and @decocms/apps-shopify/image (#694), StudioBridge takes its trusted origins from the binding (#695), and @decocms/tanstack owns its own copy (#696). CLAUDE.md conflict: tests/ (helper guardrails) and examples/ lines combined. @decocms/nextjs, in the same commit so every package type-checks: - src/draft.ts (DRAFT_PARAM/COOKIE/HEADER, draftResponseHeaders) and src/studio.ts (STUDIO_ORIGINS, STUDIO_FRAME_ANCESTORS, isStudioOrigin): the package's own copy, same values as @decocms/tanstack's, never imported from it. The proxy, drafts.ts, /server and config.test.ts use it; the root exports it. - StudioBridge (src/StudioBridge.ts): blocks' bridge with trustedOrigins set to STUDIO_ORIGINS, so the layout still passes only the site. - /image-loader stays platform-neutral; its next/image golden comparison moves to tests/nextjs-image-loader.golden.test.ts, which composes @decocms/apps-vtex/image with decoCdn as a Next storefront does: 1,212 cases from blocks' and apps-vtex's fixtures, none changed. exports.test.ts pins that the package depends on no @decocms/tanstack or @decocms/apps-*. - nextjs-binding-smoke: decoCdn({ fit: "contain" }) (blocks' default fit is now cover) and a check of the origins the bridge answers. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WNwbSEePYNcY5YCgqZURig
tlgimenes
added a commit
that referenced
this pull request
Oct 14, 2026
Brings in the PO review down the stack: blocks without the draft names or Studio's origins (#693), the platform-neutral @decocms/blocks/image with the @decocms/apps-vtex/image and @decocms/apps-shopify/image helper subpaths (#694), StudioBridge's required trustedOrigins (#695), and each binding's own copy of the draft names and Studio's origins (#696, #697). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WNwbSEePYNcY5YCgqZURig
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WNwbSEePYNcY5YCgqZURig
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WNwbSEePYNcY5YCgqZURig
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WNwbSEePYNcY5YCgqZURig
Brings P1-P3's PO decisions (NODE_ENV dev mode, first-match multivariate, deco schema --check, decoCdn leading strip, edit shortcut on by default). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016ZsmzpZ2zahRBoATBb2tBu
… default DecoDocument no longer defaults editShortcut to false, so the "." shortcut follows @decocms/blocks/preview's default (on). An explicit false still turns it off (PO decision 4, 2026-10-15). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016ZsmzpZ2zahRBoATBb2tBu
…utes responses A `routes` response is another origin's page (a proxied checkout, an A/B test's other site); the worker's `preload` hints name this app's assets, so it no longer appends them there. Security headers and CDN-Cache-Control still apply at the single exit. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016ZsmzpZ2zahRBoATBb2tBu
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016ZsmzpZ2zahRBoATBb2tBu
The "." shortcut now opens the page on screen in Studio: DecoDocument reads `pathTemplate` (and optionally `pageId`) from the deepest matched route's loader data, as v7's document read its CMS route's `path` and `blockKey`, and passes it to StudioBridge. It re-renders with the router, so a client-side navigation sends the next page. A route that returns neither leaves Studio to pick the page from the URL. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016ZsmzpZ2zahRBoATBb2tBu
…e's own document A site whose layout DecoDocument can't express (a skip link before <main>) kept its own document and rendered only StudioBridge, so its draft pages had no "Preview mode" badge and "." sent no page template. DecoPreview is what DecoDocument mounts for Studio and drafts, on its own: the request's draft (and CDN segment token) published to the browser, StudioBridge with the page on screen, and DraftBadge. DecoDocument renders the same pieces. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016ZsmzpZ2zahRBoATBb2tBu
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016ZsmzpZ2zahRBoATBb2tBu
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016ZsmzpZ2zahRBoATBb2tBu
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016ZsmzpZ2zahRBoATBb2tBu
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.
Brings
@decocms/tanstackback for v8 aspackages/tanstack. It is for TanStack Start on Cloudflare Workers, deployed the Deco way, and it is opinionated: there is onecreateDecoWorker({...}), an option only where a current site needs a different value, androutesas the one escape hatch. It depends only on@decocms/blocks. Stacked on #695 (P3).As you asked, the draft host allowlist lives here in the binding, not in the framework.
@decocms/blockskeeps its host behaviour unchanged.Per your review of #693, this package also owns what #693 had put in
@decocms/blocks. That means the draft names, the draft response headers and Studio's origins. Their values are unchanged: this is a move.@decocms/blocksexports none of them now.What's in it
.(root)DRAFT_PARAM(__draft),DRAFT_COOKIE(__deco_draft),DRAFT_HEADER(x-deco-draft),draftResponseHeaders(pointer)(no-store, private,Vary: Cookie,noindex),STUDIO_ORIGINS,STUDIO_FRAME_ANCESTORS,isStudioOrigin. No imports, browser-safe./workercreateDecoWorker. Server only./servercontentClient(cms, request?),requestDraft,markPrivate,isServerFnCall. Server only./startdecoServerFnFetch, safe in the client bundle./routercreateDecoRouter,decoParseSearch/decoStringifySearch,PAGE_STATUS_HEADER./reactDecoDocument,NavigationProgress,StableOutlet./vitedecoTanstack({ buildHash })andgitBuildHash()./scopeAsyncLocalStorage. It is a conditional export withworkerdandnodebeforebrowser.Always on in
createDecoWorker/deco/_livenessanswers OK./deco/*,/live/*and/.decofileanswer 404.frame-ancestorsfrom this package'sSTUDIO_FRAME_ANCESTORS, and noX-Frame-Options. v7's security headers are sent too.x-deco-draft, removing any copy that arrives from outside. Draft responses getno-store, private,Vary: Cookieandnoindex, and only a real draft skips the cache.matchRoutedoes.segmentparts. It does stale-while-revalidate and stale-if-error. Signed-in, private and degraded (x-deco-degraded) responses are never stored, and safe cookies are stripped from the stored copy.__cseg. The page publishes a segment token. The CDN may cache a GET server function only when the token in its URL matches the one the worker recomputes; every other response getsCDN-Cache-Control: no-store, set at one exit./fonts/are immutable.cf-cache-statusis dropped on a HIT.x-page-statussets the document's status.onCache({ profile, decision, ms, status })is the only metrics hook (D3).Draft host allowlist (D1)
This ports v7's
readAllowedHosts/isDraftHostAllowedas is.CMSblock's, orcreateCMS's). A site that declares none previews only on its Deco hosts, as in v7; blocks' own default (every host, forcms.draftPointer) is unchanged and isn't used by the worker.siteare always added, exactly:<site>.deco.siteand<site>.deco-cx.workers.dev.previewHosts: [...]is v7'sDECO_ALLOWED_PREVIEW_HOSTS: it replaces theCMSblock's list, and the Deco hosts stay allowed.previewHosts: "none"is the kill switch: no host previews, the Deco hosts and"*"included.?__draft=offends a preview on any host.Every one of these cases is tested in
worker.test.ts.The rest
decoTanstack({ buildHash: process.env.WORKERS_CI_COMMIT_SHA })uses the CI's sha (12 characters), thengit rev-parse --short=12, then the time, as v7 did.vite devgets"dev", and the package reads no env.decoContent()stays in@decocms/blocks/vite;decoTanstack()only calls it.DecoDocumentrendersdata-theme="light", theDECO.eventsbus and thedata-eventobserver, the progress bar andStableOutlet, the published__csegtoken and draft,StudioBridge, andDraftBadge. It passesSTUDIO_ORIGINSas the bridge's requiredtrustedOrigins, which is the same list the bridge answered before feat: @decocms/blocks/preview, the draft badge and the Studio bridge #695 dropped its own copy. Its options arelang,bodyClassName,account,readyDelay,outlet(mainordiv),editShortcutandnonce.editShortcutis left to the bridge's default, so the "." edit shortcut is on unless a site passeseditShortcut={false}(PO decision 4, 2026-10-15).Tests
packages/tanstack: 123 tests.decoServerFnFetch.DecoDocumentSSR, including the origins it passes to the Studio bridge.draftResponseHeadersand Studio's origins (values pinned, lists frozen,isStudioOrigincases).@decocms/apps-*package.--conditions=workerd,worker,browser./react,/startand/router: nonode:, noAsyncLocalStorage, no CMS.examples/tanstack-worker-smokeis the existing smoke app moved onto the package.bun run smokechecks 25 headers and markers on workerd (vite preview, Miniflare). A new CI job,tanstack-worker-smoke, builds it and runs it.guides.cli.test.tsin-11 now allows the bindings. Both bindings and everyapps-*package depend only on@decocms/blocks.bun run checkpasses. The knip hint aboutesbuildis already on P3.bun run buildpasses. Plain Node imports the built root export.bun run skills:checkandbun run skills:readme:checkpass.bun run test: 2277 passed, 3 failed.delivery.cli.test.ts, the known failure.schema.test.tsunder full-suite load. That file passes 58/58 when run alone.The four TanStack sites, rewritten on local branches
None of these are pushed. Each is on its own worktree, on branch
feat/decocms-tanstack-workerfromfeat/next-major. Each site links tarballs of this branch's@decocms/blocksand@decocms/tanstackpacked at 8.3.0, with anoverridesentry so only one copy of blocks is installed.vite previewcheckframe-ancestors; the page loader's server function is CDN-cacheable with its token?q=answers 200?asJsonAll of the VTEX storefront's vendored v7 worker (
src/vendor/tanstack/**) goes away.For the PO
<site>.deco.siteand<site>.deco-cx.workers.devpreview. Local development (Studio's local mode onlocalhost:5173) needspreviewHosts: ["localhost:5173"]in dev or the host in theCMSblock, as v7 neededDECO_ALLOWED_PREVIEW_HOSTS.x-deco-draftthroughcontentClient. The worker also sets the draft cookie, so the sites' draft-cookie middleware instart.tsgoes away.site, for the Deco preview hosts.previewHosts.preload.fonts, for the VTEX storefront.csp.frameAncestors, for the VTEX storefront's marketing-tool editors.segmentcan return"private", for a signed-in shopper.segmentcan overridedevice: both Shopify storefronts merge tablets into mobile.RequestContextand loader-cache scope, the VTEX middleware, and the A/B split. These are what a full S4 migration would move next.hydrateoption, so it keeps its owncreateRouterwith the exported search functions.<main id>, so it keeps its ownRootLayout. It rendersDecoPreview(2026-10-16, below), so it has the badge and__cseg.contentClientcould adopt it.@decocms/apps-*package. TheImagecomponents come in feat: the v7-to-v8 migrator and skill use @decocms/tanstack and @decocms/nextjs #700; there, a site wires in its platform's URL helper itself (@decocms/apps-vtex/imageor@decocms/apps-shopify/image).createPageLoader/pageState, and theImage/Picturecomponents. They are not needed by the four worker entries and are left for the site PRs. Release config and npm commands are for P6.Session: https://claude.ai/code/session_01WNwbSEePYNcY5YCgqZURig
Preload hints only on the app's pages (2026-10-15,
68167723)preloadhints (Link: rel=preloadfor the site's CSS and fonts) now go only on HTML the app rendered. Aroutesresponse (a proxied checkout, an A/B test's legacy page) is another origin's page, so it gets none; v7's worker didn't send them there either. Security headers andCDN-Cache-Controlstill apply at the single exit. The handler'sroutesresult is marked internally (routed), so the worker knows nothing about A/B or compat.routesHTML response keeps its ownLinkand the security headers but none of the worker's hints, while the app's page has them. Reverting the check fails it."." opens the page on screen, and
DecoPreview(2026-10-16,8b568030,6a3abe98)DecoDocumenthands the bridge the page on screen:pathTemplate(and optionallypageId) from the deepest matched route's loader data, as v7's document read its CMS route'spath. A page route returnspathTemplate: match.entry.path.DecoPreview({ site, editShortcut?, nonce? })from/reactis whatDecoDocumentmounts for Studio and drafts, for a site that keeps its own document: the published draft and__cseg,StudioBridgewith the page, andDraftBadge. It closes follow-up 2 above: the blog renders it and now shows the badge, keeping its skip link.DecoPreviewin a site's own document publishes the draft and mounts the bridge after the site's markup.🤖 Generated with Claude Code
https://claude.ai/code/session_016ZsmzpZ2zahRBoATBb2tBu