Skip to content

fix(web): CMS without dev server, subdir package path, and reliable preview refresh#4670

Merged
guitavano merged 6 commits into
mainfrom
guitavano/decofile-schema-fallback-v1
Jul 22, 2026
Merged

fix(web): CMS without dev server, subdir package path, and reliable preview refresh#4670
guitavano merged 6 commits into
mainfrom
guitavano/decofile-schema-fallback-v1

Conversation

@guitavano

@guitavano guitavano commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

Summary

Makes the Blocks/Content CMS usable when the sandbox dev server is down, extends it to projects whose code lives in a subdirectory, and fixes the preview so it reliably auto-refreshes after an edit.

1. CMS works without the dev server

Read the committed .deco/*.gen.json snapshots straight from the working tree (via the daemon file proxy) as a fallback for the live /.decofile + /live/_meta routes. The Blocks editor opens, the preview URL-bar page dropdown populates, and edits (which persist to the FS) still work even when the dev server is crashed/paused. The live routes take over once it comes back up (lifecycle re-invalidates the queries). crashed is treated as recoverable instead of terminal.

2. Subdir package path support

The daemon resolves file ops against the repo root, but a project may live under a package path (metadata.runtime.path, e.g. eitri-shopping-monte-carlo-shared). New decoRepoPath() helper prefixes that package path onto every .deco/* daemon path — committed reads (blocks.gen.json / meta.gen.json) and block writes/deletes (generic + blog) — so <pkg>/.deco/... resolves correctly. The live routes already resolve relative to the dev-server cwd, so only the daemon-relative paths needed the prefix. The file-changed SSE handler now matches /.deco/ too, so subdir projects aren't misrouted.

3. Reliable preview auto-refresh after an edit

Previously the iframe reloaded immediately on save — racing the dev server rebuild and often showing stale content, with no second reload. Now a .deco/* file-changed (Blocks save, external/agent write, decofile regen) reloads the iframe via the debounced rebuild-wait (500ms) using the existing scroll/focus-preserving reload. The dead notifySaved/previewRevision plumbing was removed. A new reloadStart signal shows the loading overlay instantly on change (before the debounce); the iframe's onLoad clears it.

Testing

  • bun run fmt, bun run --cwd=apps/mesh check (tsc), bun run lint (0 errors) all pass
  • Unit tests green, incl. new deco-repo-path.test.ts and updated reducer/tab-state tests
  • Manually verified on a root-project site: form edits and preview auto-refresh (with instant loading overlay)

Follow-up (not in this PR)

  • File-explorer .deco/blocks/ filters still assume repo root (JSON viewer only) — minor, subdir projects would mis-filter that list.

🤖 Generated with Claude Code


Summary by cubic

Make the CMS and preview navigation work without the dev server, add subdirectory package support, and make preview refresh on .deco/* edits reliable. Blocks/Content and the preview URL bar read committed snapshots when the server is down and switch to live data when it’s running.

  • New Features

    • CMS fallback to committed .deco/blocks.gen.json and .deco/meta.gen.json via the daemon; live /.decofile and /live/_meta take over once running (queries revalidated on the lifecycle transition).
    • Treat crashed as recoverable so Blocks/Content stay editable from committed data; the preview URL-bar page/global dropdowns also load from the snapshot.
    • Subdirectory support: new decoRepoPath prefixes metadata.runtime.path on all daemon .deco/* reads/writes (Blocks + blog), and file-changed now matches /.deco/ for subdir projects.
    • Reliable preview refresh: when running, debounce .deco/* change reloads by 500ms to wait for rebuilds; subscribeReloadStart shows the loading overlay immediately; reload preserves scroll/focus.
  • Bug Fixes

    • Skip .deco/* invalidation and iframe reloads unless the dev server is running to avoid clobbering optimistic saves and overlay flashes on a dead preview.
    • Fixed stripLineNumbers to remove only the <n>\t prefix, preserving lines with \r, U+2028, or U+2029.
    • isDecoOnlyDiff now recognizes <pkg>/.deco/... so pure CMS edits in subdirectory projects can be published directly.

Written for commit 0526053. Summary will update on new commits.

Review in cubic

guitavano and others added 6 commits July 20, 2026 12:07
Read the committed `.deco/blocks.gen.json` (decofile) and `.deco/meta.gen.json`
(live meta) straight from the working tree via the daemon file-read proxy, so
the Content tab shows and is editable even before the dev server boots or when
the dev script has crashed (block writes already persist to the FS). The live
`/.decofile` + `/live/_meta` routes still take over once the dev server is up
(re-invalidated on the lifecycle `running` transition).

Also fixes `stripLineNumbers`, which used a `(.*)` capture whose `.` does not
match `\r`, U+2028, or U+2029 — a single-line JSON payload with an embedded
line separator was silently truncated at the first such char, corrupting large
files (e.g. an 11MB decofile cut in half). Switched to a prefix-only `replace`
that preserves the rest of each line verbatim.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Stop gating the preview's decofile/meta fetch on `devServerReady` so the URL-bar
page list and global-sections dropdown read the committed `.deco/*.gen.json`
snapshot when the dev server is down (page create + SEO edits persist to the FS).
The inline visual editor still requires the dev server — it overlays the page
rendered inside the iframe — but its activate postMessage is a no-op without a
rendered page, so nothing breaks.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…is down

When the dev server is paused/crashed the lifecycle phase is `crashed` ("was
running, stopped responding"), which `resolveBlocksTabState` treated as a hard
sandbox error — so the Blocks form editor was unavailable even though the
committed `.deco/*.gen.json` is still readable and block edits persist to the
FS (same as the Content tab). Treat `crashed` like `running` and let the data
drive the state, and stop gating BlocksPanel's decofile/meta fetch on
devServerReady so it reads the committed snapshot. The live preview canvas
stays broken until the dev server is back; genuine setup failures
(clone/install/start-failed) remain terminal errors.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ile edits

Resolve the committed `.deco/*.gen.json` snapshots (and block writes/deletes)
under the virtual MCP's package path (`metadata.runtime.path`) so the CMS works
for projects that don't live at the repo root (e.g. `<pkg>/.deco/...`). The
daemon resolves file ops against the repo root, so the fallback reads and the
FS-backed writes now prefix the package path via `decoRepoPath`.

Also refresh the preview reliably after a decofile edit: a `.deco/*`
`file-changed` (block save, external/agent write) now reloads the iframe via the
debounced rebuild-wait, replacing the immediate save reload that raced the dev
server rebuild and left the preview stale. The loading overlay shows instantly
via a new `reloadStart` signal, then clears on iframe load.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…LineNumbers tests

- B1 (blocker): gate the `.deco/*` file-changed invalidation + iframe reload on
  the dev server being `running`. When it's down, `blocks.gen.json` is a stale
  build artifact the dev server can't regenerate, so refetching it overwrote the
  optimistic cache update from useSaveBlock/useDeleteBlock and the edit visibly
  reverted — defeating the committed-snapshot editing feature. Also stops the
  loading overlay flashing over a dead preview.
- I1: isDecoOnlyDiff now recognizes `<pkg>/.deco/...` so pure-CMS edits in a
  subdir package-path project can still be published directly (were misclassified
  as code changes and forced into Submit-for-review).
- I2: add stripLineNumbers unit tests, incl. the \r / U+2028 / U+2029 regression
  the replace()-over-capture change fixes.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Rebase onto main pulled in main's refactor of the blog mutation hooks
(shared postToSandbox helper + a context-free unit test). Resolving `useVirtualMCP`
inside useSaveBlogBlock/useDeleteBlogBlock made them require ProjectContext, which
that unit test doesn't provide. Thread the package path in via params instead:
a new `usePackagePath` hook resolves it at the call sites (content-browser + the
post/category/record editors), keeping the mutation hooks free of ProjectContext.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@guitavano
guitavano force-pushed the guitavano/decofile-schema-fallback-v1 branch from ad77d8b to 0526053 Compare July 20, 2026 15:18
@guitavano
guitavano merged commit 3f5da08 into main Jul 22, 2026
14 checks passed
@guitavano
guitavano deleted the guitavano/decofile-schema-fallback-v1 branch July 22, 2026 12:19
decocms Bot pushed a commit that referenced this pull request Jul 22, 2026
PR: #4670 fix(web): CMS without dev server, subdir package path, and reliable preview refresh
Bump type: patch

- decocms (apps/mesh/package.json): 4.92.0 -> 4.92.1

Deploy-Scope: web
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