import { TAtscriptAnnotatedType, TAtscriptDataType, TSerializedAnnotatedType, TValidatorOptions, TValidatorPlugin } from "@atscript/typescript/utils"; import { Client, TCrudOp, TCrudPermissions, TCrudPermissions as TCrudPermissions$1, TDbActionInfo, TDbActionInfo as TDbActionInfo$1, TDbActionIntent, TDbActionLevel, TDbActionProcessor } from "@atscript/db-client"; //#region src/shared/annotation-keys.d.ts declare const UI_TYPE: "ui.type"; declare const UI_FORM_PLACEHOLDER: "ui.form.placeholder"; declare const UI_FORM_HINT: "ui.form.hint"; declare const UI_FORM_CLASSES: "ui.form.classes"; declare const UI_FORM_STYLES: "ui.form.styles"; declare const UI_FORM_AUTOCOMPLETE: "ui.form.autocomplete"; declare const UI_FORM_DISABLED: "ui.form.disabled"; declare const UI_FORM_OPTIONS: "ui.form.options"; declare const UI_FORM_ORDER: "ui.form.order"; declare const UI_FORM_TYPE: "ui.form.type"; declare const UI_FORM_COMPONENT: "ui.form.component"; declare const UI_FORM_HIDDEN: "ui.form.hidden"; declare const UI_FORM_ATTR: "ui.form.attr"; declare const UI_FORM_GRID_COL_SPAN: "ui.form.grid.colSpan"; declare const UI_FORM_GRID_ROW_SPAN: "ui.form.grid.rowSpan"; declare const UI_FORM_SUBMIT_TEXT: "ui.form.submit.text"; declare const UI_FORM_LABEL_SINGULAR: "ui.form.label.singular"; declare const UI_FORM_ACTION: "ui.form.action"; declare const UI_FORM_PREFIX: "ui.form.prefix"; declare const UI_FORM_PREFIX_REF: "ui.form.prefix.ref"; declare const UI_FORM_PREFIX_ICON: "ui.form.prefix.icon"; declare const UI_FORM_SUFFIX: "ui.form.suffix"; declare const UI_FORM_SUFFIX_REF: "ui.form.suffix.ref"; declare const UI_FORM_SUFFIX_ICON: "ui.form.suffix.icon"; declare const UI_TABLE_WIDTH: "ui.table.width"; declare const UI_TABLE_COMPONENT: "ui.table.component"; declare const UI_TABLE_SELECT_WITH: "ui.table.selectWith"; declare const UI_TABLE_EXCLUDE: "ui.table.exclude"; declare const UI_TABLE_ATTR: "ui.table.attr"; declare const UI_TABLE_CLASSES: "ui.table.classes"; declare const UI_TABLE_STYLES: "ui.table.styles"; declare const UI_TABLE_TYPE: "ui.table.type"; declare const UI_TABLE_ORDER: "ui.table.order"; declare const UI_DICT_LABEL: "ui.dict.label"; declare const UI_DICT_DESCR: "ui.dict.descr"; declare const UI_DICT_ATTR: "ui.dict.attr"; declare const UI_DICT_FILTERABLE: "ui.dict.filterable"; declare const UI_DICT_SORTABLE: "ui.dict.sortable"; declare const UI_DICT_SEARCHABLE: "ui.dict.searchable"; declare const UI_NAV_GROUP: "ui.nav.group"; declare const UI_NAV_ORDER: "ui.nav.order"; declare const UI_NAV_HIDDEN: "ui.nav.hidden"; declare const DB_REL_FK: "db.rel.FK"; declare const DB_HTTP_PATH: "db.http.path"; declare const DB_AMOUNT_CURRENCY: "db.amount.currency"; declare const DB_AMOUNT_CURRENCY_REF: "db.amount.currency.ref"; declare const DB_UNIT: "db.unit"; declare const DB_UNIT_REF: "db.unit.ref"; declare const DB_COLUMN_PRECISION: "db.column.precision"; declare const WF_ACTION_WITH_DATA: "wf.action.withData"; declare const META_LABEL: "meta.label"; declare const META_ID: "meta.id"; declare const META_DESCRIPTION: "meta.description"; declare const META_READONLY: "meta.readonly"; declare const META_REQUIRED: "meta.required"; declare const META_DEFAULT: "meta.default"; declare const META_SENSITIVE: "meta.sensitive"; declare const EXPECT_MAX_LENGTH: "expect.maxLength"; declare const UI_FORM_FN_PREFIX: "ui.form.fn."; declare const UI_FORM_FN_LABEL: "ui.form.fn.label"; declare const UI_FORM_FN_PLACEHOLDER: "ui.form.fn.placeholder"; declare const UI_FORM_FN_DESCRIPTION: "ui.form.fn.description"; declare const UI_FORM_FN_HINT: "ui.form.fn.hint"; declare const UI_FORM_FN_HIDDEN: "ui.form.fn.hidden"; declare const UI_FORM_FN_DISABLED: "ui.form.fn.disabled"; declare const UI_FORM_FN_READONLY: "ui.form.fn.readonly"; declare const UI_FORM_FN_OPTIONS: "ui.form.fn.options"; declare const UI_FORM_FN_ATTR: "ui.form.fn.attr"; declare const UI_FORM_FN_VALUE: "ui.form.fn.value"; declare const UI_FORM_FN_CLASSES: "ui.form.fn.classes"; declare const UI_FORM_FN_STYLES: "ui.form.fn.styles"; declare const UI_FORM_FN_TITLE: "ui.form.fn.title"; declare const UI_FORM_FN_SUBMIT_TEXT: "ui.form.fn.submit.text"; declare const UI_FORM_FN_SUBMIT_DISABLED: "ui.form.fn.submit.disabled"; declare const UI_TABLE_FN_PREFIX: "ui.table.fn."; declare const UI_TABLE_FN_ATTR: "ui.table.fn.attr"; declare const UI_TABLE_FN_CLASSES: "ui.table.fn.classes"; declare const UI_TABLE_FN_STYLES: "ui.table.fn.styles"; declare const UI_FORM_VALIDATE: "ui.form.validate"; //#endregion //#region src/value-help/types.d.ts /** An option for select/radio fields — either a plain string or a `{ key, label }` pair. */ type TFormEntryOptions = { key: string; label: string; } | string; /** * Minimal sync probe output for a value-help–eligible prop. * * Emitted by `extractValueHelp(prop)` at def-construction time. Consumers use * `url` to key the lazy resolver (`resolveValueHelp(url)`) that fetches the * target's own `/meta` endpoint and returns the field-role details. */ interface ValueHelpInfo { /** HTTP path to the value-help target (from the target's `@db.http.path`). */ url: string; /** * Field on the target that this FK references (from `prop.ref.field`, e.g. "id"). * This is the value committed to the FK field when the user picks a row. */ targetField: string; } //#endregion //#region src/form/types.d.ts /** Form action metadata — the action id and display label. */ interface TFormAction { id: string; label: string; } /** * A single form field definition — thin pointer to the ATScript prop. * * All metadata (label, disabled, options, etc.) lives in `prop.metadata` * and is resolved on demand via resolve utilities. */ interface FormFieldDef { /** Dot-separated path relative to the parent data context. `''` = root. */ path: string; prop: TAtscriptAnnotatedType; /** * Render-key the renderer dispatches on. For structured kinds (array, * object, tuple, multi-variant union) this stays the kind name so that * `isArrayField`/`isObjectField`/`isUnionField`/`isTupleField` keep * working downstream (validator resetValue, child path provide, AsArray * recursion). Primitives may store an `@ui.form.type`/`@ui.type` * override here directly — for those there is no structural behaviour * to preserve. */ type: string; /** * Optional `@ui.form.type` (or `@ui.type`) override for structured * kinds. When set, the renderer looks this up in the `types` map FIRST * and falls back to `type` only when the map has no entry. Letting the * override live in a separate field keeps the structural type guards * (`isArrayField` et al.) on `type` honest while still allowing a * consumer to attach a flat custom widget to e.g. a `string[]`. */ customType?: string; phantom: boolean; name: string; /** True when no `ui.fn.*` metadata keys exist. Vue perf flag. */ allStatic: boolean; /** * `@ui.form.pushDown` — render this field below the submit button in its * own grid, instead of in the main field grid above submit. Set on * top-level form fields (typically secondary `ui.action` links). The field * stays in `fields[]` for validation/data; only its render slot moves. */ pushDown: boolean; } /** * Complete form definition — produced by createFormDef(). * Form-level metadata (title, submit) resolved on demand via resolveFormProp. */ interface FormDef { type: TAtscriptAnnotatedType; /** Root field representing the entire form. For interface types this is `type='object'`; for single-type forms it is a leaf field. */ rootField: FormFieldDef; fields: FormFieldDef[]; /** * Render partition of `fields` by `@ui.form.pushDown`, precomputed once so * the renderer never re-scans per frame. `mainFields` (above submit) plus * `pushDownFields` (below submit) cover `fields` exactly once. In the common * case nothing is pushed down: `mainFields === fields` (same ref) and * `pushDownFields` is empty. */ mainFields: FormFieldDef[]; pushDownFields: FormFieldDef[]; flatMap: Map; } /** One branch of a union type — used by union fields and union array items. */ interface FormUnionVariant { /** Display label — from @meta.label or auto-generated (e.g. "1. String") */ label: string; /** The annotated type for this variant */ type: TAtscriptAnnotatedType; /** Pre-built FormDef for object variants (undefined for primitives) */ def?: FormDef; /** Pre-built field def for primitive variants (undefined for objects) */ itemField?: FormFieldDef; /** Design type for primitive variants ('string', 'number', 'boolean') */ designType?: string; } /** Extended field def for array-typed fields. */ interface FormArrayFieldDef extends FormFieldDef { /** ATScript annotated type of array items (from TAtscriptTypeArray.of) */ itemType: TAtscriptAnnotatedType; /** Pre-built template field def for items (path=''). */ itemField: FormFieldDef; } /** Extended field def for object (interface/type) nested fields. */ interface FormObjectFieldDef extends FormFieldDef { /** Pre-built FormDef for the nested object's fields */ objectDef: FormDef; } /** Extended field def for union fields — standalone union props and union array items. */ interface FormUnionFieldDef extends FormFieldDef { /** Available union branches. */ unionVariants: FormUnionVariant[]; } /** Extended field def for tuple fields — fixed-length with typed positions. */ interface FormTupleFieldDef extends FormFieldDef { /** Pre-built field defs, one per tuple position. */ itemFields: FormFieldDef[]; } /** Type guard: checks if a field def is an array field. */ declare function isArrayField(field: FormFieldDef): field is FormArrayFieldDef; /** Type guard: checks if a field def is an object field. */ declare function isObjectField(field: FormFieldDef): field is FormObjectFieldDef; /** Type guard: checks if a field def is a union field. */ declare function isUnionField(field: FormFieldDef): field is FormUnionFieldDef; /** Type guard: checks if a field def is a tuple field. */ declare function isTupleField(field: FormFieldDef): field is FormTupleFieldDef; //#endregion //#region src/form/create-form-def.d.ts /** * Converts an ATScript annotated type into a FormDef. * * - **Object types** (`kind === 'object'`): produces an object root with nested fields. * - **Non-object types** (primitive, array, union, etc.): produces a single leaf root field * with `path: ''`. * * @param opts.versionColumn - Name of a server-managed OCC version column to * exclude from `fields[]` (it stays in `flatMap` so the wire payload is * unchanged). Root-table concept; not propagated into nested recursive calls. */ declare function createFormDef(type: TAtscriptAnnotatedType, opts?: { versionColumn?: string; }): FormDef; /** * Builds union variant definitions from a union annotated type. * Iterates top-level items directly — one variant per item. */ declare function buildUnionVariants(typeDef: TAtscriptAnnotatedType): FormUnionVariant[]; //#endregion //#region src/form/form-actions.d.ts /** One declared form action: its id and whether it carries form data. */ interface FormActionInfo { id: string; withData: boolean; } /** * Declared actions of a form — the union of `@ui.form.action` ids and * `@wf.action.withData` ids across all fields. `withData` distinguishes a * data-carrying workflow action (sends the current form payload) from a plain * stateless action. Single source of truth for "what actions can a host fire". */ declare function getDeclaredFormActions(def: FormDef): FormActionInfo[]; //#endregion //#region src/shared/field-resolver.d.ts /** Options for field and form property resolution. */ interface TResolveOptions { /** When true, any non-undefined static value is returned as `true` (for boolean flags like ui.disabled). */ staticAsBoolean?: boolean; /** Transform the raw static value before returning. */ transform?: (raw: unknown) => T; } /** * Pluggable resolver interface for field/form metadata. * @atscript/ui provides a static implementation (reads only static annotation values). * ui-fns extends it with dynamic `new Function` compilation for `ui.fn.*` keys. */ interface FieldResolver { /** Resolve a field-level metadata property. */ resolveFieldProp(prop: TAtscriptAnnotatedType, fnKey: string, staticKey: string | undefined, scope: Record, opts?: TResolveOptions): T | undefined; /** Resolve a form-level metadata property. */ resolveFormProp(type: TAtscriptAnnotatedType, fnKey: string, staticKey: string | undefined, scope: Record, opts?: TResolveOptions): T | undefined; /** Check if a prop has dynamic annotations (ui.fn.*). */ hasComputedAnnotations(prop: TAtscriptAnnotatedType): boolean; } /** Static resolver — ignores fn keys, reads only static metadata. */ declare class StaticFieldResolver implements FieldResolver { resolveFieldProp(prop: TAtscriptAnnotatedType, _fnKey: string, staticKey: string | undefined, _scope: Record, opts?: TResolveOptions): T | undefined; resolveFormProp(type: TAtscriptAnnotatedType, _fnKey: string, staticKey: string | undefined, _scope: Record, opts?: TResolveOptions): T | undefined; hasComputedAnnotations(_prop: TAtscriptAnnotatedType): boolean; } /** Resolves a static metadata value. Exported for reuse by dynamic resolvers. */ declare function resolveStatic(metadata: TAtscriptAnnotatedType["metadata"], staticKey: string | undefined, opts?: TResolveOptions): T | undefined; /** Default static resolver instance. */ declare const defaultResolver: StaticFieldResolver; /** Replace the active resolver (called by ui-fns to install dynamic resolution). */ declare function setResolver(resolver: FieldResolver): void; /** Get the current active resolver. */ declare function getResolver(): FieldResolver; /** Resolve a field-level metadata property via the active resolver. */ declare function resolveFieldProp(prop: TAtscriptAnnotatedType, fnKey: string, staticKey: string | undefined, scope: Record, opts?: TResolveOptions): T | undefined; /** Resolve a form-level metadata property via the active resolver. */ declare function resolveFormProp(type: TAtscriptAnnotatedType, fnKey: string, staticKey: string | undefined, scope: Record, opts?: TResolveOptions): T | undefined; /** Check if a prop has dynamic annotations via the active resolver. */ declare function hasComputedAnnotations(prop: TAtscriptAnnotatedType): boolean; /** * SSOT for field hidden resolution — resolves `@ui.form.fn.hidden` * (dynamic, via the active resolver) with static `@ui.form.hidden` * presence as the fallback. Absent both → `false` (visible). */ declare function isFieldHidden(prop: TAtscriptAnnotatedType, scope: Record): boolean; /** * Reads a static metadata value from an ATScript prop. * Typed overload for known AtscriptMetadata keys; falls back to `unknown` for other keys. */ declare function getFieldMeta(prop: TAtscriptAnnotatedType, key: K): AtscriptMetadata[K] | undefined; declare function getFieldMeta(prop: TAtscriptAnnotatedType, key: string): unknown; /** Checks whether a metadata key is present on an ATScript prop. */ declare function hasFieldMeta(prop: TAtscriptAnnotatedType, key: string): boolean; /** Ensures a value is an array — returns as-is if already one, wraps in `[x]` otherwise. */ declare function asArray(x: T | T[]): T[]; /** * Parses static `ui.attr` metadata into a key-value record. * Exported so ui-fns can reuse this without duplicating the parsing logic. */ declare function parseStaticAttrs(staticAttrs: unknown): Record | undefined; /** Per-surface attr key pair — defaults to the form-side keys. */ interface TResolveAttrsKeys { staticKey?: string; fnKey?: string; } /** * Resolves `` + `` attr metadata on demand. * Defaults read `ui.form.attr` + `ui.form.fn.attr`; pass `{ staticKey, fnKey }` to read * the table-side pair (`ui.table.attr` + `ui.table.fn.attr`) or any other surface. */ declare function resolveAttrs(prop: TAtscriptAnnotatedType, scope: Record, keys?: TResolveAttrsKeys): Record | undefined; //#endregion //#region src/value-help/resolve.d.ts /** * Field-role + capability metadata for a value-help target, lazily resolved * from the target's own `/meta` endpoint. */ interface ResolvedValueHelp { url: string; primaryKeys: string[]; labelField: string; descrField: string | undefined; attrFields: string[]; filterableFields: string[]; sortableFields: string[]; searchable: boolean; targetType: TAtscriptAnnotatedType; } /** * Lazily fetch and extract value-help metadata for the given URL. * * - Issues exactly one `GET {url}/meta` per URL across the session (shared via meta-cache). * - Concurrent callers with the same URL share the in-flight promise. * - If the underlying fetch rejects, the cache entry is evicted so a later * retry performs a fresh fetch. */ declare function resolveValueHelp(url: string): Promise; /** Thin alias over `resetMetaCache` — retained so existing test code keeps working. */ declare function resetValueHelpCache(): void; //#endregion //#region src/value-help/value-help-client.d.ts interface ValueHelpSearchOptions { /** Search term. Empty or undefined returns all records. */ text?: string; /** "form" = PK + label + descr; "filter" = all dict fields including attrs. Default: "form". */ mode?: "form" | "filter"; /** Max results. Default: 20. */ limit?: number; /** Override the computed select fields. */ select?: string[]; } interface ValueHelpResult { items: Record[]; } /** * Value-help query client. Wraps a `Client` from `@atscript/db-client` * with FK-specific search logic (regex fallback for non-searchable tables, * $select scoping). * * Consumers resolve the target's metadata once via `resolveValueHelp(url)` * and pass the resulting `ResolvedValueHelp` to `search()`. Label resolution * for cells is deliberately unsupported — cells always display raw ids. */ declare class ValueHelpClient { private readonly _client; constructor(client: Client); /** * Search the target with value-help semantics. * * - If target is searchable → sends `$search` (server full-text) * - If not searchable → sends `$or` regex across select fields + exact PK match */ search(resolved: ResolvedValueHelp, opts?: ValueHelpSearchOptions): Promise; } //#endregion //#region src/value-help/dict-paths.d.ts /** * Paths that make up the "dict view" of a value-help target: * PKs + label + descr + attr fields. Used by filter dialogs to clamp * visible columns to the dictionary subset. */ declare function valueHelpDictPaths(resolved: ResolvedValueHelp): Set; //#endregion //#region src/value-help/extract-literals.d.ts /** * Extracts options from a union of literal types (e.g. 'a' | 'b' | 'c'). * Returns undefined if the type is not a pure union of literals. * * Handles nested unions created by flattenAnnotatedType, which recurses * into union items and produces synthetic unions containing both individual * literals and the original union type as nested items. */ declare function extractLiteralOptions(prop: TAtscriptAnnotatedType): { key: string; label: string; }[] | undefined; /** Returns true when the annotated type is a union composed entirely of literal values. */ declare function isPureLiteralUnion(prop: TAtscriptAnnotatedType): boolean; //#endregion //#region src/value-help/extract-ref.d.ts /** * Synchronous probe. Returns `{ url, targetField }` iff: * 1. the prop carries `@db.rel.FK`, * 2. the prop has a `.ref`, * 3. the ref's target metadata carries `@db.http.path`. */ declare function extractValueHelp(prop: TAtscriptAnnotatedType): ValueHelpInfo | undefined; //#endregion //#region src/value-help/resolve-options.d.ts /** Extracts the key from an option entry. */ declare function optKey(opt: TFormEntryOptions): string; /** Extracts the display label from an option entry. */ declare function optLabel(opt: TFormEntryOptions): string; /** * Converts raw option annotation value to a normalized array. */ declare function parseStaticOptions(raw: unknown): TFormEntryOptions[]; /** * Resolves options from metadata with a fallback chain: * 1. `@ui.form.fn.options` (dynamic, compiled by ui-fns) * 2. `@ui.form.options` (static annotation) * 3. Literal union type extraction (auto-derived from type) * 4. Future: dictionary / value-help lookup */ declare function resolveOptions(prop: TAtscriptAnnotatedType, scope: Record): TFormEntryOptions[] | undefined; //#endregion //#region src/form/path-utils.d.ts /** * Joins a dot-separated path prefix with a segment. Empty-safe on both * sides: an empty segment returns the prefix as-is, an empty prefix * returns the segment as-is (no leading/trailing dots). */ declare function joinPath(prefix: string, segment: string): string; /** * Gets a nested value by dot-separated path. * Always dereferences `obj.value` first (form data is wrapped in `{ value: domainData }`). * When `path` is empty, returns the root domain data (`obj.value`). */ declare function getByPath(obj: Record, path: string): unknown; /** * Sets a nested value by dot-separated path. * Always dereferences `obj.value` first (form data is wrapped in `{ value: domainData }`). * When `path` is empty, sets the root domain data (`obj.value = value`). * Creates intermediate objects if they do not exist. */ declare function setByPath(obj: Record, path: string, value: unknown): void; /** * Deletes the own key at a dot-separated path (form-data wrapper aware — derefs * `obj.value` first). Walks to the parent WITHOUT vivifying intermediate nodes: * if any ancestor is missing, the call is a no-op (nothing to delete). * * Unlike `setByPath(obj, path, undefined)`, this leaves NO own key behind — the * leaf reads as absent (`'k' in parent === false`), which keeps `deepEqual` * structural comparisons in sync (a present `undefined` own-key and an absent * key are NOT structurally equal under the own-key walk). Used by * {@link applyFormChanges} to apply a clear-to-`undefined` change as a delete. * * Empty path clears the root domain value (`obj.value = undefined`). */ declare function deleteByPath(obj: Record, path: string): void; /** Value resolver function type — created once per form, reused across calls. */ type TFormValueResolver = (prop: TAtscriptAnnotatedType, path: string) => unknown; declare function createFormValueResolver(data?: Record, context?: Record): TFormValueResolver; declare function createFormData(type: T, resolver?: TFormValueResolver): { value: TAtscriptDataType; }; declare function detectUnionVariant(value: unknown, variants: FormUnionVariant[]): number; //#endregion //#region src/form/clone.d.ts /** * Optional per-value unwrap hook. Lets a framework caller strip a reactive * proxy off every visited value before it is copied (e.g. Vue's `toRaw`). The * core never needs it — it is `undefined` here and the value passes through. */ type CloneUnwrap = (value: unknown) => unknown; /** * Structural deep clone of plain JSON-ish data (objects / arrays / primitives / * `Date`). Walks OWN-ENUMERABLE keys only (matches the own-key discipline in * `diff.ts` — never copies an accidental prototype) and copies leaves by value. * * `structuredClone` is deliberately NOT used: it throws on functions and on Vue * reactive proxies. The optional `unwrap` hook lets a framework caller * de-proxy each value first (vue-form passes `toRaw`); the core omits it. * * The SINGLE deep-clone primitive for the form engine — used by * `applyFormChanges`, `buildFormRebase`, and vue-form's baseline snapshot. Do * not reimplement structural cloning elsewhere. */ declare function deepClone(value: T, unwrap?: CloneUnwrap): T; //#endregion //#region src/form/validate.d.ts /** Per-call options for the form validator function. */ interface TFormValidatorCallOptions { data: Record; context?: Record; } /** Replace the default validator plugins applied to every form/field validator. */ declare function setDefaultValidatorPlugins(plugins: TValidatorPlugin[]): void; /** Get the currently registered default validator plugins. */ declare function getDefaultValidatorPlugins(): TValidatorPlugin[]; /** * Returns a reusable validator function for a whole FormDef. * * Validator is created once and reused on every call. * ATScript's @expect.* validation runs automatically. * For custom `ui.fn.*` validators, install ui-fns and pass its plugin via `opts.plugins`. */ declare function getFormValidator(def: FormDef, opts?: Partial): (callOpts: TFormValidatorCallOptions) => Record; /** Options for createFieldValidator. */ interface TFieldValidatorOptions { /** Only report errors at the root path (for structure/array container validation). */ rootOnly?: boolean; } /** * Creates a cached validator function for a single ATScript prop. * * The `Validator` instance is created lazily on first call and reused. * Returns `true` when valid, or the first error message string when invalid. */ declare function createFieldValidator(prop: TAtscriptAnnotatedType, opts?: TFieldValidatorOptions): (value: unknown, externalCtx?: { data: unknown; context: unknown; }) => true | string; //#endregion //#region src/form/diff.d.ts /** * One field that differs between baseline and current. * * - `kind: 'set'` — scalar / object / union / tuple field whose value changed * (including a clear-to-`null`). `before` / `after` are the whole values at * `path`. * - `kind: 'array'` — array field whose membership or item content changed. * `before` / `after` are the whole arrays. * * NOTE: `before` / `after` hold live references into the supplied `baseline` / * `current` containers — see {@link buildFormDiff} for the snapshot contract. */ interface FormFieldChange { /** Dot-separated path relative to the form root (matches FormFieldDef.path). */ path: string; kind: "set" | "array"; before: unknown; after: unknown; } /** Options for {@link buildFormDiff}. */ interface FormDiffOptions { /** * Optimistic-concurrency control. When `true` (default), a top-level * `$cas: { [versionColumn]: baselineVersion }` sibling is auto-included in * the patch whenever the form has a `@db.column.version` column AND the * patch is non-empty AND a baseline version value exists. `false` suppresses * it entirely. * * Independent of `$cas`, the `@db.column.version` column is ALWAYS excluded * from the SET diff: it is server-managed, and a direct write to it is * rejected by `@atscript/db` (`DbError('VERSION_COLUMN_WRITE')`). It is only * ever round-tripped through `$cas`. */ cas?: boolean; } /** Result of {@link buildFormDiff}. */ interface FormDiffResult { /** True when at least one field changed (revert-aware). */ isDirty: boolean; /** Per-field changes (revert-aware — reverted fields are absent). */ changes: FormFieldChange[]; /** * `@atscript/db` patch object — flat, keyed by field name. Empty `{}` when * nothing changed. Carries a top-level `$cas` sibling when `opts.cas` is on * and a version column exists. */ patch: Record; } /** * Diffs a form's `current` data against its `baseline` snapshot, producing both * a changed-fields list and an `@atscript/db` patch object. * * Both `baseline` and `current` are the WRAPPED form-data container * (`{ value: domainData }`) so this reuses {@link getByPath}. * * Revert-aware: a value edited back to its baseline produces no change and no * patch entry. * * Snapshot contract: the result is NOT a deep copy. `$insert` items, `$replace` * arrays, scalar leaf values, and `changes[].before/after` all hold live * references into `baseline` / `current`. Callers that keep editing the form * after building the patch must snapshot first (e.g. build the patch at submit * time on a frozen clone). This is the common Vue v-model flow. */ declare function buildFormDiff(def: FormDef, baseline: Record, current: Record, opts?: FormDiffOptions): FormDiffResult; /** * Structural deep equality (order-sensitive for arrays). `NaN` equals `NaN` * (revert-aware for NaN scalars) while `0` / `-0` stay equal (matches DB * intent — `===` treats them equal, only NaN is special-cased). * * The single comparator shared across the form engine: diff, conflict * detection ({@link buildFormRebase}), and apply all route through this — never * reimplement equality elsewhere. */ declare function deepEqual(a: unknown, b: unknown): boolean; //#endregion //#region src/form/dirty.d.ts /** * True when the field at dot-path `path` is dirty given a {@link FormFieldChange} * list (as produced by {@link buildFormDiff}). * * The change list is leaf-grained for scalars/objects but WHOLE-ARRAY for arrays, * so a field at `path` is dirty iff some change path equals `path` OR starts with * `path + "."`: * * - scalar / leaf field (incl. nested `address.city`) → exact match. * - object / section container → no entry at its own path, only its leaves → * matched by the PREFIX branch. * - whole-array field → one entry at the array root → exact match. * - a field rendered for an array-ITEM leaf (e.g. `items.0.qty`) → NOT detectable: * the array diff emits a single whole-array change at the array root, never * per-item leaf paths, so this correctly returns false (the array container * lights up instead). This is a known, documented limitation. * * The prefix uses `path + "."` so field `item` never matches a change at `items` * (no false positives). * * Empty `path` `''` is the wrapped form root — every change is nested under it, * so it is considered dirty iff there are ANY changes. */ declare function isPathDirty(changes: FormFieldChange[], path: string): boolean; /** * Precomputes the set of ALL dirty paths from a {@link FormFieldChange} list so * that membership is an O(1) `Set.has(path)` instead of {@link isPathDirty}'s * per-call O(changes) prefix scan. Callers that probe many fields against the * same change list (e.g. a form rendering one field per leaf) build this once * and query it per field. * * For each change path `C` it adds `C` AND every dot-prefix ancestor of `C` * (so `'address.city'` adds both `'address.city'` and `'address'`), matching * `isPathDirty`'s "exact OR `path + '.'` prefix" predicate — an ancestor * container is dirty exactly when some change is nested under it. The wrapped * root `''` is added iff there are ANY changes, mirroring `isPathDirty('')`. * * INVARIANT (locked, tested): for EVERY path `P`, * `collectDirtyPaths(changes).has(P) === isPathDirty(changes, P)`. This is a * precompute of the SAME predicate, not a second one — keep them in lockstep. */ declare function collectDirtyPaths(changes: FormFieldChange[]): Set; //#endregion //#region src/form/apply.d.ts /** * Applies a {@link FormFieldChange} list onto a WRAPPED form-data container * (`{ value: domainData }`), mutating it in place and returning the same * reference. The inverse direction of {@link buildFormDiff}: where the diff * READS `(baseline, current)` into changes, this WRITES changes onto data. * * IMPORTANT: pass a CLONE, never the live fetched row — every write mutates * `data` directly. Callers that need the original intact should * `deepClone(data)` first (see {@link deepClone}). * * Per-change semantics (the single place the apply rules live, so * {@link buildFormRebase} stays consistent): * * - `kind: 'set'`: * - `change.after === undefined` → DELETE the own key at `change.path` (walk * to parent, `delete`). A cleared field must read as ABSENT, not as a * present `undefined` own-key — otherwise a re-diff sees a structural * mismatch where the form intends "no value". `setByPath(…, undefined)` * leaves an own key behind, so we use {@link deleteByPath} instead. * - otherwise → `setByPath(data, change.path, change.after)`. * - `kind: 'array'`: whole-array set via `setByPath(data, change.path, * change.after)` (LOCKED Option A — no per-element merge; the diff already * carried the full after-array). * * The `def` is currently unused by the apply walk (paths fully describe the * write target) but is part of the signature for parity with * `buildFormDiff`/`buildFormRebase`, so the rebase engine threads one `def` * uniformly through diff + apply. */ declare function applyFormChanges(_def: FormDef, data: Record, changes: FormFieldChange[]): Record; //#endregion //#region src/form/rebase.d.ts /** Options for {@link buildFormRebase}. */ interface FormRebaseOptions { /** * How to resolve a field changed on BOTH sides (local edit vs. upstream * edit) to a different value: * - `'ours'` (default) — keep the local edit, discard upstream's value. * - `'theirs'` — take upstream's value, discard the local edit. * * A field changed on both sides to the SAME value is never a conflict. */ conflict?: "ours" | "theirs"; } /** Result of {@link buildFormRebase}. */ interface FormRebaseResult { /** * The rebased WRAPPED form-data container (`{ value }`). Always a fresh deep * clone of `upstream` with the local diff reapplied — never aliases any * input container. */ next: Record; /** * Paths that were changed on both sides to different values (same-path * conflicts), plus ancestor paths whose subtree upstream cleared while local * still edited a leaf under it (ancestor-clear conflicts). De-duplicated. */ conflicts: string[]; /** * The diff of `next` against the NEW baseline (`upstream`) — i.e. exactly the * changes that survive on top of upstream. Empty `[]` when the rebased form * equals upstream (a fully clean / fully reverted rebase). * * The returned `reapplied` does NOT alias the returned `next`, so installing * `next` as live form data never retroactively mutates the returned change set. */ reapplied: FormFieldChange[]; } /** * Pure 3-way rebase for a change-tracked form. Given the current baseline `B0`, * the live form `C`, and a fresh upstream `U`, produces the form rewritten as * `U` + the local diff (`C` vs `B0`) reapplied on top: * * - Fields the user never touched adopt upstream's value. * - Local edits survive (reapplied onto the upstream clone). * - Fields changed on BOTH sides to different values are conflicts, resolved by * `opts.conflict` (`'ours'` keeps local, `'theirs'` takes upstream). * * All inputs are WRAPPED form-data containers (`{ value: domainData }`). The * result `next` is a fresh container; no input is mutated. * * `diffOptions` are forwarded to BOTH internal `buildFormDiff` passes so the * same field exclusions apply (notably the `@db.column.version` column and the * `$cas` policy) on the local and upstream sides — keep them identical to the * options the caller uses for its own change tracking. */ declare function buildFormRebase(def: FormDef, baseline: Record, current: Record, upstream: Record, opts?: FormRebaseOptions, diffOptions?: FormDiffOptions): FormRebaseResult; //#endregion //#region src/form/union-detect.d.ts /** * True when ANY union field in the form resolves to a DIFFERENT discriminated * variant between two wrapped data containers. A variant picker typically * detects its variant index once at setup and keys the variant subtree on it, * so a rebase that lands a different variant (via conflict OR an upstream-only * switch) needs a remount to re-detect. This walks union + nested-object fields * and compares `detectUnionVariant` at each union path. * * Scope note (pragmatic): walks standalone + nested-OBJECT union fields. Unions * nested INSIDE array items are not walked — an array renderer that keeps a * stable per-item key across in-place value mutations would not remount an * existing row's picker on an upstream-driven variant flip, but that collision * (a 3-way rebase landing a different union variant inside an unchanged array * row) is a rare edge. TODO: extend to array-item unions if a real consumer * hits a stuck picker inside an array row. */ declare function unionVariantChanged(def: FormDef, before: Record, after: Record): boolean; //#endregion //#region src/form/error-utils.d.ts /** * Framework-agnostic helpers for working with form-error maps keyed by * dotted path. Used by AsForm to drive error badges and auto-open * collapsed sections; safe to share with React (or any other) bindings. * * Convention: * - Keys are dotted paths (`a.b.c`); empty string and `__form` denote * the form-level error. * - Values may be `string | undefined`; falsy entries are dropped on * merge. */ /** * Merge any number of partial error maps into a single dense * `Record`. Falsy values are skipped — later sources do * NOT overwrite earlier ones with an empty value. */ declare function mergeErrorMaps(...maps: Array | undefined>): Record; /** * Return `errors` without the entries whose key is in `paths`. * * Identity-preserving: when no key matches, the ORIGINAL `errors` object * is returned unchanged — callers compare `result !== errors` to detect * that something was pruned and skip spurious reactive writes. */ declare function omitPaths(errors: Record, paths: ReadonlySet): Record; /** * Yield every ancestor prefix of a dotted path, longest-first * (`a.b.c` → `a.b.c`, `a.b`, `a`). Returns the path itself first so * callers can include it in the iteration without a special case. * * Empty paths and the form-level key (`__form`) yield nothing. */ declare function iteratePathAncestors(path: string): Generator; /** * Build an indexed `Map` so each * struct in the tree can render an error-count badge in O(1). * * For every error path, the count is incremented on the path itself * AND every dotted-path ancestor — so a struct at `a.b` reports the * total of all errors at `a.b` or below. */ declare function buildDescendantErrorCounts(errors: Record): Map; //#endregion //#region src/form/grid.d.ts /** Grid layout parsing for `@ui.form.grid.colSpan` / `@ui.form.grid.rowSpan`. */ declare const DEFAULT_COL_SPAN = 12; declare const DEFAULT_ROW_SPAN = 1; /** Accepts "1"-"12" and the aliases "full" (12), "half" (6), "third" (4). */ declare function parseColSpan(raw: string | undefined): number | undefined; /** Accepts numeric strings "1"+; rejects "0", negatives, decimals, aliases. */ declare function parseRowSpan(raw: string | undefined): number | undefined; interface GridSpec { col: { desktop: number; narrow: number; }; row: { desktop: number; narrow: number; }; } /** * Shape returned by `getFieldMeta(prop, UI_FORM_GRID_COL_SPAN | …ROW_SPAN)` — * atscript codegen produces a struct from named multi-arg annotation specs. */ interface GridSpanArgs { desktop: string; narrow?: string; } /** * Resolve a field's grid footprint. Narrow defaults to full-width / single-row * regardless of the desktop value, so authors can opt into a narrow override * via the second annotation arg without it inheriting an unintended desktop span. */ declare function resolveGridSpec(colSpan: GridSpanArgs | undefined, rowSpan: GridSpanArgs | undefined): GridSpec; /** * Build the UnoCSS class string for a field's grid footprint. * * - Skips desktop classes that match the default (`as-grid-item` already * covers `col-span-full row-span-1`). * - Skips narrow overrides that match the desktop value (no override needed). * - The narrow variant uses the custom `as-narrow:` prefix, which the * atscript-ui UnoCSS preset rewrites to `@container as-grid (max-width: * 480px) { ... }`. The parent grid is registered as * `container-name: as-grid` via the `as-form-grid` shortcut, so the * rule resolves against the actual grid's inline size — not the viewport. * * Returned string is space-separated, ready to drop into a Vue class binding. */ declare function buildGridClasses(spec: GridSpec): string; //#endregion //#region src/form/labels.d.ts /** Singular label for an array field (used by AsArray for "Add "). */ declare function resolveSingularLabel(meta: TAtscriptAnnotatedType | undefined): string; //#endregion //#region src/form/measurement.d.ts /** * Resolved measurement annotations — currency / unit-of-measure / numeric * precision. Read once at form/table-def construction time and surfaced as * already-resolved values so downstream renderers (cells, default form * components, custom inputs) never re-read annotation metadata. */ interface MeasurementInfo { /** Literal currency code from `@db.amount.currency 'EUR'`. */ currencyCode?: string; /** Sibling-field path from `@db.amount.currency.ref 'fieldName'`. */ currencyRefField?: string; /** Literal unit-of-measure from `@db.unit 'kg'`. */ unitCode?: string; /** Sibling-field path from `@db.unit.ref 'fieldName'`. */ unitRefField?: string; /** Decimal scale (fraction digits) — second arg of `@db.column.precision precision, scale`. */ precisionScale?: number; } /** * Read measurement annotations off a single field prop. Returns `undefined` * for any annotation that's absent — callers can spread the result into a * larger record. */ declare function extractMeasurement(prop: TAtscriptAnnotatedType): MeasurementInfo; //#endregion //#region src/form/decimal-format.d.ts /** * Framework-agnostic decimal formatting + parsing helpers shared by * `@atscript/vue-table` (read-only cell display) and `@atscript/vue-form` * (editable amount/measure inputs). Symmetric output is the contract — * a value rendered in a cell must read identically when displayed in * the form composables, modulo currency / unit adornment. * * The functions here are intentionally pure (no `Number()` round-trips * in the storage value path) — decimal-as-string correctness depends on * not bouncing through floats. */ interface CurrencyDisplay { /** Narrow symbol: "$" / "€" / "US$" depending on locale. Falls back to code on Intl failure. */ symbol: string; /** Whether the symbol typically sits left or right of the amount. */ position: "prefix" | "suffix"; } interface DecimalParts { sign: "" | "-"; /** Integer part, no thousands separator, no leading zeros beyond "0". */ integer: string; /** Decimal part as captured, no separator. Empty string if absent. */ decimal: string; } interface FormatDecimalOptions { value: string | number | null | undefined; /** Scale used for display (typically the effective scale, not DB scale). Trailing zeros pad. */ scale?: number; locale?: string; /** When set → Intl.NumberFormat with style:currency. Symbol/grouping handled by Intl. */ currency?: string; /** When set (and no currency) → " ". */ unit?: string; /** * Whether to group thousands. Grouping is reserved for measured values, so * the default is derived: true when `currency`, `unit`, or `scale` is set, * false for plain numbers. Pass explicitly to override. */ useGrouping?: boolean; } /** "." in en-US, "," in fr-FR. Returns "." when locale is undefined. */ declare function getDecimalSeparator(locale?: string): string; /** * "," in en-US, NNBSP (U+202F) in fr-FR. Returns "" when no grouping is * applied (or when Intl rejects the locale). */ declare function getThousandsSeparator(locale?: string): string; declare function getCurrencyDisplayParts(code: string, locale?: string): CurrencyDisplay; /** * Currency's natural decimal count via Intl. JPY=0, USD/EUR=2, BHD/KWD=3. * Returns `undefined` for codes Intl doesn't know — caller falls back to * `dbPrecisionScale`. */ declare function getCurrencyDecimals(code: string, locale?: string): number | undefined; /** * Parse a user-typed decimal string. Returns the canonical decimal * (no thousands separator, "." as decimal separator) or `null` if invalid. * Accepts both "." and "," as the decimal separator (locale-aware). * Strips the locale thousands separator. Preserves sign. Does NOT * enforce scale. */ declare function parseDecimalInput(raw: string, locale?: string): string | null; /** * Enforce a fractional-digit count by truncating or padding. String-only — * no float arithmetic. Default behaviour truncates (no rounding) so digits * the user typed can't silently shift. Pass `roundHalfUp: true` to round. * * enforceScale("12.345", 2) → "12.34" (truncate) * enforceScale("12.3", 4) → "12.3000" (pad) * enforceScale("12", 0) → "12" * enforceScale("12.99", 0) → "12" (no rounding) */ declare function enforceScale(s: string, scale: number | undefined, opts?: { roundHalfUp?: boolean; }): string; declare function splitDecimalString(s: string): DecimalParts; declare function joinDecimalString(parts: DecimalParts): string; declare function formatDecimalForDisplay(opts: FormatDecimalOptions): string; /** * Insert the locale's thousands separator into a plain integer string. * Pure string-based — no float math, handles arbitrary length. */ declare function groupInteger(integer: string, locale?: string): string; //#endregion //#region src/table/types.d.ts /** Search index metadata from the server. */ interface SearchIndexInfo { name: string; description?: string; type?: "text" | "vector"; } /** Relation summary in meta response. */ interface RelationInfo { name: string; direction: "to" | "from" | "via"; isArray: boolean; } /** Per-field capability flags. */ interface FieldMeta { sortable: boolean; filterable: boolean; } /** Meta response from moost-db `/meta` endpoint. */ interface MetaResponse { searchable: boolean; vectorSearchable: boolean; searchIndexes: SearchIndexInfo[]; primaryKeys: string[]; /** * Preferred row identifier (UI/wire addressing). From * `@db.table.preferredId.uniqueIndex` — defaults to `primaryKeys` when the * server omits it (older servers / stub fixtures). Drives identifier object * construction for action POSTs and `'navigate'` URL `$1` substitution. */ preferredId: string[]; /** * Server-managed OCC column name (from `@db.column.version`). When present, * names a normal `int` field that ships with rows like any other column. * Consumers MUST keep the field's value in update payloads — the server * auto-lifts it to `$cas` to detect concurrent writes — but MUST NOT render * it as a user-facing column, filter, or sorter. `createTableDef` skips it * from the generated `columns[]` array on this basis. */ versionColumn?: string; crud: TCrudPermissions$1; actions: TDbActionInfo$1[]; relations: RelationInfo[]; fields: Record; type: TSerializedAnnotatedType; } /** * Server-declared actions grouped by `level`. Built by `createTableDef` from * `meta.actions[]` — sorted within each group by `(order ?? 0)` then * declaration order. `default.{table,row,rows}` is the first `default: true` * entry per level (or `undefined`). The synthesised `__remove` UI action is * never selected as a default. */ interface TableActionsModel { table: TDbActionInfo$1[]; row: TDbActionInfo$1[]; rows: TDbActionInfo$1[]; default: { table?: TDbActionInfo$1; row?: TDbActionInfo$1; rows?: TDbActionInfo$1; }; } /** Complete table definition — produced by createTableDef(). */ interface TableDef { type: TAtscriptAnnotatedType; columns: ColumnDef[]; /** * Flattened type tree (path → annotated prop). Empty Map for non-object roots. * Excludes phantom types. Consumers (e.g. cell-resolver) read this instead * of re-walking the type. */ flatMap: Map; /** * Server-returnable field paths (from meta.fields) — the gate for * @ui.table.selectWith targets, includes @ui.table.exclude fields. */ fetchableFields: Set; primaryKeys: string[]; /** Preferred row identifier — see `MetaResponse.preferredId`. */ preferredId: string[]; /** Server-managed OCC column name — see `MetaResponse.versionColumn`. */ versionColumn?: string; /** Per-op CRUD permissions advertised in `/meta`. Key absent → denied. */ crud: TCrudPermissions$1; canRemove: boolean; /** Server-declared actions, grouped by level with defaults pre-resolved. */ actions: TableActionsModel; searchable: boolean; vectorSearchable: boolean; searchIndexes: SearchIndexInfo[]; relations: RelationInfo[]; } /** A single column definition — built from field metadata + annotations. */ interface ColumnDef { /** Field path in dot-notation (e.g. 'address.city'). */ path: string; /** Display label — from @meta.label or humanized path. */ label: string; /** Display type — from @ui.table.type, then @ui.type, then inferred from designType. */ type: string; /** Named component override from @ui.table.component — looked up in the table components map. */ component?: string; /** * Extra leaf field paths to include in `$select` whenever this column is displayed. * Never rendered as columns; declared via @ui.table.selectWith. */ selectWith?: string[]; /** Whether this column supports sorting. */ sortable: boolean; /** Whether this column supports filtering. */ filterable: boolean; /** * Whether the column accepts `null` values (atscript prop is `optional`). * Drives operator-picker availability — `null` / `notNull` are dropped * for non-nullable columns since they can never match. */ nullable: boolean; /** Default column width from @ui.table.width. */ width?: string; /** Maximum length constraint from @expect.maxLen — used to derive default column width. */ maxLen?: number; /** Initial column ordering from @ui.table.order (lower = first). */ order: number; /** Enumerated options for union literal types (e.g. 'a' | 'b' | 'c'). */ options?: { key: string; label: string; }[]; /** Value-help info for FK columns (from extractValueHelp). */ valueHelpInfo?: ValueHelpInfo; /** Literal currency code from `@db.amount.currency 'EUR'`. */ currencyCode?: string; /** Sibling field path from `@db.amount.currency.ref 'fieldName'`. */ currencyRefField?: string; /** Literal unit-of-measure from `@db.unit 'kg'`. */ unitCode?: string; /** Sibling field path from `@db.unit.ref 'fieldName'`. */ unitRefField?: string; /** Decimal scale (fraction digits) — second arg of `@db.column.precision precision, scale`. */ precisionScale?: number; /** * Synthesised, locked-chrome column. When `true`: header-cell column-menu * skipped, resize handle skipped, drag-reorder excluded, NOT in the * `columnNames` v-model. Used for the row-actions pseudo-column * (`path: '__actions'`). */ fixed?: boolean; } /** A single sort directive. */ interface SortControl { field: string; direction: "asc" | "desc"; } /** Pagination state. */ interface PaginationControl { page: number; itemsPerPage: number; } /** Reactive query state for a table — mirrors @uniqu/core controls. */ interface TableQueryState { sort?: SortControl[]; pagination?: PaginationControl; search?: string; filters?: Record; } //#endregion //#region src/table/create-table-def.d.ts /** * Builds a TableDef from a moost-db MetaResponse. * * 1. Deserializes `meta.type` into a live TAtscriptAnnotatedType * 2. Flattens to discover all field paths * 3. Builds ColumnDef per field using annotations + meta.fields capabilities * 4. Sorts by @ui.table.order */ declare function createTableDef(meta: MetaResponse, preDeserializedType?: TAtscriptAnnotatedType): TableDef; //#endregion //#region src/client-factory.d.ts /** * Factory that creates a `Client` for a given URL. * * Single contract shared by every atscript-ui primitive that needs to talk * to an atscript-db-compatible endpoint: table composables, FK value-help, * and any future consumer. Produces a `Client` configured with whatever * transport / auth wiring the host application wants. */ type ClientFactory = (url: string) => Client; /** * Override the app-wide default factory. Call once at startup (e.g. in * `entry-client.ts`) to wire shared fetch, credentials, error handling, etc. * Every table, value-help picker, and other client consumer will pick it up. */ declare function setDefaultClientFactory(factory: ClientFactory): void; /** Current app-wide default factory. Falls back to `new Client(url)`. */ declare function getDefaultClientFactory(): ClientFactory; /** Reset the default factory to the built-in one (primarily for tests). */ declare function resetDefaultClientFactory(): void; //#endregion //#region src/shared/meta-cache.d.ts /** * Shared per-URL cache. A single entry holds the `Client` instance, the raw * `/meta` promise, the deserialized type, and lazily-populated derived shapes * (`ResolvedValueHelp` for value-help, `TableDef` for tables). Both * `resolveValueHelp` and `useTable` route through it so a given URL triggers * at most one network round-trip and one `deserializeAnnotatedType`. */ interface MetaCacheEntry { client: Client; meta: Promise; type: Promise; resolved?: Promise; tableDef?: Promise; } /** * Get or create the cache entry for `url`. First caller's `factory` seeds the * `Client`; subsequent callers reuse it. On `meta` rejection, the entry is * evicted so the next call retries. */ declare function getMetaEntry(url: string, factory?: ClientFactory): MetaCacheEntry; declare function resetMetaCache(): void; //#endregion //#region src/shared/str.d.ts /** Safely convert an unknown value to a string without triggering no-base-to-string lint errors. */ declare function str(value: unknown): string; //#endregion //#region src/table/column-resolver.d.ts /** Get sortable columns. */ declare function getSortableColumns(def: TableDef): ColumnDef[]; /** Get filterable columns. */ declare function getFilterableColumns(def: TableDef): ColumnDef[]; /** Find a column by path. */ declare function getColumn(def: TableDef, path: string): ColumnDef | undefined; //#endregion //#region src/table/navigate-href.d.ts /** * Compute the href a `processor: 'navigate'` action would open — synchronously, * at render time. Mirrors the interpolation `Client` performs when the action * is invoked (`action.value` with every `$1` replaced by the URL-encoded, * `/`-joined `preferredId` fields — see `encodeNavigateId`), so tables can * render navigate actions as real `` anchors and native link behaviour * (middle-click → new tab, copy link, hover preview) just works. * * Returns `undefined` when no link is possible — the caller should fall back to * a button and let `Client` handle the invoke: * * - `action.processor !== 'navigate'` — backend/custom actions stay buttons; * - row-level action with `id === undefined` — the row is not identifiable * (note this deliberately differs from `Client`, which navigates to the raw * template in that case; a raw-template href would be a broken link); * - row-level action with an empty `preferredId` — `$1` has nothing to encode. * * Table/rows-level navigate actions carry no `$1` placeholder and return * `action.value` verbatim. */ declare function navigateHrefFor(action: TDbActionInfo$1, id: Record | undefined, preferredId: readonly string[]): string | undefined; //#endregion //#region src/nav/model-routes.d.ts /** A navigable route derived from a DB-backed model's metadata. */ interface TModelRoute { model: TAtscriptAnnotatedType; /** Route path without leading/trailing slashes — mountable anywhere. */ path: string; /** Display label — from @meta.label or humanized last path segment. */ label: string; kind: "table" | "view"; /** Nav section from @ui.nav.group — grouping is the consumer's job. */ group?: string; /** Position from @ui.nav.order — lower first, undefined last. */ order?: number; /** From @ui.nav.hidden — hidden routes are still returned; consumers filter. */ hidden?: boolean; } /** * Derives navigable routes from DB-backed models' metadata. * * A model is included only when it is a DB entity (`@db.table`, `@db.view`, * or `@db.view.for`) AND a path can be derived: `@db.http.path` first, then * the string value of `@db.table` / `@db.view`, then the type's own id * as-is. Models where none of these yield a non-empty path are omitted. * * Routes are sorted by `order` ascending (undefined last, ties keep input * order). Hidden models are returned with `hidden: true` — filtering and * grouping are left to the consumer. */ declare function buildModelRoutes(models: readonly TAtscriptAnnotatedType[]): TModelRoute[]; //#endregion export { type ClientFactory, type CloneUnwrap, type ColumnDef, type CurrencyDisplay, DB_AMOUNT_CURRENCY, DB_AMOUNT_CURRENCY_REF, DB_COLUMN_PRECISION, DB_HTTP_PATH, DB_REL_FK, DB_UNIT, DB_UNIT_REF, DEFAULT_COL_SPAN, DEFAULT_ROW_SPAN, type DecimalParts, EXPECT_MAX_LENGTH, type FieldMeta, type FieldResolver, type FormActionInfo, type FormArrayFieldDef, type FormDef, type FormDiffOptions, type FormDiffResult, type FormFieldChange, type FormFieldDef, type FormObjectFieldDef, type FormRebaseOptions, type FormRebaseResult, type FormTupleFieldDef, type FormUnionFieldDef, type FormUnionVariant, type FormatDecimalOptions, type GridSpanArgs, type GridSpec, META_DEFAULT, META_DESCRIPTION, META_ID, META_LABEL, META_READONLY, META_REQUIRED, META_SENSITIVE, type MeasurementInfo, type MetaCacheEntry, type MetaResponse, type PaginationControl, type RelationInfo, type ResolvedValueHelp, type SearchIndexInfo, type SortControl, StaticFieldResolver, type TCrudOp, type TCrudPermissions, type TDbActionInfo, type TDbActionIntent, type TDbActionLevel, type TDbActionProcessor, type TFieldValidatorOptions, type TFormAction, type TFormEntryOptions, type TFormValidatorCallOptions, type TFormValueResolver, type TModelRoute, type TResolveOptions, type TableActionsModel, type TableDef, type TableQueryState, UI_DICT_ATTR, UI_DICT_DESCR, UI_DICT_FILTERABLE, UI_DICT_LABEL, UI_DICT_SEARCHABLE, UI_DICT_SORTABLE, UI_FORM_ACTION, UI_FORM_ATTR, UI_FORM_AUTOCOMPLETE, UI_FORM_CLASSES, UI_FORM_COMPONENT, UI_FORM_DISABLED, UI_FORM_FN_ATTR, UI_FORM_FN_CLASSES, UI_FORM_FN_DESCRIPTION, UI_FORM_FN_DISABLED, UI_FORM_FN_HIDDEN, UI_FORM_FN_HINT, UI_FORM_FN_LABEL, UI_FORM_FN_OPTIONS, UI_FORM_FN_PLACEHOLDER, UI_FORM_FN_PREFIX, UI_FORM_FN_READONLY, UI_FORM_FN_STYLES, UI_FORM_FN_SUBMIT_DISABLED, UI_FORM_FN_SUBMIT_TEXT, UI_FORM_FN_TITLE, UI_FORM_FN_VALUE, UI_FORM_GRID_COL_SPAN, UI_FORM_GRID_ROW_SPAN, UI_FORM_HIDDEN, UI_FORM_HINT, UI_FORM_LABEL_SINGULAR, UI_FORM_OPTIONS, UI_FORM_ORDER, UI_FORM_PLACEHOLDER, UI_FORM_PREFIX, UI_FORM_PREFIX_ICON, UI_FORM_PREFIX_REF, UI_FORM_STYLES, UI_FORM_SUBMIT_TEXT, UI_FORM_SUFFIX, UI_FORM_SUFFIX_ICON, UI_FORM_SUFFIX_REF, UI_FORM_TYPE, UI_FORM_VALIDATE, UI_NAV_GROUP, UI_NAV_HIDDEN, UI_NAV_ORDER, UI_TABLE_ATTR, UI_TABLE_CLASSES, UI_TABLE_COMPONENT, UI_TABLE_EXCLUDE, UI_TABLE_FN_ATTR, UI_TABLE_FN_CLASSES, UI_TABLE_FN_PREFIX, UI_TABLE_FN_STYLES, UI_TABLE_ORDER, UI_TABLE_SELECT_WITH, UI_TABLE_STYLES, UI_TABLE_TYPE, UI_TABLE_WIDTH, UI_TYPE, ValueHelpClient, type ValueHelpInfo, type ValueHelpResult, type ValueHelpSearchOptions, WF_ACTION_WITH_DATA, applyFormChanges, asArray, buildDescendantErrorCounts, buildFormDiff, buildFormRebase, buildGridClasses, buildModelRoutes, buildUnionVariants, collectDirtyPaths, createFieldValidator, createFormData, createFormDef, createFormValueResolver, createTableDef, deepClone, deepEqual, defaultResolver, deleteByPath, detectUnionVariant, enforceScale, extractLiteralOptions, extractMeasurement, extractValueHelp, formatDecimalForDisplay, getByPath, getColumn, getCurrencyDecimals, getCurrencyDisplayParts, getDecimalSeparator, getDeclaredFormActions, getDefaultClientFactory, getDefaultValidatorPlugins, getFieldMeta, getFilterableColumns, getFormValidator, getMetaEntry, getResolver, getSortableColumns, getThousandsSeparator, groupInteger, hasComputedAnnotations, hasFieldMeta, isArrayField, isFieldHidden, isObjectField, isPathDirty, isPureLiteralUnion, isTupleField, isUnionField, iteratePathAncestors, joinDecimalString, joinPath, mergeErrorMaps, navigateHrefFor, omitPaths, optKey, optLabel, parseColSpan, parseDecimalInput, parseRowSpan, parseStaticAttrs, parseStaticOptions, resetDefaultClientFactory, resetMetaCache, resetValueHelpCache, resolveAttrs, resolveFieldProp, resolveFormProp, resolveGridSpec, resolveOptions, resolveSingularLabel, resolveStatic, resolveValueHelp, setByPath, setDefaultClientFactory, setDefaultValidatorPlugins, setResolver, splitDecimalString, str, unionVariantChanged, valueHelpDictPaths };