import { z } from 'zod'; import type { ActionFieldDef, FieldOptionsConfig, OptionDef, VisibleWhen } from './types'; /** * Apps register validator implementations by slug. The slug is the value * `OrgConfig.validators[]` returns for a $org. reference. */ export declare function registerValidator(slug: string, fn: (s: z.ZodString) => z.ZodString): void; export declare function buildZodSchema(fields: ActionFieldDef[]): z.ZodObject<{ [x: string]: z.ZodType>; }, z.core.$strip>; /** * Returns the line-items columns of a repeatable-group field, tolerating both * the camelCase `itemFields` (the authored SDK shape) and the raw snake_case * `item_fields` that the kernel serves in action metadata. Empty when the * field is not a line-items group. */ export declare function getItemFields(field: ActionFieldDef): ActionFieldDef[]; /** A field is a repeatable line-items group when it declares item columns. */ export declare function isLineItemsField(field: ActionFieldDef): boolean; /** * Resolves the balance rule of a line-items field, tolerating both the * camelCase authored shape and the snake_case the kernel serves. Returns * normalized `{ debitColumn, creditColumn, message, requireNonzero }` or * `undefined` when the field declares no balance constraint. */ export declare function getBalanceRule(field: ActionFieldDef): { debitColumn: string; creditColumn: string; message?: string; requireNonzero: boolean; } | undefined; /** Coerces a cell value to a finite number, treating blanks/garbage as 0. */ export declare function toNumber(v: unknown): number; /** * Sums each `total`-flagged column of a line-items field across its rows. * Pure — no React — so the renderer and unit tests share one implementation. * Returns a map of column key → summed value. Rounds to cents to avoid float * drift (0.1 + 0.2 noise) that would make a genuinely balanced entry look off. */ export declare function computeLineItemTotals(field: ActionFieldDef, rows: any[] | undefined): Record; /** * Live line-amount formula for action / form line-items grids: * `(qty|quantity) * (unit_price|…) - (discount|…)` → `subtotal|line_total|importe`. * * Pure + convention-based so create_sales_order (and similar modals) show * Importe as the user types without each manifest declaring a client formula. * No-op when the row has no amount column or no qty/price pair. */ export declare function applyLineItemRowFormulas(itemFields: ActionFieldDef[], row: Record): Record; export interface BalanceState { debit: number; credit: number; /** credit − debit, rounded to cents. Zero when balanced. */ diff: number; balanced: boolean; message?: string; } /** * Evaluates a line-items field's balance rule against its rows. Returns * `undefined` when the field declares no balance rule. `balanced` is true when * the two summed columns are equal (and, unless `requireNonzero` is false, * strictly positive). Pure — drives both the indicator and the submit gate. */ export declare function evaluateBalance(field: ActionFieldDef, rows: any[] | undefined): BalanceState | undefined; export declare function resolveWidget(field: ActionFieldDef): string; /** * Resolves a field's FK target, tolerating the camelCase `ref` (authored SDK * shape) and the snake_case `source` / `relation` aliases the kernel manifest * may serve for a belongs_to column. Returns the trimmed model key, or * `undefined` when the field declares no relation. */ export declare function getFieldRef(field: ActionFieldDef): string | undefined; /** True when a field declares an FK target the SDK can resolve options against. */ export declare function fieldHasRef(field: ActionFieldDef): boolean; /** * Resolves a field's cascade dependency — the key of another form field whose * current value scopes this picker's options (`filter_value`). Tolerates the * camelCase `dependsOn` (authored SDK shape) and the snake_case `depends_on` * the kernel manifest serves. Returns the trimmed field key, or `undefined` * when the field declares no dependency. */ export declare function getDependsOn(field: ActionFieldDef): string | undefined; /** * Resolves the cascade `filter_value` for a field from the surrounding form * context. The depended-on key is matched against the current row first (a * sibling item-field on the same line) and then the header form values, so a * line-items cell can depend on either a sibling cell OR a header field (e.g. * `source_warehouse_id`). Returns the stringified value, or `''` when the * field has no dependency or the depended-on value is empty/unset. */ export declare function resolveDependsValue(field: ActionFieldDef, formValues?: Record | null, rowValues?: Record | null): string; /** * Filters a STATIC enum's `options[]` by each option's `when` gate against the * current form values. Pure — no React, no side effects. * * Rule per option: * - No `when` → always included (retrocompat; existing enums untouched). * - With `when`: the gating field is `when.field ?? dependsOn`. If neither is * present the option is included (nothing to gate on). Otherwise the form's * value for that field is compared AS STRING: included when (no `in`, or * value ∈ `in`) AND (no `not_in`, or value ∉ `not_in`). Tolerates the * snake_case `not_in` the kernel serves alongside camelCase `notIn`. * * `formValues` is the flat map of the surrounding form/row values the gating * field is read from; `dependsOn` is the containing field's declared dependency * used as the default gating field. */ export declare function applyOptionWhen(options: OptionDef[] | undefined, formValues: Record | null | undefined, dependsOn?: string): OptionDef[]; /** * Reads a field's `visible_when` predicate, tolerating the camelCase alias * (`visibleWhen`) an app may author and the snake_case (`visible_when`) the * kernel serves. Returns `undefined` when the field declares neither. */ export declare function getVisibleWhen(field: { visible_when?: VisibleWhen; visibleWhen?: VisibleWhen; } | null | undefined): VisibleWhen | undefined; /** * Evaluates a `visible_when` predicate against the current flat form values. * Pure — no React, no side effects. * * - No predicate → `true` (the field is always visible; retrocompat). * - With a predicate: read the value of the sibling `cond.field` from * `formValues` (as string, null/undefined → ''). Visible when it is a member * of `cond.in` (any-of, wins when present) OR equals `cond.equals`. A * predicate with an empty `field` is a no-op (visible). A predicate that * names a field but declares neither `in` nor `equals` hides nothing * (visible) — nothing to gate on. * * `cond` may be the raw block off either the snake_case or camelCase slot; use * `getVisibleWhen` to normalize first. */ export declare function evaluateVisibleWhen(cond: VisibleWhen | null | undefined, formValues: Record | null | undefined): boolean; /** * Strip a DynamicTable / URL filter token down to the comparable scalar the * kernel `visible_when.equals` / `.in` predicates expect. * * `eq:customer` → `customer`, bare `customer` stays, `in:a,b` keeps the raw * multi-value (list-scope only gates on known single-eq scopes today). */ export declare function scopeValueFromFilterToken(raw: unknown): string; /** * Flat "known field → value" map for list/board surfaces. Built from locked * `defaultFilters` (nav / branch scope) plus active `dynamicFilters`. Only * fields present here are considered known — see * `evaluateVisibleWhenForListScope`. */ export declare function buildListScopeValues(defaultFilters?: Record | null, dynamicFilters?: Record | null): Record; /** * List/board variant of `evaluateVisibleWhen`. * * Forms always have a live sibling value (or ''). Lists often do not — a * mixed AccountStatement table has no single `party_type`. Hiding every * `visible_when` column when the governing field is unknown would wipe both * Cliente and Proveedor on the unscoped view. Rule: if the governing field is * not in `scope` (or is empty), keep the column; once the scope pins it * (sidebar locked_scope / defaultFilters / a single-eq chip), apply the same * predicate as the form. */ export declare function evaluateVisibleWhenForListScope(cond: VisibleWhen | null | undefined, scope: Record | null | undefined): boolean; /** * Reads a field's enriched options-resolution config, tolerating the camelCase * `optionsConfig` (authored SDK shape) and the snake_case `options_config` the * kernel manifest serves. Returns `undefined` when the field declares none. */ export declare function getOptionsConfig(field: ActionFieldDef): FieldOptionsConfig | undefined; /** * Resolves where a picker should fetch its options from, honouring an * `optionsConfig.source` (the dependent/scoped routing the kernel serves) and * falling back to the field's `ref` for retrocompat. * * - With `optionsConfig.source`: query the SOURCE model → * `{ endpoint: '/options/', fieldKey: }`. * - Without it: keep `ref`-based resolution → `{ ref }` (the hook's canonical * path), `fieldKey` defaulting to `'id'`. * * The returned shape feeds straight into `useOptionsResolver` args. */ export declare function resolveOptionsSource(field: ActionFieldDef): { endpoint?: string; ref?: string; fieldKey: string; }; /** * Normalizes an upload field's config, tolerating both the camelCase authored * SDK shape and the snake_case the kernel serves (`max_size`, `storage_path`). * Pure — shared by both field renderers and unit tests. */ export declare function getUploadConfig(field: ActionFieldDef): { accept?: string; maxSize?: number; storagePath?: string; }; //# sourceMappingURL=dynamic-form-schema.d.ts.map