Skip to content

v3.16.0

Choose a tag to compare

@58bits 58bits released this 07 Jul 10:36

Highlights

  • @byline/client + @byline/core + @byline/search-postgrescross-collection zone search + hydrate. The second search entry point is live: client.search({ zone, query }) returns heterogeneous hits ranked together across every collection indexed into a named zone, each hit carrying its collectionPath. Zone membership resolves from the runtime collection definitions via the new resolveSearchZones helper — the same rule the indexing assembler applies, so query scope and index contents can't drift. Per-collection read abilities apply with graceful degradation (collections the actor can't read are excluded; the ability error surfaces only when none are readable), and unknown zones throw ERR_VALIDATION. Both entry points now take hydrate: true: core batch-reads each collection's hit ids through the normal read path and attaches a shaped ClientDocument as hit.document, projected to the collection's admin.itemView columns when registered. Hydration also drops stale index entries whose document no longer resolves. New types: ZoneSearchOptions, HydratedSearchHit, ClientSearchResults.

  • @byline/clientrow-level authorization on search. search() now enforces beforeRead row scoping — "rank in the provider, authorise in core": when a collection configures a beforeRead hook, candidate hit ids are re-resolved through the normal read path (the same predicate merge + SQL compile every other read uses) and unauthorized hits are dropped. Owner-only drafts, multi-tenant isolation and the other beforeRead recipes now hold on search exactly as on find(). Collections without a hook skip the second query entirely — public search pays nothing. Two documented approximations: total / facet counts remain the provider's pre-authorization numbers, and a page can come back shorter than limit under scoping (paginate on offset). _bypassBeforeRead: true is the system escape hatch.

  • @byline/adminmulti-select relation picker for hasMany fields. The picker opens in multi-select mode: rows toggle a check state, already-added targets render as disabled "Already added" rows, and "Add selected (n)" appends the whole batch in pick order — several picks in one trip instead of reopening the modal per item. Single-select relation fields are untouched (the picker branches on a multiple prop). Two new i18n keys ship across all seven admin locales.

  • @byline/core + @byline/db-postgres$some / $every / $none query quantifiers. Relation fields in a where clause now take quantifiers over the target set: { authors: { $some: { name: 'X' } } }, $every (vacuously true for empty sets, Prisma-style), and $none ($none: {} = "no targets at all"). A plain nested sub-where remains shorthand for $some; multiple quantifier keys AND together; quantifiers also work on single relations. Unresolvable targets (deleted, or drafts under published reads) are ignored by all three — the same visibility rule populate applies.

  • @byline/ui — improved accessibility props for help text, input, and textarea components.

Bug Fixes

  • @byline/db-postgres — nested relation where filters on hasMany fields silently matched nothing: multi-target items store the array index as field_name ('0', '1', …) with the field name in parent_path, so the relation EXISTS never found the rows. hasMany filters now match on parent_path.
  • @byline/cli — the example collection templates carried an obsolete search: { fields: [...] } key (inert — the shipped API is body), and the docs template omitted the content container field from search.body, silently excluding document bodies from the index on fresh installs. All five templates repaired.
  • @byline/ui — accessibility fixes for Search, Checkbox, Label, and focus-ring contrast.

Chores

  • monorepo — dead-code sweep (−17,500 lines, including a 16,615-line orphaned emoji table in @byline/richtext-lexical that shipped in the published dist) and unused-dependency cleanup across eight packages, now guarded by a knip step in CI that fails on unused production dependencies.
  • monorepo — repaired ~164 stale documentation references left by the docs restructure; the admin editor Playwright smoke suite completed its growth checklist (file upload, content-locale switch + translation save, duplicate, restore-version).

Breaking Changes

  • @byline/client — the BylineClient.search property (which held the SearchProvider instance) is renamed searchProvider; the search name now belongs to the cross-collection query method. Action: if you read the provider directly off a client instance (client.search as an object rather than calling it), rename to client.searchProvider. client.collection(x).search() and the ServerConfig.search config key are unchanged — no known consumer touches the property, which is why this rides a minor.

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