ci: retrigger release workflow after suppression token in #175 body - #176
Merged
Conversation
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>
vibe-dex
pushed a commit
that referenced
this pull request
May 14, 2026
…#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>
7 tasks
vibe-dex
added a commit
that referenced
this pull request
May 19, 2026
Reverts the full chain of commits introduced in PRs #164, #165, #166, #167, #170, #174, #175, #176, #177 plus the two semantic-release auto commits (5.1.0, 5.1.1). Root cause: PR #164 (Framework-agnostic entrypoints: /core, /tanstack, /next, /node) repointed package.json exports from src/ to dist/ and split the framework into multiple bundle chunks via tsup. This is correct in principle, but the tsup output produces a separate copy of every module per entry tier. Files with module-level mutable state (let foo = ..., new Map(), new Set() at top level) end up with one copy per dist entry, so writes through one export resolve a different copy than reads through another export. Symptoms observed on @decocms/start@5.1.0+ and 5.3.0-rc.0/rc.1: - GET/POST /deco/invoke/site/loaders/<any-site-loader> → 404 "Unknown handler: site/loaders/<name>" despite the loader being correctly emitted into site/server/cms/loaders.gen.ts and registered via setInvokeLoaders() in setup.ts. The site's setup.ts mutates the getRegisteredLoaders closure inside dist/core/admin/index.js, while handleInvoke (mounted on the catch-all route) reads getRegisteredLoaders from a different copy of invoke.ts bundled into dist/tanstack/routes/index.js — which still holds the default () => ({}). - OTel direct-POST channels silently dropped (metrics + error logs) — same pattern in src/core/sdk/observability.ts and src/core/sdk/logger.ts. Partially fixed on the fix/o11y-shared-state-singleton branch (the rc.1 work) but the fix never covered invoke.ts handler registry. PR #167 patched two other #164 regressions (CLI scripts dropped from the tsup entries, ESM bundle wrapping require() in a broken __require shim) and PR #166 finalized the publish surface — both strictly downstream of #164. #174 (router preload options) and #170/#175/ #176/#177 (CI / release machinery) build on the same foundation. Path forward: A future re-attempt at framework-agnostic entrypoints must (a) emit a single shared bundle for the admin/invoke handler registry, the observability state, and any other module-level mutable state, or (b) hoist that state onto a globalThis-keyed singleton from the start, with a CI guard that fails any new module-level mutable state inside src/core/. This revert intentionally takes us back to the single-bundle src/-exports world where the bug is latent but inert. Verification: - npm run build → succeeds against the pre-#164 source layout - On a casaevideo build pinned to a snapshot from this revert, POST /deco/invoke/site/loaders/adressByCep returns 500 ("Cannot read properties of undefined (reading 'replace')" from the loader body, not a 404) — i.e. the registry contains the handler again, matching v5.0.0 behaviour. This is the working-baseline state. Re-landing #174's preload options on top of the restored src/ layout is a follow-up. Co-authored-by: Cursor <cursoragent@cursor.com>
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.
Problem
PR #175 (which fixed the release CI by dropping
@semantic-release/git) was merged, but the release workflow did not run on the merge commit.Root cause: the PR #175 body quoted the canonical semantic-release suppression token verbatim while documenting what the dropped plugin used to emit:
The squash-merge commit message inherited that quote, GitHub Actions saw the token anywhere in the message, and the workflow was silently skipped. The release.yml header comment warns about this exact pitfall.
Result: the fix from #175 is on
mainbut no release was published, so@decocms/start@5.1.1remains on npm.Fix
This PR is a no-op commit whose title and body do not contain the literal suppression token, so the merge push triggers the release workflow normally. Same recovery pattern used after PR #171.
The only file change is a one-line addition to the
release.ymlheader comment noting #175 as a second occurrence of this gotcha, so the breadcrumb is up to date for the next person.Test plan
@semantic-release/gitblockage from fix(release): drop @semantic-release/git to satisfy main branch protection #175's fix)@decocms/start@5.2.0is published to npm (semverfeatfrom feat(router): expose preload options + add pdp-fast-navigation skill #174)v5.2.0git tag and GitHub release appearFollow-up
Once published, two storefront PRs that depend on #174's new options can fast-follow:
Both currently use a
createTanStackRouterdirect workaround that I will revert tocreateDecoRouterafter the npm publish.Generated with Claude Code.
Summary by cubic
Retriggers the Release workflow skipped after #175 because the squash-merge message quoted the semantic-release skip token. Pushes a no-op commit that omits the token to trigger Release CI and updates
.github/workflows/release.ymlcomments to note #171 and #175, unblocking@decocms/start@5.2.0.Written for commit 674b0d3. Summary will update on new commits.