Skip to content

v6.7.0

Choose a tag to compare

@58bits 58bits released this 25 Sep 13:32
· 72 commits to develop since this release

Highlights

  • @byline/core, @byline/client, @byline/db-postgres, @byline/db-mysql — Advertised locales now decide public delivery (#102). The advertised-locales checkboxes were always meant to say which translations a document releases, but they only fed hreflang, sitemaps and language menus. A complete but unchecked translation was still served to anyone who requested it. In a collection with advertiseLocales: true, a public read now delivers a translation only while its checkbox is set and the selected published version is complete in it. An unchecked translation behaves exactly like a missing one: fallback reads resolve to the next eligible locale and end at the source, omit excludes the document, and exact empty reads return empty localized fields while keeping non-localized values. The source language is always delivered, whatever its checkbox says. Checking a translation that is complete in the published version releases it as soon as the save commits. Checking one that exists only in a newer draft releases nothing until that draft is published. Collections without advertiseLocales keep completeness-based resolution. Core decides eligibility in one place (resolveReadLocale), and both adapters apply it identically before projection, hooks and queries, verified by new shared conformance suites (locale-visibility, locale-query-semantics).

  • @byline/core, @byline/client — New localeVisibility read option. Every read now carries localeVisibility: 'public' | 'editorial', defaulted from status: omitted or 'published' reads are 'public', and 'any' reads are 'editorial'. The two are independent, so status: 'published', localeVisibility: 'editorial' reviews unchecked translations of the published version. Under 'editorial', fallback and omit use any complete translation, and exact reads return stored values, including partial translations for editing. 'editorial' requires an authenticated actor; an anonymous request fails with ERR_UNAUTHENTICATED. _bypassBeforeRead skips beforeRead row scoping only; it never bypasses locale visibility.

  • @byline/core, @byline/client — resolvedLocale on every read result. Every reconstructed ClientDocument, populated relation target and tree node now reports resolvedLocale: string | null: the locale its fields were selected in. It is null for a withheld public exact read, a locale: 'all' read, or a locale-agnostic version. Hosts no longer need to infer from the URL, the checkbox set and the completeness ledger which language they are actually showing. Locale-agnostic documents also report _localeAgnostic on every read surface. Public reads keep exposing the published version's _availableVersionLocales, including complete unchecked locales: the checkbox controls delivery of translated values, not secrecy about translation activity.

  • @byline/db-postgres, @byline/db-mysql — Queries match what the read shows. Localized where filters, sorts, list text queries, relation hops and document-tree structural reads now evaluate each document in the locale it is shown in. A filter on a document whose Spanish is withheld matches its source values rather than stored Spanish that would never be returned. A withheld value sorts as missing. Each relation hop resolves its target under the target collection's own checkboxes, so a checked parent cannot authorize an unchecked target. Omit filtering happens before COUNT, LIMIT and OFFSET, so total, totalPages and successive pages stay consistent. The initial findByPath lookup also reaches a document whose source differs from the current default, and returns nothing rather than an arbitrary document when a slug is ambiguous.

  • @byline/client, @byline/cli — Search indexes and serves only publicly deliverable locales. indexDocument pins localeVisibility: 'public', so an index slice holds only the source and checked, complete translations, and no authenticated or system caller can widen it. The reference and scaffolded hooks reindex on requested.path || requested.availableLocales, so a checkbox change updates search, including no-op reconciliation retries. Every public search also re-checks each hit's locale, even without beforeRead and even with _bypassBeforeRead, so a stale slice is dropped before a reindex completes. Hydration reads each hit in its own locale and never substitutes source content.

  • @byline/admin, @byline/host-tanstack-start, @byline/i18n — Preview and editor copy explain delivery. Preview reads use editorial visibility, so an editor can review an unchecked translation at its public URL. The Preview button keeps the content locale selected in the editor even when that translation is unchecked. The single preview toggle now describes itself as showing saved drafts and withheld translations. The Preview button says unsaved changes are not included. The advertised-locales widget explains the public delivery rule, and its source row states that the source stays available while published. The save confirmation explains that checking an already-published translation releases it as soon as the save commits. All eight admin bundles are updated.

Bug Fixes

  • @byline/core, @byline/db-postgres, @byline/db-mysql — Fallback no longer depends on which fields a read projects. Completeness was judged from the rows a read happened to load, so a title-only list could decide a translation was complete and show it, while the full read of the same document fell back to the source. Language selection now uses the version's whole completeness ledger, so projected, full, detail and batch reads agree.

  • @byline/richtext-lexical — Read-time population replaces stale copied values. Link and inline-image refreshes merged the current target into the previously copied envelope. A title or image the target no longer supplies therefore survived, and a link whose path could not be composed kept its old URL. Copied values are now replaced, never merged. A link with no usable path is marked _resolved: false and renders as plain text. An inline image whose media is missing, denied or has no usable URL loses its copied image data and preview, so no stale image is rendered or exported to Markdown. Save-time embeds read targets with public visibility, so an editor's save can no longer copy an unchecked translation into a stored snapshot.

  • @byline/cli — Scaffolded Pages preview URLs use the content default locale. The starter Pages builder prefixed the URL by comparing against the admin interface's default locale, so a site whose admin and content defaults differ produced wrong preview links. It now follows the content default, and the template documents that the prefix belongs to the host's public routing rule.

Chores

  • monorepo — The reference application demonstrates the contract:
    • its preview-aware reads pass explicit visibility;
    • Docs and News gained locale-aware preview builders;
    • Pages now uses the public routing rule for its prefix;
    • preview responses suppress hreflang alternates and the language menu rather than advertise draft completeness;
    • canonical URLs follow the advertised set and page areas.
  • monorepo — Twelve documentation pages were updated. They include a new "Public delivery of advertised locales" section and an "Editorial policy for localized content" section in docs/08-internationalization/03-content-locales.md. The specification, plan and a traceable test report are recorded under specs/.

Migrations

No database schema or data migration is required: this release reads the existing checkbox and completeness tables. Three read-contract changes and two rollout steps need attention.

  • Review each document's advertised locales before upgrading. In collections that advertise locales, complete translations that were never checked stop being publicly delivered. Nothing is checked automatically. Check the translations you intend to publish.

  • Public reads can no longer request locale: 'all'. They fail with ERR_VALIDATION on every collection, whether or not it advertises locales. Multi-locale reads are editorial. If a public or viewer-client call passes locale: 'all', change it to status: 'any' or localeVisibility: 'editorial' with an authenticated actor.

  • Public exact reads withhold incomplete translations on every collection. A public onMissingLocale: 'empty' read previously returned a partial translation's stored values; it now returns empty localized fields with non-localized values intact. Editorial exact reads still return partial values for editing.

  • Public search totals are page-local. Every public search now reports total as the number of surviving hits on the returned page and omits provider facets. A page showing "N results" from a public search shows the hits on that page.

  • After upgrading, rebuild each search index and clear application caches. Use client.collection(path).reindex() or the admin Reindex button, and your existing cache-clear procedure. Withdrawing a translation has the same limits as unpublish: fresh origin reads change immediately, local caches clear through the reference hooks, cluster fan-out is best-effort, CDN responses remain until their TTL unless purged, and rich-text snapshots saved into other documents keep their copied values until those documents are re-saved.

All other @byline/* packages bumped to 6.7.0 in lockstep with no behavioural changes this cycle.