Skip to content

Releases: web-stacked/caretcms

CaretCMS 0.3.0

Choose a tag to compare

@web-stacked web-stacked released this 20 Aug 12:20

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

Choose a tag to compare

@web-stacked web-stacked released this 19 Aug 23:49

Added

  • Astro 7 live-collection cache tags. caretLoader() now attaches Astro 7
    cacheHint tags (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-forged caret_session cookie. The fallback is now gated on a
    build-time dev signal (reliable on Cloudflare Workers, unlike NODE_ENV).
  • Auth: Worker env bindings honored. CARET_EDIT_PASSWORD /
    CARET_SESSION_SECRET are now read from the Cloudflare Worker env, 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/compiler 4 / 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 .astro source parsing works unchanged against compiler 4; the e2e
    harness was adapted to Astro 7's new managed background dev server (astro dev now 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-header selector (opt back into content-push
    with the caret-push-content body 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_collection now run under the collection lock
    (TOCTOU + serialization against reorder_entries).
  • Rewrite scope-stack no longer mis-tracks bindings across HTML comments,
    <script>/<style> bodies, or >-in-attribute values.
  • Editor a11y: aria-live status + 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/cloudflare gains a MemoryKV conformance test suite; its
    single-writer / eventual-consistency limitation is now documented.
  • @caretcms/caretize and @caretcms/zod gain prepublishOnly version guards;
    validate:versions now 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

Choose a tag to compare

@web-stacked web-stacked released this 24 Jun 20:24

Highlights

  • Static deliverycaret({ delivery: "static" }) for static Astro sites: dev authoring in astro dev, build-time HTML bake in astro build, optional publish webhook after Publish. See docs/static-delivery.md.
  • caretize init defaults to static delivery for static Astro projects.
  • caretize: named-import loop binding, astro:assets Image/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

Choose a tag to compare

@web-stacked web-stacked released this 12 Jun 02:20

Added

  • First npm publish of @caretcms/caretize (the data-caret auto-tagger CLI,
    with a README) and @caretcms/zod (Zod → JSON Schema bridge).
  • @caretcms/core/contracts subpath exporting the shared contract surface:
    identifier grammar (COLLECTION_NAME_RE, ENTRY_ID_RE, EDITOR_ID_RE),
    the rewrite engine's REWRITABLE_TEXT_TAGS, and the rich-text allowlist.
    @caretcms/cloudflare now 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-routes tiers now filter by the same tag
    allowlist — previously such bindings saved through the editor but never
    appeared for visitors.
  • caretize --bind-*: a declaration preceding getCollection() no longer
    steals the receiver capture (which minted bindings like
    blog::${undefined}::field or 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 (n now skips);
    --scope labels 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_SECRET in 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.
  • FilesystemAdapter validates 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_collection normalizes ids (lowercase) like every
    other mutation instead of rejecting what save_field accepts.
  • 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.root instead of process.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 (single buildTemplate, with
    integer seeding 0).

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/cms entry points.