Releases: web-stacked/caretcms
Release list
CaretCMS 0.3.0
CaretCMS 0.3.0
CaretCMS 0.3.0 makes editing an Astro site feel much closer to editing the page
itself.
Rendered Markdown prose can now be edited on the page. Caret connects supported
paragraphs, headings, lists, quotes, and text styles to their exact place in the
source file. Changes remain drafts until they are published. If the file has
changed since editing began, Caret stops instead of overwriting newer work.
Studio and the live page can also find each other. Clicking a field on either
side opens or scrolls to the matching field and briefly marks it. The link works
in the sidebar and across separate Studio and preview tabs.
This release also improves repeatable fields, image editing, collection cards,
mobile actions, accessibility, English and Spanish Studio text, and save-state
messages. Collection rules such as singleton, create, reorder, and delete are
now enforced by the server. Invalid writes are rejected before they can damage
stored content, and one malformed entry no longer prevents a whole collection
from loading.
Cloudflare R2 uploads now fail with a useful configuration error when Caret
cannot return a working public URL. Astro development mode keeps request context
and registered schemas intact when Vite loads more than one copy of the runtime.
The release supports Astro 6 and Astro 7 and requires Node.js 22.12 or newer.
See the changelog
for the complete list of changes.
CaretCMS 0.2.0
Added
- Astro 7 live-collection cache tags.
caretLoader()now attaches Astro 7
cacheHinttags (caret:<collection>,caret:<collection>::<id>) to published
content so routes/CDNs can cache it and a publish can purge it by tag. Editor
and draft requests carry no hint — they must always render the latest edit.
Security
- Auth: no forgeable sessions in a locked deployment. When no editor password
is configured, production builds no longer sign sessions with the public dev
fallback secret — a "locked" (read-only) deployment could otherwise be unlocked
with an attacker-forgedcaret_sessioncookie. The fallback is now gated on a
build-time dev signal (reliable on Cloudflare Workers, unlikeNODE_ENV). - Auth: Worker env bindings honored.
CARET_EDIT_PASSWORD/
CARET_SESSION_SECRETare now read from the Cloudflare Workerenv, not just
process.env, so binding-only deployments authenticate (and don't silently
fall through to the public fallback secret). - Rich-text links reject protocol-relative URLs (
//evil.com), closing an
open-redirect/phishing vector; embedded config JSON and theme-token CSS are now
escaped/validated before injection.
Changed
- Astro 7 support (toolchain modernized). Verified and pinned to Astro 7.0.6 /
Vite 8 /@astrojs/compiler4 / Vitest 4.1.10 / fast-check 4 / Tailwind 4.3.2.
Core's Astro peer range is now^6.0.0 || ^7.0.0(Astro 5 is no longer
supported), and Node 20 is dropped — Astro 7 requires Node>=22.12.0.
caretize's.astrosource parsing works unchanged against compiler 4; the e2e
harness was adapted to Astro 7's new managed background dev server (astro devnow daemonizes) via a small foreground wrapper. - Embedded delivery defaults to
auto.caret()now resolves delivery mode
automatically for embedded setups. - Inline editor: 409 conflicts no longer destroy your edit. A save conflict
keeps your text in the field and offers an explicit "Keep mine / Load latest"
choice instead of silently overwriting it (inline and in the Studio). - Studio panel is an overlay drawer and no longer reflows host layout or
depends on a hard-coded#main-headerselector (opt back into content-push
with thecaret-push-contentbody class).
Fixed
- Mutation write path: unhandled promise rejection from the per-key locks on
adapter failure;mutate/ history-restore routes now return curated JSON
errors instead of leaking a framework 500. create_collection/delete_collectionnow run under the collection lock
(TOCTOU + serialization againstreorder_entries).- Rewrite scope-stack no longer mis-tracks bindings across HTML comments,
<script>/<style>bodies, or>-in-attribute values. - Editor a11y:
aria-livestatus +role="alert"toasts, keyboard-visible image
"Replace", higher-contrast toolbar text, Studio panel loading state + focus
management; no-JS login shows its error; Studio object-array edits keep field
types.
Internal
@caretcms/cloudflaregains a MemoryKV conformance test suite; its
single-writer / eventual-consistency limitation is now documented.@caretcms/caretizeand@caretcms/zodgainprepublishOnlyversion guards;
validate:versionsnow enforces cross-package@caretcms/*peer lockstep; CI
builds the example apps (API-drift guard) and adds an informational Astro 7
compatibility job.
v0.1.2
Highlights
- Static delivery —
caret({ delivery: "static" })for static Astro sites: dev authoring inastro dev, build-time HTML bake inastro build, optional publish webhook after Publish. See docs/static-delivery.md. - caretize
initdefaults to static delivery for static Astro projects. - caretize: named-import loop binding,
astro:assetsImage/Picture binding, per-file storage-key registry. - core: route overlap warnings, unknown option key warnings, data-caret resolver parity fixes.
npm packages
@caretcms/core@0.1.2@caretcms/caretize@0.1.2
Full changelog: CHANGELOG.md
v0.1.1 — audit fixes, contracts subpath, first caretize/zod publish
Added
- First npm publish of
@caretcms/caretize(thedata-caretauto-tagger CLI,
with a README) and@caretcms/zod(Zod → JSON Schema bridge). @caretcms/core/contractssubpath exporting the shared contract surface:
identifier grammar (COLLECTION_NAME_RE,ENTRY_ID_RE,EDITOR_ID_RE),
the rewrite engine'sREWRITABLE_TEXT_TAGS, and the rich-text allowlist.
@caretcms/cloudflarenow imports these instead of carrying copies; a
cross-package parity test holds caretize's deliberate mirrors byte-identical.- caretize: skipped-candidate hints now cover collection loops
(--bind-collections) and dynamic routes (--bind-routes), not just--rich.
Fixed
- Inert bindings: caretize no longer tags elements the rewrite engine
cannot render (div,code,cite,b,i,mark,q), and the
--bind-collections/--bind-routestiers now filter by the same tag
allowlist — previously such bindings saved through the editor but never
appeared for visitors. - caretize
--bind-*: a declaration precedinggetCollection()no longer
steals the receiver capture (which minted bindings like
blog::${undefined}::fieldor silently found zero targets), and
template loops whose callback parameter shadows the entry variable are
skipped instead of bound to the wrong collection. - caretize: failed writes roll back only the current run's files — previously
the rollback could restore a previous run's backups over newer hand edits. - caretize: Ctrl-C at a prompt aborts cleanly (exit 130) instead of hanging;
unrecognized review input re-prompts instead of accepting (nnow skips);
--scopelabels are validated against the runtime grammar;--report
requires a file path; quitting or a zero-change run no longer prints the
success footer. - Missing
CARET_SESSION_SECRETin production no longer 500s every request
carrying a session cookie: session checks fail closed as signed-out (logged
once) and the login route returns an explanatory configuration error. FilesystemAdaptervalidates collection/entry ids on reads and filters
invalid stems from listings — uppercase bindings now fail consistently
everywhere instead of resolving only on case-insensitive (macOS) dev
filesystems;create_collectionnormalizes ids (lowercase) like every
other mutation instead of rejecting whatsave_fieldaccepts.- Middleware binding probe matches attribute syntax, so pages that merely
mention "data-caret" in prose no longer run the rewrite engine or lose the
signed-in empty-state hint. - Collection auto-detection pins
markdownStorage()to the detected
config.rootinstead ofprocess.cwd(). - Cloud live-sync resolves array dot-paths (
items.0.title) the same as the
server rewrite engine; Studio entry templates no longer differ between
user-created and inferred collections (singlebuildTemplate, with
integerseeding0).
Documentation
- Quick starts now include the required SSR adapter; core README documents the
production env vars (CARET_SESSION_SECRET), what gets written to disk +
recommended.gitignore, markdownStorage/localUploads production caveats,
and the/admin·/admin/cmsentry points.