Skip to content

feat: v8 framework packages — @decocms/tanstack, @decocms/nextjs, @decocms/compat-v7, /preview, lockstep release and the migrator - #722

Merged
tlgimenes merged 12 commits into
mainfrom
feat/migrator-invoke-scaffold
Oct 18, 2026
Merged

tlgimenes merged 12 commits into
mainfrom
feat/migrator-invoke-scaffold

Conversation

@tlgimenes

@tlgimenes tlgimenes commented Oct 18, 2026 •

Copy link
Copy Markdown
Contributor

This PR replaces the 11 stacked PRs #695 … #707 so the rest of the v8 framework packages land on main as one commit and one release, 8.4.0, publishing all 11 packages together: @decocms/blocks, @decocms/tanstack, @decocms/nextjs, @decocms/compat-v7 and the seven @decocms/apps-*. Its branch is #707's (feat/migrator-invoke-scaffold), already rebased onto main with one commit per former PR and their trees unchanged, plus one commit that raises every @decocms/blocks peer floor to ^8.4.0.

#693 and #694 are already on main and shipped in 8.3.0 (NODE_ENV dev default, deco schema --check, first-match multivariate, the platform-neutral /image with @decocms/apps-vtex/image and @decocms/apps-shopify/image).

What lands

#695 — @decocms/blocks/preview: the draft badge and the Studio bridge

  • DraftBadge({ pointer, exitHref? }): v7's "Preview mode" pill, unchanged on screen. Renders nothing without a pointer, on the server and inside a frame. The inlined Deco mark is now a 36px PNG (~2KB, v7 inlined ~22KB).
  • StudioBridge({ site, trustedOrigins, editShortcut?, nonce? }): v7's LiveControls as one static inline script, so it runs before hydration and a Server Component can render it. trustedOrigins is required; it answers only the parent frame from those origins.
  • @decocms/blocks exports no Studio origins and no draft names: the bindings own them.
  • PO decision 4: the "." / Ctrl+Shift+E edit shortcut is on by default, as in v7; editShortcut={false} turns it off.

#696 — @decocms/tanstack for v8

#697 — @decocms/nextjs for v8

#699 — lockstep release

  • .releaserc.json publishes every package in packages/ at one version on latest from main, blocks first, then the bindings.
  • Every package that builds on blocks takes it as a caret peer (now ^8.4.0) with workspace:* only in devDependencies, so a site installs one blocks copy.
  • scripts/sync-versions.mjs writes the version and refuses a plain in-repo dependency or a peer floor above the release. tests/release.test.ts checks the allowlist, the ranges, every export's shape and what each tarball ships; CI runs it on the built dist.

#700 — the migrator and skill use the bindings

  • The v7-to-v8 script and the deco-v7-to-v8-migration skill move sites onto @decocms/tanstack / @decocms/nextjs instead of copying v7's worker, draft, bridge and image code.
  • @decocms/tanstack/react gets v7's Image, Picture, Source (same props and markup, URLs from ImageUrlProvider); 160 golden markup cases, zero changed.
  • PO decisions 1, 2 and 5: no dev flag; the script adds deco schema --check to the site's CI; decoCdn strips only a leading asset host and the report lists every URL that changes.

#702 — @decocms/compat-v7: types, device, scripts, clx

  • The PO-approved home (2026-10-14) for v7's pure helpers on v8, so migrated sites stop keeping copies. No v7 runtime (ctx, invoke, request scope), no env reads, nothing added to blocks.
  • /types (SectionProps = the loader's awaited return, per the PO), /device, /script, /clx. v7's own files are hash-pinned fixtures and every helper is compared against them over seeded inputs.

#703 — @decocms/compat-v7/matchers

  • v7's website matchers with v7's results; each takes the request as its second argument. random is latest 7.x's sticky random on the deco_segment cookie (PO decision), keyed by the saved block's name (cohort).

#704 — @decocms/compat-v7/sections

  • runSectionLoaders / runSectionLoader: v7's (props, req) section loaders after a page resolves, with v7's nested walk (deep, or nested: "direct" for 7.77.12 and earlier), __pageUrl/__pagePath, and the degraded list. v7's mixins. Reading ctx throws with what to use instead.

#705 — @decocms/compat-v7 /commerce, /tanstack, /nextjs

  • /commerce/*: v7's @decocms/apps-commerce pure files under the same layout (AST-equal to v7, 5,000 generated inputs each).
  • /tanstack and /nextjs: matcherContext, commitSegmentCookie, cohortSegment, requestDevice, DeviceProvider.
  • /tanstack/worker (PO decision 6): v7's withABTesting legacy-origin split as a createDecoWorker routes handler, matched to v7 over 3,000 seeded requests. PO decision 3 checked against the compat random.

#706 — the migrator imports @decocms/compat-v7

  • Rewrites v7 helper and @decocms/apps-commerce imports onto compat-v7, rewrites ctx.device, turns registerSectionLoaders into sectionLoaders and wires loadSections, registers the matchers the content uses and writes the image URLs module.
  • PO decision 8: every section's own loader runs, and each one v7 never ran is reported. PO decision 9: blocks are registered under their v7 names only.

#707 — the migrator writes invoke, app clients, the page setup and stubs

  • Each /deco/invoke key becomes one server function (TanStack Start GET loaders marked private and POST actions; Next.js "use server"), imported at each call site.
  • PO decision 7: VTEX invoke-map keys need an explicit --vtex-invoke keep|v8 choice, no default.
  • deco-vtex/-shopify/-wake/-resend app blocks become src/clients/<app>.ts; src/migration-stubs.ts holds deprecated stubs for v7 runtime with no port; the page setup (src/cms.ts, open-page, the catch-all route) is written per binding.

This PR's own commit — peer floors ^8.4.0

The bindings and compat-v7 use blocks APIs that 8.3.0 doesn't have (@decocms/blocks/preview and the rest of this stack), so every @decocms/blocks peer (and compat-v7's optional binding peers) is ^8.4.0. tests/release.test.ts syncs at 8.4.0 and 8.5.1 and refuses 8.3.x; the migrator writes ^8.4.0; CLAUDE.md, the README and the skill name 8.4 as the floor.

Checks

  • Release dry run in a throwaway clone of a mirror with the tags (deleted afterwards; nothing pushed to GitHub or published): main + this branch squashed into one commit with this PR's title. semantic-release --dry-run: "Found git tag blocks-v8.3.0 … The next release version is 8.4.0". The prepare step (VERSION=8.4.0 node scripts/sync-versions.mjs && bun run build): 11 manifests at 8.4.0, every peer ^8.4.0, all builds exit 0. npm publish --dry-run --tag latest for all 11: @decocms/blocks@8.4.0 … @decocms/apps-wake@8.4.0, each "with tag latest". The 11 tarballs installed together: npm ls @decocms/blocks shows one 8.4.0, every other entry deduped; no required peer is unmet.
  • Gates at the top: bun run check, bun run build, skills:check, skills:readme:check, bun test tests/release.test.ts (42 pass), the compat-v7 tests (13 files, 153 pass), and bun run test under a 2 GB cap: 122 files pass, 1 skipped; 2,746 tests pass, 95 skipped, 0 fail.

Landing

  1. Approve, then squash with this PR's feat: title. The squash message is the PR body (repo setting), so this body is what commit-analyzer reads: one feat:, a minor release.
  2. The release publishes 8.4.0 on latest for all 11 packages.
  3. Before landing, check that npm Trusted Publishing for @decocms/tanstack, @decocms/nextjs and @decocms/compat-v7 accepts main's .github/workflows/release.yml. The bindings were last published from the 7.x branch: npm's trusted publisher names the repo and workflow file, not a branch, so main should be accepted, but if either is tied to a GitHub environment, add it for main first. compat-v7's trust config already exists and its 0.0.0 placeholder is published.

Once this lands, the 11 stacked PRs can be closed.

npm commands for the PO after the release (not run)

# 1. Remove the stale `next` dist-tag (8.1.0) from blocks and every apps-* that has it (all seven do today).
npm dist-tag rm @decocms/blocks next
npm dist-tag rm @decocms/apps-algolia next
npm dist-tag rm @decocms/apps-magento next
npm dist-tag rm @decocms/apps-resend next
npm dist-tag rm @decocms/apps-sfmc-personalization next
npm dist-tag rm @decocms/apps-shopify next
npm dist-tag rm @decocms/apps-vtex next
npm dist-tag rm @decocms/apps-wake next

# 2. Rewrite the 8.0.0 deprecation (it says "use @latest (7.x)", wrong once latest is 8.4.0).
npm deprecate @decocms/tanstack@8.0.0 "Published by mistake. Use ^8.4.0 for v8, or 7.x for v7."
npm deprecate @decocms/nextjs@8.0.0 "Published by mistake. Use ^8.4.0 for v8, or 7.x for v7."

# 3. Deprecate the two prereleases (not deprecated today).
npm deprecate @decocms/tanstack@"8.0.0-next.0 || 8.1.0-next.0" "Prerelease. Use ^8.4.0 for v8, or 7.x for v7."
npm deprecate @decocms/nextjs@"8.0.0-next.0 || 8.1.0-next.0" "Prerelease. Use ^8.4.0 for v8, or 7.x for v7."

No latest-7 command is needed: #698 already moved latest-7 to 7.80.2 for both bindings. latest moves to 8.4.0 by itself when the release publishes.

Checks afterwards:

npm view @decocms/blocks dist-tags      # { latest: '8.4.0', 'latest-7': '7.80.2' }, no next
npm view @decocms/tanstack dist-tags    # { latest: '8.4.0', 'latest-7': '7.80.2' }
npm view @decocms/nextjs dist-tags      # { latest: '8.4.0', 'latest-7': '7.80.2' }
npm view @decocms/compat-v7 dist-tags   # { latest: '8.4.0' }
for p in algolia magento resend sfmc-personalization shopify vtex wake; do npm view @decocms/apps-$p dist-tags; done   # latest: '8.4.0', no next
npm view @decocms/tanstack@8.0.0 deprecated
npm view @decocms/nextjs@8.1.0-next.0 deprecated
npm view @decocms/tanstack@8.4.0 peerDependencies   # @decocms/blocks: '^8.4.0'

🤖 Generated with Claude Code

https://claude.ai/code/session_016ZsmzpZ2zahRBoATBb2tBu


Summary by cubic

Replaces PRs #695–#707 so the v8 framework packages land as one commit and one release: 8.4.0 publishes all 11 packages together (@decocms/blocks, @decocms/tanstack, @decocms/nextjs, @decocms/compat-v7, and the seven @decocms/apps-*). The v7-to-v8 migrator and its skill now move sites onto these bindings instead of copying v7's worker, draft, bridge, and image code into the site.

What ships

  • @decocms/blocks/preview: the draft badge and Studio bridge, as one static inline script that runs before hydration.
  • @decocms/tanstack: the TanStack Start binding on Cloudflare Workers — drafts, edge cache, CMS redirects, draft names and Studio origins.
  • @decocms/nextjs: the Next.js App Router binding — draft proxy, content client, image loader, Studio bridge, without hosting assumptions.
  • @decocms/compat-v7: v7's pure helpers (types, device, scripts, clx, matchers, section loaders, commerce files) with v7's output, so migrated sites stop keeping their own copies.
  • The migrator rewrites /deco/invoke calls into server functions, writes the page setup per binding, registers v7 matchers and section loaders, and reports everything left for a person.

Release and migration

  • All packages release in lockstep at one version on latest; every package that builds on blocks takes it as a ^8.4.0 caret peer, so a site installs one blocks copy.
  • Existing v7 sites stay on latest-7; next dist-tags and misplaced 8.0.0/prerelease deprecations must be cleaned up after release (commands in the PR body).

Written for commit 6195fe5. Summary will update on new commits.

View guided diff Turn on auto-fix

tlgimenes and others added 12 commits October 18, 2026 15:54
…695)

Rebased onto main as one commit per PR (PO, 2026-10-18); the previous history is kept on backup/blocks-preview-2026-10-18.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016ZsmzpZ2zahRBoATBb2tBu
…r, decoTanstack) (#696)

Rebased onto main as one commit per PR (PO, 2026-10-18); the previous history is kept on backup/tanstack-v8-2026-10-18.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016ZsmzpZ2zahRBoATBb2tBu
…draft names and Studio origins, withDeco() and a platform-neutral image loader (#697)

Rebased onto main as one commit per PR (PO, 2026-10-18); the previous history is kept on backup/nextjs-v8-2026-10-18.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016ZsmzpZ2zahRBoATBb2tBu
…blocks at 8.3.0 (#699)

Rebased onto main as one commit per PR (PO, 2026-10-18); the previous history is kept on backup/release-8-3-2026-10-18.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016ZsmzpZ2zahRBoATBb2tBu
…cms/nextjs (#700)

Rebased onto main as one commit per PR (PO, 2026-10-18); the previous history is kept on backup/migrator-uses-bindings-2026-10-18.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016ZsmzpZ2zahRBoATBb2tBu
…, scripts and clx (#702)

Rebased onto main as one commit per PR (PO, 2026-10-18); the previous history is kept on backup/compat-v7-core-2026-10-18.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016ZsmzpZ2zahRBoATBb2tBu
…dom (#703)

Rebased onto main as one commit per PR (PO, 2026-10-18); the previous history is kept on backup/compat-v7-matchers-2026-10-18.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016ZsmzpZ2zahRBoATBb2tBu
…#704)

Rebased onto main as one commit per PR (PO, 2026-10-18); the previous history is kept on backup/compat-v7-sections-2026-10-18.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016ZsmzpZ2zahRBoATBb2tBu
Rebased onto main as one commit per PR (PO, 2026-10-18); the previous history is kept on backup/compat-v7-commerce-bindings-2026-10-18.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016ZsmzpZ2zahRBoATBb2tBu
… loaders, views and image URLs wired (#706)

Rebased onto main as one commit per PR (PO, 2026-10-18); the previous history is kept on backup/migrator-compat-imports-2026-10-18.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016ZsmzpZ2zahRBoATBb2tBu
…, the page setup, and stubs for v7 runtime (#707)

Rebased onto main as one commit per PR (PO, 2026-10-18); the previous history is kept on backup/migrator-invoke-scaffold-2026-10-18.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016ZsmzpZ2zahRBoATBb2tBu
The bindings and @decocms/compat-v7 use blocks APIs that 8.3.0 doesn't
have (/preview and the rest of this stack), so every package that builds
on blocks now takes ^8.4.0, and compat-v7 takes the bindings at ^8.4.0 as
well. The release test syncs at 8.4.0 and 8.5.1 and refuses 8.3.x; the
migrator writes ^8.4.0 and the docs name 8.4 as the floor.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016ZsmzpZ2zahRBoATBb2tBu
@tlgimenes
tlgimenes marked this pull request as ready for review October 18, 2026 19:18
@tlgimenes
tlgimenes requested a review from a team October 18, 2026 19:18
@tlgimenes
tlgimenes requested a review from vibe-dex as a code owner October 18, 2026 19:18
@tlgimenes
tlgimenes merged commit 776fc14 into main Oct 18, 2026
11 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant