Byline CMS
  • Home
  • Docs
  • About
Byline CMS
View on GitHub
  • Getting Started
    • Overview
    • CLI
    • Development environment and example application
    • Configuration
    • Upgrading from 3.21 to 4.x
  • Why Byline
    • Overview
    • Mission & Vision
    • Content Management in the Time of AI
  • Key Architectural Decisions
    • Overview
    • Core Document Storage
    • Core Composition
    • Transactions
    • Path Grammar
    • Deployment Topologies
  • Collections
    • Overview
    • Fields
    • Blocks
    • Relationships
    • Document Trees
    • Document Paths
    • File / Media Uploads
    • Rich Text Editor
    • Collection Versioning
  • Reading & Delivery
    • Overview
    • Search & Document Extraction
    • Client SDK (@byline/client)
    • Routing & API
    • Transports
    • Markdown Export
    • MCP Server
    • Caching
  • Search
    • Overview
    • Configure search
    • Indexing and reindexing
    • Search API
    • Search provider contract
    • Portable multilingual search analysis
    • PostgreSQL and MySQL search providers
    • Attachment extraction for search
  • Auth & Security
    • Overview
    • Authentication & Authorization
    • Auditability
  • Internationalization (i18n)
    • Overview
    • The host i18n system
    • Admin interface translations
    • Content locales
    • Administering content locales
  • Admin UI
    • Overview
    • UI Kit (@byline/ui)
    • Client-config registration
  • API Reference
    • Overview
    • Configuration API
    • Collections API
    • Fields API
    • Client SDK API
  • Testing
  • Home

Client SDK API

Companions:

  • Client SDK — runnable recipes and explanation for reads, writes, filtering, population, preview, and request authority.
  • Configuration API — the request-bound public, viewer, admin, and system client getters.
  • Relationships — populate syntax, depth, relation envelopes, and type overlays.
  • Authentication and authorization — abilities, RequestContext, row predicates, and trusted escape hatches.

This reference lists the public @byline/client construction, query, write, search, history, audit, indexing, and document-tree surface. All operations resolve a RequestContext and enforce the corresponding collection ability unless the method is explicitly described as trusted maintenance infrastructure.

createBylineClient(config)

function createBylineClient<Registry = RegisteredCollections>(
config: BylineClientConfig
): BylineClient<Registry>

The default registry comes from generated declaration merging. In a configured application, client.collection('docs') therefore infers the collection path and generated field shape without an explicit generic.

import { createSuperAdminContext } from '@byline/auth'
import { createBylineClient } from '@byline/client'
import { getServerConfig } from '@byline/core'
const client = createBylineClient({
config: getServerConfig(),
requestContext: createSuperAdminContext({ id: 'content-import' }),
})

BylineClientConfig

Property

Requirement or default

Description

config

Optional shorthand

Resolved server config supplying database, collections, storage, search, slugifier, rich-text adapters, and locale defaults.

db

Required without config

Database adapter. An explicit value overrides config.db.

collections

Required without config

Collection tuple. An explicit value overrides config.collections.

storage

config.storage

Installation storage provider forwarded into document lifecycle contexts and hooks. Document deletion retains uploaded objects.

search

config.search

Search provider used by collection and zone search. Calls fail clearly when no provider exists.

richTextToText

config.fields.richText.toText

Plain-text extractor used while constructing search projections.

contentLocales

Configured content locales, then [defaultLocale]

Locales walked by indexing operations.

logger

Registered core logger, then silent logger

Structured lifecycle logger.

defaultLocale

Configured content default, then en

Implicit locale for reads, writes, paths, and indexing.

slugifier

config.slugifier, then slugify

Document-path slugifier used by lifecycle writes.

richTextPopulate

config.fields.richText.populate

Read-time rich-text relation refresher.

requestContext

Required in practice

Static RequestContext or per-operation factory. Omission makes operations fail with ERR_UNAUTHENTICATED.

An explicit disaggregated property wins over the same value from config. This supports tests and migrations that substitute one dependency without registering a complete core.

BylineClient properties

Property

Type

Description

db

IDbAdapter

Resolved database adapter.

collections

readonly CollectionDefinition[]

Resolved schema tuple.

storage

IStorageProvider | undefined

Resolved storage provider.

logger

BylineLogger

Resolved lifecycle logger.

defaultLocale

string

Default content locale.

slugifier

SlugifierFn | undefined

Custom path slugifier, or undefined when lifecycle code should use the built-in default.

richTextPopulate

RichTextPopulateFn | undefined

Resolved read-time rich-text adapter.

searchProvider

SearchProvider | undefined

Resolved search driver. The query method is named search().

richTextToText

RichTextToTextFn | undefined

Resolved search-index text extractor.

contentLocales

string[]

Locales walked by indexing operations.

requestContext

requestContext?:
| RequestContext
| (() => RequestContext | Promise<RequestContext>)

Use a static context for a script that authenticates once. Use a factory for request-bound code. A factory must return the same logical authority, including requestId, throughout one request; host adapters use request memoization to satisfy that contract.

BylineClient methods

collection(path)

client.collection<TPath extends keyof Registry & string>(
path: TPath
): CollectionHandle<Registry[TPath]>

Returns a collection-scoped handle or throws ERR_NOT_FOUND when the configured tuple has no matching path.

search(options)

client.search(options: ZoneSearchOptions): Promise<ClientSearchResults>

Runs cross-collection ranked search over one configured zone. Collections the actor cannot read are excluded; beforeRead applies per collection.

resolveRequestContext()

client.resolveRequestContext(): Promise<RequestContext>

Resolves the configured static context or factory. Framework and application integrations rarely need to call it directly.

Collection record lookups

client.resolveCollectionRecord(path: string): Promise<{ id: string; version: number }>
client.resolveCollectionId(path: string): Promise<string>

Both use a per-client cache. Lifecycle writes use the version to stamp collection_version; ordinary reads usually need only the ID.

CollectionHandle method index

Method

Returns

Purpose

find(options?)

Promise<FindResult<F>>

Paginated current-document query.

findOne(options?)

Promise<ClientDocument<F> | null>

First matching current document.

findById(id, options?)

Promise<ClientDocument<F> | null>

Current document by logical ID.

findByPath(path, options?)

Promise<ClientDocument<F> | null>

Current document by locale-resolved path.

search(options)

Promise<ClientSearchResults>

Ranked search scoped to this collection.

create(data, options?)

Promise<CreateDocumentResult>

Creates a logical document and first immutable version.

update(id, data, options?)

Promise<UpdateDocumentResult>

Full-document replacement that creates a new immutable version.

changeStatus(id, nextStatus)

Promise<ChangeStatusResult>

Applies one valid workflow transition.

unpublish(id)

Promise<UnpublishResult>

Archives the currently published version or versions.

restoreVersion(id, sourceVersionId)

Promise<RestoreVersionResult>

Copies historical content into a new current version.

delete(id)

Promise<DeleteDocumentResult>

Soft-deletes the document and reconciles associated structural state.

count(options?)

Promise<number>

Editorial current-version count, optionally for one exact status.

countByStatus()

Promise<Array<{ status, count }>>

Editorial counts grouped by workflow status.

history(id, options?)

Promise<FindResult<F>>

Paginated immutable version history.

findByVersion(versionId, options?)

Promise<ClientDocument<F> | null>

One exact historical version, constrained to this collection.

auditLog(id, options?)

Promise<AuditLogPage>

Paginated document-grain non-versioned audit entries.

indexDocument(id)

Promise<void>

Reconciles one document's published locale projections into search.

removeFromIndex(id)

Promise<void>

Removes one document's projections from search.

reindex()

Promise<ReindexResult>

Clears and rebuilds this collection's search index.

placeTreeNode(id, options)

Promise<{ orderKey: string }>

Places, reorders, or reparents one node in a tree collection.

removeFromTree(id, options?)

Promise<void>

Makes a tree document unplaced without deleting it.

getSubtree(options?)

Promise<TreeNode<F>[]>

Reads a nested tree or subtree.

getAncestors(id, options?)

Promise<ClientDocument<F>[]>

Reads root-first breadcrumbs excluding the queried node.

getTreeParent(id, options?)

Promise<TreeParentResult>

Reads placed/root/child state with hidden-parent redaction.

Current-document reads

find(options?)

handle.find<F = RegisteredFields>(options?: FindOptions<F>): Promise<FindResult<F>>
interface FindOptions<F> {
where?: WhereClause
select?: (keyof F & string)[] | string[]
sort?: SortSpec
locale?: string
page?: number
pageSize?: number
populate?: PopulateSpec
depth?: number
status?: 'published' | 'any'
onMissingLocale?: 'fallback' | 'empty' | 'omit'
}

Option

Default

Description

where

None

Caller predicate over fields and reserved document keys.

select

All fields

Field projection. The option is named select; returned content remains under doc.fields.

sort

Adapter default

String, array, or object sort specification.

locale

Client default

Requested content locale.

page

1

One-based page.

pageSize

20

Documents per page.

populate

None

Relation population specification.

depth

1 when populate is set, otherwise 0

Maximum relation traversal depth, clamped by the internal read context.

status

published

Source view. where.status remains a separate exact-status filter.

onMissingLocale

fallback

Missing-localized-content behavior.

Every read option type also carries trusted _bypassBeforeRead?: true; hook re-entry shapes carry _readContext. Public application code must not use either escape hatch.

findOne(options?)

handle.findOne<F>(options?: {
where?: WhereClause
select?: string[]
locale?: string
populate?: PopulateSpec
depth?: number
status?: 'published' | 'any'
onMissingLocale?: 'fallback' | 'empty' | 'omit'
}): Promise<ClientDocument<F> | null>

Uses the same read pipeline as find() and returns the first match.

findById(id, options?)

handle.findById<F>(documentId: string, options?: {
select?: string[]
locale?: string
populate?: PopulateSpec
depth?: number
status?: 'published' | 'any'
onMissingLocale?: 'fallback' | 'empty' | 'omit'
lenient?: boolean
}): Promise<ClientDocument<F> | null>

lenient: true skips rows that cannot be reconstructed against the current schema and returns _restoreWarnings. It is intended for the admin recovery/edit path; public reads should fail rather than serve partial data.

findByPath(path, options?)

handle.findByPath<F>(path: string, options?: {
select?: string[]
locale?: string
populate?: PopulateSpec
depth?: number
status?: 'published' | 'any'
onMissingLocale?: 'fallback' | 'empty' | 'omit'
}): Promise<ClientDocument<F> | null>

Resolves the path with the request locale and document source-locale fallback rules. Path conflicts are prevented by the storage uniqueness contract.

Filtering and sorting

WhereClause is the client alias for the canonical QueryPredicate from @byline/core.

where: {
$and: [
{ status: 'published' },
{ views: { $gte: 100 } },
{ category: { path: 'news' } },
],
}

Reserved keys such as status and path address document metadata. Relation objects without $ operators become nested predicates against the target collection. Client SDK documents the complete operator behavior and strict security-predicate boundary.

sort: 'publishedOn'
sort: '-publishedOn'
sort: ['-publishedOn', 'title']
sort: { publishedOn: 'desc' }

Missing-locale policy

Value

Behavior

fallback

Returns the document and resolves localized values through the locale fallback chain.

empty

Returns the document with missing requested-locale values empty. Used by authoring flows.

omit

Excludes documents unavailable in the requested locale; detail reads return null.

Relation population always uses fallback behavior so a populated graph does not develop locale holes.

ClientDocument

interface ClientDocument<F> {
id: string
versionId: string
path: string
status: string
sourceLocale?: string
createdAt: Date
updatedAt: Date
createdBy?: string
eventType?: string
fields: F
_restoreWarnings?: string[]
availableLocales?: string[]
_availableVersionLocales?: string[]
_localeAgnostic?: boolean
}

Property

Description

id

Stable logical document ID.

versionId

Specific immutable version returned by this read.

path

Locale-resolved document path.

status

Workflow status of the returned version.

sourceLocale

Stable content locale assigned when the document was created.

createdAt, updatedAt

Version timestamps.

createdBy

Actor ID that created this immutable version, when recorded.

eventType

Lifecycle action that produced the version.

fields

Collection field data.

_restoreWarnings

Lenient reconstruction warnings.

availableLocales

Editor-advertised locale set stored at document grain.

_availableVersionLocales

Derived locales structurally available on this returned version.

_localeAgnostic

Indicates that the document has no localized content.

find() returns { docs, meta }, where meta contains total, page, pageSize, and totalPages.

Population type helpers

type WithPopulated<F, K extends keyof F, Target> = /* one relation */
type WithPopulatedMany<F, K extends keyof F, Target> = /* hasMany relation */

These helpers overlay the operation-specific populated shape on canonical generated types. They do not trigger population at runtime.

type PopulatedArticle = WithPopulated<ArticleFields, 'category', CategoryFields>
const article = await client.collection('articles').findById<PopulatedArticle>(id, {
populate: { category: '*' },
})

Writes

create(data, options?)

handle.create(data: Record<string, any>, options?: {
locale?: string
status?: string
path?: string
availableLocales?: string[]
}): Promise<CreateDocumentResult>

Option

Default

Description

locale

Client default

Locale of the submitted field values and new document source locale.

status

Collection workflow default

Initial workflow status.

path

Derived from useAsPath, then UUID

Explicit initial document path.

availableLocales

Empty set

Initial editor-advertised content locales.

update(id, data, options?)

handle.update(documentId: string, data: Record<string, any>, options?: {
locale?: string
path?: string
availableLocales?: string[]
}): Promise<UpdateDocumentResult>

Updates use whole-document replacement semantics and mint a new immutable version. Omitting path or availableLocales preserves the existing document-grain value; an explicit empty locale array clears the advertised set.

Workflow and restoration

handle.changeStatus(documentId: string, nextStatus: string): Promise<ChangeStatusResult>
handle.unpublish(documentId: string): Promise<UnpublishResult>
handle.restoreVersion(
documentId: string,
sourceVersionId: string
): Promise<RestoreVersionResult>

changeStatus() accepts a valid adjacent transition or reset to the first workflow status. Publishing archives other published versions of the same document. restoreVersion() copies all-locale historical content into a new version and defaults its status to the first workflow status; it never silently republishes.

delete(id)

handle.delete(documentId: string): Promise<DeleteDocumentResult>

Soft-deletes every version and path row, appends audit data, reconciles tree edges where applicable, and then runs post-commit consumers. The result distinguishes a clean commit from a commit whose post-commit side effects failed. Do not retry a committed delete merely because a post-commit hook failed.

Editorial metadata

These methods authorize against the any read mode and reject anonymous callers. They apply beforeRead so metadata cannot expose hidden rows.

handle.count(options?: { status?: string }): Promise<number>
handle.countByStatus(): Promise<Array<{ status: string; count: number }>>

count() is an editorial current-version workflow count, not a published-view equivalent of find().meta.total.

history(id, options?)

handle.history<F>(documentId: string, options?: {
locale?: string
page?: number
pageSize?: number
order?: string
desc?: boolean
}): Promise<FindResult<F>>

Every historical version is independently scoped through beforeRead before pagination and totals are returned.

findByVersion(versionId, options?)

handle.findByVersion<F>(versionId: string, options?: {
select?: string[]
locale?: string
}): Promise<ClientDocument<F> | null>

The query is constrained to the handle's collection. Unknown, cross-collection, and predicate-hidden versions all return null.

auditLog(id, options?)

handle.auditLog(documentId: string, options?: {
page?: number
pageSize?: number
locale?: string
}): Promise<AuditLogPage>

Returns newest-first non-versioned system-field, status, tree, and deletion events. It returns an empty page when the access gate hides the document or the adapter lacks the optional audit query at runtime.

Search

Collection search

handle.search(options: {
query: string
matching?: SearchMatching
locale?: string
status?: 'published' | 'any'
where?: QueryPredicate
facets?: string[]
limit?: number
offset?: number
hydrate?: boolean
}): Promise<ClientSearchResults>

The collection path is implied by the handle. hydrate: true attaches a shaped ClientDocument to each authorized hit.

Zone search

client.search(options: {
query: string
zone: string
matching?: SearchMatching
locale?: string
status?: 'published' | 'any'
where?: QueryPredicate
facets?: string[]
limit?: number
offset?: number
hydrate?: boolean
}): Promise<ClientSearchResults>

The exact result, matching, facet, hydration, and authorization behavior is in Search API.

Index maintenance

handle.indexDocument(documentId: string): Promise<void>
handle.removeFromIndex(documentId: string): Promise<void>
handle.reindex(): Promise<{
collectionPath: string
documents: number
indexed: number
}>

indexDocument() mirrors published content for every configured locale and removes stale projections when the document is no longer publishable. It no-ops when the collection or provider is not configured for search. removeFromIndex() removes every locale projection for the document. reindex() requires the collection's reindex ability and rebuilds the complete collection projection.

These methods have different trust boundaries. indexDocument() requires published-read ability but bypasses beforeRead row predicates so lifecycle synchronization can see every published document. removeFromIndex() delegates directly to the provider without resolving a request context or checking an ability; reserve it for trusted lifecycle and maintenance code. reindex() requires the reindex ability, and its internal document reads also require published-read ability while bypassing beforeRead.

Document trees

Every tree method requires CollectionDefinition.tree: true. Tree writes use the collection update ability; reads use the read ability and apply status and beforeRead at each structural edge.

placeTreeNode(id, options)

handle.placeTreeNode(documentId: string, options: {
parentDocumentId: string | null
beforeDocumentId?: string | null
afterDocumentId?: string | null
reconcile?: boolean
}): Promise<{ orderKey: string }>

beforeDocumentId is the left neighbor, so the node lands immediately after it. afterDocumentId is the right neighbor, so the node lands immediately before it. Both are resolved within the target parent group. reconcile re-runs post-commit tree consumers for an otherwise exact no-op.

removeFromTree(id, options?)

handle.removeFromTree(
documentId: string,
options?: { reconcile?: boolean }
): Promise<void>

Deletes the structural edge and makes the document unplaced. It does not delete the document or mint a version.

getSubtree(options?)

handle.getSubtree<F>(options?: {
rootDocumentId?: string | null
depth?: number
locale?: string
select?: string[]
status?: 'published' | 'any'
}): Promise<Array<{
document: ClientDocument<F>
depth: number
children: TreeNode<F>[]
}>>

rootDocumentId: null reads the whole forest from collection roots. A value includes that document as the subtree root. Hidden or unpublished nodes break the structural spine; descendants are not promoted.

getAncestors(id, options?)

handle.getAncestors<F>(documentId: string, options?: {
locale?: string
select?: string[]
status?: 'published' | 'any'
}): Promise<ClientDocument<F>[]>

Returns ancestors root-first and excludes the queried document. Visibility breaks truncate the chain.

getTreeParent(id, options?)

handle.getTreeParent(documentId: string, options?: {
locale?: string
status?: 'published' | 'any'
}): Promise<{
placed: boolean
parentDocumentId: string | null
parentVisibility: 'none' | 'visible' | 'redacted'
}>

placed: false means unplaced. placed: true with no parent means root. A visible child whose parent is hidden remains placed, but the parent ID is redacted.

Document trees documents the storage model, mutation guarantees, audit behavior, invalidation, and authoring UI.

PreviousFields API
NextTesting

On this Page

  • createBylineClient(config)
  • BylineClientConfig
  • BylineClient properties
  • requestContext
  • BylineClient methods
  • collection(path)
  • search(options)
  • resolveRequestContext()
  • Collection record lookups
  • CollectionHandle method index
  • Current-document reads
  • find(options?)
  • findOne(options?)
  • findById(id, options?)
  • findByPath(path, options?)
  • Filtering and sorting
  • Missing-locale policy
  • ClientDocument
  • Population type helpers
  • Writes
  • create(data, options?)
  • update(id, data, options?)
  • Workflow and restoration
  • delete(id)
  • Editorial metadata
  • history(id, options?)
  • findByVersion(versionId, options?)
  • auditLog(id, options?)
  • Search
  • Collection search
  • Zone search
  • Index maintenance
  • Document trees
  • placeTreeNode(id, options)
  • removeFromTree(id, options?)
  • getSubtree(options?)
  • getAncestors(id, options?)
  • getTreeParent(id, options?)
Byline CMS

Building the future of content management, one commit at a time.

Project

  • Documentation
  • Roadmap
  • Contributing
  • Releases

Community

  • GitHub Discussions
  • Blog
  • Newsletter

Legal

  • Privacy Policy
  • Terms of Use
  • Cookies

© 2026 Infonomic Company Limited and contributors. Open source and built with ❤️ by the community.