Conversation
…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>
…#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>
|
🎉 This PR is included in version 5.2.0-next.1 🎉 The release is available on:
Your semantic-release bot 📦🚀 |
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.
Summary
Promotes
nexttomainso semantic-release publishes the validated prerelease (5.1.2-next.1on@decocms/start@next) as stable5.1.2on@latest. The@v5moveable tag advances too.Three commits land:
fix(build):— externalize stateful subpaths so module state lives in one bundle. This is THE invoke 404 fix for 5.1.x (casaevideo and any other site that hitUnknown handlersince 5.1.0).ci(release):— drop@semantic-release/git, sidestep branch-protection push. Required so the release workflow doesn't try to push a commit back to a protected branch under the new rulesets.ci:— empty-commit recovery after ci(release): drop @semantic-release/git to unblock @next publishing #171's body inherited the workflow-suppression token through the squash-merge.After merge: stable
5.1.2lands on@decocms/start@latest,@nextdist-tag moves to it as well (semantic-release channel-merge behavior — intentional, keeps@nextfrom falling behind), and@v5repoints tov5.1.2.Test plan
5.1.2to@latestnpm view @decocms/start dist-tags→{ latest: '5.1.2', next: '5.1.2' }git tag --sort=-v:refname | head -3showsv5.1.2and the moveablev5@nextpin and rely on^5.1.2from@latest🤖 Generated with Claude Code
Summary by cubic
Promotes
5.1.2-next.1of@decocms/start@nextto stable5.1.2on@latest;@nextand@v5now 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
@decocms/start/node/daemon:/_healthcheck(returnsADMIN_COMPAT_VERSION),/_ready,/watchSSE,/fs/*, JWT guard, and a Node adapter (toNodeMiddleware).createDecoAdminRouteandcreateDecoAdminRouteHandlers(GET/POST/PATCH/DELETE), with corrected App Router mounting; re-exportshandleDecoHealthcheck,handleDecoReadiness, andADMIN_COMPAT_VERSIONfrom@decocms/start/next.Bug Fixes
getRenderShellConfigfrom@decocms/start/admin.npm publishdefaults tolatestwhennextRelease.channelis empty..next,.turbo,dist) to stop SSE floods.@semantic-release/gitto avoid pushing to protected branches.Written for commit 85816e7. Summary will update on new commits.