import pino from 'pino'; import { FlowExecutor } from './executor/FlowExecutor'; import { FlowContext, FlowEngineContext, FlowRuntimeContext } from './flowContext'; import { FlowSettings } from './flowSettings'; import { FlowModel } from './models'; import { ReactView } from './ReactView'; import { FlowResource } from './resources'; import { Emitter } from './emitter'; import ModelOperationScheduler from './scheduler/ModelOperationScheduler'; import type { ScheduleOptions, ScheduledCancel } from './scheduler/ModelOperationScheduler'; import type { ActionDefinition, ApplyFlowCacheEntry, CreateModelOptions, EnsureBatchResult, EventDefinition, FlowModelLoaderInputMap, FlowModelOptions, IFlowModelRepository, ModelConstructor, PersistOptions, ResourceType } from './types'; /** * FlowEngine is the core class of the flow engine, responsible for managing flow models, actions, model repository, and more. * It provides capabilities for registering, creating, finding, persisting, replacing, and moving models. * Supports flow definitions, action definitions, model class inheritance and filtering. * Integrates FlowEngineContext, FlowSettings, and ReactView for context, configuration, and view rendering. * * Main features: * - Register, get, and find model classes and model instances * - Register and get action definitions * - Persist and query models via the model repository * - Register flow definitions * - Create, find, replace, move, and destroy model instances * - Support for model class inheritance and filtering * - Internationalization support * - Integration with React view rendering * * @example * const engine = new FlowEngine(); * engine.registerModels({ MyModel }); * engine.setModelRepository(new MyRepository()); * const model = engine.createModel({ use: 'MyModel', uid: 'xxx' }); */ export declare class FlowEngine { #private; /** * Global action registry */ private _actionRegistry; /** * Global event registry */ private _eventRegistry; /** * Registered model classes. * Key is the model class name, value is the model class constructor. * @private */ private _modelClasses; /** * Registered model entries. * Key is the model class name, value is the model loader entry. * @private */ private _modelLoaders; /** * In-flight model loading promises. * Key is the model class name, value is the loading promise. * @private */ private _loadingModelPromises; /** * Whether model-loader preload has completed in this session. * @private */ private _modelLoadersPreloaded; /** * In-flight model-loader preload promise. * @private */ private _modelLoadersPreloadPromise?; /** * Created model instances. * Key is the model instance UID, value is the model instance object. * @private */ private _modelInstances; /** * The current model repository instance, implements IFlowModelRepository. * Used for model persistence and queries. * @private */ private _modelRepository; /** * Flow application cache. * Key is the cache key, value is ApplyFlowCacheEntry. * @private */ private _applyFlowCache; /** * Model saving state tracking. * Key is the model UID, value is the save promise. * @private */ private _savingModels; private _loadedPageCache; /** * Flow engine context object. * @private */ private _flowContext; /** * 视图作用域引擎的栈式链表指针。 * - previousEngine:打开当前视图的上一个引擎 * - nextEngine:在当前之上的下一个引擎 */ private _previousEngine?; private _nextEngine?; /** * 视图销毁回调。由 useDrawer / useDialog 在创建弹窗视图时注册, * 供外部(如 afterSuccess)通过引擎栈遍历来关闭多层弹窗。 * embed 视图(usePage)不注册此回调,因此 destroyView() 会自然跳过。 */ private _destroyView?; private _resources; /** * Data change registry used to coordinate "refresh on active" across view-scoped engines. * * Keyed by: dataSourceKey -> resourceName -> version. * - mark: increments version * - get: returns current version (default 0) * * NOTE: ViewScopedFlowEngine proxies delegate non-local fields/methods to parents, so this * registry naturally lives on the root engine instance and is shared across the whole view stack. */ private _dataSourceDirtyVersions; /** * 引擎事件总线(目前用于模型生命周期等事件)。 * ViewScopedFlowEngine 持有自己的实例,实现作用域隔离。 */ emitter: Emitter; /** 调度器:仅在 View 作用域引擎本地启用;根/Block 作用域默认不持有 */ private _modelOperationScheduler?; logger: pino.Logger; /** * Flow settings, including components and form scopes. * @public */ flowSettings: FlowSettings; /** * Experimental API: Integrates React view rendering capability into FlowEngine. * This property may change or be removed in the future. Use with caution. * @experimental * @public */ reactView: ReactView; /** * Flow executor that runs event flows. */ executor: FlowExecutor; /** * Constructor. Initializes React view, registers default model and form scopes. */ constructor(); /** 获取/创建当前引擎的调度器(仅在本地作用域) */ getScheduler(): ModelOperationScheduler; /** 释放并清理当前引擎本地调度器(若存在) */ disposeScheduler(): void; /** * Mark a data source resource as "dirty" (changed). * This is used by data blocks to decide whether to refresh when a view becomes active. */ markDataSourceDirty(dataSourceKey: string, resourceName: string): number; /** * Get current dirty version for a data source resource. * Returns 0 when no writes have been recorded. */ getDataSourceDirtyVersion(dataSourceKey: string, resourceName: string): number; /** 在目标模型生命周期达成时执行操作(仅在 View 引擎本地存储计划) */ scheduleModelOperation(fromModelOrUid: FlowModel | string, toUid: string, fn: (model: FlowModel) => Promise | void, options?: ScheduleOptions): ScheduledCancel; /** 上一个引擎(根引擎为 undefined) */ get previousEngine(): FlowEngine | undefined; /** 下一个引擎(若存在) */ get nextEngine(): FlowEngine | undefined; /** * 将当前引擎链接到 prev 之后(用于视图打开时形成栈关系)。 */ linkAfter(engine: FlowEngine): void; /** * 将当前引擎从栈中移除并修复相邻指针(用于视图关闭时)。 */ unlinkFromStack(): void; /** * 注册视图销毁回调(由 useDrawer / useDialog 调用)。 */ setDestroyView(fn: () => void): void; /** * 关闭当前引擎关联的弹窗视图。 * 路由触发的弹窗会先 navigation.back() 清理 URL,再 destroy() 移除元素; * 非路由弹窗直接 destroy()。 * embed 视图不注册回调,调用时返回 false 自动跳过。 * @returns 是否成功执行 */ destroyView(): boolean; /** * Get the flow engine context object. * @returns {FlowEngineContext} Flow engine context */ get context(): FlowEngineContext; get dataSourceManager(): import("./data-source").DataSourceManager; /** * Get the flow application cache. * @returns {Map} Flow application cache map * @internal */ get applyFlowCache(): Map; /** * Set the model repository for persisting and querying model instances. * If a model repository was already set, it will be overwritten and a warning will be printed. * @param {IFlowModelRepository} modelRepository The model repository instance implementing IFlowModelRepository. * @example * flowEngine.setModelRepository(new MyFlowModelRepository()); */ setModelRepository(modelRepository: IFlowModelRepository): void; get modelRepository(): IFlowModelRepository | null; /** * Internationalization translation method, calls the context's t method. * @param {string} keyOrTemplate Translation key or template string * @param {any} [options] Optional parameters * @returns {string} Translated string */ translate(keyOrTemplate: string, options?: any): string; /** * Register multiple actions. * @param {Record} actions Action definition object collection */ registerActions(actions: Record): void; /** * Get a registered action definition. * @template TModel Specific FlowModel subclass type * @param {string} name Action name * @returns {ActionDefinition | undefined} Action definition, or undefined if not found */ getAction>(name: string): ActionDefinition | undefined; /** * Get all registered global actions. * Returns a new Map to avoid external mutation of internal state. */ getActions>(): Map>; /** * Register multiple events. */ registerEvents(events: Record): void; /** * Get a registered event definition. */ getEvent(name: string): EventDefinition | undefined; /** * Get all registered global events. */ getEvents(): Map>; /** * for proxy instance, the #registerModel can't be called. */ private _registerModel; /** * Register multiple model classes. * @param {Record} models Model class map, key is model name, value is model constructor * @returns {void} * @example * flowEngine.registerModels({ UserModel, OrderModel }); */ registerModels(models: Record>): void; /** * Register multiple model loader entries. * The `extends` field declares parent class(es) for async subclass discovery via `getSubclassesOfAsync`. * It accepts `string | ModelConstructor | (string | ModelConstructor)[]` and is normalized to `string[]` internally. * @param {FlowModelLoaderInputMap} loaders Model loader input map * @returns {void} * @example * flowEngine.registerModelLoaders({ * DemoModel: { * extends: 'BaseModel', * loader: () => import('./models/DemoModel'), * }, * }); */ registerModelLoaders(loaders: FlowModelLoaderInputMap): void; /** * Get a registered model class (constructor) asynchronously. * This will first ensure the model loader entry is resolved. * @param {string} name Model class name * @returns {Promise} Model constructor, or undefined if not found */ getModelClassAsync(name: string): Promise; /** * Get all registered model classes asynchronously. * This will first ensure all registered model loader entries are resolved. * @returns {Promise>} Model class map */ getModelClassesAsync(): Promise>; /** * Create and register a model instance asynchronously. * This will first ensure all string-based model references in the model tree are resolved. * @template T FlowModel subclass type, defaults to FlowModel. * @param {CreateModelOptions} options Model creation options * @returns {Promise} Created model instance */ createModelAsync(options: CreateModelOptions, extra?: { delegateToParent?: boolean; delegate?: FlowContext; }): Promise; /** * Normalize a loader result into a model constructor. * @param {string} name Model class name * @param {FlowModelLoaderResult} loaded Loader result * @returns {ModelConstructor | null} Normalized model constructor * @private */ private normalizeModelLoaderResult; /** * Collect string-based model names from a model tree. * @param {unknown} data Model tree data * @param {Set} names Model name set * @private */ private collectModelNamesFromTree; /** * Collect additional model names from object-form meta.createModelOptions defaults. * @param {ModelConstructor} modelClass Model class constructor * @param {Set} names Model name set * @private */ private collectModelNamesFromMetaDefaults; /** * Ensure a single model class is available. * @param {string} name Model class name * @returns {Promise} Model constructor or null when resolution fails * @private */ private ensureModel; /** * Ensure multiple model classes are available. * @param {string[]} names Model class names * @returns {Promise} Batch ensure result * @private */ private ensureModels; /** * Resolve all unresolved string-based model references in a model tree before synchronous creation begins. * * Use this when you already have a model tree object, such as repository-returned data or resolved * `createModelOptions`, and you need to ensure every string `use` in that tree has been loaded and * registered into `_modelClasses` before calling `createModel()`. * * @param {unknown} data Model tree data * @returns {Promise} Batch ensure result */ resolveModelTree(data: unknown): Promise; /** * Preload all currently registered unresolved model loaders. * * This method is intended for flow-settings/discovery style entry points that need registered model * classes to exist before UI is rendered, without requiring callers to know which specific models * will be touched next. * * @returns {Promise} Batch ensure result */ preloadModelLoaders(): Promise; registerResources(resources: Record): void; createResource(resourceType: ResourceType, options?: { context?: FlowContext; }): T; /** * Get all registered model classes. * @returns {Map} Model class map */ getModelClasses(): Map; /** * Get a registered model class (constructor). * @param {string} name Model class name * @returns {ModelConstructor | undefined} Model constructor, or undefined if not found */ getModelClass(name: string): ModelConstructor | undefined; /** * Find a registered model class by predicate. * @param predicate Callback function, arguments are (name, ModelClass), returns true if matched * @returns {[string, ModelConstructor] | undefined} Matched model class and name */ findModelClass(predicate: (name: string, ModelClass: ModelConstructor) => boolean): [string, ModelConstructor] | undefined; /** * Filter model classes by base class (supports multi-level inheritance), with optional custom filter. * @param {string | ModelConstructor} baseClass Base class name or constructor * @param {(ModelClass: ModelConstructor, className: string) => boolean} [filter] Optional filter function * @returns {Map} Model classes inherited from base class and passed the filter */ getSubclassesOf(baseClass: string | ModelConstructor, filter?: (ModelClass: ModelConstructor, className: string) => boolean): Map; /** * Asynchronously get all subclasses of a base class, including those registered via model loaders. * Merges results from already-loaded classes (_modelClasses) and async loader entries with matching `extends` declarations. * Loader-resolved classes are validated with `isInheritedFrom`; mismatches are warned and excluded. * @param {string | ModelConstructor} baseClass Base class name or constructor * @param {(ModelClass: ModelConstructor, className: string) => boolean} [filter] Optional filter function * @returns {Promise>} Model classes that are subclasses of the base class */ getSubclassesOfAsync(baseClass: string | ModelConstructor, filter?: (ModelClass: ModelConstructor, className: string) => boolean): Promise>; /** * Create and register a model instance. * If an instance with the same UID exists, returns the existing instance. * @template T FlowModel subclass type, defaults to FlowModel. * @param {CreateModelOptions} options Model creation options * @returns {T} Created model instance */ createModel(options: CreateModelOptions, extra?: { delegateToParent?: boolean; delegate?: FlowContext; }): T; /** * 按类上的 resolveUse 链路解析最终用于实例化的模型类。 * 允许模型类根据上下文动态指定实际使用的类,支持多级 resolveUse。 */ private _resolveModelClass; /** * 尝试应用当前模型可用 flow 的 defaultParams(如果存在)到 model.stepParams。 * 仅对尚未存在的步骤参数进行填充,不覆盖已有值。 */ _applyFlowDefinitionDefaultParams(model: FlowModel): Promise; /** * Get a model instance by UID. * @template T FlowModel subclass type, defaults to FlowModel. * @param {string} uid Model instance UID * @returns {T | undefined} Model instance, or undefined if not found */ getModel(uid: string, global?: boolean): T | undefined; /** * Iterate all registered model instances. * @template T FlowModel subclass type, defaults to FlowModel. * @param {(model: T) => void} callback Callback function */ forEachModel(callback: (model: T) => void): void; /** * Remove a local model instance. * @param {string} uid UID of the model instance to destroy * @returns {boolean} Returns true if successfully destroyed, false otherwise (e.g. instance does not exist) */ removeModel(uid: string): boolean; /** * Remove a local model instance and all its sub-models recursively. * @param {string} uid UID of the model instance to destroy * @returns {boolean} Returns true if successfully destroyed, false otherwise */ removeModelWithSubModels(uid: string): boolean; /** * Check if the model repository is set. * @returns {boolean} Returns true if set, false otherwise. * @private */ private ensureModelRepository; /** * Try to locate a model instance in previous engines (view stack) by uid. * This is mainly used by view-scoped engines to reuse already-loaded model trees * (e.g. models created from local JSON) without hitting the repository. */ private findModelInPreviousEngines; /** * Try to locate a sub-model in previous engines (view stack) by (parentId, subKey). */ private findSubModelInPreviousEngines; /** * Hydrate a model into current engine from an already-existing model instance in previous engines. * - Avoids repository requests when the model tree is already present in memory. */ private hydrateModelFromPreviousEngines; /** * Load a model instance (prefers local, falls back to repository). * @template T FlowModel subclass type, defaults to FlowModel. * @param {any} options Load options * @returns {Promise} Loaded model instance or null */ loadModel(options: any): Promise; /** * Find a sub-model by parent model ID and subKey. * @template T FlowModel subclass type, defaults to FlowModel. * @param {string} parentId Parent model UID * @param {string} subKey Sub-model key * @returns {T | null} Found sub-model or null */ findModelByParentId(parentId: string, subKey: string): T | null; /** * Load or create a model instance. * @template T FlowModel subclass type, defaults to FlowModel. * @param {any} options Load or create options * @returns {Promise} Model instance or null */ loadOrCreateModel(options: any, extra?: { skipSave?: boolean; delegateToParent?: boolean; delegate?: FlowContext; }): Promise; /** * Persist and save a model instance. * Prevents concurrent saves of the same model by tracking save operations. * If a model is already being saved, subsequent calls will wait for the existing save to complete. * * @template T FlowModel subclass type, defaults to FlowModel. * @param {T} model Model instance to save * @param {object} [options] Save options * @param {boolean} [options.onlyStepParams] Whether to save only step parameters * @returns {Promise} Repository save result */ saveModel(model: T, options?: { onlyStepParams?: boolean; }): Promise; /** * Perform the actual model save operation. * @template T FlowModel subclass type, defaults to FlowModel. * @param {T} model Model instance to save * @param {object} [options] Save options * @returns {Promise} Repository save result * @private */ _performModelSave(model: T, options?: { onlyStepParams?: boolean; }): Promise; /** * Destroy a model instance (persistently delete and remove local instance). * @param {string} uid UID of the model to destroy * @returns {Promise} Whether destroyed successfully */ destroyModel(uid: string): Promise; /** * Duplicate a model tree via repository API. * Returns the duplicated model JSON (root with subModels) or null if not available. * @param {string} uid UID of the model to duplicate * @returns {Promise} Duplicated model JSON or null */ duplicateModel(uid: string): Promise>; /** * Replace a model instance with a new instance of a class. * @template T New model type * @param {string} uid UID of the model to replace * @param {Partial | ((oldModel: FlowModel) => Partial)} [optionsOrFn] * Options for creating the new model, supports two forms: * 1. Pass options directly * 2. Pass a function that receives current options and returns new options * @returns {Promise} Newly created model instance */ replaceModel(uid: string, optionsOrFn?: Partial | ((currentOptions: FlowModelOptions) => Partial)): Promise; /** * Move a model instance within its parent model. * @param {string | number} sourceId Source model UID * @param {string | number} targetId Target model UID * @returns {Promise} No return value */ moveModel(sourceId: string | number, targetId: string | number, options?: PersistOptions): Promise; /** * Filter model classes by parent class (supports multi-level inheritance). * @param {string | ModelConstructor} parentClass Parent class name or constructor * @returns {Map} Model classes inherited from the specified parent class */ filterModelClassByParent(parentClass: string | ModelConstructor): Map; /** * Generate a unique key for the flow application cache. * @param {string} prefix Prefix * @param {string} flowKey Flow key * @param {string} modelUid Model UID * @returns {string} Unique cache key * @internal */ static generateApplyFlowCacheKey(prefix: string, flowKey: string, modelUid: string): string; }