/** * 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 */ /** * Helpers shared by the per-operation lifecycle modules. Internal to the * `document-lifecycle/` directory — nothing here is re-exported through * the barrel (`index.ts`), so the package's public surface is unchanged * by the per-operation split. */ import { type CollectionDefinition, type CollectionHookSlot, type IDbAdapter } from '../../@types/index.js'; import type { BylineLogger } from '../../lib/logger.js'; import type { SlugifierFn } from '../../utils/slugify.js'; import type { DocumentLifecycleContext } from './context.js'; /** * The acting user's id for the version audit trail (`created_by` on * `byline_document_versions`). * * Returns the id only when it is a real **persisted user id** — i.e. a UUID. * Synthetic actors used by scripts, seeds, and tests (e.g. * `createSuperAdminContext({ id: 'import-docs-script' })`, or the default * `'super-admin'`) are **not** users: their non-UUID ids would be rejected by * the `uuid` column outright, and the correct audit value for a system/tooling * write is NULL regardless. So a non-UUID id — and a missing `requestContext` * (the seeds/migrations escape hatch) — both yield `undefined` → NULL * `created_by`, which the history strip renders as "unknown". Real * `AdminAuth` / `UserAuth` actors always carry UUID ids, so their attribution * is unaffected. See docs/07-auth-and-security/02-auditability.md — Workstream 1. */ export declare function actorId(ctx: DocumentLifecycleContext): string | undefined; /** * Safely invoke an optional hook slot, awaiting the result if it returns a * Promise. When the slot is an array of functions they are executed * sequentially in order. */ export declare function invokeHook(hook: CollectionHookSlot | undefined, ctx: Ctx): Promise; /** * Run the registered richtext embed adapter across every rich-text leaf * in the outgoing document data. Mirror of the read-side * `populateRichTextFields` — fires once per write, mutates `data` in * place. Per-leaf errors are logged and swallowed by `embedRichTextFields` * itself (branch C); document-level errors propagate. * * No-op when no embed adapter is registered. The bootstrap validator * (step 7 of the link-refactor strategy) will eventually fail-fast for * collections that declare `embedRelationsOnSave: true` without a * registered adapter; until then a missing adapter is silent and writes * proceed unmodified. */ export declare function applyRichTextEmbed(ctx: DocumentLifecycleContext, data: Record): Promise; /** * For collections with `orderable: true` on their schema definition, compute * an append-at-end fractional-index key for a newly-inserted document. * Returns `undefined` when the collection hasn't opted in (or has no * definition registered, e.g. in unit-test environments), so the storage row * gets `order_key = NULL` and the existing "no ordering" behavior holds. */ export declare function maybeAppendOrderKey(ctx: DocumentLifecycleContext, collectionPath: string): Promise; /** Extract `id` from the document object returned by `createDocumentVersion`. */ export declare function extractVersionId(document: any): string; /** Extract the logical document id from the document object returned by `createDocumentVersion`. */ export declare function extractDocumentId(document: any): string; /** * Detect a unique-constraint violation on * `byline_document_paths(collection_id, locale, path)` and translate it * to `ERR_PATH_CONFLICT`. Any other error is rethrown unchanged. * * Driver anatomy (SQLSTATE codes, `cause`-chain walking, constraint-name * carriage) is delegated to `db.classifyError` — the adapter seam that * canonicalises a raw driver error into a `DbErrorClassification`. This * function only knows the classification codes and the path constraint's * name substring; it stays targeted to the path constraint so unrelated * unique violations aren't spuriously rebranded as path conflicts. */ export declare function rethrowPathConflict(db: IDbAdapter, err: unknown, path: string, locale: string, operation: 'create' | 'update' | 'duplicate'): never; /** * Detect whether an error is the `ERR_PATH_CONFLICT` raised by * `rethrowPathConflict`. Used by `duplicateDocument`'s retry logic to * keep the conflict-handling path separate from genuine errors. */ export declare function isPathConflictError(err: unknown): boolean; /** * Resolve the path argument the storage primitive should receive on an * update operation. Phase 1 only writes path rows under the default * content locale; on translation saves a supplied path is dropped with * a `logger.warn`, leaving the existing default-locale row untouched. * * Returns `undefined` to signal the storage primitive should skip the * path write entirely (no upsert). */ export declare function resolvePathForUpdate(args: { explicitPath: string | null; currentPath: string | undefined; requestLocale: string; sourceLocale: string; documentId: string; logger?: BylineLogger; }): string | undefined; /** * Derive the `path` value written into `byline_document_paths` at * create time. * * 1. `definition.useAsPath` set → slugify the named source field's value * in the default content locale. * 2. Source field absent / empty → fall back to `crypto.randomUUID()`. * * Caller passes explicit overrides separately; this helper only handles * the auto-derivation cascade. */ export declare function derivePath(definition: CollectionDefinition, data: Record, defaultLocale: string, slugifier: SlugifierFn): string; /** * Strip the synthetic `_id` / `_type` meta keys from every block and * array-item node in a reconstructed document tree. * * Reconstructed `locale: 'all'` trees carry stable `_id` values for * blocks and array items (see CLAUDE.md → "Block/array items carry a * stable `_id`"). For a *duplicate*, the new document is conceptually a * fresh entity — its blocks should get fresh meta ids rather than * inheriting the source's. Mutates the tree in place. * * Distinct from `restoreDocumentVersion`, which deliberately preserves * `_id`s so block identity is stable across history. */ export declare function stripMetaIdsInPlace(value: unknown): void;