Skip to content

release: promote 5.1.2-next.1 to stable#173

Open
vibe-dex wants to merge 4 commits into
mainfrom
next
Open

release: promote 5.1.2-next.1 to stable#173
vibe-dex wants to merge 4 commits into
mainfrom
next

Conversation

@vibe-dex

@vibe-dex vibe-dex commented May 11, 2026

Copy link
Copy Markdown
Contributor

Summary

Promotes next to main so semantic-release publishes the validated prerelease (5.1.2-next.1 on @decocms/start@next) as stable 5.1.2 on @latest. The @v5 moveable tag advances too.

Three commits land:

After merge: stable 5.1.2 lands on @decocms/start@latest, @next dist-tag moves to it as well (semantic-release channel-merge behavior — intentional, keeps @next from falling behind), and @v5 repoints to v5.1.2.

Test plan

  • Release workflow on main runs and publishes 5.1.2 to @latest
  • npm view @decocms/start dist-tags{ latest: '5.1.2', next: '5.1.2' }
  • git tag --sort=-v:refname | head -3 shows v5.1.2 and the moveable v5
  • Casaevideo can drop the @next pin and rely on ^5.1.2 from @latest

🤖 Generated with Claude Code


Summary by cubic

Promotes 5.1.2-next.1 of @decocms/start@next to stable 5.1.2 on @latest; @next and @v5 now point to this version. Adds full Next adapter admin coverage via a shared Web-standard daemon and fixes the 5.1.x invoke 404s.

  • New Features

    • Shared Web-standard daemon in @decocms/start/node/daemon: /_healthcheck (returns ADMIN_COMPAT_VERSION), /_ready, /watch SSE, /fs/*, JWT guard, and a Node adapter (toNodeMiddleware).
    • Next adapter composes the dispatcher: createDecoAdminRoute and createDecoAdminRouteHandlers (GET/POST/PATCH/DELETE), with corrected App Router mounting; re-exports handleDecoHealthcheck, handleDecoReadiness, and ADMIN_COMPAT_VERSION from @decocms/start/next.
    • TanStack daemon middleware now wraps the shared dispatcher; volumes WebSocket remains unchanged.
    • Router API exposes preload/pending options for faster PDP navigation; adds the PDP fast navigation skill doc.
  • Bug Fixes

    • Externalized stateful subpaths during build so module state is shared; fixes invoke “Unknown handler” 404s. Also exports getRenderShellConfig from @decocms/start/admin.
    • npm publish defaults to latest when nextRelease.channel is empty.
    • JSON Patch on non-JSON files returns a 200 conflict instead of 500.
    • Unified daemon ignore list (e.g., .next, .turbo, dist) to stop SSE floods.
    • Removed @semantic-release/git to avoid pushing to protected branches.

Written for commit 85816e7. Summary will update on new commits.

vibe-dex and others added 3 commits May 11, 2026 15:30
…e bundle (#169)

Since 5.1.0, tsup's per-entry self-contained bundles (`splitting: false`)
inlined every relative import — including `src/core/admin/invoke.ts`'s
module-level `handlerRegistry`. Each published subpath ended up with its
own private copy: `setInvokeLoaders` wrote to setup.js's copy while
`decoInvokeRoute` read routes.js's empty copy, returning 404 for every
`/deco/invoke/<key>`. Same write/read split affected cms blocks/sections,
commerce loaders, request context, URL origins, logger, and OTEL state.

The tsup config now runs an esbuild plugin that rewrites cross-subpath
relative imports of stateful modules to bare `@decocms/start/<subpath>`
specifiers marked external. Node's module loader dedupes bare specifiers
at runtime, so every subpath bundle shares the one canonical module
instance. Source code is unchanged — the plugin only transforms paths
at build time, so tsc/vitest/IDE resolution keep working.

Also exports `getRenderShellConfig` from the admin barrel — required
because htmlShell.ts and workerEntry.ts now reach it through the bare
specifier.

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…ush (#171)

The git plugin's only job is committing a 2-line package.json bump back
to the branch as `chore(release): X.Y.Z [skip ci]`. Doing so requires
pushing directly to a protected branch — which fails under both classic
branch protection and the new Repository Rulesets because GITHUB_TOKEN
(github-actions[bot]) can't be added to the bypass list. Workarounds
require a custom GitHub App, deploy key, or PAT.

We don't need that commit. Releases still work:
- prepareCmd bumps package.json in the runner (ephemeral) so `npm publish`
  ships the correct version inside the tarball.
- Tags are pushed by semantic-release core, then materialized on the
  remote by @semantic-release/github creating the GitHub Release.
- The moveable @v5 tag advance step in release.yml still finds the new
  tag and force-pushes.
- Next release run reads tags (not package.json) to compute the next
  version — confirmed in semantic-release's FAQ.

Tradeoff: the in-repo package.json version drifts from npm after each
release. Purely cosmetic — npm registry is the source of truth, and
`npm view @decocms/start versions` shows the actual shipped versions.

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…172)

The squash-merge of #171 carried the canonical workflow-suppression
token through from the PR body, which silently prevented release.yml
from running on next. This empty commit recovers per the recovery
instructions documented in release.yml's top comment.
@vibe-dex vibe-dex requested a review from a team May 11, 2026 19:29
…#178)

* feat(router): expose preload options + add pdp-fast-navigation skill (#174)

createDecoRouter only exposed defaultPreload, omitting all the TanStack
Router options that control how long a prefetch is reused. Result: even
with `<Link preload="intent">`, hover prefetch was refetched on click
because the default staleTime is short — wasted work, slow perceived
navigation on commerce storefronts.

Expose the missing options:
- defaultPreloadStaleTime
- defaultPreloadGcTime
- defaultPreloadDelay
- defaultStaleTime
- defaultPendingMs
- defaultPendingMinMs

All optional, all forwarded to createTanStackRouter as-is. No default
changes — sites must opt in (commerce sweet spot is staleTime: 60_000).

Also add `.cursor/skills/deco-pdp-fast-navigation/SKILL.md` documenting
the full pattern (5 levers: intent preload + eager sections + staleTime
+ createCachedLoader + reserved-height fallback) discovered while
optimizing a commerce PDP from multi-second click delay to sub-second
perceived navigation.

The skill explicitly recommends `createCachedLoader` over hand-rolled
LRU maps for heavy loaders (thumbnail format detection, Vimeo oEmbed).

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>

* ci: retrigger release workflow after suppression token in #175 body (#176)

PR #175 body referenced the semantic-release suppression token
verbatim while documenting what the dropped @semantic-release/git
plugin used to emit. The squash-merge commit message inherited that
verbatim quote and the release workflow was silently skipped, so the
fix from #175 itself never reached npm.

This is a no-op commit whose title and body do not contain the
literal suppression token, so the next push event triggers the
release workflow normally. Same recovery pattern used after PR #171.

Also expanded the workflow header comment to note that #175 hit the
same gotcha — small breadcrumb for the next person.

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>

* fix(release): default to latest tag when nextRelease.channel is empty (#177)

semantic-release sets nextRelease.channel from the branches config.
For the main branch (no prerelease flag), channel is null, so
'npm publish --access public --tag ${nextRelease.channel}' interpolates
to 'npm publish --access public --tag ' (trailing empty argument), and
npm rejects with:

  npm error Tag name must not be a valid SemVer range:

Default to 'latest' when channel is falsy. main still publishes under
the default npm dist-tag, next branch (which has prerelease: true and
channel='next') keeps its own tag.

This regressed silently because the previous prepare step
@semantic-release/git always failed on the branch protection rule
before publish was reached, so the publishCmd path was never exercised
on main. After dropping that plugin in the previous release fix, the
publish step finally ran and surfaced this issue.

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>

* docs(spec): next adapter admin coverage + shared daemon refactor design

Captures the brainstorming session for closing three gaps in the Next.js
adapter: hosting probes (/_healthcheck, /_ready), broken route-mounting
docs, and missing /watch + /fs/* coverage. Lands a shared Web-standard
daemon core in src/node/daemon/ consumed by both adapters; the
Connect-style wrapping stays as a thin Vite-specific shim.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(plan): next adapter admin coverage + shared daemon implementation plan

17-task TDD-discipline plan derived from the matching spec. Phases: core
foundation (version + readiness), node/daemon tier (jwt → auth → handlers →
adapter → dispatcher), TanStack refactor onto shared core, Next adapter
exports + handlers, docs rewrite, final verification.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* feat(core/admin): add ADMIN_COMPAT_VERSION pinned to deco-cx/deco 1.177.x

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* feat(core/admin): add handleDecoReadiness backed by getRevision()

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* refactor(daemon): move JWT primitives to src/node/daemon/jwt

Pure Web-Crypto verifyAdminJwt + tokenIsValid relocate to a framework-neutral
tier so the new Web-standard auth wrapper can consume them without crossing
the next/ → tanstack/ boundary. tanstack/daemon/auth.ts keeps its Connect-style
middleware and re-exports the JWT symbols for back-compat.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* feat(node/daemon): add requireAdminJwt Web-standard guard

Returns Response (401/403) to short-circuit or null to continue. Mirrors
createAuthMiddleware's semantics including the DANGEROUSLY_ALLOW_PUBLIC_ACCESS
bypass.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* feat(node/daemon): add handleDecoHealthcheck Web-standard handler

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* refactor(daemon): move broadcast channel + .deco scanner to src/node/daemon

src/tanstack/daemon/watch.ts becomes a thin Connect-style shim over the
new shared scanner + channel; the chokidar wrapper for Next-side use lives
in src/node/daemon/watcher.ts (lazy singleton, never instantiated from
TanStack).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* feat(node/daemon): Web-standard handleWatchSse SSE handler

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* feat(node/daemon): Web-standard handleFsRequest

GET/PATCH/DELETE on /fs/file/<path> plus the /fs/grep stub the admin search
UI hits. Refuses path traversal. Broadcasts fs-sync events on mutate paths
so the existing SSE channel stays in sync.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* feat(node/daemon): toNodeMiddleware Web↔Connect adapter

Lets the new Web-standard route handlers plug into Vite's middleware stack
without duplicating any dispatch logic. Honors backpressure and treats a
null return as fall-through.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* feat(node/daemon): createDecoAdminRoute dispatcher

Single Web-standard entry point composing all daemon handlers behind
configurable route-group flags. Defaults dev tooling (watch, fs) to off
in production; throws at construction if an auth-gated group is enabled
without a site name.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* feat(pkg): export @decocms/start/node/daemon

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* refactor(tanstack/daemon): compose shared Web-standard route handler

createDaemonMiddleware delegates probes, fs, watch, and admin-protocol
dispatch to createDecoAdminRoute via toNodeMiddleware. Volumes WebSocket
binding stays in-place because it requires raw httpServer access. Public
signature unchanged; new optional routes field forwards group toggles.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* refactor(next): handleDecoAdminRoute composes shared dispatcher

Brings probes, watch, fs, and the corrected route-mounting JSDoc into the
Next adapter without duplicating logic. handleDecoAdminRoute is now a
pre-instantiated createDecoAdminRoute that reads DECO_SITE.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* feat(next): createDecoAdminRouteHandlers convenience factory

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* feat(next): expose new admin coverage surface from the barrel

Adds createDecoAdminRoute, createDecoAdminRouteHandlers, decoAdminRouteHandlers,
handleDecoHealthcheck, handleDecoReadiness, ADMIN_COMPAT_VERSION, and the
related types.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(next): rewrite App Router integration guide with correct route layout

Removes the broken single-catchall recipe and replaces it with the
escaped-folder layout that survives Next App Router's _folder privacy rule
and Turbopack's %2E behaviour. Documents the createDecoAdminRouteHandlers
config pattern and the per-group toggles.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* build(tsup): include src/node/daemon entries

Without this glob the new src/node/daemon/* sources only had .d.ts emitted
by tsc; tsup's bundle pipeline never saw them, so dist/node/daemon/index.js
and friends were missing and the @decocms/start/node/daemon subpath would
fail at runtime.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(core/admin): re-export ADMIN_COMPAT_VERSION + handleDecoReadiness from barrel

Without these the tsup externalizer routes cross-bundle imports of
src/core/admin/version + readiness to the @decocms/start/admin subpath
(per DIR_OWNERS in tsup.config.ts) and resolves the named imports to
undefined at runtime. Symptoms: /_healthcheck returned 200 with an empty
body, /_ready threw TypeError: handleDecoReadiness is not a function.

The bug was invisible to vitest because it runs against TypeScript source
and bypasses the bundle externalizer. Caught by the final whole-branch
review's dist-level smoke test.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* feat(node/daemon): canonical DAEMON_IGNORED_DIRS with .next/.turbo/dist filters

Three call sites (watch.ts shouldIgnore, volumes.ts walkFiles, volumes.ts
broadcastChange) each carried their own copy of the ignore list. Consumer
testing against Next 16 / Turbopack reported the SSE channel flooded with
.next/dev/server/* fs-sync events on every rebuild because the list didn't
cover framework artefact dirs.

Consolidates the list into src/node/daemon/ignored.ts and extends it with
.next, .turbo, dist, build, .cache, coverage. Both watch.ts and volumes.ts
delegate to the new isIgnoredPath. shouldIgnorePath is preserved as a
deprecated re-export to keep watcher.ts and any external imports working.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* feat(next): expose PATCH and DELETE from createDecoAdminRouteHandlers

The previous {GET, POST} pair broke the documented one-line route file
pattern for /fs/file/*: PATCH (JSON-Patch apply) and DELETE (rm) requests
fell through to 405 because Next App Router only forwards exported method
handlers. Consumers had to fall back to calling createDecoAdminRoute
directly, defeating the purpose of the helper.

Widens DecoAdminRouteHandlers to {GET, POST, PATCH, DELETE} (single handler
reference; the dispatcher already branches on method internally). Updates
the JSDoc example in adminRoute.ts and the layout in docs/using-from-nextjs.md
to re-export all four. Default-instance proxy gains the same two methods.
Smoke test asserts reference equality across all four methods.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs: CONTRIBUTING.md + scripts/dev-link-into.sh for consumer testing

Documents the Turbopack-vs-symlinks gotcha (subpath exports fail to resolve
through bun link / npm link with Next 16 + Turbopack — confirmed against
16.2.6) and the dist-overlay workaround. Helper script bundles the rebuild
+ overlay into one command.

Keeps bun link documented as the path-of-first-resort for Vite/Webpack
consumers where it still works.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(node/daemon): JSON-patch against non-JSON file returns 200 conflict, not 500

A Next consumer hit PATCH /fs/file/README.md with a type:'json' patch. The
on-disk plaintext content tripped JSON.parse inside applyPatch with a
SyntaxError that escaped the JsonPatchError catch and bubbled all the way
to a 500 with a stack trace. Server is healthy; the file's shape just
doesn't match the patch's expectations — that's exactly the soft-conflict
case the existing TEST_OPERATION_FAILED branch already handles.

Splits the inner JSON.parse into its own try/catch (returns conflict),
applies the same symmetry to the text-patch branch. Test asserts 200
{conflict:true} on a plaintext target.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* feat(node/daemon): add onRequest per-request hook to DecoAdminRouteOptions

Real consumers commonly need to run something before every dispatched admin
request — the canonical case being 'await ensureSetup()' so the block
registry is hydrated before handleMeta / handleDecofileRead /
handleDecoReadiness read it. Wrapping the helper's returned methods by hand
requires re-introducing the four-method dance the helper was supposed to
remove and quietly depends on the all-methods-share-one-handler internal.

onRequest runs after the master enabled check, before pathname dispatch.
Returning undefined continues; returning a Response short-circuits — useful
for custom auth gates and maintenance-mode early-outs without overriding
the whole helper. Four new tests cover: called-once-per-request, Response
short-circuit, undefined continues, and disabled-route skips the hook.
Documented in createDecoAdminRouteHandlers' JSDoc and the App Router guide.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Jonas Jesus <jonasdasilvajesus@outlook.com>
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown

🎉 This PR is included in version 5.2.0-next.1 🎉

The release is available on:

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants