Repository navigation
Cloudhal 0.5.0
All @cloudhal/* packages and create-cloudhal at 0.5.0.
Changes
-
Typed custom fields, step 1 (RFC-0041 / ADR-0043).
Site.collections.<key>.fieldstakes an ordered list of 1–30 field definitions in nine types (text,richText,number,boolean,date,datetime,url,image,select), discriminated bytype, each with per-locale labels,localizedand (exceptboolean)requiredToPublish. The new@cloudhal/core-ts/fieldssubpath (Worker-safe, eval-free) checks definitions (reserved keys, unique keys and options, 30 per collection, 200 per site, 256 KB of collection settings, the plain-edit guard), checks values through ADR-0030'svalidateProps(only changed values; unknown keys refused once a collection has definitions; 256 KB per entry), checksrequiredToPublish, emits the JSON Schema agents receive (strict-mode safe), and resolves values across translations (resolveFields). Nothing reads it yet: the store, API, MCP, Studio and renderer adopt it in later steps, so nothing changes for existing sites. -
Typed custom fields, step 3 (RFC-0041 §6 / ADR-0043): field operations.
runFieldOperation/continueFieldOperation/revertFieldOperation/fieldOperationStatusin@cloudhal/core-tsrunrename_field,change_field_type,set_field_localizedandremove_field: a dry run (entries touched, values moved, converted, cleared, removed, unchanged and unconvertible, per locale, with samples), abefore …snapshot whose id is the operation id, the new definition with itsmigrationmarker (phase A), entries rewritten in guarded batches of 200 that resume after an interruption (phase B), the marker dropped once nothing is pending (phase C) and anaftersnapshot. Only the draft graph changes. A type change follows a closed conversion table (convertFieldValue, exported from@cloudhal/core-ts/fields) and refuses values it cannot convert (field_values_unconvertible) unlessonInvalid: "clear". One operation per collection at a time (operation_in_progress). Reverting restores the earlier definition and the entries nobody edited since, and converts edited ones back.- Readers stay consistent mid-run:
resolveFieldsconverts values still in the old type, and a field being removed reads as gone; a person's entry write during an operation goes through the marker, so edits and the operation converge. - Translations: changing only non-localized field values of an original no longer marks its translations stale (their recorded source hash follows, in the same batch); operations keep fresh translations fresh.
- API:
POST /api/sites/:id/collections/:key/fields/operations(dryRun,?continue=<id>),GET …/:operationId,POST …/:operationId/revert(site:settingsandcontent:write), and the same under/api/adminwith the deployment token. - CLI:
cloudhal fields rename|retype|localize|remove|continue|revert [--dry-run] [--remote]; the dry run also lists theme files that read the field directly.
-
Typed custom fields, step 6 (RFC-0041 §9 / ADR-0043): renderer and themes. Additive only:
entry.fieldsstill means exactly what is stored, and themes copied before this release build and render as before (a frozen 0.4.0 theme joins the compat test).GraphSource.entryFields(entry, options?)on live and snapshot sources (andentryFields(source, entry, options?)from@cloudhal/astro-renderer/fieldsfor any source): an entry's typed fields as a theme draws them, by key in definition order. Values are resolved by the language rules (a translation's empty localized field reads the original's,fromOriginal; non-localized fields come from the translation group's original; language editions own their values), labelled in the page's language and made safe: rich text as HTML from the article body's markdown pipeline (raw HTML escaped,safeHrefon links), URLs throughsafeHref(dropped when unsafe), images as<img>attributes with the asset's alt in the page's language, everything else as formatted text. AlsorenderFields,hasShownFields, andresolveFields,formatFieldValue,fieldLabel,fieldHelp,optionLabelre-exported.formatFieldValue(value, def, { locale, defaultLocale?, timeZone?, words? })in@cloudhal/core-ts/fields: a value as plain text withIntl(numbers, dates that never shift a day, instants in their own zone, option labels as a list, yes/no words).EntryFields.astroin@cloudhal/astro-renderer/components: a plain, unstyled<dl class="ch-fields">of the fields that have a value, withdata-field/data-typehooks for themes; nothing at all when none has one.- Blog starter: articles of collections with fields show a "Details" list under the cover (English, Turkish and Japanese words). Entries of collections without definitions render byte for byte as before.
- New guide:
docs/guides/fields.md(defining fields in Studio, MCP, the API and the CLI; operations; languages; theme API; security).
-
Typed custom fields, step 2 (RFC-0041 / ADR-0043): the store and the API enforce field definitions.
- Site writes (
updateSite,createSite,PUT /api/sites/:id/collections/:key, dry run included) check definitions: reserved (field_key_reserved) and duplicate keys or options,minimumabovemaximum, 30 fields per collection and 200 per site (too_many_fields), 256 KB of collection settings (too_large). A plain edit never loses a value: changing a field'stype,localizedormultiple, or dropping a key or a select option that an entry still holds, is refused with409 field_change_needs_operation, naming the field operation to use. Other site writes do not re-run the checks. - Entry writes check only the field values that changed:
422 invalid_fields,unknown_field(a new key without a definition, once the collection has definitions; stored unknown keys are kept),field_not_localized(a translation's own copy of a non-localized value) andrequired_field(review or published without arequiredToPublishvalue; drafts save freely).fieldsis capped at 256 KB per entry in every collection when it changes (too_large). Image values must be image assets of the site, and image and rich-text asset references are recorded inasset_refsunderfields.<key>, so a used file cannot be deleted. Every refusal lists its problems with paths indetails.issues(fields/startsAt/at). - API inputs remove a key with
nullin a collection that has definitions. Collections without definitions keepfieldsas any JSON, exactly as before. - Search:
textandrichTextfields markedsearchableadd their words to the entry's search text at the next publish (off by default; sites without searchable fields index byte for byte as before). refuseFieldIssuesandfieldRefusalCodeare exported from@cloudhal/core-ts/fields.
- Site writes (
Patch Changes
-
Typed custom fields, step 6 (RFC-0041 §9 / ADR-0043): renderer and themes. Additive only:
entry.fieldsstill means exactly what is stored, and themes copied before this release build and render as before (a frozen 0.4.0 theme joins the compat test).GraphSource.entryFields(entry, options?)on live and snapshot sources (andentryFields(source, entry, options?)from@cloudhal/astro-renderer/fieldsfor any source): an entry's typed fields as a theme draws them, by key in definition order. Values are resolved by the language rules (a translation's empty localized field reads the original's,fromOriginal; non-localized fields come from the translation group's original; language editions own their values), labelled in the page's language and made safe: rich text as HTML from the article body's markdown pipeline (raw HTML escaped,safeHrefon links), URLs throughsafeHref(dropped when unsafe), images as<img>attributes with the asset's alt in the page's language, everything else as formatted text. AlsorenderFields,hasShownFields, andresolveFields,formatFieldValue,fieldLabel,fieldHelp,optionLabelre-exported.formatFieldValue(value, def, { locale, defaultLocale?, timeZone?, words? })in@cloudhal/core-ts/fields: a value as plain text withIntl(numbers, dates that never shift a day, instants in their own zone, option labels as a list, yes/no words).EntryFields.astroin@cloudhal/astro-renderer/components: a plain, unstyled<dl class="ch-fields">of the fields that have a value, withdata-field/data-typehooks for themes; nothing at all when none has one.- Blog starter: articles of collections with fields show a "Details" list under the cover (English, Turkish and Japanese words). Entries of collections without definitions render byte for byte as before.
- New guide:
docs/guides/fields.md(defining fields in Studio, MCP, the API and the CLI; operations; languages; theme API; security).
Patch Changes
-
Typed custom fields, step 4 (RFC-0041 §8 / ADR-0043): MCP.
list_collectionsreturns each collection's field definitions (fields) andfieldsSchema, the JSON Schema of an entry's values with labels and help in the askedlocale(default: the site's).create_entry/update_entrycheck field values inprecheckwith the store's checker (changed keys only, unknown keys, a translation's copy of a non-localized value,requiredToPublishfor review and published, image andasset:references), so a refused call never reaches a person; each issue keeps its path (fields/startsAt/at).update_entrytakesfieldsas a merge patch (nullremoves a key), and its approval names typed changes readably ("Starts at (startsAt) → 5 Nov 2026 19:30 Istanbul", option labels, values quoted and truncated).update_collectiontakesfields(the whole list) for free definition edits; changes that could lose values are refused withfield_change_needs_operation, naming the operation tool.- New tools
rename_field,change_field_type,set_field_localized,remove_field(site:write+content:write): always a person holdingsite:settings, in every mode includingbypass; the approval shows the dry run (entries touched, values moved, converted or cleared, samples),dryRun: truereports without asking, and a call that would clear values withoutonInvalid: "clear"is refused before anyone is asked. A run that stops at its budget answersdone: falsewith anoperationId; calling the same tool again with it continues the operation after a new approval. - Hints for every field error code, and server instructions telling agents to read
fieldsSchemabefore writing entries and to use the operation tools for risky changes.
Patch Changes
-
Typed custom fields, step 5 (RFC-0041 §7 / ADR-0043): Studio.
- Entry editor › Fields: collections with field definitions get a "Fields" card in the entry editor (loaded only for them), one control per type — text, rich text (the body editor), number, yes/no, date, date and time in its own zone, link, image (the media picker) and choice (one or several). Labels and help follow the Studio language, required fields say "Needed to publish", and the API's issues show on their field. On a translation, shared (non-localized) fields are read-only with the original's value and a link to it; empty per-language fields show the original's value as their placeholder. Values save with the entry.
- Collection settings › Fields: a builder to add fields (the key follows the label until saved), reorder them and edit labels, help, limits and options, saved together. Renaming, changing a type or the languages of a saved field, and removing one open a dialog that runs the dry run first (entries changed, values moved, converted or cleared, per language, examples, a note about themes), needs confirmation — and an explicit opt-in to clear values that cannot be converted — then runs the operation to the end and offers Revert. A running operation shows its progress and can be continued. Only people who may change site settings edit fields; others see them read-only.
- Activity and Approvals name the collection and field tools, field operations that convert or remove values ask for confirmation before approval, and every field error code reads as a sentence in the Studio language. New words live in a lazy
fieldsnamespace (drafts in every language, awaiting review).
Patch Changes
- Studio (RFC-0040 §4): a collection's settings get a Comments section (saved in the site's comment settings), the site overview lists recent content across every collection, and entries open at
/sites/<id>/collections/<collection>/<entry>— the old/articles/<entry>links redirect there. The command palette goes to each collection.
Upgrade
npm install @cloudhal/cli@0.5.0 @cloudhal/core-ts@0.5.0 @cloudhal/astro-renderer@0.5.0 @cloudhal/cloudflare@0.5.0
npx cloudhal deployDocs: https://cloudhal.dev/docs/start/installation#upgrading