import { AnySchema } from 'yup';
import { ComponentType } from 'react';
import { default as default_2 } from 'react';
import { EdgeProps } from 'reactflow';
import { EdgeTypes } from 'reactflow';
import { FormikProps } from 'formik';
import { GroupBase } from 'react-select';
import { JSX as JSX_2 } from 'react/jsx-runtime';
import { NodeProps } from 'reactflow';
import { NodeTypes } from 'reactflow';
import { ObjectSchema } from 'yup';
import { ReactNode } from 'react';
import { StylesConfig } from 'react-select';
import { useFormik } from 'formik';
import * as Yup from 'yup';

export declare const ActionNode: ({ id, data }: NodeProps) => JSX_2.Element;

declare interface ActiveField {
    /** The contenteditable div inside FormulaInput */
    editorRef: default_2.RefObject<HTMLDivElement | null>;
    /** Saved Range from the last selection — restored before inserting */
    savedRange: Range | null;
    fieldId: string;
    /** Optionally, the field can provide a direct way to insert a variable into its state */
    onInsert?: (path: string, label: string) => void;
}

export declare interface AddStepContext {
    edgeId: string;
    nodeId: string;
    sourceNodeId: string;
    targetNodeId: string;
    position: 'between';
    referenceNodeId: string;
    referenceNodeType?: string;
    stepVisibility?: unknown;
    filterId?: string;
    branch?: string;
}

/**
 * Wire shape the backend `/api/v1/workflow-template` endpoint is expected
 * to return. Top-level fields mirror the persistence model; everything
 * UI-related lives under `templateUI`. Use with `templateRegistry.registerFromApi(list)`.
 */
export declare interface ApiWorkflowTemplate {
    key: string;
    name: string;
    state?: string;
    description?: string;
    allowedTasks?: string[];
    allowedSources?: string[];
    configuration?: Record<string, unknown>;
    templateUI?: Partial<Omit<WorkflowTemplate, 'triggerKey' | 'label' | 'description' | 'availableTasks'>>;
}

export declare interface ApplicationTaskLike {
    name?: string;
    taskKey?: string;
    applicationUuid?: string;
    configuration?: unknown[];
    ui?: {
        bpmnEmit?: BpmnEmitSpec;
        [key: string]: unknown;
    };
    [key: string]: unknown;
}

export declare const ApprovalNode: ({ id, data }: NodeProps) => JSX_2.Element;

/** True if the AST contains at least one non-text node. */
export declare function astHasRefs(nodes: FormulaASTNode[]): boolean;

/**
 * Convert AST nodes to the flat FormulaToken[] the DOM layer uses.
 * This keeps FormulaInput decoupled from the AST type directly.
 */
export declare function astToTokens(nodes: FormulaASTNode[], configEnabled?: boolean): FormulaToken[];

/**
 * Base defaults shared by every node descriptor. A new node only has to specify
 * what makes it different — these fill in the rest.
 *
 * - `formSchema: []`            → no config form unless the node defines one
 * - `bpmnEntry` / `bpmnExit`    → incoming/outgoing flow connects to the node id itself
 * - `emitBpmnElements`          → a single generic bpmn:Task; override for real output
 */
export declare const baseNodeDefaults: Pick<NodeDescriptor, 'formSchema' | 'bpmnEntry' | 'bpmnExit' | 'emitBpmnElements'>;

export declare interface BpmnElement {
    id: string;
    $type: string;
    [key: string]: unknown;
}

export declare interface BpmnEmitSpec {
    kind: 'linear' | 'gated' | 'filter' | 'approval';
    serviceTasks?: ServiceTaskSpec[];
    gateway?: GatewaySpec;
    templateFlows?: TemplateFlowSpec[];
    outgoingConditions?: Record<string, string>;
    dmnEmit?: DmnEmitSpec;
    callActivity?: Record<string, unknown>;
}

export declare interface BpmnSaveOptions {
    processId?: string;
    processName?: string;
}

declare type BranchChain = CanvasSlot[];

export declare interface BranchMap {
    [filterId: string]: {
        [branchKey: string]: BranchChain;
    };
}

/**
 * Generate a backend-ready payload from canvas state + task definitions.
 *
 * @example
 *   const payload = buildBackendPayload({
 *     state: { slots, branches },
 *     tasksByKey: { USER_CREATION: {...}, USER_GROUP_ASSIGNMENT: {...} },
 *     context: { customerKey: '51995', workflowName: 'My WF' },
 *     config: { triggerToCategory: { CUSTOM_TRIGGER: 'CUSTOM_CATEGORY' } },
 *   });
 *   await api.post('/process', payload);
 */
export declare function buildBackendPayload(opts: BuildPayloadOptions): Record<string, unknown>;

export declare function buildEvaluationPayload({ values, conditionConfig, }: {
    values: Record<string, unknown>;
    conditionConfig?: ConditionConfig;
}): EvaluationPayload;

/**
 * Returns an empty presence-marker object {}.
 * The backend uses the key's existence in FormulaConfig to know
 * the field value was serialized as _P('...') rather than _DE_{_P('...')}.
 */
export declare function buildFieldConfig(): FieldFormulaConfig;

/**
 * Build a bracket-notation path from a root and optional extra segments.
 * Each segment is wrapped in [\"...\"] so the path evaluator can handle
 * any key (camelCase, spaces, hyphens, etc.) uniformly.
 *
 * Examples:
 *   buildFormulaPath('data.user', 'email')
 *     → 'data.user.[\"email\"]'
 *   buildFormulaPath('data.input', 'groupAssignPolicy', 'dmnKey')
 *     → 'data.input.[\"groupAssignPolicy\"].[\"dmnKey\"]'
 *   buildFormulaPath('data.trigger', 'assignee', 'email')
 *     → 'data.trigger.[\"assignee\"].[\"email\"]'
 */
export declare function buildFormulaPath(root: string, ...segments: string[]): string;

export declare interface BuildPayloadConfig {
    /**
     * Map of trigger eventType → workflowCategory string. Defaults to a small
     * IAM-shaped fallback; consumers should pass the full map they use.
     */
    triggerToCategory?: Record<string, string>;
    /** eventType values that should set `sources: ['SCHEDULER']` and skip the message block. */
    schedulerEventTypes?: string[];
    /** DMN LHS prefix for condition expressions (default IAM-style). */
    conditionPathPrefix?: string;
    /** Fallback workflowCategory when eventType isn't mapped. */
    defaultWorkflowCategory?: string;
    /** End-event ids — override per backend convention. */
    endEventIds?: {
        success: string;
        failure: string;
        rejected: string;
    };
    /** Names rendered on end events. */
    endEventNames?: {
        success: string;
        failure: string;
        rejected: string;
    };
    /** Start event id used in the outer chain. */
    startEventId?: string;
}

export declare interface BuildPayloadContext {
    customerKey: string;
    workflowName: string;
    /** Anything else the host wants exposed via `from: 'ctx', key: '...'`. */
    [key: string]: unknown;
}

export declare interface BuildPayloadOptions {
    state: PayloadCanvasState;
    tasksByKey: Record<string, ApplicationTaskLike>;
    context: BuildPayloadContext;
    config?: BuildPayloadConfig;
}

export declare function buildSelectStyles(hasError: boolean, isMulti?: boolean): StylesConfig<any, boolean, GroupBase<any>>;

/**
 * Builds a Yup ObjectSchema from a flat FieldDescriptor[].
 * Validates required fields and applies type-appropriate rules.
 * Recurses into object/schema children.
 */
export declare function buildValidationSchema(fields: FieldDescriptor[]): Yup.ObjectSchema<any>;

/**
 * Walks upstream from `currentNodeId` (excluding it), collects each ancestor's
 * outputSchema, and returns a `VariableGroup[]` ready for `<FlowForm variableGroups>`.
 *
 * - Excludes the current node (a node never references its own outputs).
 * - Deduplicates ancestors via id — diamond graphs don't produce duplicate groups.
 * - Skips ancestors with empty outputSchema (no group rendered for nodes that emit nothing).
 * - Preserves traversal order — the closest parent appears first in the picker.
 */
export declare function buildVariableGroups<TNode>(opts: BuildVariableGroupsOptions<TNode>): VariableGroup[];

export declare interface BuildVariableGroupsOptions<TNode> {
    /** Id of the node currently being configured (its outputs are NOT included). */
    currentNodeId: string;
    /** All nodes in the canvas / workflow. */
    nodes: TNode[];
    /** Return the immediate parent node(s) — consumer walks its own edge model. */
    getParents: (node: TNode, nodes: TNode[]) => TNode[];
    /** Return the node's output schema array (empty array if none). */
    getOutputSchema: (node: TNode) => OutputSchemaItem[];
    /** Return the runtime path prefix for this node (e.g. 'endUser', 'data.1'). */
    nodePath: (node: TNode) => string;
    /** Optional — group label shown in the picker. Defaults to `nodePath(node)`. */
    nodeLabel?: (node: TNode) => string;
    /**
     * Optional — function reading a node's id. Defaults to `(n) => (n as any).id`.
     * Override if your node model nests the id (e.g. `n.data.id`).
     */
    getNodeId?: (node: TNode) => string;
}

export declare const builtInNodeTypes: NodeTypes;

export declare interface CanvasSlot {
    id: string;
    kind: SlotKind;
    reactFlowType: string;
    descriptorType?: string;
    formData?: Record<string, unknown>;
    nodeData?: Record<string, unknown>;
    deletable?: boolean;
    label?: string;
    /** Maps branch key → display label. e.g. { pass: 'Pass', fail: 'Fail' } */
    branchLabels?: Record<string, string>;
}

export declare interface ChildRouterProps {
    field: FieldDescriptor;
    pathPrefix: string;
    depth: number;
    values: Record<string, unknown>;
    errors: Record<string, unknown>;
    touched: Record<string, unknown>;
    setFieldValue: (name: string, value: unknown) => void;
    setFieldTouched: (name: string, touched: boolean) => void;
    compact?: boolean;
    inlineLabel?: boolean;
    /**
     * Item-scoped values when this child is rendered inside an array item.
     * ArrayField sets it to `items[i]` per row; ObjectField/TabsField pass
     * whatever they received through unchanged. FieldRouter folds this into
     * `ctx.item` for shouldHide/shouldDisable/compute callbacks.
     */
    item?: Record<string, unknown>;
}

export declare interface ChipToken {
    type: 'chip';
    expr: string;
    label: string;
    path: string;
    kind: 'de-expr' | 'path-ref';
}

/**
 * Concatenation of multiple nodes (future).
 * Serializes by joining all child serializations.
 */
export declare interface ConcatNode {
    type: 'concat';
    values: FormulaASTNode[];
}

export declare const conditionBranchDescriptor: NodeDescriptor;

/**
 * Top-level condition config map: pathPrefix → ConditionNode[].
 *
 * Example:
 *   { "email": [
 *       { field: "email", operator: "isNull", value: "" },
 *       { type: "group", connector: "and", entries: [
 *           { field: "role", operator: "equals", value: "FE" },
 *           { field: "role", operator: "equals", value: "UX", connector: "or" },
 *         ]},
 *       { field: "salary", operator: "equals", value: "5000000", connector: "and" },
 *     ]
 *   }
 */
export declare type ConditionConfig = Record<string, ConditionNode[]>;

/**
 * A single condition row (leaf node).
 * connector: how this node joins the previous sibling ('and' | 'or'). Ignored on index 0.
 */
export declare interface ConditionEntry {
    /** Discriminator — omit or set to 'leaf' for a plain condition row */
    type?: 'leaf';
    field: string;
    fieldLabel: string;
    operator: string;
    value: string;
    connector?: 'and' | 'or';
}

/**
 * Conditional expression (future).
 * e.g. if status == "active" then name else "unknown"
 */
export declare interface ConditionExprNode {
    type: 'condition';
    if: FormulaASTNode;
    then: FormulaASTNode;
    else: FormulaASTNode;
}

/** One column in a per-field condition row */
export declare interface ConditionFieldDef {
    /** Key used to store this column's value in ConditionEntry */
    id: string;
    /**
     * 'select'   — native <select> with user-supplied options
     * 'operator' — native <select> pre-filled with the standard operator list (no options needed)
     * 'text'     — plain <input>
     * any other string — falls back to <input>
     */
    type: 'select' | 'operator' | 'text' | string;
    colSpan?: number;
    label?: string;
    placeholder?: string;
    /** Options for select columns — user defines these, renderer just renders them */
    options?: Array<{
        value: string;
        label: string;
    }>;
    optionsSource?: OptionsSource;
    /** When true, renders a FormulaInput chip editor instead of a plain <input> */
    formula?: boolean;
}

/**
 * A parenthesised group of condition nodes.
 * Renders as an indented, bordered block — e.g. (Role = "FE" OR Role = "UX").
 */
export declare interface ConditionGroup {
    type: 'group';
    entries: ConditionNode[];
    connector?: 'and' | 'or';
}

/** Either a leaf row or a nested group */
export declare type ConditionNode = ConditionEntry | ConditionGroup;

declare interface ControlledProps extends FormulaProps {
    schema: FormSchema;
    formik: FormikProps<Record<string, unknown>>;
    initialValues?: never;
    onSubmit?: never;
    children?: never;
    form?: never;
}

export declare interface DataSourceDefinition {
    fetch: (query: string, page: number) => Promise<DataSourceFetchResult>;
}

export declare interface DataSourceFetchResult {
    options: TablePickerOption[];
    hasNextPage: boolean;
    nextPage?: number;
}

declare class DataSourceRegistry {
    private sources;
    register(key: string, definition: DataSourceDefinition): void;
    get(key: string): DataSourceDefinition | undefined;
    has(key: string): boolean;
}

export declare const dataSourceRegistry: DataSourceRegistry;

export declare const defaultFlowForgeMessages: FlowForgeMessages;

/**
 * Build a node descriptor on top of {@link baseNodeDefaults}.
 *
 * Supply the four required identity fields plus only the behaviour you want to
 * override. Everything else inherits the base.
 *
 *   export const startEventDescriptor = defineNode({
 *     type: 'startEvent',
 *     label: 'Start',
 *     matches: (id) => id === 'start',
 *     reactFlowType: 'startNode',
 *     emitBpmnElements: (id) => [{ id, $type: 'bpmn:StartEvent' }], // override
 *   });
 */
export declare function defineNode(overrides: RequiredNodeFields & Partial<NodeDescriptor>): NodeDescriptor;

export declare interface DmnDefinition {
    id: string;
    [key: string]: unknown;
}

export declare interface DmnEmitSpec {
    tableName: string;
    inputExpr: string;
    hitPolicy?: string;
    outputs?: DmnOutputSpec[];
    operatorMap?: Record<string, string>;
    valuesField?: string;
}

export declare interface DmnOutputSpec {
    id: string;
    label?: string;
    name: string;
    typeRef?: string;
}

/** @deprecated Use FlowForm */
export declare const DynamicFormRenderer: default_2.ForwardRefExoticComponent<FlowFormProps & default_2.RefAttributes<FlowFormHandle>>;

/** @deprecated Use FlowFormProps */
export declare type DynamicFormRendererProps = FlowFormProps;

export declare const EdgeWithPlusLabel: ({ id: edgeId, sourceX, sourceY, targetX, targetY, sourcePosition, targetPosition, source, target, data, }: EdgeProps<EdgeWithPlusLabelData>) => JSX_2.Element;

export declare interface EdgeWithPlusLabelData {
    label?: string;
    onAddStepClick?: (sourceNodeId: string, context: AddStepContext) => void;
    referenceNodeType?: string;
    stepVisibility?: unknown;
}

/**
 * End event — a fixed skeleton node with no user-editable form.
 * The canvas seeds the main-spine end as the literal slot id `'end'`, and one
 * end per branch as `'end-${filterId}-${branch}'` (see WorkflowCanvas.tsx).
 * `matches` must cover both shapes so every terminal node resolves via `forId`
 * during descriptor-driven BPMN load — otherwise branch ends get skipped.
 *
 * Inherits formSchema (none) and bpmnEntry/bpmnExit from the base node.
 */
export declare const endEventDescriptor: NodeDescriptor;

export declare const EndNode: () => JSX_2.Element;

export declare const errorTextStyle: React.CSSProperties;

export declare interface EvaluationConditionEntry {
    field: string;
    operator: string;
    value?: string;
    connector?: 'and' | 'or';
}

export declare interface EvaluationConditionGroup {
    type: 'group';
    entries: EvaluationConditionNode[];
    connector?: 'and' | 'or';
}

export declare type EvaluationConditionNode = EvaluationConditionEntry | EvaluationConditionGroup;

export declare interface EvaluationPayload {
    values: Record<string, unknown>;
    conditions?: Record<string, EvaluationConditionNode[]>;
}

export declare interface ExecutionRecord {
    id: string;
    workflowId?: string;
    triggeredBy?: string;
    triggeredAt: string;
    status: ExecutionStatus;
    inputs?: Record<string, unknown>;
    steps: ExecutionStep[];
    completedAt?: string;
    error?: string;
}

export declare type ExecutionStatus = 'running' | 'success' | 'failed' | 'cancelled';

export declare interface ExecutionStep {
    nodeId: string;
    nodeType?: string;
    label?: string;
    startedAt: string;
    completedAt?: string;
    status: StepStatus;
    inputs?: Record<string, unknown>;
    outputs?: Record<string, unknown>;
    branchTaken?: string;
    error?: string;
}

export declare interface ExtensionFieldSpec {
    name: string;
    source?: {
        type: 'literal' | 'json' | 'taskConfig' | 'formData';
        value?: unknown;
        shape?: Record<string, FieldRef>;
        passthrough?: boolean;
        exclude?: string[];
        key?: string;
    };
}

/**
 * Extract the display label from a path expression.
 * Prefers the last [\"key\"] bracket segment; falls back to the last dot-segment.
 *
 * 'data.user.[\"email\"]'                                          →  "email"
 * 'data.input.[\"groupAssignPolicy\"].[\"dmnKey\"]'               →  "dmnKey"
 * 'data.trigger.[\"assignee\"].[\"email\"]'                       →  "email"
 */
export declare function extractLabel(path: string): string;

declare interface FetchResult {
    options: TablePickerOption[];
    hasNextPage: boolean;
    nextPage?: number;
}

export declare const FF: {
    readonly INPUT_HEIGHT: 38;
    readonly INPUT_PADDING: "0 12px";
    readonly INPUT_FONT_SIZE: 14;
    readonly BORDER_RADIUS: 6;
    readonly BORDER_COLOR: "#ced4da";
    readonly BORDER_COLOR_HOVER: "#adb5bd";
    readonly BORDER_COLOR_FOCUS: "#86b7fe";
    readonly BORDER_COLOR_ERROR: "#dc3545";
    readonly BORDER: "1px solid #ced4da";
    readonly BORDER_ERROR: "1px solid #dc3545";
    readonly FOCUS_SHADOW: "0 0 0 3px rgba(13,110,253,0.18)";
    readonly FOCUS_SHADOW_ERROR: "0 0 0 3px rgba(220,53,69,0.18)";
    readonly COLOR_LABEL: "#212529";
    readonly COLOR_PLACEHOLDER: "rgba(0,0,0,0.38)";
    readonly COLOR_HELPER: "#6c757d";
    readonly COLOR_ERROR: "#dc3545";
    readonly COLOR_DISABLED_BG: "#f8f9fa";
    readonly COLOR_DISABLED_TEXT: "rgba(0,0,0,0.38)";
    readonly FONT_SIZE_LABEL: 13;
    readonly FONT_SIZE_INPUT: 14;
    readonly FONT_SIZE_HELPER: 12;
    readonly FONT_WEIGHT_LABEL: 500;
    readonly LABEL_MB: 5;
    readonly HELPER_MT: 4;
    readonly FIELD_MB: 20;
};

export declare const FIELD_TYPE_OPTIONS: Array<{
    value: string;
    label: string;
}>;

declare type FieldComponent = ComponentType<FieldComponentProps>;

export declare interface FieldComponentProps {
    field: FieldDescriptor;
    value: unknown;
    values: Record<string, unknown>;
    onChange: (value: unknown) => void;
    onBlur: () => void;
    error?: string;
    touched?: boolean;
    /** Current formula config map (host-owned). Passed down to formula-enabled fields. */
    formulaConfig?: FormulaConfig;
    /** Called by a field when its formula AST changes. Host app updates its state. */
    onFormulaConfigChange?: (config: FormulaConfig) => void;
    /**
     * When true: field renders label + input in a single horizontal row.
     * Used inside ObjectField groups for compact two-column mapping layout.
     */
    inlineLabel?: boolean;
}

/** Condition definition attached to a FieldDescriptor */
export declare interface FieldConditionDef {
    fields: ConditionFieldDef[];
    /** Enables nested condition groups. Defaults to false. */
    allowGroups?: boolean;
    /** Optional depth limit for nested groups when allowGroups is true. */
    maxGroupDepth?: number;
}

export declare interface FieldContext {
    /** Full top-level form values (always). */
    values: Record<string, unknown>;
    /**
     * Item-scoped values for a field rendered INSIDE an array item.
     * Lets `shouldHide` / `shouldDisable` / `shouldRequire` / `compute` see
     * sibling-in-same-row fields without having to splice paths manually:
     *
     *   { id: 'template', shouldHide: ({ item }) => item?.valueSource !== 'template' }
     *
     * `undefined` when the field is NOT inside an array item (i.e. top-level
     * fields and fields inside plain `type: 'object'` children at top level).
     * Nested arrays update `item` to the immediate parent row's values.
     */
    item?: Record<string, unknown>;
}

export declare interface FieldDescriptor {
    /**
     * The formik key for this field.
     * Use `id` (preferred) or `name` — both are accepted.
     * `id` takes precedence if both are provided.
     */
    id?: string;
    name?: string;
    type: FieldType | string;
    /** Child field descriptors — used by type: 'object' to render a nested group. */
    children?: FieldDescriptor[];
    /** Optional per-field condition guard — renders a condition row below this field. */
    condition?: FieldConditionDef;
    label?: string;
    placeholder?: string;
    required?: boolean;
    showOptional?: boolean;
    disabled?: boolean | ((ctx: FieldContext) => boolean);
    hidden?: boolean;
    colSpan?: number;
    dividerAfter?: boolean;
    info?: string;
    helperText?: string;
    dataTestId?: string;
    validation?: AnySchema;
    shouldHide?: (ctx: FieldContext) => boolean;
    shouldDisable?: (ctx: FieldContext) => boolean;
    shouldRequire?: (ctx: FieldContext) => boolean;
    /**
     * When true, the field's value is auto-cleared (reset to `defaultValue`,
     * or removed if no default) any time `shouldHide` evaluates to true —
     * including on mount when the saved data has orphan values from a prior
     * configuration. Default: false (values persist while hidden, preserving
     * legacy behavior).
     *
     * Use this on conditional fields where stale data would corrupt the
     * payload (e.g. `template` should be empty when `valueSource !== 'template'`).
     */
    clearOnHide?: boolean;
    defaultValue?: unknown;
    compute?: (ctx: FieldContext) => unknown;
    transform?: FieldTransform;
    onChange?: (value: unknown, ctx: FieldContext & {
        setFieldValue: (name: string, value: unknown) => void;
    }) => void;
    /**
     * Declarative dynamic options. The renderer translates this into a paged,
     * cached, abortable async loader via the host's resolver registry.
     * Mutually compatible with static `options`: static wins if both set.
     */
    optionsSource?: OptionsSource;
    [key: string]: unknown;
}

/**
 * Presence marker for a field that has formula config enabled.
 * When a field's formula config toggle is ON, its key appears in FormulaConfig
 * with an empty object value. The backend uses this to detect that the value
 * stored in Formik was serialized as _P('...') rather than _DE_{_P('...')}.
 *
 * Example: { "dmnKey": {} }
 */
export declare type FieldFormulaConfig = Record<string, never>;

export declare interface FieldRef {
    from: 'literal' | 'task' | 'ctx' | 'slot' | 'formData';
    key?: string;
    value?: unknown;
}

export declare const fieldRegistry: {
    register(type: string, component: FieldComponent): void;
    get(type: string): FieldComponent | undefined;
    has(type: string): boolean;
    /** List every registered field type. Used by the DEV-mode "did you mean…"
     *  suggestion when a schema specifies an unknown `type`. */
    keys(): string[];
};

/** Optional pre-defined field suggestions (e.g. common fields for this node type) */
export declare interface FieldSuggestion {
    label: string;
    field: FieldDescriptor;
}

export declare interface FieldTransform {
    in?: (value: unknown) => unknown;
    out?: (value: unknown) => unknown;
}

export declare type FieldType = 'text' | 'textarea' | 'number' | 'toggle' | 'radio-group' | 'select' | 'descriptive-select' | 'key-value' | 'array' | 'object' | 'reference' | 'cron' | 'schema';

export declare const FilterNode: ({ id, data }: NodeProps) => JSX_2.Element;

declare interface FixedEdge {
    id: string;
    source: string;
    target: string;
}

declare interface FixedNode {
    id: string;
    type: string;
    data?: Record<string, unknown>;
    deletable?: false;
}

declare const FlowForgeCanvas: ({ nodeRegistry, templateRegistry, initialValue, nodeTypes: consumerNodeTypes, edgeTypes: consumerEdgeTypes, onSave, readOnly, theme, messages: messageOverrides, canvasOptions, renderTriggerSelector, loadTriggerSources, renderNodePicker, renderNodeConfig, onNodeClick: onNodeClickProp, maxNodes, layoutDirection, executionRecord, onFetchWorkflow, hideHeader, workflowName, onWorkflowNameChange, onCancel, workflowStatus, workflowStatusColor, saveLabel, optionsResolvers, }: FlowForgeCanvasProps) => JSX_2.Element;
export { FlowForgeCanvas }
export { FlowForgeCanvas as WorkflowCanvas }

/** All ReactFlow behaviour settings — serialisable as JSON config */
export declare interface FlowForgeCanvasOptions {
    /** Fit the whole graph into view on mount. Default: true */
    fitView?: boolean;
    fitViewPadding?: number;
    /** Show the zoom-in / zoom-out / fit controls. Default: true */
    showControls?: boolean;
    /** Show the mini-map overview. Default: false */
    showMiniMap?: boolean;
    /** Pan the canvas by scrolling (no Ctrl needed). Default: true */
    panOnScroll?: boolean;
    /** Zoom with the scroll wheel. Default: false */
    zoomOnScroll?: boolean;
    minZoom?: number;
    maxZoom?: number;
    /** Snap nodes to a grid while dragging. Default: false */
    snapToGrid?: boolean;
    snapGrid?: [number, number];
    /**
     * How branches under a conditional/gateway node are arranged.
     * 'horizontal' (default): branches spread side-by-side (Dagre).
     * 'vertical': branches stack top-to-bottom, indented right under their parent (Workato style).
     */
    branchLayout?: 'horizontal' | 'vertical';
    /**
     * How much of a node's data to show on its card.
     * 'full' (default): show configured value badges / the descriptor's custom body.
     * 'title-only': show just the node title — for teams that want minimal cards.
     */
    nodeBody?: 'full' | 'title-only';
}

export declare interface FlowForgeCanvasProps {
    nodeRegistry: NodeTypeRegistry;
    templateRegistry: TemplateRegistry;
    /** Pre-populate the canvas from a previously saved WorkflowState. */
    initialValue?: WorkflowState;
    nodeTypes?: NodeTypes;
    edgeTypes?: EdgeTypes;
    onSave?: (workflow: WorkflowState) => void;
    /** Disables all editing — no add/delete/config, edges have no "+" button */
    readOnly?: boolean;
    /** Brand colors applied across edges, plus button, and node accents */
    theme?: FlowForgeTheme;
    /** Built-in UI labels for i18n/white-label copy. */
    messages?: Partial<FlowForgeMessages>;
    /** ReactFlow behaviour settings — all serialisable as plain JSON */
    canvasOptions?: FlowForgeCanvasOptions;
    /** Replace the trigger selector UI entirely */
    renderTriggerSelector?: (templates: WorkflowTemplate[], onSelect: (t: WorkflowTemplate) => void, onClose: () => void) => default_2.ReactNode;
    /**
     * Optional async loader for trigger sources. When provided, the default
     * trigger selector goes to a second stage after the user picks a trigger:
     * the loader is called with the trigger's key, and if it returns a non-empty
     * list, the user picks one or more sources before the canvas is seeded.
     * Picked sources are merged into the trigger node's `nodeData.sources` so
     * TriggerNode can render the "via [chip] [chip]" line.
     *
     * Return `[]` for triggers that have no sources — stage 2 is skipped.
     */
    loadTriggerSources?: (triggerKey: string) => Promise<Array<{
        label: string;
        value: string;
    }>>;
    /** Replace the node picker UI entirely */
    renderNodePicker?: (descriptors: NodeDescriptor[], onSelect: (d: NodeDescriptor) => void, onClose: () => void) => default_2.ReactNode;
    /** Replace the node config drawer entirely */
    renderNodeConfig?: (descriptor: NodeDescriptor | undefined, slot: CanvasSlot | null, onSave: (id: string, values: Record<string, unknown>) => void, onClose: () => void) => default_2.ReactNode;
    /** Intercept node click — return true to suppress default behaviour */
    onNodeClick?: (slot: CanvasSlot) => boolean | void;
    /** Global cap on total user task nodes */
    maxNodes?: number;
    /** Flow layout direction. 'TB' = top-to-bottom (default), 'LR' = left-to-right */
    layoutDirection?: 'TB' | 'LR';
    /**
     * When provided, renders an execution overlay on the canvas nodes:
     * green = success, red = failed, grey = skipped/pending.
     * Combine with readOnly=true to show a past run without editing.
     */
    executionRecord?: ExecutionRecord;
    /**
     * Called when a SubWorkflowNode's "Preview" button is clicked.
     * Return the WorkflowState for the given workflowId to render it in a drawer.
     */
    onFetchWorkflow?: (workflowId: string) => Promise<WorkflowState>;
    /** Hide the built-in top bar (Save / Cancel / name). Default false. */
    hideHeader?: boolean;
    /** Display name in the header. */
    workflowName?: string;
    /** Make the header name click-to-edit. */
    onWorkflowNameChange?: (name: string) => void;
    /** Cancel button shows only when this handler is provided. */
    onCancel?: () => void;
    /** Status pill text + color (e.g. 'Draft' / 'amber'). */
    workflowStatus?: string;
    workflowStatusColor?: 'gray' | 'green' | 'amber' | 'red' | string;
    /** Override the Save button label. */
    saveLabel?: string;
    /**
     * Host-registered map of named option resolvers. Fields in any node's
     * `formSchema` may declare `optionsSource: { id, dependsOn, params }` to
     * populate a select asynchronously. Transport-agnostic — the host's
     * resolver can use axios, fetch, GraphQL, etc.
     *
     * Example:
     *   optionsResolvers={{
     *     'app:groups': async ({ appId }, { cursor=0 }) => {
     *       const res = await api.get(`/groups?startIndex=${cursor}&count=50`);
     *       return {
     *         options: res.data.map(g => ({ value: g.uuid, label: g.name })),
     *         nextCursor: res.data.length === 50 ? cursor + 50 : undefined,
     *       };
     *     }
     *   }}
     *
     * Resolvers are cached for the session keyed by (resolverId, deps). Use
     * `useOptionsResolvers().invalidate(id)` to bust a cache entry manually.
     */
    optionsResolvers?: OptionsResolvers;
}

export declare interface FlowForgeFieldDefinition {
    /** The unique type identifier (e.g. 'text', 'image-upload') */
    type: string;
    /** The display name for the field picker dropdown */
    label: string;
    /**
     * The component used to render the field in the live form.
     * If omitted, relies on a previously registered component in DynamicFormRenderer.
     */
    component?: ComponentType<FieldComponentProps>;
    /**
     * Instead of a React component, you provide a FlowForm schema!
     * The Schema Builder Modal will automatically render this schema
     * to ask the user for configuration settings.
     */
    configSchema?: {
        fields: FieldDescriptor[];
    };
    /**
     * Validation builder for this field type.
     */
    buildValidation?: (field: FieldDescriptor) => Yup.Schema;
}

export declare function FlowForgeHeader({ workflowName, onWorkflowNameChange, status, statusColor, onSave, onCancel, saveLabel, saveDisabled, }: FlowForgeHeaderProps): JSX_2.Element;

/**
 * FlowForgeHeader — top bar that ships with FlowForgeCanvas by default.
 *
 * Renders the workflow name, a status pill, Cancel, and primary Save
 * button. Calls back via `onSave` / `onCancel`. The canvas itself wires
 * `onSave` to the latest WorkflowState behind the scenes — consumers
 * only provide a callback that receives that state.
 *
 * Opt out of the built-in header by passing `hideHeader={true}` on
 * FlowForgeCanvas; you can still mount this component standalone.
 */
export declare interface FlowForgeHeaderProps {
    /** Workflow display name shown on the left. */
    workflowName?: string;
    /** Optional editable callback — when provided, name becomes click-to-edit. */
    onWorkflowNameChange?: (name: string) => void;
    /** Status pill text (e.g. 'Draft', 'Published', 'Unsaved'). */
    status?: string;
    /** Status pill color — one of these or a custom hex. */
    statusColor?: 'gray' | 'green' | 'amber' | 'red' | string;
    /** Click handler for the primary Save button. Async-aware: spinner shows during await. */
    onSave?: () => void | Promise<void>;
    /** Click handler for Cancel. Button hidden when not provided. */
    onCancel?: () => void;
    /** Custom label for the Save button. Defaults to "Save". */
    saveLabel?: string;
    /** Disable Save button (e.g. while there are no unsaved changes). */
    saveDisabled?: boolean;
}

export declare interface FlowForgeMessages {
    addTriggerTitle: string;
    addTriggerTooltip: string;
    addTriggerButton: string;
    chooseTrigger: string;
    noTriggers: string;
    addStepTitle: string;
    chooseAction: string;
    noActions: string;
    configureStep: string;
    loadingConfiguration: string;
    noConfigurationNeeded: string;
    save: string;
    cancel: string;
}

export declare const FlowForgeRegistry: Registry;

export declare interface FlowForgeTheme {
    primaryColor?: string;
    edgeColor?: string;
    textColor?: string;
    mutedTextColor?: string;
    surfaceColor?: string;
    borderColor?: string;
    dangerColor?: string;
    borderRadius?: number;
    fontFamily?: string;
    /** ReactFlow canvas background style. 'none' hides the background entirely. Default: 'dots' */
    background?: 'dots' | 'lines' | 'cross' | 'none';
    /** Background dot/line color. Default: '#e0e0e0' */
    backgroundColor?: string;
}

export declare const FlowForm: default_2.ForwardRefExoticComponent<FlowFormProps & default_2.RefAttributes<FlowFormHandle>>;

/**
 * Imperative API exposed via `ref` on `<FlowForm>`. Lets a host drive Save
 * from a footer button outside the form without writing forwardRef
 * boilerplate per-section. See README for the canonical pattern.
 */
export declare interface FlowFormHandle {
    /**
     * Touch every field, validate the form, and (when valid) call `onSave`
     * with the full payload. Returns `{ isValid, values, errors }` so the
     * caller can also branch off the result directly.
     */
    save: () => Promise<SaveResult>;
    /** Reset to initial values + clear touched/errors. */
    reset: () => void;
    /** Run validation and return errors without touching fields. */
    validate: () => Promise<Record<string, unknown>>;
    /** Push server-side errors back into formik state for display. */
    setErrors: (errors: Record<string, unknown>) => void;
    /** Read the current values. Includes the conditionConfig sidecar. */
    getValues: () => Record<string, unknown>;
    /** Programmatic write — useful for pre-filling on edit. */
    setValues: (values: Record<string, unknown>) => void;
}

export declare interface FlowFormInstance {
    values: Record<string, unknown>;
    errors: Record<string, unknown>;
    isValid: boolean;
    isDirty: boolean;
    isSubmitting: boolean;
    formulaConfig: FormulaConfig;
    conditionConfig: ConditionConfig;
    /** Validate and submit — safe to call from any button outside the form. */
    submit: () => void;
    reset: (nextValues?: Record<string, unknown>) => void;
    setFieldValue: (field: string, value: unknown) => void;
    _schema: FormSchema;
    _formik: ReturnType<typeof useFormik<Record<string, unknown>>>;
    _formulaConfig: FormulaConfig;
    _onFormulaConfigChange: (config: FormulaConfig) => void;
    _conditionConfig: ConditionConfig;
    _onConditionConfigChange: (config: ConditionConfig) => void;
}

export declare type FlowFormProps = UncontrolledProps | ControlledProps | HookProps;

declare type FormLayout = 'flat' | 'stepper' | 'tabs' | 'sections';

export declare interface FormSchema {
    layout?: FormLayout;
    /**
     * Removes the bottom margin on every field.
     * Use for filter bars and inline forms where fields sit in a tight horizontal row.
     */
    compact?: boolean;
    fields?: FieldDescriptor[];
    steps?: FormStep[];
}

declare interface FormStep {
    label: string;
    hint?: string;
    fields: FieldDescriptor[];
}

/** Union of all AST node types */
export declare type FormulaASTNode = TextNode | PathRefNode | ConcatNode | FunctionNode | ConditionExprNode;

/**
 * Top-level formula config map: fieldId → FieldFormulaConfig (empty marker {}).
 * A key is present only when that field's formula config toggle is ON.
 *
 * When toggle is OFF: field key absent, Formik value = _DE_{_P('...')}
 * When toggle is ON:  field key present as {}, Formik value = _P('...')
 *
 * Example: { "dmnKey": {} }
 */
export declare type FormulaConfig = Record<string, FieldFormulaConfig>;

export declare function FormulaInput({ expression, onExpressionChange, onBlur, placeholder, disabled, error, id, formulaConfigEnabled, onFormulaConfigToggle, onPickerOpen, compact, }: FormulaInputProps): JSX_2.Element;

export declare interface FormulaInputProps {
    /** AST — source of truth. Host app owns this. */
    expression: FormulaASTNode[];
    /** Called with the new AST on every edit. */
    onExpressionChange: (nodes: FormulaASTNode[]) => void;
    onBlur?: () => void;
    placeholder?: string;
    disabled?: boolean;
    error?: boolean;
    id?: string;
    /** Whether formulaConfig emission is active (controls the { } toggle highlight). */
    formulaConfigEnabled?: boolean;
    /** Called when user clicks the { } toggle button. */
    onFormulaConfigToggle?: () => void;
    /** Future: open variable picker drawer. */
    onPickerOpen?: () => void;
    /** Compact mode — reduces height/padding to match native form controls in tight rows. */
    compact?: boolean;
}

declare interface FormulaProps {
    formulaConfig?: FormulaConfig;
    onFormulaConfigChange?: (config: FormulaConfig) => void;
    /**
     * Key under `formik.values` where formulaConfig is auto-roundtripped
     * when the host doesn't supply explicit `formulaConfig` /
     * `onFormulaConfigChange`. Defaults to `_formulaConfig`. Mirrors
     * `conditionConfigKey`.
     */
    formulaConfigKey?: string;
    /**
     * Optional variable groups for the built-in Smart Values picker.
     * When provided, DynamicFormRenderer automatically wraps itself in
     * VariablePickerProvider — every FormulaInput gets a picker button and
     * drag-and-drop support with no extra setup from the host.
     *
     * For advanced layout control (picker rendered elsewhere on the page),
     * wrap with <VariablePickerProvider> manually instead.
     */
    variableGroups?: VariableGroup[];
    /** Active per-field condition guards. Key = field pathPrefix. */
    conditionConfig?: ConditionConfig;
    onConditionConfigChange?: (config: ConditionConfig) => void;
    /**
     * Key under `formik.values` where conditionConfig is auto-roundtripped
     * when the host doesn't supply explicit `conditionConfig` /
     * `onConditionConfigChange`. Defaults to `_conditionConfig`.
     */
    conditionConfigKey?: string;
    /**
     * Called by `flowFormRef.current.save()` once validation passes.
     * Receives the full payload (formik values incl. conditionConfig sidecar)
     * + a meta object with `isValid` / `errors`.
     *
     * Available in controlled AND uncontrolled mode. In uncontrolled mode it
     * runs in addition to `onSubmit`.
     */
    onSave?: (values: Record<string, unknown>, meta: {
        isValid: boolean;
        errors: Record<string, unknown>;
    }) => void;
    /**
     * Host-registered resolver map for declarative dynamic options.
     * Fields with `optionsSource: { id: '...', dependsOn: ... }` look up
     * their loader in this map. Transport-agnostic — use axios, fetch,
     * GraphQL, anything that returns a Promise.
     */
    optionsResolvers?: OptionsResolvers;
}

export declare type FormulaToken = TextToken | ChipToken;

/**
 * A built-in function call (future).
 * e.g. upcase, format_date, number_to_text
 */
export declare interface FunctionNode {
    type: 'function';
    name: string;
    args: FormulaASTNode[];
}

export declare interface GatewaySpec {
    idTemplate: string;
    name?: string;
}

/** True if the string contains at least one formula token. */
export declare function hasFormulaTokens(value: unknown): boolean;

export declare const helperTextStyle: React.CSSProperties;

/** Props when using the useFlowForm() hook — simplest API. */
declare interface HookProps {
    form: FlowFormInstance;
    schema?: never;
    formik?: never;
    initialValues?: never;
    onSubmit?: never;
    formulaConfig?: never;
    onFormulaConfigChange?: never;
    conditionConfig?: never;
    onConditionConfigChange?: never;
    variableGroups?: never;
    children?: never;
}

export declare interface InfiniteOption {
    value: string;
    label: string;
    [key: string]: unknown;
}

export declare function InfiniteSelectField({ field: rawField, value, onChange, onBlur, error, touched, }: FieldComponentProps): JSX_2.Element;

export declare function inputStyle(opts: {
    hasError?: boolean;
    isDisabled?: boolean;
    extraStyle?: React.CSSProperties;
}): React.CSSProperties;

/**
 * Context passed to `NodeDescriptor.canInsert(ctx)` describing where on the
 * canvas the user clicked "+ Add step". Used by position-aware insertion rules.
 */
declare interface InsertContext {
    /** The slot the user clicked under (the one whose "+" edge was clicked). */
    insertAfterSlot: CanvasSlot | null;
    /** Every slot before the insertion point, including the click slot.
     *  When inside a branch: spine up to + including the branching parent, then
     *  the branch's own slots up to the insertion point. */
    upstreamSlots: CanvasSlot[];
    /** Every slot after the insertion point in the same chain. */
    downstreamSlots: CanvasSlot[];
    /** Branch context, if the insertion is happening inside a branch. */
    branch: {
        filterId: string;
        branch: string;
    } | null;
    /** The currently active template (the one whose trigger is in use). */
    template: WorkflowTemplate | null;
}

export declare function isFormula(value: unknown): value is string;

export declare interface LoadPageParams {
    page: number;
    search: string;
    signal: AbortSignal;
}

export declare interface LoadPageResult {
    options: InfiniteOption[];
    hasMore: boolean;
}

export declare function loadWorkflowFromBpmn(xml: string): WorkflowState;

export declare function makeSubWorkflowDescriptor(opts?: SubWorkflowDescriptorOptions): NodeDescriptor;

export declare interface NodeDescriptor {
    type: string;
    label: string;
    icon?: ReactNode;
    /**
     * Optional "app" this action belongs to (Slack, Salesforce, …). When present,
     * the node picker drills down: stage 1 lists unique apps, stage 2 lists this
     * app's actions, stage 3 is the action's config form. Descriptors without an
     * `app` field appear ungrouped at stage 1, alongside the app cards.
     */
    app?: {
        key: string;
        label: string;
        icon?: ReactNode;
        description?: string;
    };
    matches: (id: string) => boolean;
    bpmnEntry: (nodeId: string) => string;
    bpmnExit: (nodeId: string) => string;
    emitBpmnElements: (nodeId: string, nodeData: unknown) => BpmnElement[];
    emitDmnDefinition?: (nodeId: string, nodeData: unknown) => DmnDefinition;
    outgoingCondition?: (nodeId: string, targetId: string, nodeData: unknown) => string;
    reactFlowType: string;
    previewNodeType?: string;
    /**
     * Optional custom node-card body. When provided, the node renderer shows this
     * instead of the default value badges — lets a node author fully design the
     * card body while keeping the shared frame (title, edit/delete, handles).
     * Receives the node's saved formData.
     */
    renderNode?: (nodeData: Record<string, unknown>) => ReactNode;
    /**
     * Position constraint — this descriptor can be inserted only if at least ONE
     * of the listed tokens appears in the upstream chain of the click site.
     * Tokens can be a descriptorType (e.g. 'createUserTask'), a slot id
     * (e.g. 'event-userCreated'), or a slot kind (e.g. 'triggerFixed').
     * Ignored when `canInsert` is set.
     */
    insertAfter?: string[];
    /**
     * Symmetric — must appear DOWNSTREAM of the click site. Same token rules
     * as `insertAfter`. Ignored when `canInsert` is set.
     */
    insertBefore?: string[];
    /**
     * Full custom rule. Overrides `insertAfter` / `insertBefore`. Receives the
     * click context (upstream/downstream slots, branch info, active template);
     * returns `true` to allow the descriptor at this insertion point.
     */
    canInsert?: (ctx: InsertContext) => boolean;
    /** Maps branch key → display label. e.g. { pass: 'Pass', fail: 'Fail' }. Only applies to branching nodes (filterNode, approvalNode). */
    branchLabels?: Record<string, string>;
    formSchema: FieldDescriptor[] | ((nodeId: string) => Promise<FieldDescriptor[]>);
    maxPerWorkflow?: number;
    relatedNodePrefixes?: string[];
}

export declare class NodeTypeRegistry {
    private descriptors;
    register(descriptor: NodeDescriptor): this;
    forType(type: string): NodeDescriptor | undefined;
    forId(id: string): NodeDescriptor | undefined;
    list(): NodeDescriptor[];
}

export declare const nodeTypeRegistry: NodeTypeRegistry;

export declare interface NotificationChannelConfig {
    label: string;
    /** Fetch recipients/channels for this notification channel at runtime */
    fetchRecipients?: () => Promise<NotificationChannelOption[]>;
}

export declare interface NotificationChannelOption {
    value: string;
    label: string;
}

declare class NotificationChannelRegistry {
    private channels;
    register(key: string, config: NotificationChannelConfig): void;
    get(key: string): NotificationChannelConfig | undefined;
    list(): Array<{
        key: string;
    } & NotificationChannelConfig>;
    has(key: string): boolean;
}

export declare const notificationChannelRegistry: NotificationChannelRegistry;

export declare const notificationDescriptor: NodeDescriptor;

export declare interface ObjectFieldRendererProps {
    field: FieldDescriptor;
    pathPrefix: string;
    depth: number;
    values: Record<string, unknown>;
    errors: Record<string, unknown>;
    touched: Record<string, unknown>;
    setFieldValue: (name: string, value: unknown) => void;
    setFieldTouched: (name: string, touched: boolean) => void;
    compact?: boolean;
    renderFieldRouter: (props: ChildRouterProps) => default_2.ReactNode;
    /** Item-scoped values passed through unchanged from any parent ArrayField. */
    item?: Record<string, unknown>;
}

/** A resolver function — transport-agnostic. */
export declare type OptionsResolver = (deps: Record<string, unknown>, ctx: OptionsResolverContext) => Promise<OptionsResolverResult>;

export declare interface OptionsResolverContext {
    cursor?: unknown;
    input?: string;
    /** Full top-level form values, in case a resolver needs read-only access. */
    values?: Record<string, unknown>;
    /** AbortSignal — resolvers SHOULD honor this when their transport supports it. */
    signal?: AbortSignal;
}

/** Resolver return shape — matches Pipedream's `options` contract. */
export declare interface OptionsResolverResult {
    options: Array<{
        value: unknown;
        label: string;
        isDisabled?: boolean;
        [key: string]: unknown;
    }>;
    /** Opaque cursor returned to the next call. Omit to signal "no more pages". */
    nextCursor?: unknown;
}

export declare type OptionsResolvers = Record<string, OptionsResolver>;

declare interface OptionsResolversContextValue {
    resolvers: OptionsResolvers;
    /**
     * Bust a single resolver's cache. Useful for an explicit "Refresh" button.
     * Pass undefined to clear ALL cached pages for that resolver.
     */
    invalidate: (resolverId: string, depsKey?: string) => void;
}

export declare function OptionsResolversProvider({ resolvers, children }: ProviderProps): JSX_2.Element;

export declare interface OptionsSource {
    /** Resolver id — must match a key in the host's `optionsResolvers` map. */
    id: string;
    dependsOn?: string[] | Record<string, string>;
    params?: Record<string, unknown>;
    resolveValueId?: string;
}

export declare interface OutputSchemaItem {
    key: string;
    label: string;
    /** Optional — display only. Lets the picker show a type chip ("ABC" / 123). */
    type?: string;
    /** Optional — shown under/beside the label in the picker (Workato-style). */
    sample?: string | number | boolean;
    /** Optional tooltip text (independent of `sample`). */
    description?: string;
    /** Nested fields — renders as an expandable subgroup. */
    children?: OutputSchemaItem[];
}

/**
 * Parse a raw backend string into an AST node array.
 *
 * "Hello _DE_{_P('data.input.[\"dmnKey\"]')} world"
 * →
 * [
 *   { type: 'text',     value: 'Hello ' },
 *   { type: 'path-ref', path: 'data.input.["dmnKey"]', label: 'dmnKey' },
 *   { type: 'text',     value: ' world' },
 * ]
 */
/**
 * Parse a raw backend string into an AST node array.
 *
 * configEnabled = false (default): only _DE_{_P(...)} tokens become chips.
 *   _P('...') without the DE wrapper stays as plain text.
 * configEnabled = true: both _DE_{_P(...)} and _P('...') become chips.
 */
export declare function parseToAST(raw: string, configEnabled?: boolean): FormulaASTNode[];

/**
 * A reference to a value from a previous node's output.
 * Serializes to: _DE_{_P('path')}
 *
 * Example:
 *   path:  "data.input.[\"groupAssignPolicy\"].[\"dmnKey\"]"
 *   label: "dmnKey"   ← last ["key"] segment, for display
 */
export declare interface PathRefNode {
    type: 'path-ref';
    path: string;
    label: string;
}

/**
 * buildBackendPayload — generic BPMN/DMN/canvasState emitter driven by each
 * task's `ui.bpmnEmit` block. Consumer ships per-task bpmnEmit specs from
 * the backend; the package handles the walk.
 *
 * Originally lived in IAM as `flowforgeStateToBackendJson`. Moved into the
 * package so every consumer gets the same emitter — and so DMN/filter/
 * approval fixes ship once, to everyone.
 *
 * Consumer injects:
 *   - canvasState         — `{ slots, branches }` from the canvas
 *   - tasksByKey          — `{ [descriptorType]: ApplicationTask }` lookup
 *   - context             — host-specific scalars (customerKey, workflowName)
 *   - config              — IAM-shaped defaults (path prefix, end-event ids,
 *                           trigger→category map, scheduler events)
 *
 * Returns a JSON object ready to POST to the backend.
 */
export declare type PayloadCanvasSlot = {
    id: string;
    kind?: string;
    descriptorType?: string;
    nodeData?: Record<string, unknown>;
    formData?: Record<string, unknown>;
    [key: string]: unknown;
};

export declare type PayloadCanvasState = {
    slots?: PayloadCanvasSlot[];
    branches?: Record<string, unknown>;
};

declare interface ProviderProps {
    resolvers?: OptionsResolvers;
    children: default_2.ReactNode;
}

declare class Registry {
    private fields;
    constructor();
    register(def: FlowForgeFieldDefinition): void;
    get(type: string): FlowForgeFieldDefinition | undefined;
    getAll(): FlowForgeFieldDefinition[];
    /** Gets all allowed options for the Type Picker in SchemaBuilder */
    getTypeOptions(): Array<{
        value: string;
        label: string;
    }>;
}

/** The fields every node MUST provide — there is no sensible default for these. */
declare type RequiredNodeFields = Pick<NodeDescriptor, 'type' | 'label' | 'matches' | 'reactFlowType'>;

export declare const restApiDescriptor: NodeDescriptor;

export declare const RestApiNode: ({ id, data }: NodeProps) => JSX_2.Element;

/**
 * Result of `FlowFormHandle.save()`.
 *   - `isValid`: true when no validation errors
 *   - `values`: the latest formik values (includes conditionConfig sidecar
 *     under `_conditionConfig` by default, configurable via prop)
 *   - `errors`: per-path validation errors (empty object when isValid)
 */
export declare interface SaveResult {
    isValid: boolean;
    values: Record<string, unknown>;
    errors: Record<string, unknown>;
}

export declare function saveWorkflowToBpmn(workflow: WorkflowState, options?: BpmnSaveOptions): string;

export declare function SchemaBuilder({ value, onChange, suggestions, label, onPayload, validate, onValidityChange, variableGroups, initialValues: initialValuesProp, initialFormulaConfig, initialConditionConfig, }: SchemaBuilderProps): JSX_2.Element;

export declare function SchemaBuilderDrawer({ value, onChange, suggestions, onPayload, onDone, validate, onValidityChange, label, drawerTitle, drawerWidth, }: SchemaBuilderDrawerProps): JSX_2.Element;

export declare interface SchemaBuilderDrawerProps extends SchemaBuilderProps {
    label?: string;
    drawerTitle?: string;
    drawerWidth?: number;
    /**
     * Fired when the user clicks Done.
     * @param schema   Save this to DB — pass it back to FlowForm/SchemaBuilder to restore the form
     * @param payload  Send this to backend — contains conditionExpressions, formulaConfig, values, evaluationPayload
     */
    onDone?: (schema: FieldDescriptor[], payload: SchemaBuilderPayload | null) => void;
}

export declare interface SchemaBuilderPayload {
    /** The FieldDescriptor[] schema — save this to DB to restore the editor */
    schema: FieldDescriptor[];
    /** Formula AST per field — part of editor state */
    formulaConfig: FormulaConfig;
    /** Condition rows per field — part of editor state */
    conditionConfig: ConditionConfig;
    /** Serialized condition expression string per field — ready for backend rule engine */
    conditionExpressions: Record<string, string>;
    /** Live form values entered by the user */
    values: Record<string, unknown>;
    /** Backend-ready evaluation payload (formulas resolved against values) */
    evaluationPayload: ReturnType<typeof buildEvaluationPayload>;
}

export declare interface SchemaBuilderProps {
    value: FieldDescriptor[];
    onChange: (fields: FieldDescriptor[]) => void;
    suggestions?: FieldSuggestion[];
    label?: string;
    /** Fires on every change: schema edit, value input, formula/condition update */
    onPayload?: (payload: SchemaBuilderPayload) => void;
    /** Whether to auto-validate required fields (shows inline error messages) */
    validate?: boolean;
    /** Called whenever form validity changes — wire to enable/disable your Save button */
    onValidityChange?: (isValid: boolean) => void;
    /** Optional variable groups to seamlessly enable the Variable Picker for formula fields */
    variableGroups?: VariableGroup[];
    /** Saved form values to restore when reopening — keys match field ids */
    initialValues?: Record<string, unknown>;
    /** Saved formula config to restore when reopening */
    initialFormulaConfig?: FormulaConfig;
    /** Saved condition config to restore when reopening */
    initialConditionConfig?: ConditionConfig;
}

/**
 * Serialize an AST back to the backend expression string.
 * path-ref nodes always serialize as _DE_{_P('...')} (the evaluated form).
 *
 * [
 *   { type: 'text',     value: 'Hello ' },
 *   { type: 'path-ref', path: 'data.input.["dmnKey"]', label: 'dmnKey' },
 * ]
 * →  "Hello _DE_{_P('data.input.[\"dmnKey\"]')}"
 */
export declare function serializeAST(nodes: FormulaASTNode[]): string;

/**
 * Serialize AST to the formula-config-enabled format.
 * path-ref nodes → _P('...') (no _DE_ wrapper).
 * Used when formulaConfig toggle is ON.
 */
export declare function serializeASTAsConfig(nodes: FormulaASTNode[]): string;

/**
 * Serialize a ConditionConfig into a map of field → expression string.
 *
 * Example output:
 *   {
 *     email: "isNotPresent(_P('data.input.[\"email\"]'))",
 *     firstName: "_P('data.input.[\"firstName\"]') == 'abhi'"
 *   }
 */
export declare function serializeConditionExpressions(conditionConfig: ConditionConfig): Record<string, string>;

export declare interface ServiceTaskSpec {
    idTemplate: string;
    name?: string;
    flowableClass?: string;
    extensionFields?: ExtensionFieldSpec[];
}

declare type SlotKind = 'start' | 'end' | 'addTrigger' | 'triggerFixed' | 'userTask' | 'addStep' | 'filter' | 'approval';

/**
 * Start event — a fixed skeleton node with no user-editable form.
 * The canvas seeds it as the literal slot id `'start'` (see buildInitialSlots
 * in WorkflowCanvas.tsx). This descriptor exists so the registry can resolve
 * that id via `forId('start')` and emit it during descriptor-driven BPMN save.
 *
 * Inherits formSchema (none) and bpmnEntry/bpmnExit from the base node.
 */
export declare const startEventDescriptor: NodeDescriptor;

export declare const StartNode: () => JSX_2.Element;

export declare type StepStatus = 'pending' | 'running' | 'success' | 'failed' | 'skipped';

export declare function stripFormulaTokens(value: string): string;

/** Pre-built static descriptor (no dynamic workflow list). Swap for makeSubWorkflowDescriptor when you have an API. */
export declare const subWorkflowDescriptor: NodeDescriptor;

/**
 * Sub-Workflow node — calls another saved workflow by ID.
 *
 * The host app must provide `fetchWorkflowOptions` at registration time so the
 * `workflowId` select field can populate. Inject it via the descriptor factory:
 *
 *   import { makeSubWorkflowDescriptor } from '@miniorange/flowforge';
 *   nodeTypeRegistry.register(makeSubWorkflowDescriptor({
 *     fetchWorkflowOptions: async () => myApi.listWorkflows(),
 *   }));
 */
export declare interface SubWorkflowDescriptorOptions {
    /** Return a list of available workflows for the workflowId select field */
    fetchWorkflowOptions?: () => Promise<Array<{
        label: string;
        value: string;
    }>>;
}

export declare const SubWorkflowPreviewDrawer: default_2.FC<SubWorkflowPreviewDrawerProps>;

declare interface SubWorkflowPreviewDrawerProps {
    isOpen: boolean;
    onClose: () => void;
    workflowId: string | null;
    workflowLabel?: string;
    /** Host-provided async loader — returns the WorkflowState for the given ID */
    onFetchWorkflow: (workflowId: string) => Promise<WorkflowState>;
}

export declare interface TabDefinition {
    id: string;
    label: string;
    fields: FieldDescriptor[];
}

export declare function TablePickerField({ field: rawField, value, onChange, onBlur, error, touched }: FieldComponentProps): JSX_2.Element;

export declare interface TablePickerFieldDescriptor extends FieldDescriptor {
    columns: Array<{
        key: string;
        label: string;
        width?: number;
    }>;
    fetchOptions?: (query: string, page: number) => Promise<FetchResult>;
    dataSource?: string;
    isMulti?: boolean;
    pageSize?: number;
}

export declare interface TablePickerOption {
    value: string;
    label: string;
    [key: string]: unknown;
}

export declare interface TabsFieldDescriptor extends FieldDescriptor {
    tabs?: TabDefinition[];
    variant?: 'pill' | 'line';
    alignment?: 'left' | 'center' | 'right' | 'center-left' | 'center-right';
    height?: 'auto' | 'fixed';
    margin?: 'normal' | 'none';
    activeColor?: string;
    activeTextColor?: string;
    inactiveTextColor?: string;
}

export declare interface TemplateFlowSpec {
    from: string;
    to: string;
    idTemplate?: string;
    condition?: string | null;
}

export declare class TemplateRegistry {
    private templates;
    /**
     * Register a template. Normalises `allowedTasks` (the backend's name) →
     * `availableTasks` (FlowForge's canonical name) so consumers can pass
     * either without rewriting.
     */
    register(template: WorkflowTemplate): this;
    /**
     * Register a list of templates fetched from `GET /api/v1/workflow-template`.
     *
     * The API shape is:
     *   {
     *     key, name, description, allowedTasks, allowedSources,
     *     configuration,            // runtime BPMN — ignored by the canvas
     *     templateUI: {             // ← UI bag, spread onto the template
     *       triggerCategory, icon, tags, category, author, popularity,
     *       source, product, taskLabels, maxTasks, skeletonState, …
     *     }
     *   }
     *
     * Anything in `templateUI` overrides the top-level shorthand where there's
     * an overlap. Bad rows (missing `key`) are skipped with a DEV warning
     * rather than throwing, so one broken template doesn't blank the picker.
     *
     * Returns `this` for chaining and the count of templates registered.
     */
    registerFromApi(list: ApiWorkflowTemplate[]): this;
    lookup(triggerKey: string): WorkflowTemplate | undefined;
    list(): WorkflowTemplate[];
    listByCategory(category: string): WorkflowTemplate[];
    listByTag(tag: string): WorkflowTemplate[];
    search(query: string): WorkflowTemplate[];
    categories(): string[];
    /** Remove every template — useful before re-loading from backend. */
    clear(): this;
}

export declare const templateRegistry: TemplateRegistry;

/**
 * FlowForge Formula AST
 *
 * The AST is the source of truth for formula fields.
 * The _DE_{_P(...)} string is a derived serialization produced at submit
 * time for the backend engine — it is never the primary storage format.
 *
 * Extensibility: add new node types here as the engine grows.
 * Current: text + path-ref (covers all real usage today)
 * Future:  concat, function, condition
 */
/** Plain text segment — rendered as-is */
export declare interface TextNode {
    type: 'text';
    value: string;
}

export declare interface TextToken {
    type: 'text';
    value: string;
}

/** Parse a raw string to the flat token list (used for paste/input).
 *  configEnabled mirrors the formula config toggle state. */
export declare function tokenize(raw: string, configEnabled?: boolean): FormulaToken[];

export declare const TriggerNode: ({ data }: NodeProps) => JSX_2.Element;

declare interface UncontrolledProps extends FormulaProps {
    schema: FormSchema;
    initialValues: Record<string, unknown>;
    onSubmit: (values: Record<string, unknown>) => void | Promise<void>;
    formik?: never;
    form?: never;
    validationSchema?: ObjectSchema<any>;
    /** Pre-mark fields as touched so validation errors show immediately */
    initialTouched?: Record<string, boolean>;
    /** Called on every values change — use to observe live form values */
    onValuesChange?: (values: Record<string, unknown>) => void;
    /** Called whenever form validity changes — use to enable/disable a parent Save button */
    onValidityChange?: (isValid: boolean) => void;
    children?: (props: {
        isSubmitting: boolean;
    }) => default_2.ReactNode;
    /**
     * Optional HTML `id` for the underlying <form> element. Use this when the
     * submit button lives outside the form (e.g. in a drawer footer) — a
     * `<button type="submit" form={formId}>` will still trigger this form's
     * submit via the HTML5 form attribute.
     */
    formId?: string;
}

export declare function unwrapFormula(value: string): string;

/**
 * Returns a drop-in `loadOptions` for react-select when a field's
 * `optionsSource` is set and the host has registered a matching resolver.
 * Otherwise returns `enabled: false` and the host falls back to the
 * descriptor's static `options` (or no options).
 */
export declare function useDynamicOptions({ source, values }: UseDynamicOptionsArgs): UseDynamicOptionsResult;

declare interface UseDynamicOptionsArgs {
    source: OptionsSource | undefined;
    values: Record<string, unknown>;
}

declare interface UseDynamicOptionsResult {
    /** True when the host configured a usable resolver for this field. */
    enabled: boolean;
    /** Drop-in `loadOptions(inputValue) => Promise<Option[]>` for react-select. */
    loadOptions: ((input: string) => Promise<OptionsResolverResult['options']>) | undefined;
    /** Drop-in `loadValue(ids) => Promise<Option[]>` for edit-mode hydration. */
    loadValue: ((ids: unknown[]) => Promise<OptionsResolverResult['options']>) | undefined;
    /** Stable key derived from deps — feed to react-select's `key` to refresh on change. */
    depsKey: string;
    /** Manually invalidate this field's cache (e.g. for a Refresh button). */
    refresh: () => void;
}

export declare function useFlowForm({ schema, initialValues, onSubmit, showErrorsImmediately, }: UseFlowFormOptions): FlowFormInstance;

export declare interface UseFlowFormOptions {
    schema: FormSchema;
    initialValues: Record<string, unknown>;
    /**
     * Called only when form is valid and submitted.
     * Receives raw formik values AND the fully-resolved evaluation payload
     * (formula chips resolved, condition expressions serialized).
     */
    onSubmit: (values: Record<string, unknown>, evaluation: EvaluationPayload) => void | Promise<void>;
    /** Pre-mark all fields as touched so errors show immediately (e.g. edit mode). */
    showErrorsImmediately?: boolean;
}

export declare function useOptionsResolvers(): OptionsResolversContextValue;

export declare function useVariablePickerContext(): VariablePickerContextValue | null;

export declare interface VariableGroup {
    label: string;
    icon?: default_2.ReactNode;
    items: VariableItem[];
}

export declare interface VariableItem {
    /** Display label shown in the picker */
    label: string;
    /** Formula path used to build _DE_{_P('...')} / _P('...') */
    path: string;
    /** Optional description shown below the label */
    description?: string;
    /** Nested sub-items — renders as an expandable group in the picker */
    children?: VariableItem[];
}

export declare function VariablePicker({ width, title, mode, floating, }: VariablePickerProps): JSX_2.Element | null;

declare interface VariablePickerContextValue {
    groups: VariableGroup[];
    isOpen: boolean;
    openPicker: () => void;
    closePicker: () => void;
    /**
     * Called by FormulaOverlay when formula mode is toggled ON or OFF.
     * Pass the anchor HTMLElement (the toggle button) when turning ON so the
     * picker can position itself next to it.
     */
    notifyFormulaToggle: (on: boolean, anchor?: HTMLElement | null) => void;
    /** FormulaInput calls this on focus to register as the active target */
    registerField: (field: ActiveField) => void;
    /** FormulaInput calls this on selection change to save cursor position */
    saveRange: (range: Range | null) => void;
    /** Picker calls this on item click or drop — inserts chip into active field */
    insertVariable: (path: string, label: string) => void;
    /** Currently active field id — used by FormulaInput to show drop-valid state */
    activeFieldId: string | null;
    /** Signal that a field has been focused/clicked — used to auto-open picker panel */
    notifyFieldFocus: (fieldId: string, anchor?: HTMLElement | null) => void;
    /** DOM element the popover should anchor to */
    anchorEl: HTMLElement | null;
}

export declare interface VariablePickerProps {
    /** Panel width in px. Default: 300 */
    width?: number;
    /** Title shown in panel header. Default: 'Smart Values' */
    title?: string;
    /**
     * 'drawer' — always visible as a sidebar panel (default).
     * 'popover' — absolutely positioned, shown/hidden via isOpen.
     */
    mode?: 'drawer' | 'popover';
    floating?: boolean;
}

export declare function VariablePickerProvider({ groups, children }: VariablePickerProviderProps): JSX_2.Element;

declare interface VariablePickerProviderProps {
    groups: VariableGroup[];
    children: default_2.ReactNode;
}

export declare const webhookTriggerDescriptor: NodeDescriptor;

export declare const WebhookTriggerNode: ({ data }: NodeProps) => JSX_2.Element;

export declare const webhookTriggerTemplate: WorkflowTemplate;

/** @deprecated Use FlowForgeCanvasProps */
export declare type WorkflowCanvasProps = FlowForgeCanvasProps;

export declare const WorkflowExecutionHistory: default_2.FC<WorkflowExecutionHistoryProps>;

declare interface WorkflowExecutionHistoryProps {
    records: ExecutionRecord[];
    /** Called when the "view on canvas" button is clicked for a record */
    onViewOnCanvas?: (record: ExecutionRecord) => void;
}

export declare interface WorkflowState {
    slots: CanvasSlot[];
    branches: BranchMap;
}

export declare interface WorkflowTemplate {
    triggerKey: string;
    label: string;
    description?: string;
    icon?: ReactNode;
    triggerCategory?: 'event' | 'scheduler' | 'webhook' | string;
    /**
     * Task IDs (descriptor types) that can be inserted into this workflow.
     * `allowedTasks` is accepted as an alias for backend payloads that use
     * that name — TemplateRegistry.register() normalises them.
     */
    availableTasks?: string[];
    allowedTasks?: string[];
    maxTasks?: number;
    taskLabels?: Record<string, string>;
    fixedNodes?: FixedNode[];
    fixedEdges?: FixedEdge[];
    insertionPoints?: string[];
    source?: string;
    product?: string;
    /** Pre-built workflow state to clone when user selects this template */
    skeletonState?: WorkflowState;
    /** Tags for filtering in the template library */
    tags?: string[];
    /** Category grouping in the library */
    category?: string;
    /** Team or author that owns this template */
    author?: string;
    /** Relative popularity score (higher = shown first in library) */
    popularity?: number;
}

export declare const WorkflowTemplateLibrary: default_2.FC<WorkflowTemplateLibraryProps>;

declare interface WorkflowTemplateLibraryProps {
    templates: WorkflowTemplate[];
    onSelectTemplate: (template: WorkflowTemplate) => void;
    onStartFromScratch?: () => void;
}

export declare function wrapFormula(expression: string): string;

export { }
