Repository navigation
Cloudhal 0.6.0
All @cloudhal/* packages and create-cloudhal at 0.6.0.
Changes
- Collections stage 3 contract and pure core (RFC-0042 step 1, ADR-0044).
CollectionSettingsgains optionallistFields(up to 4 field keys),expiry({ field, action: "unlist" | "hide", afterMinutes? }) andstructuredData({ type: "Event" | "JobPosting" | "Product" | "Recipe", properties }, each property sourced bykind:field,entry,siteor a plain-texttextconstant);contentListsections gainwhere(up to 4FieldConditions) andorderBy(FieldOrder), both new incommon.schema.json. New@cloudhal/core-ts/structured-data: the closed preset table,checkStructuredData(save-time mapping check) andstructuredDataFor(an entry's JSON-LD, none when a required value is missing, capped at 32 KB).@cloudhal/core-ts/fieldsadds the listing evaluator (checkFieldQuery,parseFieldQuery,matchesFieldQuery,compareByField) and the derived expiry gate (fieldGateInstant,expiryInstant,effectiveUntil,dayStartIn). Nothing reads them yet: no behaviour change. - Collections stage 3 in the renderer (RFC-0042 step 3, ADR-0044). A collection's
expirygives every entry a derived gate (min(availability.until, field date + grace); a date ends at the next day's start in the site's zone), applied by both published sources at render time:unlistkeeps the entry's page but leavesentries(),allEntries(), term filters and archives, related posts, feeds, the sitemap,llms.txtand search (search rows'gateUntil);hideanswers 404 like an expiredavailability. The gate index adds every derived instant and every value instant of date/datetime list fields, so the edge cache expires there without a purge; previews ignore derived gates and say "Ended on …". New theme APIs:GraphSource.queryEntriesandqueryEntries(source, q)(./queries) list a collection by its list fields (where,orderBy,sort,filter,limit,offset,includeExpired) with one evaluator on live and snapshot sources;contentListEntries;GraphSource.routableEntries(entries with a public URL, unlisted included);withStructuredDataandentryStructuredData(./seo) replace the genericBlogPostingwith the collection's JSON-LD preset when the entry has every required value.ContentList.astrohonourswhere/orderBy, also for theme copies that pass a source's list.entryHeadis unchanged, so old themes keep today's output; the blog starter callswithStructuredDataandcontentListEntries. The site Worker'sGET /__cloudhal/featuresanswers{ "gates": 2 }, and writers (store, API, MCP, bundle import) refuse a new or changedexpirywith409 gates_unsupporteduntil it does (GateSupport.enforced(siteId, version),EXPIRY_GATES_VERSION). A live entry whose published change adds a derived gate or moves it earlier is never low risk inautomode (expiringEntries, auto-check codeexpires, for publishes and releases). Sites without the new settings render as before. - Collections stage 3 in the store and the API (RFC-0042 step 2, ADR-0044).
updateSitechecks the new collection settings when they change:listFieldsandexpiry.fieldname fields of the collection (unknown_field), the expiry field is a date or datetime field (invalid_expiry), and a structured-data preset passescheckStructuredData(structured_data_invalid; warnings are not refused). Unlisting, dropping or retyping a list field, or dropping a select option, thatcontentListsections still filter or sort by is refused aslist_field_in_usenaming the pages, kept true by a guard on the site CAS. Page writes check changedcontentListwhere/orderByagainst the collection's list fields (invalid_query, withsections/<i>/…paths). Field operations follow:rename_fieldrenames the field inlistFields,expiry, structured-data sources and sections' queries in phase A's batch (and back on revert);remove_fieldrefuses while any of them names the field;change_field_typerefuses when the new type would break them. NewqueryContentEntries(andapplyFieldQuery) filters and orders a collection's entries by list fields with the shared evaluator over resolved values.GET /api/sites/:id/entriestakeswhere(JSON),orderBy(JSON),limit(1–100) andcursor; withlimitit answers{ entries, total, nextCursor? }, without it the plain array as before. New error codesinvalid_query,structured_data_invalid,invalid_expiry(422) andlist_field_in_use(409). Sites without the new settings behave as before.
Patch Changes
- Typed fields follow-ups (RFC-0041). One asset check for field values,
fieldAssetIssuesin@cloudhal/core-ts/media(withfieldAssetRefsandnewFieldAssetRefs), now used by both the store's entry write and MCP'screate_entry/update_entryprecheck; same codes and messages. Machine translation now follows §5:get_translation_sourcereturns only the localized text and rich-text field values to translate (fields) and names the shared ones (sharedFields);save_translationtakes translatedfields, refuses shared ones in precheck withfield_not_localized(paths indetails.issues), and no longer copies the source's field values into a new translation in the same site. New helpers in@cloudhal/core-ts/fields:localizedFieldValues,translatableFieldValues,sharedFieldKeys,sharedFieldIssues. Studio's "write by hand" draft copies only localized field values. - Per-collection feeds (RFC-0042 step 6, ADR-0044). Each collection with a permalink prefix has an RSS feed at
<prefix>/rss.xml(and/<locale><prefix>/rss.xmlor the locale's domain): its newest listed entries, so expiry and time gates apply as in the site feed, with the same cache tag and edge-cache cap;feed: falseanswers 404. Thecloudhal()integration serves it from a middleware on every target, only where the theme's own routes answered 404, so a theme's own route wins and old theme copies gain the feeds; static builds write them becausestaticPaths().feedsnow lists every collection feed path for the starter's[...path]/rss.xmlroute. New theme APIcollectionFeedLink(site, collection, origin, locale?)(./seo,./collection-feeds) gives the<link rel="alternate">; the blog starter adds it on entry pages and on pages that list a collection. Previews now listcontentListsections withwhere/orderBythrough the same evaluator as the site (renderSectionHtml's new optionallistingargument, passed byrenderPagePreview), so an entry without the field's value no longer shows under "upcoming". New guide:docs/guides/structured-data.md. - Collections stage 3 in the renderer (RFC-0042 step 3, ADR-0044). A collection's
expirygives every entry a derived gate (min(availability.until, field date + grace); a date ends at the next day's start in the site's zone), applied by both published sources at render time:unlistkeeps the entry's page but leavesentries(),allEntries(), term filters and archives, related posts, feeds, the sitemap,llms.txtand search (search rows'gateUntil);hideanswers 404 like an expiredavailability. The gate index adds every derived instant and every value instant of date/datetime list fields, so the edge cache expires there without a purge; previews ignore derived gates and say "Ended on …". New theme APIs:GraphSource.queryEntriesandqueryEntries(source, q)(./queries) list a collection by its list fields (where,orderBy,sort,filter,limit,offset,includeExpired) with one evaluator on live and snapshot sources;contentListEntries;GraphSource.routableEntries(entries with a public URL, unlisted included);withStructuredDataandentryStructuredData(./seo) replace the genericBlogPostingwith the collection's JSON-LD preset when the entry has every required value.ContentList.astrohonourswhere/orderBy, also for theme copies that pass a source's list.entryHeadis unchanged, so old themes keep today's output; the blog starter callswithStructuredDataandcontentListEntries. The site Worker'sGET /__cloudhal/featuresanswers{ "gates": 2 }, and writers (store, API, MCP, bundle import) refuse a new or changedexpirywith409 gates_unsupporteduntil it does (GateSupport.enforced(siteId, version),EXPIRY_GATES_VERSION). A live entry whose published change adds a derived gate or moves it earlier is never low risk inautomode (expiringEntries, auto-check codeexpires, for publishes and releases). Sites without the new settings render as before.
Patch Changes
-
Collections stage 3, step 4 (RFC-0042 §7 / ADR-0044): MCP.
list_collectionsreturns, per collection, itslistFieldswith each field's type, operators (ops) and whether it sorts, and, for a collection with a JSON-LD preset,structuredData: the type, every path it offers (required ones, "at least one of" groups, defaults, the field types, entry and site properties, constants and vocabulary each takes) and the preset's warnings.update_collectiontakeslistFields,expiryandstructuredData(nullremoves one). The store's dry run checks them inprecheck, sounknown_field,invalid_expiry,structured_data_invalid,list_field_in_useandgates_unsupportedrefuse the call, with paths, before a person is asked. The approval says what changes in words ("Events leave listings, feeds, the sitemap and search (their pages stay) 1 hour after "Ends at" (endsAt); 2 published entries are already past it", "structured data: Event, maps startDate ← field startsAt, …", vocabulary warnings), and the answer lists the preset's warnings. Policy is unchanged (site:write, a person holdingsite:settingsapproves in every mode).list_entriestakeswhere,orderBy,limitandcursor, run by core-ts's shared evaluator (queryContentEntries); withlimitit answerstotalandnextCursor. Invalid queries are refused asinvalid_querywith their paths.create_page/update_pagecheck a changedcontentListsection'swhere/orderByinprecheck(invalid_query,sections/0/where/1/value).- New read-only tool
preview_structured_data(content:read): the JSON-LD an entry's page emits under its collection's preset, built by the renderer'sentryStructuredData, with the issues (no preset, a required value missing, over 32 KB) and the preset's warnings. 109 → 110 tools. - Hints for
invalid_query,structured_data_invalid,invalid_expiry,list_field_in_useandgates_unsupported(expiry andavailabilityalike), and a "Listings, expiry and structured data" paragraph in the server instructions. @cloudhal/astro-renderer: new subpath./structured-data(entryStructuredData,withStructuredData), so tools use it without the package root.
-
Collections stage 3 in the store and the API (RFC-0042 step 2, ADR-0044).
updateSitechecks the new collection settings when they change:listFieldsandexpiry.fieldname fields of the collection (unknown_field), the expiry field is a date or datetime field (invalid_expiry), and a structured-data preset passescheckStructuredData(structured_data_invalid; warnings are not refused). Unlisting, dropping or retyping a list field, or dropping a select option, thatcontentListsections still filter or sort by is refused aslist_field_in_usenaming the pages, kept true by a guard on the site CAS. Page writes check changedcontentListwhere/orderByagainst the collection's list fields (invalid_query, withsections/<i>/…paths). Field operations follow:rename_fieldrenames the field inlistFields,expiry, structured-data sources and sections' queries in phase A's batch (and back on revert);remove_fieldrefuses while any of them names the field;change_field_typerefuses when the new type would break them. NewqueryContentEntries(andapplyFieldQuery) filters and orders a collection's entries by list fields with the shared evaluator over resolved values.GET /api/sites/:id/entriestakeswhere(JSON),orderBy(JSON),limit(1–100) andcursor; withlimitit answers{ entries, total, nextCursor? }, without it the plain array as before. New error codesinvalid_query,structured_data_invalid,invalid_expiry(422) andlist_field_in_use(409). Sites without the new settings behave as before. -
Collections stage 3, step 5 (RFC-0042 §7 / ADR-0044): Studio.
- Collection settings get three cards, each saved on its own: Listing fields (up to four fields, ordered; a field content lists still use names those pages), Expiry (a date or date-and-time field, "Leave lists" or "Hide the page" explained in words, a grace in minutes, and how many published entries are already past it; a site Worker that does not apply expiry yet says to deploy first) and Structured data (Event, Job posting, Product or Recipe; every property offers only the sources that fit it, required ones are marked, problems show while editing, and a chosen entry's JSON-LD is previewed with a link to Google's Rich Results Test).
- Create listing page makes a draft page at the collection's address with a content list of it (upcoming first for a collection with a date listing field and an expiry) and opens it; when a page already lives there, the action opens that page.
- Collection lists show listing fields as columns, filter by them and sort by number and date fields. Filters and sort live in the URL and ask the API by field, one page at a time.
- Page editor: content list sections get conditions and an order by the collection's listing fields; refused conditions show on their row.
- Words for
invalid_query,structured_data_invalid,invalid_expiry,list_field_in_useandgates_unsupported, thepreview_structured_datatool and the expiry auto-publish check. Translations are AI drafts awaiting review. @cloudhal/api: new read-onlyGET /api/sites/:siteId/entries/:entryId/structured-data(content:read), the REST twin of MCP'spreview_structured_data: the preset document an entry's page emits, its issues and the preset's warnings.
Patch Changes
Upgrade
npm install @cloudhal/cli@0.6.0 @cloudhal/core-ts@0.6.0 @cloudhal/astro-renderer@0.6.0 @cloudhal/cloudflare@0.6.0
npx cloudhal deployDocs: https://cloudhal.dev/docs/start/installation#upgrading