import type { StructuralMutationReceipt } from '@byline/core' /** * This Source Code is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * Copyright (c) Infonomic Company Limited */ /** * Framework-neutral function contracts that field/form components in * `@byline/ui` need from the host application. The host wires concrete * implementations via `BylineFieldServicesProvider` — typically thin * adapters around TanStack Start server functions, Next.js server * actions, or any other RPC-style transport. */ import type { StoredFileValue } from '@byline/core' export interface CollectionListParams { page?: number page_size?: number order?: string desc?: boolean query?: string locale?: string status?: string fields?: string[] } export interface CollectionListDoc { id: string path?: string [field: string]: unknown } export interface CollectionListResponse { docs: CollectionListDoc[] meta: { totalPages?: number; [k: string]: unknown } included: { collection: { id: string; [k: string]: unknown } } } export type GetCollectionDocumentsFn = (input: { collection: string params: CollectionListParams }) => Promise export interface UploadedFileResult { documentId?: string documentVersionId?: string /** * The persisted file value, including the `variants` array with * `storagePath`, `storageUrl`, `width`, `height`, and `format` for each * generated derivative. Single source of truth — the legacy top-level * `variants: { name, url }[]` is gone. */ storedFile: StoredFileValue } export type UploadFieldFn = ( collection: string, formData: FormData, createDocument?: boolean ) => Promise // --- Document tree (the `tree: true` primitive — docs/04-collections/04-document-trees.md) ----- /** One hydrated ancestor in a document's breadcrumb trail (root-first). */ export interface TreeAncestor { id: string title: string path?: string } export interface PlaceTreeNodeInput { expectedRevision: number collection: string documentId: string /** The new parent; `null` makes the document a root node. */ parentDocumentId: string | null /** Optional sibling neighbours (left = land after, right = land before). */ beforeDocumentId?: string | null afterDocumentId?: string | null } /** Place / move a document within its collection's tree. */ export type PlaceTreeNodeFn = ( input: PlaceTreeNodeInput ) => Promise<{ orderKey: string } & StructuralMutationReceipt> /** Remove a document from the tree (back to the unplaced state). */ export type RemoveFromTreeFn = (input: { collection: string documentId: string expectedRevision: number }) => Promise /** Resolve a document's ancestor chain, root-first, hydrated with titles. */ export type GetTreeAncestorsFn = (input: { collection: string documentId: string }) => Promise /** * Resolve a document's placement state — the tri-state (unplaced / root / child) * that `getTreeAncestors` cannot express (it returns `[]` for both root and * unplaced). `placed: false` = unplaced; `placed: true` + null parent = root. */ export type GetTreeParentFn = (input: { collection: string documentId: string }) => Promise<{ placed: boolean; parentDocumentId: string | null }> /** See `BylineFieldServices.canCreateInCollection`. */ export type CanCreateInCollectionFn = (collectionPath: string) => boolean /** See `BylineFieldServices.getCreateDocumentUrl`. */ export type GetCreateDocumentUrlFn = (collectionPath: string) => string export interface BylineFieldServices { getCollectionDocuments: GetCollectionDocumentsFn uploadField: UploadFieldFn /** * Document-tree operations, consumed by the sidebar tree-placement widget. * Optional — only hosts that serve `tree: true` collections need to wire * them; the widget guards on their presence. */ placeTreeNode?: PlaceTreeNodeFn removeFromTree?: RemoveFromTreeFn getTreeAncestors?: GetTreeAncestorsFn getTreeParent?: GetTreeParentFn /** * Whether the viewer may create documents in a collection, used to decide * whether to offer a create affordance in the relation picker. * * Cosmetic only: the create view enforces the ability server-side regardless * of what this returns. Optional, like the tree operations above — a host that * wires neither this nor `getCreateDocumentUrl` simply gets no affordance, and * the widget guards on their presence. */ canCreateInCollection?: CanCreateInCollectionFn /** * Root-relative URL of a collection's create view, built from the host's * configured admin path. * * Root-relative rather than absolute because no origin is available during the * server render, and the admin base path is host configuration — * `@byline/admin` must not assume `/admin`. */ getCreateDocumentUrl?: GetCreateDocumentUrlFn }