@platforma-sdk/model 1.63.0 → 1.63.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/_virtual/_rolldown/runtime.cjs +12 -22
- package/dist/_virtual/_rolldown/runtime.js +6 -11
- package/dist/annotations/converter.cjs +4 -5
- package/dist/annotations/converter.cjs.map +1 -1
- package/dist/annotations/converter.d.ts.map +1 -0
- package/dist/annotations/converter.js +1 -2
- package/dist/annotations/converter.js.map +1 -1
- package/dist/annotations/index.cjs +1 -1
- package/dist/annotations/index.js +1 -1
- package/dist/annotations/types.d.ts +0 -1
- package/dist/annotations/types.d.ts.map +1 -0
- package/dist/bconfig/index.cjs +2 -2
- package/dist/bconfig/index.js +2 -2
- package/dist/bconfig/lambdas.d.ts +0 -1
- package/dist/bconfig/lambdas.d.ts.map +1 -0
- package/dist/bconfig/normalization.cjs +4 -5
- package/dist/bconfig/normalization.cjs.map +1 -1
- package/dist/bconfig/normalization.d.ts.map +1 -0
- package/dist/bconfig/normalization.js +1 -2
- package/dist/bconfig/normalization.js.map +1 -1
- package/dist/bconfig/types.cjs +1 -2
- package/dist/bconfig/types.cjs.map +1 -1
- package/dist/bconfig/types.d.ts +0 -1
- package/dist/bconfig/types.d.ts.map +1 -0
- package/dist/bconfig/types.js +1 -1
- package/dist/bconfig/util.d.ts.map +1 -0
- package/dist/bconfig/v3.d.ts.map +1 -0
- package/dist/block_api_v1.d.ts.map +1 -0
- package/dist/block_api_v2.d.ts.map +1 -0
- package/dist/block_api_v3.d.ts.map +1 -0
- package/dist/block_migrations.cjs +2 -3
- package/dist/block_migrations.cjs.map +1 -1
- package/dist/block_migrations.d.ts.map +1 -0
- package/dist/block_migrations.js +1 -2
- package/dist/block_migrations.js.map +1 -1
- package/dist/block_model.cjs +16 -17
- package/dist/block_model.cjs.map +1 -1
- package/dist/block_model.d.ts +0 -2
- package/dist/block_model.d.ts.map +1 -0
- package/dist/block_model.js +4 -5
- package/dist/block_model.js.map +1 -1
- package/dist/block_model_legacy.cjs +10 -11
- package/dist/block_model_legacy.cjs.map +1 -1
- package/dist/block_model_legacy.d.ts +0 -3
- package/dist/block_model_legacy.d.ts.map +1 -0
- package/dist/block_model_legacy.js +1 -2
- package/dist/block_model_legacy.js.map +1 -1
- package/dist/block_state_patch.d.ts.map +1 -0
- package/dist/block_state_util.cjs +1 -2
- package/dist/block_state_util.cjs.map +1 -1
- package/dist/block_state_util.d.ts.map +1 -0
- package/dist/block_state_util.js +1 -1
- package/dist/block_state_util.js.map +1 -1
- package/dist/block_storage.cjs +5 -12
- package/dist/block_storage.cjs.map +1 -1
- package/dist/block_storage.d.ts.map +1 -0
- package/dist/block_storage.js +5 -11
- package/dist/block_storage.js.map +1 -1
- package/dist/block_storage_callbacks.cjs +4 -5
- package/dist/block_storage_callbacks.cjs.map +1 -1
- package/dist/block_storage_callbacks.js +3 -4
- package/dist/block_storage_callbacks.js.map +1 -1
- package/dist/block_storage_facade.cjs +2 -3
- package/dist/block_storage_facade.cjs.map +1 -1
- package/dist/block_storage_facade.d.ts +0 -1
- package/dist/block_storage_facade.d.ts.map +1 -0
- package/dist/block_storage_facade.js +1 -2
- package/dist/block_storage_facade.js.map +1 -1
- package/dist/columns/column_collection_builder.cjs +6 -7
- package/dist/columns/column_collection_builder.cjs.map +1 -1
- package/dist/columns/column_collection_builder.d.ts.map +1 -0
- package/dist/columns/column_collection_builder.js +1 -2
- package/dist/columns/column_collection_builder.js.map +1 -1
- package/dist/columns/column_selector.cjs +1 -2
- package/dist/columns/column_selector.cjs.map +1 -1
- package/dist/columns/column_selector.d.ts.map +1 -0
- package/dist/columns/column_selector.js +1 -1
- package/dist/columns/column_selector.js.map +1 -1
- package/dist/columns/column_snapshot.cjs +1 -2
- package/dist/columns/column_snapshot.cjs.map +1 -1
- package/dist/columns/column_snapshot.d.ts.map +1 -0
- package/dist/columns/column_snapshot.js +1 -1
- package/dist/columns/column_snapshot_provider.cjs +1 -2
- package/dist/columns/column_snapshot_provider.cjs.map +1 -1
- package/dist/columns/column_snapshot_provider.d.ts.map +1 -0
- package/dist/columns/column_snapshot_provider.js +1 -1
- package/dist/columns/column_snapshot_provider.js.map +1 -1
- package/dist/columns/ctx_column_sources.cjs +3 -4
- package/dist/columns/ctx_column_sources.cjs.map +1 -1
- package/dist/columns/ctx_column_sources.d.ts +0 -1
- package/dist/columns/ctx_column_sources.d.ts.map +1 -0
- package/dist/columns/ctx_column_sources.js +1 -2
- package/dist/columns/ctx_column_sources.js.map +1 -1
- package/dist/columns/index.cjs +5 -5
- package/dist/columns/index.js +5 -5
- package/dist/components/PFrameForGraphs.cjs +4 -5
- package/dist/components/PFrameForGraphs.cjs.map +1 -1
- package/dist/components/PFrameForGraphs.d.ts +0 -1
- package/dist/components/PFrameForGraphs.d.ts.map +1 -0
- package/dist/components/PFrameForGraphs.js +2 -3
- package/dist/components/PFrameForGraphs.js.map +1 -1
- package/dist/components/PlAnnotations/filter.d.ts.map +1 -0
- package/dist/components/PlAnnotations/filters_ui.cjs +1 -2
- package/dist/components/PlAnnotations/filters_ui.cjs.map +1 -1
- package/dist/components/PlAnnotations/filters_ui.d.ts +0 -2
- package/dist/components/PlAnnotations/filters_ui.d.ts.map +1 -0
- package/dist/components/PlAnnotations/filters_ui.js +1 -1
- package/dist/components/PlAnnotations/filters_ui.js.map +1 -1
- package/dist/components/PlDataTable/createPlDataTable/createPlDataTableV2.cjs +9 -10
- package/dist/components/PlDataTable/createPlDataTable/createPlDataTableV2.cjs.map +1 -1
- package/dist/components/PlDataTable/createPlDataTable/createPlDataTableV2.d.ts +0 -1
- package/dist/components/PlDataTable/createPlDataTable/createPlDataTableV2.d.ts.map +1 -0
- package/dist/components/PlDataTable/createPlDataTable/createPlDataTableV2.js +1 -2
- package/dist/components/PlDataTable/createPlDataTable/createPlDataTableV2.js.map +1 -1
- package/dist/components/PlDataTable/createPlDataTable/createPlDataTableV3.cjs +14 -15
- package/dist/components/PlDataTable/createPlDataTable/createPlDataTableV3.cjs.map +1 -1
- package/dist/components/PlDataTable/createPlDataTable/createPlDataTableV3.d.ts +0 -2
- package/dist/components/PlDataTable/createPlDataTable/createPlDataTableV3.d.ts.map +1 -0
- package/dist/components/PlDataTable/createPlDataTable/createPlDataTableV3.js +1 -2
- package/dist/components/PlDataTable/createPlDataTable/createPlDataTableV3.js.map +1 -1
- package/dist/components/PlDataTable/createPlDataTable/index.cjs +3 -4
- package/dist/components/PlDataTable/createPlDataTable/index.cjs.map +1 -1
- package/dist/components/PlDataTable/createPlDataTable/index.d.ts +0 -1
- package/dist/components/PlDataTable/createPlDataTable/index.d.ts.map +1 -0
- package/dist/components/PlDataTable/createPlDataTable/index.js +1 -2
- package/dist/components/PlDataTable/createPlDataTable/index.js.map +1 -1
- package/dist/components/PlDataTable/createPlDataTableSheet.cjs +1 -2
- package/dist/components/PlDataTable/createPlDataTableSheet.cjs.map +1 -1
- package/dist/components/PlDataTable/createPlDataTableSheet.d.ts +0 -1
- package/dist/components/PlDataTable/createPlDataTableSheet.d.ts.map +1 -0
- package/dist/components/PlDataTable/createPlDataTableSheet.js +1 -1
- package/dist/components/PlDataTable/index.cjs +5 -5
- package/dist/components/PlDataTable/index.js +5 -5
- package/dist/components/PlDataTable/labels.cjs +4 -5
- package/dist/components/PlDataTable/labels.cjs.map +1 -1
- package/dist/components/PlDataTable/labels.js +1 -2
- package/dist/components/PlDataTable/labels.js.map +1 -1
- package/dist/components/PlDataTable/state-migration.cjs +4 -5
- package/dist/components/PlDataTable/state-migration.cjs.map +1 -1
- package/dist/components/PlDataTable/state-migration.d.ts.map +1 -0
- package/dist/components/PlDataTable/state-migration.js +1 -2
- package/dist/components/PlDataTable/state-migration.js.map +1 -1
- package/dist/components/PlDataTable/typesV4.d.ts.map +1 -0
- package/dist/components/PlDataTable/typesV5.d.ts +0 -1
- package/dist/components/PlDataTable/typesV5.d.ts.map +1 -0
- package/dist/components/PlMultiSequenceAlignment.cjs +2 -3
- package/dist/components/PlMultiSequenceAlignment.cjs.map +1 -1
- package/dist/components/PlMultiSequenceAlignment.d.ts.map +1 -0
- package/dist/components/PlMultiSequenceAlignment.js +1 -2
- package/dist/components/PlMultiSequenceAlignment.js.map +1 -1
- package/dist/components/PlSelectionModel.cjs +1 -2
- package/dist/components/PlSelectionModel.cjs.map +1 -1
- package/dist/components/PlSelectionModel.d.ts.map +1 -0
- package/dist/components/PlSelectionModel.js +1 -1
- package/dist/components/index.cjs +11 -11
- package/dist/components/index.d.ts +0 -2
- package/dist/components/index.js +10 -10
- package/dist/config/actions.cjs +1 -2
- package/dist/config/actions.cjs.map +1 -1
- package/dist/config/actions.d.ts.map +1 -0
- package/dist/config/actions.js +1 -1
- package/dist/config/actions_kinds.d.ts.map +1 -0
- package/dist/config/index.cjs +1 -1
- package/dist/config/index.js +1 -1
- package/dist/config/model.d.ts.map +1 -0
- package/dist/config/model_meta.d.ts.map +1 -0
- package/dist/config/type_engine.d.ts.map +1 -0
- package/dist/config/type_util.d.ts.map +1 -0
- package/dist/env_value.cjs +1 -2
- package/dist/env_value.cjs.map +1 -1
- package/dist/env_value.d.ts.map +1 -0
- package/dist/env_value.js +1 -1
- package/dist/env_value.js.map +1 -1
- package/dist/filters/converters/filterToQuery.cjs +3 -4
- package/dist/filters/converters/filterToQuery.cjs.map +1 -1
- package/dist/filters/converters/filterToQuery.d.ts.map +1 -0
- package/dist/filters/converters/filterToQuery.js +1 -2
- package/dist/filters/converters/filterToQuery.js.map +1 -1
- package/dist/filters/converters/filterUiToExpressionImpl.cjs +3 -4
- package/dist/filters/converters/filterUiToExpressionImpl.cjs.map +1 -1
- package/dist/filters/converters/filterUiToExpressionImpl.d.ts.map +1 -0
- package/dist/filters/converters/filterUiToExpressionImpl.js +1 -2
- package/dist/filters/converters/filterUiToExpressionImpl.js.map +1 -1
- package/dist/filters/converters/index.cjs +2 -2
- package/dist/filters/converters/index.js +2 -2
- package/dist/filters/distill.cjs +3 -4
- package/dist/filters/distill.cjs.map +1 -1
- package/dist/filters/distill.d.ts.map +1 -0
- package/dist/filters/distill.js +1 -2
- package/dist/filters/distill.js.map +1 -1
- package/dist/filters/index.cjs +4 -4
- package/dist/filters/index.d.ts +0 -1
- package/dist/filters/index.js +3 -3
- package/dist/filters/traverse.cjs +1 -2
- package/dist/filters/traverse.cjs.map +1 -1
- package/dist/filters/traverse.js +1 -1
- package/dist/filters/traverse.js.map +1 -1
- package/dist/filters/types.d.ts.map +1 -0
- package/dist/index.cjs +78 -76
- package/dist/index.d.ts +0 -9
- package/dist/index.js +3 -6
- package/dist/internal.cjs +1 -2
- package/dist/internal.cjs.map +1 -1
- package/dist/internal.js +1 -1
- package/dist/internal.js.map +1 -1
- package/dist/labels/derive_distinct_labels.cjs +2 -3
- package/dist/labels/derive_distinct_labels.cjs.map +1 -1
- package/dist/labels/derive_distinct_labels.d.ts.map +1 -0
- package/dist/labels/derive_distinct_labels.js +1 -2
- package/dist/labels/derive_distinct_labels.js.map +1 -1
- package/dist/labels/index.cjs +2 -2
- package/dist/labels/index.js +2 -2
- package/dist/labels/write_labels_to_specs.cjs +2 -3
- package/dist/labels/write_labels_to_specs.cjs.map +1 -1
- package/dist/labels/write_labels_to_specs.d.ts +0 -2
- package/dist/labels/write_labels_to_specs.d.ts.map +1 -0
- package/dist/labels/write_labels_to_specs.js +1 -2
- package/dist/labels/write_labels_to_specs.js.map +1 -1
- package/dist/package.cjs +7 -8
- package/dist/package.js +2 -2
- package/dist/pframe.cjs +2 -3
- package/dist/pframe.cjs.map +1 -1
- package/dist/pframe.d.ts.map +1 -0
- package/dist/pframe.js +1 -2
- package/dist/pframe.js.map +1 -1
- package/dist/pframe_utils/axes.cjs +2 -3
- package/dist/pframe_utils/axes.cjs.map +1 -1
- package/dist/pframe_utils/axes.d.ts +0 -1
- package/dist/pframe_utils/axes.d.ts.map +1 -0
- package/dist/pframe_utils/axes.js +1 -2
- package/dist/pframe_utils/axes.js.map +1 -1
- package/dist/pframe_utils/columns.cjs +5 -6
- package/dist/pframe_utils/columns.cjs.map +1 -1
- package/dist/pframe_utils/columns.d.ts +0 -1
- package/dist/pframe_utils/columns.d.ts.map +1 -0
- package/dist/pframe_utils/columns.js +1 -2
- package/dist/pframe_utils/columns.js.map +1 -1
- package/dist/pframe_utils/index.cjs +3 -4
- package/dist/pframe_utils/index.cjs.map +1 -1
- package/dist/pframe_utils/index.d.ts.map +1 -0
- package/dist/pframe_utils/index.js +2 -3
- package/dist/pframe_utils/index.js.map +1 -1
- package/dist/platforma.d.ts.map +1 -0
- package/dist/plugin_handle.cjs +1 -2
- package/dist/plugin_handle.cjs.map +1 -1
- package/dist/plugin_handle.d.ts.map +1 -0
- package/dist/plugin_handle.js +1 -1
- package/dist/plugin_model.cjs +3 -4
- package/dist/plugin_model.cjs.map +1 -1
- package/dist/plugin_model.d.ts +0 -1
- package/dist/plugin_model.d.ts.map +1 -0
- package/dist/plugin_model.js +1 -2
- package/dist/plugin_model.js.map +1 -1
- package/dist/raw_globals.cjs +3 -4
- package/dist/raw_globals.cjs.map +1 -1
- package/dist/raw_globals.d.ts.map +1 -0
- package/dist/raw_globals.js +1 -2
- package/dist/raw_globals.js.map +1 -1
- package/dist/ref_util.cjs +3 -4
- package/dist/ref_util.cjs.map +1 -1
- package/dist/ref_util.d.ts +0 -2
- package/dist/ref_util.d.ts.map +1 -0
- package/dist/ref_util.js +1 -2
- package/dist/ref_util.js.map +1 -1
- package/dist/render/accessor.cjs +4 -5
- package/dist/render/accessor.cjs.map +1 -1
- package/dist/render/accessor.d.ts.map +1 -0
- package/dist/render/accessor.js +1 -2
- package/dist/render/accessor.js.map +1 -1
- package/dist/render/api.cjs +10 -11
- package/dist/render/api.cjs.map +1 -1
- package/dist/render/api.d.ts +0 -1
- package/dist/render/api.d.ts.map +1 -0
- package/dist/render/api.js +1 -2
- package/dist/render/api.js.map +1 -1
- package/dist/render/future.cjs +2 -3
- package/dist/render/future.cjs.map +1 -1
- package/dist/render/future.d.ts.map +1 -0
- package/dist/render/future.js +1 -2
- package/dist/render/future.js.map +1 -1
- package/dist/render/index.cjs +8 -8
- package/dist/render/index.d.ts +1 -2
- package/dist/render/index.js +7 -7
- package/dist/render/internal.cjs +7 -9
- package/dist/render/internal.cjs.map +1 -1
- package/dist/render/internal.d.ts.map +1 -0
- package/dist/render/internal.js +1 -2
- package/dist/render/internal.js.map +1 -1
- package/dist/render/traversal_ops.d.ts.map +1 -0
- package/dist/render/util/axis_filtering.cjs +1 -2
- package/dist/render/util/axis_filtering.cjs.map +1 -1
- package/dist/render/util/axis_filtering.d.ts.map +1 -0
- package/dist/render/util/axis_filtering.js +1 -1
- package/dist/render/util/column_collection.cjs +5 -6
- package/dist/render/util/column_collection.cjs.map +1 -1
- package/dist/render/util/column_collection.d.ts +0 -1
- package/dist/render/util/column_collection.d.ts.map +1 -0
- package/dist/render/util/column_collection.js +1 -2
- package/dist/render/util/column_collection.js.map +1 -1
- package/dist/render/util/index.cjs +4 -4
- package/dist/render/util/index.js +4 -4
- package/dist/render/util/label.cjs +2 -3
- package/dist/render/util/label.cjs.map +1 -1
- package/dist/render/util/label.d.ts.map +1 -0
- package/dist/render/util/label.js +1 -2
- package/dist/render/util/label.js.map +1 -1
- package/dist/render/util/pcolumn_data.cjs +9 -10
- package/dist/render/util/pcolumn_data.cjs.map +1 -1
- package/dist/render/util/pcolumn_data.d.ts.map +1 -0
- package/dist/render/util/pcolumn_data.js +7 -8
- package/dist/render/util/pcolumn_data.js.map +1 -1
- package/dist/render/util/pframe_upgraders.cjs +1 -2
- package/dist/render/util/pframe_upgraders.cjs.map +1 -1
- package/dist/render/util/pframe_upgraders.js +1 -1
- package/dist/render/util/split_selectors.d.ts.map +1 -0
- package/dist/services/block_services.cjs +2 -3
- package/dist/services/block_services.cjs.map +1 -1
- package/dist/services/block_services.d.ts +2 -2
- package/dist/services/block_services.d.ts.map +1 -0
- package/dist/services/block_services.js +1 -2
- package/dist/services/block_services.js.map +1 -1
- package/dist/services/index.cjs +2 -2
- package/dist/services/index.js +2 -2
- package/dist/services/service_bridge.cjs +1 -2
- package/dist/services/service_bridge.cjs.map +1 -1
- package/dist/services/service_bridge.d.ts.map +1 -0
- package/dist/services/service_bridge.js +1 -1
- package/dist/services/service_resolve.d.ts.map +1 -0
- package/dist/version.cjs +2 -4
- package/dist/version.cjs.map +1 -1
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +1 -2
- package/dist/version.js.map +1 -1
- package/package.json +13 -13
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"block_migrations.js","names":[],"sources":["../src/block_migrations.ts"],"sourcesContent":["import { DATA_MODEL_LEGACY_VERSION } from \"./block_storage\";\n\nexport type DataVersionKey = string;\nexport type DataMigrateFn<From, To> = (prev: Readonly<From>) => To;\nexport type DataCreateFn<T> = () => T;\nexport type DataRecoverFn<T> = (version: DataVersionKey, data: unknown) => T;\n\n/**\n * Minimal interface that .transfer() accepts. PluginInstance implements this.\n * Defined here to avoid circular dependency with plugin_model.ts.\n */\nexport interface TransferTarget<Id extends string = string, TransferData = never> {\n readonly id: Id;\n /** Version key in the plugin's data model chain where transferred data enters. */\n readonly transferVersion: string;\n /** @internal Phantom field for TransferData type extraction */\n readonly __transferBrand?: TransferData;\n}\n\n/** Internal record of a single transfer step in the migration chain. */\nexport type TransferStep = {\n pluginId: string;\n /** Capture data before this step index executes. */\n beforeStepIndex: number;\n extract: (data: unknown) => unknown;\n /** Version key in the plugin's data model chain where the transferred data enters. */\n targetVersion: string;\n};\n\n/** Map of plugin ID → versioned data extracted during migration. */\nexport type TransferRecord = Record<string, DataVersioned<unknown>>;\n\n/** Versioned data wrapper for persistence */\nexport type DataVersioned<T> = {\n version: DataVersionKey;\n data: T;\n};\n\n/** Create a DataVersioned wrapper with correct shape */\nexport function makeVersionedData<T>(version: DataVersionKey, data: T): DataVersioned<T> {\n return { version, data };\n}\n\n/** Thrown when a migration step fails. */\nexport class DataMigrationError extends Error {\n name = \"DataMigrationError\";\n constructor(message: string) {\n super(message);\n }\n}\n\n/** Thrown by recover() to signal unrecoverable data. */\nexport class DataUnrecoverableError extends Error {\n name = \"DataUnrecoverableError\";\n constructor(dataVersion: DataVersionKey) {\n super(`Unknown version '${dataVersion}'`);\n }\n}\n\nexport function isDataUnrecoverableError(error: unknown): error is DataUnrecoverableError {\n return error instanceof Error && error.name === \"DataUnrecoverableError\";\n}\n\ntype MigrationStep = {\n fromVersion: DataVersionKey;\n toVersion: DataVersionKey;\n migrate: (data: unknown) => unknown;\n};\n\n/**\n * Default recover function for unknown versions.\n * Use as fallback at the end of custom recover functions.\n *\n * @example\n * .recover((version, data) => {\n * if (version === 'legacy') {\n * return transformLegacyData(data);\n * }\n * return defaultRecover(version, data);\n * })\n */\nexport const defaultRecover: DataRecoverFn<never> = (version, _data) => {\n throw new DataUnrecoverableError(version);\n};\n\n/** Symbol for internal builder creation method */\nconst FROM_BUILDER = Symbol(\"fromBuilder\");\n\n/** Legacy V1 model state shape: { args, uiState } */\nexport type LegacyV1State<Args, UiState> = { args: Args; uiState: UiState };\n\n/** Internal state passed from builder to DataModel */\ntype BuilderState<S> = {\n versionChain: DataVersionKey[];\n steps: MigrationStep[];\n transferSteps: TransferStep[];\n initialDataFn: () => S;\n recoverFn?: (version: DataVersionKey, data: unknown) => unknown;\n /** Index of the first step to run after recovery. Equals the number of steps\n * present at the time recover() was called. */\n recoverFromIndex?: number;\n};\n\ntype RecoverState = {\n recoverFn?: (version: DataVersionKey, data: unknown) => unknown;\n recoverFromIndex?: number;\n};\n\n/**\n * Abstract base for both migration chain types.\n * Holds shared state, buildStep() helper, and init().\n * migrate() cannot be shared due to a TypeScript limitation: when the base class\n * migrate() return type is abstract, subclasses cannot narrow it without losing type safety.\n * Each subclass therefore owns its migrate() with the correct concrete return type.\n *\n * @internal\n */\nabstract class MigrationChainBase<Current, Transfers extends Record<string, unknown> = {}> {\n protected readonly versionChain: DataVersionKey[];\n protected readonly migrationSteps: MigrationStep[];\n protected readonly transferSteps: TransferStep[];\n\n protected constructor(state: {\n versionChain: DataVersionKey[];\n steps: MigrationStep[];\n transferSteps?: TransferStep[];\n }) {\n this.versionChain = state.versionChain;\n this.migrationSteps = state.steps;\n this.transferSteps = state.transferSteps ?? [];\n }\n\n /** Appends a migration step and returns the new versionChain and steps arrays. */\n protected buildStep<Next>(\n nextVersion: string,\n fn: DataMigrateFn<Current, Next>,\n ): { versionChain: DataVersionKey[]; steps: MigrationStep[] } {\n if (this.versionChain.includes(nextVersion)) {\n throw new Error(`Duplicate version '${nextVersion}' in migration chain`);\n }\n const fromVersion = this.versionChain[this.versionChain.length - 1];\n const step: MigrationStep = {\n fromVersion,\n toVersion: nextVersion,\n migrate: fn as (data: unknown) => unknown,\n };\n return {\n versionChain: [...this.versionChain, nextVersion],\n steps: [...this.migrationSteps, step],\n };\n }\n\n /** Validates uniqueness and records a TransferStep. */\n protected buildTransfer<Id extends string, L>(\n target: TransferTarget<Id, L>,\n extract: (data: Current) => L,\n ): { transferSteps: TransferStep[] } {\n if (this.transferSteps.some((t) => t.pluginId === target.id)) {\n throw new Error(`Duplicate transfer for plugin '${target.id}'`);\n }\n const entry: TransferStep = {\n pluginId: target.id,\n beforeStepIndex: this.migrationSteps.length,\n extract: extract as (data: unknown) => unknown,\n targetVersion: target.transferVersion,\n };\n return { transferSteps: [...this.transferSteps, entry] };\n }\n\n /** Returns recover-specific fields for DataModel construction. Overridden by WithRecover. */\n protected recoverState(): RecoverState {\n return {};\n }\n\n /**\n * Finalize the DataModel with initial data factory.\n *\n * @param initialData - Factory function returning the initial state\n * @returns Finalized DataModel instance\n */\n init(initialData: DataCreateFn<Current>): DataModel<Current, Transfers> {\n return DataModel[FROM_BUILDER]<Current, Transfers>({\n versionChain: this.versionChain,\n steps: this.migrationSteps,\n transferSteps: this.transferSteps,\n initialDataFn: initialData,\n ...this.recoverState(),\n });\n }\n}\n\n/**\n * Migration chain after recover() or upgradeLegacy() has been called.\n * Further migrate() and transfer() calls are allowed; recover() and upgradeLegacy() are not\n * (enforced by type — no such methods on this class).\n *\n * @typeParam Current - Data type at the current point in the chain\n * @typeParam Transfers - Accumulated transfer types keyed by plugin ID\n * @internal\n */\nclass DataModelMigrationChainWithRecover<\n Current,\n Transfers extends Record<string, unknown> = {},\n> extends MigrationChainBase<Current, Transfers> {\n private readonly recoverFn?: (version: DataVersionKey, data: unknown) => unknown;\n private readonly recoverFromIndex?: number;\n\n /** @internal */\n constructor(state: {\n versionChain: DataVersionKey[];\n steps: MigrationStep[];\n transferSteps?: TransferStep[];\n recoverFn?: (version: DataVersionKey, data: unknown) => unknown;\n recoverFromIndex?: number;\n }) {\n super(state);\n this.recoverFn = state.recoverFn;\n this.recoverFromIndex = state.recoverFromIndex;\n }\n\n protected override recoverState(): RecoverState {\n return {\n recoverFn: this.recoverFn,\n recoverFromIndex: this.recoverFromIndex,\n };\n }\n\n /**\n * Add a migration step. Same semantics as on the base chain.\n * recover() and upgradeLegacy() are not available — one has already been called.\n */\n migrate<Next>(\n nextVersion: string,\n fn: DataMigrateFn<Current, Next>,\n ): DataModelMigrationChainWithRecover<Next, Transfers> {\n const { versionChain, steps } = this.buildStep(nextVersion, fn);\n return new DataModelMigrationChainWithRecover<Next, Transfers>({\n versionChain,\n steps,\n transferSteps: this.transferSteps,\n recoverFn: this.recoverFn,\n recoverFromIndex: this.recoverFromIndex,\n });\n }\n\n /**\n * Extract data at the current chain position for seeding a new plugin.\n * The extract function's return type must match the plugin's transfer data type.\n * Duplicate plugin IDs are rejected at both type and runtime level.\n */\n transfer<Id extends string, L>(\n target: TransferTarget<Id & (Id extends keyof Transfers ? never : string), L>,\n extract: (data: Current) => L,\n ): DataModelMigrationChainWithRecover<Current, Transfers & Record<Id, L>> {\n const { transferSteps } = this.buildTransfer(target, extract);\n return new DataModelMigrationChainWithRecover<Current, Transfers & Record<Id, L>>({\n versionChain: this.versionChain,\n steps: this.migrationSteps,\n transferSteps,\n recoverFn: this.recoverFn,\n recoverFromIndex: this.recoverFromIndex,\n });\n }\n}\n\n/**\n * Migration chain builder.\n * Each migrate() call advances the current data type. recover() can be called once\n * at any point — it removes itself from the returned chain so it cannot be called again.\n * Duplicate version keys throw at runtime.\n *\n * @typeParam Current - Data type at the current point in the migration chain\n * @typeParam Transfers - Accumulated transfer types keyed by plugin ID\n * @internal\n */\nclass DataModelMigrationChain<\n Current,\n Transfers extends Record<string, unknown> = {},\n> extends MigrationChainBase<Current, Transfers> {\n /** @internal */\n constructor({\n versionChain,\n steps = [],\n transferSteps = [],\n }: {\n versionChain: DataVersionKey[];\n steps?: MigrationStep[];\n transferSteps?: TransferStep[];\n }) {\n super({ versionChain, steps, transferSteps });\n }\n\n /**\n * Add a migration step transforming data from the current version to the next.\n *\n * @typeParam Next - Data type of the next version\n * @param nextVersion - Version key to migrate to (must be unique in the chain)\n * @param fn - Migration function\n * @returns Builder with the next version as current\n *\n * @example\n * .migrate<BlockDataV2>(\"v2\", (v1) => ({ ...v1, labels: [] }))\n */\n migrate<Next>(\n nextVersion: string,\n fn: DataMigrateFn<Current, Next>,\n ): DataModelMigrationChain<Next, Transfers> {\n const { versionChain, steps } = this.buildStep(nextVersion, fn);\n return new DataModelMigrationChain<Next, Transfers>({\n versionChain,\n steps,\n transferSteps: this.transferSteps,\n });\n }\n\n /**\n * Extract data at the current chain position for seeding a new plugin.\n * The extract function's return type must match the plugin's transfer data type.\n * Duplicate plugin IDs are rejected at both type and runtime level.\n *\n * Calling .transfer() on DataModelInitialChain returns DataModelMigrationChain,\n * which removes .upgradeLegacy() from the chain (preventing a problematic combination).\n *\n * @example\n * .from<V1>(\"v1\")\n * .transfer(tablePlugin, (v1) => ({ state: v1.tableState }))\n * .migrate<V2>(\"v2\", ({ tableState: _, ...rest }) => rest)\n */\n transfer<Id extends string, L>(\n target: TransferTarget<Id & (Id extends keyof Transfers ? never : string), L>,\n extract: (data: Current) => L,\n ): DataModelMigrationChain<Current, Transfers & Record<Id, L>> {\n const { transferSteps } = this.buildTransfer(target, extract);\n return new DataModelMigrationChain<Current, Transfers & Record<Id, L>>({\n versionChain: this.versionChain,\n steps: this.migrationSteps,\n transferSteps,\n });\n }\n\n /**\n * Set a recovery handler for unknown or legacy versions.\n *\n * The recover function is called when data has a version not in the migration chain.\n * It must return data of the type at this point in the chain (Current). Any migrate()\n * steps added after recover() will then run on the recovered data.\n *\n * Can only be called once — the returned chain has no recover() method.\n *\n * @param fn - Recovery function returning Current (the type at this chain position)\n * @returns Builder with migrate() and init() but without recover()\n *\n * @example\n * // Recover between migrations — recovered data goes through v3 migration\n * new DataModelBuilder<V1>(\"v1\")\n * .migrate<V2>(\"v2\", (v1) => ({ ...v1, label: \"\" }))\n * .recover((version, data) => {\n * if (version === 'legacy') return transformLegacy(data); // returns V2\n * return defaultRecover(version, data);\n * })\n * .migrate<V3>(\"v3\", (v2) => ({ ...v2, description: \"\" }))\n * .init(() => ({ count: 0, label: \"\", description: \"\" }));\n */\n recover(fn: DataRecoverFn<Current>): DataModelMigrationChainWithRecover<Current, Transfers> {\n return new DataModelMigrationChainWithRecover<Current, Transfers>({\n versionChain: this.versionChain,\n steps: this.migrationSteps,\n transferSteps: this.transferSteps,\n recoverFn: fn as (version: DataVersionKey, data: unknown) => unknown,\n recoverFromIndex: this.migrationSteps.length,\n });\n }\n}\n\n/**\n * Initial migration chain returned by `.from()`.\n * Extends DataModelMigrationChain with `upgradeLegacy()` — available only before\n * any `.migrate()` calls, since legacy data always arrives at the initial version.\n *\n * @typeParam Current - Data type at the initial version\n * @typeParam Transfers - Accumulated transfer types keyed by plugin ID\n * @internal\n */\nclass DataModelInitialChain<\n Current,\n Transfers extends Record<string, unknown> = {},\n> extends DataModelMigrationChain<Current, Transfers> {\n /**\n * Handle legacy V1 model state ({ args, uiState }) when upgrading a block from\n * BlockModel V1 to BlockModelV3.\n *\n * When a V1 block is upgraded, its stored state `{ args, uiState }` is normalized\n * to the internal default version. This method inserts a migration step from that\n * internal version to the version specified in `.from()`, using the provided typed\n * callback to transform the legacy shape. Non-legacy data passes through unchanged.\n *\n * Must be called right after `.from()` — not available after `.migrate()` calls.\n * Any `.migrate()` steps added after `upgradeLegacy()` will run on the transformed result.\n *\n * Can only be called once — the returned chain has no upgradeLegacy() method.\n * Mutually exclusive with recover().\n *\n * @typeParam Args - Type of the legacy block args\n * @typeParam UiState - Type of the legacy block uiState\n * @param fn - Typed transform from { args, uiState } to Current\n * @returns Builder with migrate() and init() but without recover() or upgradeLegacy()\n *\n * @example\n * type OldArgs = { inputFile: string; threshold: number };\n * type OldUiState = { selectedTab: string };\n * type BlockData = { inputFile: string; threshold: number; selectedTab: string };\n *\n * const dataModel = new DataModelBuilder()\n * .from<BlockData>(\"v1\")\n * .upgradeLegacy<OldArgs, OldUiState>(({ args, uiState }) => ({\n * inputFile: args.inputFile,\n * threshold: args.threshold,\n * selectedTab: uiState.selectedTab,\n * }))\n * .init(() => ({ inputFile: '', threshold: 0, selectedTab: 'main' }));\n */\n upgradeLegacy<Args, UiState = unknown>(\n fn: (legacy: LegacyV1State<Args, UiState>) => Current,\n ): DataModelMigrationChainWithRecover<Current, Transfers> {\n const wrappedFn = (data: unknown): unknown => {\n if (data !== null && typeof data === \"object\" && \"args\" in data) {\n return fn(data as LegacyV1State<Args, UiState>);\n }\n return data;\n };\n\n // Insert DATA_MODEL_LEGACY_VERSION as the true first version\n // with a migration step that transforms legacy data to the user's initial version.\n const initialVersion = this.versionChain[0];\n const step: MigrationStep = {\n fromVersion: DATA_MODEL_LEGACY_VERSION,\n toVersion: initialVersion,\n migrate: wrappedFn,\n };\n return new DataModelMigrationChainWithRecover<Current, Transfers>({\n versionChain: [DATA_MODEL_LEGACY_VERSION, ...this.versionChain],\n steps: [step, ...this.migrationSteps],\n // Shift transfer indices to account for the prepended legacy step\n transferSteps: this.transferSteps.map((t) => ({\n ...t,\n beforeStepIndex: t.beforeStepIndex + 1,\n })),\n });\n }\n}\n\n/**\n * Builder entry point for creating DataModel with type-safe migrations.\n *\n * @example\n * // Simple (no migrations):\n * const dataModel = new DataModelBuilder()\n * .from<BlockData>(\"v1\")\n * .init(() => ({ numbers: [] }));\n *\n * @example\n * // With migrations:\n * const dataModel = new DataModelBuilder()\n * .from<BlockDataV1>(\"v1\")\n * .migrate<BlockDataV2>(\"v2\", (v1) => ({ ...v1, labels: [] }))\n * .migrate<BlockDataV3>(\"v3\", (v2) => ({ ...v2, description: '' }))\n * .init(() => ({ numbers: [], labels: [], description: '' }));\n *\n * @example\n * // With recover() between migrations — recovered data goes through remaining migrations:\n * const dataModelChain = new DataModelBuilder()\n * .from<BlockDataV1>(\"v1\")\n * .migrate<BlockDataV2>(\"v2\", (v1) => ({ ...v1, labels: [] }));\n *\n * // recover() placed before the v3 migration: recovered data goes through v3\n * const dataModel = dataModelChain\n * .recover((version, data) => {\n * if (version === 'legacy' && isLegacyData(data)) return transformLegacy(data); // returns V2\n * return defaultRecover(version, data);\n * })\n * .migrate<BlockDataV3>(\"v3\", (v2) => ({ ...v2, description: '' }))\n * .init(() => ({ numbers: [], labels: [], description: '' }));\n *\n * @example\n * // With upgradeLegacy() — typed upgrade from BlockModel V1 state:\n * type OldArgs = { inputFile: string };\n * type OldUiState = { selectedTab: string };\n * type BlockData = { inputFile: string; selectedTab: string };\n *\n * const dataModel = new DataModelBuilder()\n * .from<BlockData>(\"v1\")\n * .upgradeLegacy<OldArgs, OldUiState>(({ args, uiState }) => ({\n * inputFile: args.inputFile,\n * selectedTab: uiState.selectedTab,\n * }))\n * .init(() => ({ inputFile: '', selectedTab: 'main' }));\n */\nexport class DataModelBuilder {\n /**\n * Start the migration chain with the given initial data type and version key.\n *\n * @typeParam T - Data type for the initial version\n * @param initialVersion - Version key string (e.g. \"v1\")\n * @returns Migration chain builder\n */\n from<T>(initialVersion: string): DataModelInitialChain<T> {\n return new DataModelInitialChain<T>({ versionChain: [initialVersion] });\n }\n}\n\n/**\n * DataModel defines the block's data structure, initial values, and migrations.\n * Used by BlockModelV3 to manage data state.\n *\n * Use `new DataModelBuilder()` to create a DataModel.\n *\n * @example\n * // With recover() between migrations:\n * // Recovered data (V2) goes through the v2→v3 migration automatically.\n * const dataModel = new DataModelBuilder()\n * .from<V1>(\"v1\")\n * .migrate<V2>(\"v2\", (v1) => ({ ...v1, label: \"\" }))\n * .recover((version, data) => {\n * if (version === \"legacy\") return transformLegacy(data); // returns V2\n * return defaultRecover(version, data);\n * })\n * .migrate<V3>(\"v3\", (v2) => ({ ...v2, description: \"\" }))\n * .init(() => ({ count: 0, label: \"\", description: \"\" }));\n */\nexport class DataModel<State, Transfers extends Record<string, unknown> = {}> {\n /** @internal Phantom field to anchor the Transfers type parameter. */\n declare readonly __transfers?: Transfers;\n\n /** Latest version key — O(1) access for the common \"already current\" check. */\n private readonly latestVersion: DataVersionKey;\n /** Maps each known version key to the index of the first step to run from it. O(1) lookup. */\n private readonly stepsByFromVersion: ReadonlyMap<DataVersionKey, number>;\n private readonly steps: MigrationStep[];\n private readonly transferSteps: TransferStep[];\n private readonly initialDataFn: () => State;\n private readonly recoverFn: (version: DataVersionKey, data: unknown) => unknown;\n private readonly recoverFromIndex: number;\n\n private constructor({\n versionChain,\n steps,\n transferSteps = [],\n initialDataFn,\n recoverFn = defaultRecover,\n recoverFromIndex,\n }: BuilderState<State>) {\n if (versionChain.length === 0) {\n throw new Error(\"DataModel requires at least one version key\");\n }\n this.latestVersion = versionChain[versionChain.length - 1];\n this.stepsByFromVersion = new Map(versionChain.map((v, i) => [v, i]));\n this.steps = steps;\n this.transferSteps = transferSteps;\n this.initialDataFn = initialDataFn;\n this.recoverFn = recoverFn;\n this.recoverFromIndex = recoverFromIndex ?? steps.length;\n }\n\n /**\n * Internal method for creating DataModel from builder.\n * Uses Symbol key to prevent external access.\n * @internal\n */\n static [FROM_BUILDER]<S, T extends Record<string, unknown> = {}>(\n state: BuilderState<S>,\n ): DataModel<S, T> {\n return new DataModel<S, T>(state);\n }\n\n /**\n * The latest (current) version key in the migration chain.\n */\n get version(): DataVersionKey {\n return this.latestVersion;\n }\n\n /**\n * Get a fresh copy of the initial data.\n */\n initialData(): State {\n return this.initialDataFn();\n }\n\n /**\n * Get initial data wrapped with current version.\n * Used when creating new blocks or resetting to defaults.\n */\n getDefaultData(): DataVersioned<State> {\n return makeVersionedData(this.latestVersion, this.initialDataFn());\n }\n\n private recoverFrom(data: unknown, version: DataVersionKey): DataVersioned<State> {\n // Step 1: call the recover function to get data at the recover point\n // Let errors (including DataUnrecoverableError) propagate to the caller.\n let currentData: unknown = this.recoverFn(version, data);\n\n // Step 2: run any migrations that were added after recover() in the chain\n for (let i = this.recoverFromIndex; i < this.steps.length; i++) {\n const step = this.steps[i];\n currentData = step.migrate(currentData);\n }\n\n return { version: this.latestVersion, data: currentData as State };\n }\n\n /**\n * Migrate versioned data from any version to the latest.\n * Collects transfer extractions at their designated chain positions.\n *\n * - If version is in chain, applies needed migrations (O(1) lookup)\n * - If version is unknown, attempts recovery; falls back to initial data\n * - If a migration step fails, throws so the caller can preserve original data\n *\n * Transfers only fire during normal step-by-step migration:\n * - Recovery path: returns empty transfers\n * - Fast-path (already at latest): returns empty transfers\n *\n * @param versioned - Data with version tag\n * @returns Migrated data at the latest version with transfer record\n * @throws If a migration step from a known version fails\n */\n migrate(versioned: DataVersioned<unknown>): DataVersioned<State> & { transfers: TransferRecord } {\n const { version: fromVersion, data } = versioned;\n\n // Fast path: already at latest version\n if (fromVersion === this.latestVersion) {\n return { version: this.latestVersion, data: data as State, transfers: {} };\n }\n\n // Unknown version: recovery path — empty transfers\n const startIndex = this.stepsByFromVersion.get(fromVersion);\n if (startIndex === undefined) {\n try {\n return { ...this.recoverFrom(data, fromVersion), transfers: {} };\n } catch {\n // Recovery failed (unknown version, recover fn threw, or post-recover\n // migration failed) — reset to initial data rather than blocking the update.\n return { ...this.getDefaultData(), transfers: {} };\n }\n }\n\n let currentData: unknown = data;\n const transfers: TransferRecord = {};\n\n // Run steps and check transfer entries before each step\n for (let i = startIndex; i < this.steps.length; i++) {\n for (const t of this.transferSteps) {\n if (t.beforeStepIndex === i) {\n transfers[t.pluginId] = {\n version: t.targetVersion,\n data: t.extract(currentData),\n };\n }\n }\n currentData = this.steps[i].migrate(currentData);\n }\n\n // Check for transfers positioned at or past the end of the steps array\n // (e.g., .transfer() was the last call before .init(), after all .migrate() calls)\n for (const t of this.transferSteps) {\n if (t.beforeStepIndex >= this.steps.length && t.beforeStepIndex >= startIndex) {\n transfers[t.pluginId] = {\n version: t.targetVersion,\n data: t.extract(currentData),\n };\n }\n }\n\n return { version: this.latestVersion, data: currentData as State, transfers };\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"block_migrations.js","names":[],"sources":["../src/block_migrations.ts"],"sourcesContent":["import { DATA_MODEL_LEGACY_VERSION } from \"./block_storage\";\n\nexport type DataVersionKey = string;\nexport type DataMigrateFn<From, To> = (prev: Readonly<From>) => To;\nexport type DataCreateFn<T> = () => T;\nexport type DataRecoverFn<T> = (version: DataVersionKey, data: unknown) => T;\n\n/**\n * Minimal interface that .transfer() accepts. PluginInstance implements this.\n * Defined here to avoid circular dependency with plugin_model.ts.\n */\nexport interface TransferTarget<Id extends string = string, TransferData = never> {\n readonly id: Id;\n /** Version key in the plugin's data model chain where transferred data enters. */\n readonly transferVersion: string;\n /** @internal Phantom field for TransferData type extraction */\n readonly __transferBrand?: TransferData;\n}\n\n/** Internal record of a single transfer step in the migration chain. */\nexport type TransferStep = {\n pluginId: string;\n /** Capture data before this step index executes. */\n beforeStepIndex: number;\n extract: (data: unknown) => unknown;\n /** Version key in the plugin's data model chain where the transferred data enters. */\n targetVersion: string;\n};\n\n/** Map of plugin ID → versioned data extracted during migration. */\nexport type TransferRecord = Record<string, DataVersioned<unknown>>;\n\n/** Versioned data wrapper for persistence */\nexport type DataVersioned<T> = {\n version: DataVersionKey;\n data: T;\n};\n\n/** Create a DataVersioned wrapper with correct shape */\nexport function makeVersionedData<T>(version: DataVersionKey, data: T): DataVersioned<T> {\n return { version, data };\n}\n\n/** Thrown when a migration step fails. */\nexport class DataMigrationError extends Error {\n name = \"DataMigrationError\";\n constructor(message: string) {\n super(message);\n }\n}\n\n/** Thrown by recover() to signal unrecoverable data. */\nexport class DataUnrecoverableError extends Error {\n name = \"DataUnrecoverableError\";\n constructor(dataVersion: DataVersionKey) {\n super(`Unknown version '${dataVersion}'`);\n }\n}\n\nexport function isDataUnrecoverableError(error: unknown): error is DataUnrecoverableError {\n return error instanceof Error && error.name === \"DataUnrecoverableError\";\n}\n\ntype MigrationStep = {\n fromVersion: DataVersionKey;\n toVersion: DataVersionKey;\n migrate: (data: unknown) => unknown;\n};\n\n/**\n * Default recover function for unknown versions.\n * Use as fallback at the end of custom recover functions.\n *\n * @example\n * .recover((version, data) => {\n * if (version === 'legacy') {\n * return transformLegacyData(data);\n * }\n * return defaultRecover(version, data);\n * })\n */\nexport const defaultRecover: DataRecoverFn<never> = (version, _data) => {\n throw new DataUnrecoverableError(version);\n};\n\n/** Symbol for internal builder creation method */\nconst FROM_BUILDER = Symbol(\"fromBuilder\");\n\n/** Legacy V1 model state shape: { args, uiState } */\nexport type LegacyV1State<Args, UiState> = { args: Args; uiState: UiState };\n\n/** Internal state passed from builder to DataModel */\ntype BuilderState<S> = {\n versionChain: DataVersionKey[];\n steps: MigrationStep[];\n transferSteps: TransferStep[];\n initialDataFn: () => S;\n recoverFn?: (version: DataVersionKey, data: unknown) => unknown;\n /** Index of the first step to run after recovery. Equals the number of steps\n * present at the time recover() was called. */\n recoverFromIndex?: number;\n};\n\ntype RecoverState = {\n recoverFn?: (version: DataVersionKey, data: unknown) => unknown;\n recoverFromIndex?: number;\n};\n\n/**\n * Abstract base for both migration chain types.\n * Holds shared state, buildStep() helper, and init().\n * migrate() cannot be shared due to a TypeScript limitation: when the base class\n * migrate() return type is abstract, subclasses cannot narrow it without losing type safety.\n * Each subclass therefore owns its migrate() with the correct concrete return type.\n *\n * @internal\n */\nabstract class MigrationChainBase<Current, Transfers extends Record<string, unknown> = {}> {\n protected readonly versionChain: DataVersionKey[];\n protected readonly migrationSteps: MigrationStep[];\n protected readonly transferSteps: TransferStep[];\n\n protected constructor(state: {\n versionChain: DataVersionKey[];\n steps: MigrationStep[];\n transferSteps?: TransferStep[];\n }) {\n this.versionChain = state.versionChain;\n this.migrationSteps = state.steps;\n this.transferSteps = state.transferSteps ?? [];\n }\n\n /** Appends a migration step and returns the new versionChain and steps arrays. */\n protected buildStep<Next>(\n nextVersion: string,\n fn: DataMigrateFn<Current, Next>,\n ): { versionChain: DataVersionKey[]; steps: MigrationStep[] } {\n if (this.versionChain.includes(nextVersion)) {\n throw new Error(`Duplicate version '${nextVersion}' in migration chain`);\n }\n const fromVersion = this.versionChain[this.versionChain.length - 1];\n const step: MigrationStep = {\n fromVersion,\n toVersion: nextVersion,\n migrate: fn as (data: unknown) => unknown,\n };\n return {\n versionChain: [...this.versionChain, nextVersion],\n steps: [...this.migrationSteps, step],\n };\n }\n\n /** Validates uniqueness and records a TransferStep. */\n protected buildTransfer<Id extends string, L>(\n target: TransferTarget<Id, L>,\n extract: (data: Current) => L,\n ): { transferSteps: TransferStep[] } {\n if (this.transferSteps.some((t) => t.pluginId === target.id)) {\n throw new Error(`Duplicate transfer for plugin '${target.id}'`);\n }\n const entry: TransferStep = {\n pluginId: target.id,\n beforeStepIndex: this.migrationSteps.length,\n extract: extract as (data: unknown) => unknown,\n targetVersion: target.transferVersion,\n };\n return { transferSteps: [...this.transferSteps, entry] };\n }\n\n /** Returns recover-specific fields for DataModel construction. Overridden by WithRecover. */\n protected recoverState(): RecoverState {\n return {};\n }\n\n /**\n * Finalize the DataModel with initial data factory.\n *\n * @param initialData - Factory function returning the initial state\n * @returns Finalized DataModel instance\n */\n init(initialData: DataCreateFn<Current>): DataModel<Current, Transfers> {\n return DataModel[FROM_BUILDER]<Current, Transfers>({\n versionChain: this.versionChain,\n steps: this.migrationSteps,\n transferSteps: this.transferSteps,\n initialDataFn: initialData,\n ...this.recoverState(),\n });\n }\n}\n\n/**\n * Migration chain after recover() or upgradeLegacy() has been called.\n * Further migrate() and transfer() calls are allowed; recover() and upgradeLegacy() are not\n * (enforced by type — no such methods on this class).\n *\n * @typeParam Current - Data type at the current point in the chain\n * @typeParam Transfers - Accumulated transfer types keyed by plugin ID\n * @internal\n */\nclass DataModelMigrationChainWithRecover<\n Current,\n Transfers extends Record<string, unknown> = {},\n> extends MigrationChainBase<Current, Transfers> {\n private readonly recoverFn?: (version: DataVersionKey, data: unknown) => unknown;\n private readonly recoverFromIndex?: number;\n\n /** @internal */\n constructor(state: {\n versionChain: DataVersionKey[];\n steps: MigrationStep[];\n transferSteps?: TransferStep[];\n recoverFn?: (version: DataVersionKey, data: unknown) => unknown;\n recoverFromIndex?: number;\n }) {\n super(state);\n this.recoverFn = state.recoverFn;\n this.recoverFromIndex = state.recoverFromIndex;\n }\n\n protected override recoverState(): RecoverState {\n return {\n recoverFn: this.recoverFn,\n recoverFromIndex: this.recoverFromIndex,\n };\n }\n\n /**\n * Add a migration step. Same semantics as on the base chain.\n * recover() and upgradeLegacy() are not available — one has already been called.\n */\n migrate<Next>(\n nextVersion: string,\n fn: DataMigrateFn<Current, Next>,\n ): DataModelMigrationChainWithRecover<Next, Transfers> {\n const { versionChain, steps } = this.buildStep(nextVersion, fn);\n return new DataModelMigrationChainWithRecover<Next, Transfers>({\n versionChain,\n steps,\n transferSteps: this.transferSteps,\n recoverFn: this.recoverFn,\n recoverFromIndex: this.recoverFromIndex,\n });\n }\n\n /**\n * Extract data at the current chain position for seeding a new plugin.\n * The extract function's return type must match the plugin's transfer data type.\n * Duplicate plugin IDs are rejected at both type and runtime level.\n */\n transfer<Id extends string, L>(\n target: TransferTarget<Id & (Id extends keyof Transfers ? never : string), L>,\n extract: (data: Current) => L,\n ): DataModelMigrationChainWithRecover<Current, Transfers & Record<Id, L>> {\n const { transferSteps } = this.buildTransfer(target, extract);\n return new DataModelMigrationChainWithRecover<Current, Transfers & Record<Id, L>>({\n versionChain: this.versionChain,\n steps: this.migrationSteps,\n transferSteps,\n recoverFn: this.recoverFn,\n recoverFromIndex: this.recoverFromIndex,\n });\n }\n}\n\n/**\n * Migration chain builder.\n * Each migrate() call advances the current data type. recover() can be called once\n * at any point — it removes itself from the returned chain so it cannot be called again.\n * Duplicate version keys throw at runtime.\n *\n * @typeParam Current - Data type at the current point in the migration chain\n * @typeParam Transfers - Accumulated transfer types keyed by plugin ID\n * @internal\n */\nclass DataModelMigrationChain<\n Current,\n Transfers extends Record<string, unknown> = {},\n> extends MigrationChainBase<Current, Transfers> {\n /** @internal */\n constructor({\n versionChain,\n steps = [],\n transferSteps = [],\n }: {\n versionChain: DataVersionKey[];\n steps?: MigrationStep[];\n transferSteps?: TransferStep[];\n }) {\n super({ versionChain, steps, transferSteps });\n }\n\n /**\n * Add a migration step transforming data from the current version to the next.\n *\n * @typeParam Next - Data type of the next version\n * @param nextVersion - Version key to migrate to (must be unique in the chain)\n * @param fn - Migration function\n * @returns Builder with the next version as current\n *\n * @example\n * .migrate<BlockDataV2>(\"v2\", (v1) => ({ ...v1, labels: [] }))\n */\n migrate<Next>(\n nextVersion: string,\n fn: DataMigrateFn<Current, Next>,\n ): DataModelMigrationChain<Next, Transfers> {\n const { versionChain, steps } = this.buildStep(nextVersion, fn);\n return new DataModelMigrationChain<Next, Transfers>({\n versionChain,\n steps,\n transferSteps: this.transferSteps,\n });\n }\n\n /**\n * Extract data at the current chain position for seeding a new plugin.\n * The extract function's return type must match the plugin's transfer data type.\n * Duplicate plugin IDs are rejected at both type and runtime level.\n *\n * Calling .transfer() on DataModelInitialChain returns DataModelMigrationChain,\n * which removes .upgradeLegacy() from the chain (preventing a problematic combination).\n *\n * @example\n * .from<V1>(\"v1\")\n * .transfer(tablePlugin, (v1) => ({ state: v1.tableState }))\n * .migrate<V2>(\"v2\", ({ tableState: _, ...rest }) => rest)\n */\n transfer<Id extends string, L>(\n target: TransferTarget<Id & (Id extends keyof Transfers ? never : string), L>,\n extract: (data: Current) => L,\n ): DataModelMigrationChain<Current, Transfers & Record<Id, L>> {\n const { transferSteps } = this.buildTransfer(target, extract);\n return new DataModelMigrationChain<Current, Transfers & Record<Id, L>>({\n versionChain: this.versionChain,\n steps: this.migrationSteps,\n transferSteps,\n });\n }\n\n /**\n * Set a recovery handler for unknown or legacy versions.\n *\n * The recover function is called when data has a version not in the migration chain.\n * It must return data of the type at this point in the chain (Current). Any migrate()\n * steps added after recover() will then run on the recovered data.\n *\n * Can only be called once — the returned chain has no recover() method.\n *\n * @param fn - Recovery function returning Current (the type at this chain position)\n * @returns Builder with migrate() and init() but without recover()\n *\n * @example\n * // Recover between migrations — recovered data goes through v3 migration\n * new DataModelBuilder<V1>(\"v1\")\n * .migrate<V2>(\"v2\", (v1) => ({ ...v1, label: \"\" }))\n * .recover((version, data) => {\n * if (version === 'legacy') return transformLegacy(data); // returns V2\n * return defaultRecover(version, data);\n * })\n * .migrate<V3>(\"v3\", (v2) => ({ ...v2, description: \"\" }))\n * .init(() => ({ count: 0, label: \"\", description: \"\" }));\n */\n recover(fn: DataRecoverFn<Current>): DataModelMigrationChainWithRecover<Current, Transfers> {\n return new DataModelMigrationChainWithRecover<Current, Transfers>({\n versionChain: this.versionChain,\n steps: this.migrationSteps,\n transferSteps: this.transferSteps,\n recoverFn: fn as (version: DataVersionKey, data: unknown) => unknown,\n recoverFromIndex: this.migrationSteps.length,\n });\n }\n}\n\n/**\n * Initial migration chain returned by `.from()`.\n * Extends DataModelMigrationChain with `upgradeLegacy()` — available only before\n * any `.migrate()` calls, since legacy data always arrives at the initial version.\n *\n * @typeParam Current - Data type at the initial version\n * @typeParam Transfers - Accumulated transfer types keyed by plugin ID\n * @internal\n */\nclass DataModelInitialChain<\n Current,\n Transfers extends Record<string, unknown> = {},\n> extends DataModelMigrationChain<Current, Transfers> {\n /**\n * Handle legacy V1 model state ({ args, uiState }) when upgrading a block from\n * BlockModel V1 to BlockModelV3.\n *\n * When a V1 block is upgraded, its stored state `{ args, uiState }` is normalized\n * to the internal default version. This method inserts a migration step from that\n * internal version to the version specified in `.from()`, using the provided typed\n * callback to transform the legacy shape. Non-legacy data passes through unchanged.\n *\n * Must be called right after `.from()` — not available after `.migrate()` calls.\n * Any `.migrate()` steps added after `upgradeLegacy()` will run on the transformed result.\n *\n * Can only be called once — the returned chain has no upgradeLegacy() method.\n * Mutually exclusive with recover().\n *\n * @typeParam Args - Type of the legacy block args\n * @typeParam UiState - Type of the legacy block uiState\n * @param fn - Typed transform from { args, uiState } to Current\n * @returns Builder with migrate() and init() but without recover() or upgradeLegacy()\n *\n * @example\n * type OldArgs = { inputFile: string; threshold: number };\n * type OldUiState = { selectedTab: string };\n * type BlockData = { inputFile: string; threshold: number; selectedTab: string };\n *\n * const dataModel = new DataModelBuilder()\n * .from<BlockData>(\"v1\")\n * .upgradeLegacy<OldArgs, OldUiState>(({ args, uiState }) => ({\n * inputFile: args.inputFile,\n * threshold: args.threshold,\n * selectedTab: uiState.selectedTab,\n * }))\n * .init(() => ({ inputFile: '', threshold: 0, selectedTab: 'main' }));\n */\n upgradeLegacy<Args, UiState = unknown>(\n fn: (legacy: LegacyV1State<Args, UiState>) => Current,\n ): DataModelMigrationChainWithRecover<Current, Transfers> {\n const wrappedFn = (data: unknown): unknown => {\n if (data !== null && typeof data === \"object\" && \"args\" in data) {\n return fn(data as LegacyV1State<Args, UiState>);\n }\n return data;\n };\n\n // Insert DATA_MODEL_LEGACY_VERSION as the true first version\n // with a migration step that transforms legacy data to the user's initial version.\n const initialVersion = this.versionChain[0];\n const step: MigrationStep = {\n fromVersion: DATA_MODEL_LEGACY_VERSION,\n toVersion: initialVersion,\n migrate: wrappedFn,\n };\n return new DataModelMigrationChainWithRecover<Current, Transfers>({\n versionChain: [DATA_MODEL_LEGACY_VERSION, ...this.versionChain],\n steps: [step, ...this.migrationSteps],\n // Shift transfer indices to account for the prepended legacy step\n transferSteps: this.transferSteps.map((t) => ({\n ...t,\n beforeStepIndex: t.beforeStepIndex + 1,\n })),\n });\n }\n}\n\n/**\n * Builder entry point for creating DataModel with type-safe migrations.\n *\n * @example\n * // Simple (no migrations):\n * const dataModel = new DataModelBuilder()\n * .from<BlockData>(\"v1\")\n * .init(() => ({ numbers: [] }));\n *\n * @example\n * // With migrations:\n * const dataModel = new DataModelBuilder()\n * .from<BlockDataV1>(\"v1\")\n * .migrate<BlockDataV2>(\"v2\", (v1) => ({ ...v1, labels: [] }))\n * .migrate<BlockDataV3>(\"v3\", (v2) => ({ ...v2, description: '' }))\n * .init(() => ({ numbers: [], labels: [], description: '' }));\n *\n * @example\n * // With recover() between migrations — recovered data goes through remaining migrations:\n * const dataModelChain = new DataModelBuilder()\n * .from<BlockDataV1>(\"v1\")\n * .migrate<BlockDataV2>(\"v2\", (v1) => ({ ...v1, labels: [] }));\n *\n * // recover() placed before the v3 migration: recovered data goes through v3\n * const dataModel = dataModelChain\n * .recover((version, data) => {\n * if (version === 'legacy' && isLegacyData(data)) return transformLegacy(data); // returns V2\n * return defaultRecover(version, data);\n * })\n * .migrate<BlockDataV3>(\"v3\", (v2) => ({ ...v2, description: '' }))\n * .init(() => ({ numbers: [], labels: [], description: '' }));\n *\n * @example\n * // With upgradeLegacy() — typed upgrade from BlockModel V1 state:\n * type OldArgs = { inputFile: string };\n * type OldUiState = { selectedTab: string };\n * type BlockData = { inputFile: string; selectedTab: string };\n *\n * const dataModel = new DataModelBuilder()\n * .from<BlockData>(\"v1\")\n * .upgradeLegacy<OldArgs, OldUiState>(({ args, uiState }) => ({\n * inputFile: args.inputFile,\n * selectedTab: uiState.selectedTab,\n * }))\n * .init(() => ({ inputFile: '', selectedTab: 'main' }));\n */\nexport class DataModelBuilder {\n /**\n * Start the migration chain with the given initial data type and version key.\n *\n * @typeParam T - Data type for the initial version\n * @param initialVersion - Version key string (e.g. \"v1\")\n * @returns Migration chain builder\n */\n from<T>(initialVersion: string): DataModelInitialChain<T> {\n return new DataModelInitialChain<T>({ versionChain: [initialVersion] });\n }\n}\n\n/**\n * DataModel defines the block's data structure, initial values, and migrations.\n * Used by BlockModelV3 to manage data state.\n *\n * Use `new DataModelBuilder()` to create a DataModel.\n *\n * @example\n * // With recover() between migrations:\n * // Recovered data (V2) goes through the v2→v3 migration automatically.\n * const dataModel = new DataModelBuilder()\n * .from<V1>(\"v1\")\n * .migrate<V2>(\"v2\", (v1) => ({ ...v1, label: \"\" }))\n * .recover((version, data) => {\n * if (version === \"legacy\") return transformLegacy(data); // returns V2\n * return defaultRecover(version, data);\n * })\n * .migrate<V3>(\"v3\", (v2) => ({ ...v2, description: \"\" }))\n * .init(() => ({ count: 0, label: \"\", description: \"\" }));\n */\nexport class DataModel<State, Transfers extends Record<string, unknown> = {}> {\n /** @internal Phantom field to anchor the Transfers type parameter. */\n declare readonly __transfers?: Transfers;\n\n /** Latest version key — O(1) access for the common \"already current\" check. */\n private readonly latestVersion: DataVersionKey;\n /** Maps each known version key to the index of the first step to run from it. O(1) lookup. */\n private readonly stepsByFromVersion: ReadonlyMap<DataVersionKey, number>;\n private readonly steps: MigrationStep[];\n private readonly transferSteps: TransferStep[];\n private readonly initialDataFn: () => State;\n private readonly recoverFn: (version: DataVersionKey, data: unknown) => unknown;\n private readonly recoverFromIndex: number;\n\n private constructor({\n versionChain,\n steps,\n transferSteps = [],\n initialDataFn,\n recoverFn = defaultRecover,\n recoverFromIndex,\n }: BuilderState<State>) {\n if (versionChain.length === 0) {\n throw new Error(\"DataModel requires at least one version key\");\n }\n this.latestVersion = versionChain[versionChain.length - 1];\n this.stepsByFromVersion = new Map(versionChain.map((v, i) => [v, i]));\n this.steps = steps;\n this.transferSteps = transferSteps;\n this.initialDataFn = initialDataFn;\n this.recoverFn = recoverFn;\n this.recoverFromIndex = recoverFromIndex ?? steps.length;\n }\n\n /**\n * Internal method for creating DataModel from builder.\n * Uses Symbol key to prevent external access.\n * @internal\n */\n static [FROM_BUILDER]<S, T extends Record<string, unknown> = {}>(\n state: BuilderState<S>,\n ): DataModel<S, T> {\n return new DataModel<S, T>(state);\n }\n\n /**\n * The latest (current) version key in the migration chain.\n */\n get version(): DataVersionKey {\n return this.latestVersion;\n }\n\n /**\n * Get a fresh copy of the initial data.\n */\n initialData(): State {\n return this.initialDataFn();\n }\n\n /**\n * Get initial data wrapped with current version.\n * Used when creating new blocks or resetting to defaults.\n */\n getDefaultData(): DataVersioned<State> {\n return makeVersionedData(this.latestVersion, this.initialDataFn());\n }\n\n private recoverFrom(data: unknown, version: DataVersionKey): DataVersioned<State> {\n // Step 1: call the recover function to get data at the recover point\n // Let errors (including DataUnrecoverableError) propagate to the caller.\n let currentData: unknown = this.recoverFn(version, data);\n\n // Step 2: run any migrations that were added after recover() in the chain\n for (let i = this.recoverFromIndex; i < this.steps.length; i++) {\n const step = this.steps[i];\n currentData = step.migrate(currentData);\n }\n\n return { version: this.latestVersion, data: currentData as State };\n }\n\n /**\n * Migrate versioned data from any version to the latest.\n * Collects transfer extractions at their designated chain positions.\n *\n * - If version is in chain, applies needed migrations (O(1) lookup)\n * - If version is unknown, attempts recovery; falls back to initial data\n * - If a migration step fails, throws so the caller can preserve original data\n *\n * Transfers only fire during normal step-by-step migration:\n * - Recovery path: returns empty transfers\n * - Fast-path (already at latest): returns empty transfers\n *\n * @param versioned - Data with version tag\n * @returns Migrated data at the latest version with transfer record\n * @throws If a migration step from a known version fails\n */\n migrate(versioned: DataVersioned<unknown>): DataVersioned<State> & { transfers: TransferRecord } {\n const { version: fromVersion, data } = versioned;\n\n // Fast path: already at latest version\n if (fromVersion === this.latestVersion) {\n return { version: this.latestVersion, data: data as State, transfers: {} };\n }\n\n // Unknown version: recovery path — empty transfers\n const startIndex = this.stepsByFromVersion.get(fromVersion);\n if (startIndex === undefined) {\n try {\n return { ...this.recoverFrom(data, fromVersion), transfers: {} };\n } catch {\n // Recovery failed (unknown version, recover fn threw, or post-recover\n // migration failed) — reset to initial data rather than blocking the update.\n return { ...this.getDefaultData(), transfers: {} };\n }\n }\n\n let currentData: unknown = data;\n const transfers: TransferRecord = {};\n\n // Run steps and check transfer entries before each step\n for (let i = startIndex; i < this.steps.length; i++) {\n for (const t of this.transferSteps) {\n if (t.beforeStepIndex === i) {\n transfers[t.pluginId] = {\n version: t.targetVersion,\n data: t.extract(currentData),\n };\n }\n }\n currentData = this.steps[i].migrate(currentData);\n }\n\n // Check for transfers positioned at or past the end of the steps array\n // (e.g., .transfer() was the last call before .init(), after all .migrate() calls)\n for (const t of this.transferSteps) {\n if (t.beforeStepIndex >= this.steps.length && t.beforeStepIndex >= startIndex) {\n transfers[t.pluginId] = {\n version: t.targetVersion,\n data: t.extract(currentData),\n };\n }\n }\n\n return { version: this.latestVersion, data: currentData as State, transfers };\n }\n}\n"],"mappings":"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"}
|
package/dist/block_model.cjs
CHANGED
|
@@ -1,18 +1,17 @@
|
|
|
1
|
-
|
|
2
|
-
const require_plugin_handle = require(
|
|
3
|
-
const require_internal = require(
|
|
4
|
-
const require_block_storage_facade = require(
|
|
5
|
-
const require_api = require(
|
|
6
|
-
require(
|
|
7
|
-
const require_version = require(
|
|
8
|
-
const require_types = require(
|
|
9
|
-
const require_normalization = require(
|
|
10
|
-
require(
|
|
11
|
-
const require_block_services = require(
|
|
12
|
-
const require_plugin_model = require(
|
|
13
|
-
const require_block_storage_callbacks = require(
|
|
1
|
+
require("./_virtual/_rolldown/runtime.cjs");
|
|
2
|
+
const require_plugin_handle = require("./plugin_handle.cjs");
|
|
3
|
+
const require_internal = require("./internal.cjs");
|
|
4
|
+
const require_block_storage_facade = require("./block_storage_facade.cjs");
|
|
5
|
+
const require_api = require("./render/api.cjs");
|
|
6
|
+
require("./render/index.cjs");
|
|
7
|
+
const require_version = require("./version.cjs");
|
|
8
|
+
const require_types = require("./bconfig/types.cjs");
|
|
9
|
+
const require_normalization = require("./bconfig/normalization.cjs");
|
|
10
|
+
require("./bconfig/index.cjs");
|
|
11
|
+
const require_block_services = require("./services/block_services.cjs");
|
|
12
|
+
const require_plugin_model = require("./plugin_model.cjs");
|
|
13
|
+
const require_block_storage_callbacks = require("./block_storage_callbacks.cjs");
|
|
14
14
|
let _milaboratories_pl_model_common = require("@milaboratories/pl-model-common");
|
|
15
|
-
|
|
16
15
|
//#region src/block_model.ts
|
|
17
16
|
/**
|
|
18
17
|
* Merges two feature flag objects with type-aware logic:
|
|
@@ -41,7 +40,7 @@ var BlockModelV3 = class BlockModelV3 {
|
|
|
41
40
|
supportsLazyState: true,
|
|
42
41
|
supportsPframeQueryRanking: true,
|
|
43
42
|
requiresUIAPIVersion: 3,
|
|
44
|
-
requiresModelAPIVersion:
|
|
43
|
+
requiresModelAPIVersion: 2,
|
|
45
44
|
requiresCreatePTable: 2,
|
|
46
45
|
...require_block_services.BLOCK_SERVICE_FLAGS
|
|
47
46
|
};
|
|
@@ -293,7 +292,7 @@ var BlockModelV3 = class BlockModelV3 {
|
|
|
293
292
|
if (!require_internal.isInUI()) return { config: {
|
|
294
293
|
v4: {
|
|
295
294
|
configVersion: 4,
|
|
296
|
-
modelAPIVersion:
|
|
295
|
+
modelAPIVersion: 2,
|
|
297
296
|
sdkVersion: require_version.PlatformaSDKVersion,
|
|
298
297
|
renderingMode: this.config.renderingMode,
|
|
299
298
|
sections: this.config.sections,
|
|
@@ -323,7 +322,7 @@ var BlockModelV3 = class BlockModelV3 {
|
|
|
323
322
|
};
|
|
324
323
|
}
|
|
325
324
|
};
|
|
326
|
-
|
|
327
325
|
//#endregion
|
|
328
326
|
exports.BlockModelV3 = BlockModelV3;
|
|
327
|
+
|
|
329
328
|
//# sourceMappingURL=block_model.cjs.map
|
package/dist/block_model.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"block_model.cjs","names":["BLOCK_STORAGE_FACADE_VERSION","BLOCK_SERVICE_FLAGS","createAndRegisterRenderLambda","BlockRenderCtx","blockServiceNames","CREATE_PLUGIN_MODEL","BlockStorageFacadeCallbacks","applyStorageUpdate","getStorageDebugView","migrateStorage","createInitialStorage","deriveArgsFromStorage","derivePrerunArgsFromStorage","pluginOutputKey","PluginRenderCtx","isInUI","PlatformaSDKVersion","BlockStorageFacadeHandles","downgradeCfgOrLambda","getPlatformaInstance","isConfigLambda"],"sources":["../src/block_model.ts"],"sourcesContent":["import type {\n BlockRenderingMode,\n BlockSection,\n OutputWithStatus,\n PlRef,\n BlockCodeKnownFeatureFlags,\n BlockConfigContainer,\n} from \"@milaboratories/pl-model-common\";\nimport { resolveRequiredServices } from \"@milaboratories/pl-model-common\";\nimport { getPlatformaInstance, isInUI, createAndRegisterRenderLambda } from \"./internal\";\nimport type { DataModel } from \"./block_migrations\";\nimport type { PlatformaV3 } from \"./platforma\";\nimport type { BlockDefaultUiServices } from \"./services/service_resolve\";\nimport { blockServiceNames, BLOCK_SERVICE_FLAGS } from \"./services/block_services\";\nimport type { InferRenderFunctionReturn, RenderFunction } from \"./render\";\nimport { BlockRenderCtx, PluginRenderCtx } from \"./render\";\nimport type { PluginData, PluginModel, PluginOutputs, PluginParams } from \"./plugin_model\";\nimport { PluginInstance as PluginInstanceClass, CREATE_PLUGIN_MODEL } from \"./plugin_model\";\nimport { type PluginHandle, pluginOutputKey } from \"./plugin_handle\";\nimport type { RenderCtxBase } from \"./render\";\nimport { PlatformaSDKVersion } from \"./version\";\nimport {\n applyStorageUpdate,\n getStorageDebugView,\n migrateStorage,\n createInitialStorage,\n deriveArgsFromStorage,\n derivePrerunArgsFromStorage,\n} from \"./block_storage_callbacks\";\nimport { type PluginName } from \"./block_storage\";\nimport type {\n ConfigRenderLambda,\n DeriveHref,\n ConfigRenderLambdaFlags,\n InferOutputsFromLambdas,\n} from \"./bconfig\";\nimport { downgradeCfgOrLambda, isConfigLambda } from \"./bconfig\";\nimport type { PlatformaExtended } from \"./platforma\";\nimport {\n BLOCK_STORAGE_FACADE_VERSION,\n BlockStorageFacadeCallbacks,\n BlockStorageFacadeHandles,\n registerFacadeCallbacks,\n} from \"./block_storage_facade\";\n\ntype SectionsExpectedType = readonly BlockSection[];\n\ntype NoOb = Record<string, never>;\n\n/**\n * Per-property lambdas for deriving plugin params from block render context.\n * Each property is a function that receives the block's RenderCtxBase and returns the param value.\n */\nexport type ParamsInput<Params, BArgs = unknown, BData = unknown> = {\n [K in keyof Params]: (ctx: RenderCtxBase<BArgs, BData>) => Params[K];\n};\n\n/**\n * Type-erased version of ParamsInput for internal storage.\n */\ntype ParamsInputErased = Record<string, (ctx: RenderCtxBase) => unknown>;\n\n/**\n * Merges two feature flag objects with type-aware logic:\n * - `supports*` (boolean): OR — `true` if either side is `true`\n * - `requires*` (numeric): MAX — take the higher version requirement\n */\nfunction mergeFeatureFlags(\n base: BlockCodeKnownFeatureFlags,\n override: BlockCodeKnownFeatureFlags,\n): BlockCodeKnownFeatureFlags {\n const result: Record<string, boolean | number | undefined> = { ...base };\n for (const [key, value] of Object.entries(override)) {\n if (value === undefined) continue;\n const existing = result[key];\n if (typeof value === \"boolean\") {\n result[key] = (typeof existing === \"boolean\" && existing) || value;\n } else if (typeof value === \"number\") {\n result[key] = Math.max(typeof existing === \"number\" ? existing : 0, value);\n }\n }\n return result as BlockCodeKnownFeatureFlags;\n}\n\n/**\n * Plugin record: model + param derivation lambdas.\n * Type parameters are carried by PluginModel generic.\n */\nexport type PluginRecord<\n Data extends PluginData = PluginData,\n Params extends PluginParams = undefined,\n Outputs extends PluginOutputs = PluginOutputs,\n ModelServices = unknown,\n UiServices = unknown,\n> = {\n readonly model: PluginModel<Data, Params, Outputs, ModelServices, UiServices>;\n readonly inputs: ParamsInputErased;\n};\n\ninterface BlockModelV3Config<\n OutputsCfg extends Record<string, ConfigRenderLambda>,\n Data,\n Plugins extends Record<string, PluginRecord> = {},\n Transfers extends Record<string, unknown> = {},\n> {\n renderingMode: BlockRenderingMode;\n dataModel: DataModel<Data, Transfers>;\n outputs: OutputsCfg;\n sections: ConfigRenderLambda;\n title: ConfigRenderLambda | undefined;\n subtitle: ConfigRenderLambda | undefined;\n tags: ConfigRenderLambda | undefined;\n enrichmentTargets: ConfigRenderLambda | undefined;\n featureFlags: BlockCodeKnownFeatureFlags;\n argsFunction: ((data: unknown) => unknown) | undefined;\n prerunArgsFunction: ((data: unknown) => unknown) | undefined;\n plugins: Plugins;\n}\n\n/** Main entry point that each block should use in it's \"config\" module. Don't forget\n * to call {@link done()} at the end of configuration. Value returned by this builder must be\n * exported as constant with name \"platforma\" from the \"config\" module.\n * API version is 3 (for UI) and 2 (for model) */\nexport class BlockModelV3<\n Args,\n OutputsCfg extends Record<string, ConfigRenderLambda>,\n Data extends Record<string, unknown> = Record<string, unknown>,\n Href extends `/${string}` = \"/\",\n Plugins extends Record<string, PluginRecord> = {},\n Transfers extends Record<string, unknown> = {},\n> {\n private constructor(\n private readonly config: BlockModelV3Config<OutputsCfg, Data, Plugins, Transfers>,\n ) {}\n\n public static readonly FEATURE_FLAGS = {\n supportsLazyState: true,\n supportsPframeQueryRanking: true,\n requiresUIAPIVersion: 3,\n requiresModelAPIVersion: BLOCK_STORAGE_FACADE_VERSION,\n requiresCreatePTable: 2,\n ...BLOCK_SERVICE_FLAGS,\n } satisfies BlockCodeKnownFeatureFlags;\n\n /** @deprecated Use FEATURE_FLAGS */\n public static readonly INITIAL_BLOCK_FEATURE_FLAGS = BlockModelV3.FEATURE_FLAGS;\n\n /**\n * Creates a new BlockModelV3 builder with the specified data model.\n *\n * @example\n * const dataModel = new DataModelBuilder()\n * .from<BlockData>(\"v1\")\n * .init(() => ({ numbers: [], labels: [] }));\n *\n * BlockModelV3.create(dataModel)\n * .args((data) => ({ numbers: data.numbers }))\n * .sections(() => [{ type: 'link', href: '/', label: 'Main' }])\n * .done();\n *\n * @param dataModel The data model that defines initial data and migrations\n */\n public static create<\n Data extends Record<string, unknown>,\n Transfers extends Record<string, unknown> = {},\n >(dataModel: DataModel<Data, Transfers>): BlockModelV3<NoOb, {}, Data, \"/\", {}, Transfers> {\n return new BlockModelV3<NoOb, {}, Data, \"/\", {}, Transfers>({\n renderingMode: \"Heavy\",\n dataModel,\n outputs: {},\n sections: createAndRegisterRenderLambda({ handle: \"sections\", lambda: () => [] }, true),\n title: undefined,\n subtitle: undefined,\n tags: undefined,\n enrichmentTargets: undefined,\n featureFlags: { ...BlockModelV3.FEATURE_FLAGS },\n argsFunction: undefined,\n prerunArgsFunction: undefined,\n plugins: {},\n });\n }\n\n /**\n * Add output cell wrapped with additional status information to the configuration\n *\n * @param key output cell name, that can be later used to retrieve the rendered value\n * @param rf callback calculating output value using context, that allows to access\n * workflows outputs and interact with platforma drivers\n * @param flags additional flags that may alter lambda rendering procedure\n * */\n public output<const Key extends string, const RF extends RenderFunction<Args, Data, unknown>>(\n key: Key,\n rf: RF,\n flags: ConfigRenderLambdaFlags & { withStatus: true },\n ): BlockModelV3<\n Args,\n OutputsCfg & {\n [K in Key]: ConfigRenderLambda<InferRenderFunctionReturn<RF>> & {\n withStatus: true;\n };\n },\n Data,\n Href,\n Plugins,\n Transfers\n >;\n /**\n * Add output cell to the configuration\n *\n * @param key output cell name, that can be later used to retrieve the rendered value\n * @param rf callback calculating output value using context, that allows to access\n * workflows outputs and interact with platforma drivers\n * @param flags additional flags that may alter lambda rendering procedure\n * */\n public output<const Key extends string, const RF extends RenderFunction<Args, Data, unknown>>(\n key: Key,\n rf: RF,\n flags?: ConfigRenderLambdaFlags,\n ): BlockModelV3<\n Args,\n OutputsCfg & {\n [K in Key]: ConfigRenderLambda<InferRenderFunctionReturn<RF>>;\n },\n Data,\n Href,\n Plugins,\n Transfers\n >;\n public output(\n key: string,\n cfgOrRf: RenderFunction<Args, Data, unknown>,\n flags: ConfigRenderLambdaFlags = {},\n ): BlockModelV3<Args, OutputsCfg, Data, Href, Plugins, Transfers> {\n return new BlockModelV3({\n ...this.config,\n outputs: {\n ...this.config.outputs,\n [key]: createAndRegisterRenderLambda({\n handle: `block-output#${key}`,\n lambda: () => cfgOrRf(new BlockRenderCtx<Args, Data>(blockServiceNames)),\n ...flags,\n }),\n },\n });\n }\n\n /** Shortcut for {@link output} with retentive flag set to true. */\n public retentiveOutput<\n const Key extends string,\n const RF extends RenderFunction<Args, Data, unknown>,\n >(\n key: Key,\n rf: RF,\n ): BlockModelV3<\n Args,\n OutputsCfg & {\n [K in Key]: ConfigRenderLambda<InferRenderFunctionReturn<RF>>;\n },\n Data,\n Href,\n Plugins,\n Transfers\n > {\n return this.output(key, rf, { retentive: true });\n }\n\n /** Shortcut for {@link output} with withStatus flag set to true. */\n public outputWithStatus<\n const Key extends string,\n const RF extends RenderFunction<Args, Data, unknown>,\n >(key: Key, rf: RF) {\n return this.output(key, rf, { withStatus: true });\n }\n\n /**\n * Sets a function to derive block args from data.\n * This is called during setData to compute the args that will be used for block execution.\n *\n * @example\n * .args<BlockArgs>((data) => ({ numbers: data.numbers }))\n *\n * @example\n * .args<BlockArgs>((data) => {\n * if (data.numbers.length === 0) throw new Error('Numbers required'); // block not ready\n * return { numbers: data.numbers };\n * })\n */\n public args<A>(\n lambda: (data: Data) => A,\n ): BlockModelV3<A, OutputsCfg, Data, Href, Plugins, Transfers> {\n return new BlockModelV3<A, OutputsCfg, Data, Href, Plugins, Transfers>({\n ...this.config,\n argsFunction: lambda as (data: unknown) => unknown,\n });\n }\n\n /**\n * Sets a function to derive pre-run args from data (optional).\n * This is called during setData to compute the args that will be used for staging/pre-run phase.\n *\n * If not defined, defaults to using the args() function result.\n * If defined, uses its return value for the staging / prerun phase.\n *\n * The staging / prerun phase runs only if currentPrerunArgs differs from the executed\n * version of prerunArgs (same comparison logic as currentArgs vs prodArgs).\n *\n * @example\n * .prerunArgs((data) => ({ numbers: data.numbers }))\n *\n * @example\n * .prerunArgs((data) => {\n * // Return undefined to skip staging for this block\n * if (!data.isReady) return undefined;\n * return { numbers: data.numbers };\n * })\n */\n public prerunArgs(\n fn: (data: Data) => unknown,\n ): BlockModelV3<Args, OutputsCfg, Data, Href, Plugins, Transfers> {\n return new BlockModelV3<Args, OutputsCfg, Data, Href, Plugins, Transfers>({\n ...this.config,\n prerunArgsFunction: fn as (data: unknown) => unknown,\n });\n }\n\n /** Sets the lambda to generate list of sections in the left block overviews panel. */\n public sections<\n const Ret extends SectionsExpectedType,\n const RF extends RenderFunction<Args, Data, Ret>,\n >(rf: RF): BlockModelV3<Args, OutputsCfg, Data, DeriveHref<ReturnType<RF>>, Plugins, Transfers> {\n return new BlockModelV3<Args, OutputsCfg, Data, DeriveHref<ReturnType<RF>>, Plugins, Transfers>(\n {\n ...this.config,\n // Replace the default sections callback with the user-provided one\n sections: createAndRegisterRenderLambda(\n {\n handle: \"sections\",\n lambda: () => rf(new BlockRenderCtx<Args, Data>(blockServiceNames)),\n },\n true,\n ),\n },\n );\n }\n\n /** Sets a rendering function to derive block title, shown for the block in the left blocks-overview panel. */\n public title(\n rf: RenderFunction<Args, Data, string>,\n ): BlockModelV3<Args, OutputsCfg, Data, Href, Plugins, Transfers> {\n return new BlockModelV3<Args, OutputsCfg, Data, Href, Plugins, Transfers>({\n ...this.config,\n title: createAndRegisterRenderLambda({\n handle: \"title\",\n lambda: () => rf(new BlockRenderCtx<Args, Data>(blockServiceNames)),\n }),\n });\n }\n\n public subtitle(\n rf: RenderFunction<Args, Data, string>,\n ): BlockModelV3<Args, OutputsCfg, Data, Href, Plugins, Transfers> {\n return new BlockModelV3<Args, OutputsCfg, Data, Href, Plugins, Transfers>({\n ...this.config,\n subtitle: createAndRegisterRenderLambda({\n handle: \"subtitle\",\n lambda: () => rf(new BlockRenderCtx<Args, Data>(blockServiceNames)),\n }),\n });\n }\n\n public tags(\n rf: RenderFunction<Args, Data, string[]>,\n ): BlockModelV3<Args, OutputsCfg, Data, Href, Plugins, Transfers> {\n return new BlockModelV3<Args, OutputsCfg, Data, Href, Plugins, Transfers>({\n ...this.config,\n tags: createAndRegisterRenderLambda({\n handle: \"tags\",\n lambda: () => rf(new BlockRenderCtx<Args, Data>(blockServiceNames)),\n }),\n });\n }\n\n /** Sets or overrides feature flags for the block. */\n public withFeatureFlags(\n flags: Partial<BlockCodeKnownFeatureFlags>,\n ): BlockModelV3<Args, OutputsCfg, Data, Href, Plugins, Transfers> {\n return new BlockModelV3<Args, OutputsCfg, Data, Href, Plugins, Transfers>({\n ...this.config,\n featureFlags: { ...this.config.featureFlags, ...flags },\n });\n }\n\n /**\n * Defines how to derive list of upstream references this block is meant to enrich with its exports from block args.\n * Influences dependency graph construction.\n */\n public enriches(\n lambda: (args: Args) => PlRef[],\n ): BlockModelV3<Args, OutputsCfg, Data, Href, Plugins, Transfers> {\n return new BlockModelV3<Args, OutputsCfg, Data, Href, Plugins, Transfers>({\n ...this.config,\n enrichmentTargets: createAndRegisterRenderLambda({\n handle: \"enrichmentTargets\",\n lambda: lambda,\n }),\n });\n }\n\n /**\n * Registers a plugin instance with the block.\n * Consumes a transfer if one was defined for this plugin ID in the migration chain.\n *\n * Type checks:\n * - If Transfers[Id] exists, verifies it extends PTransferData (transfer type compatibility)\n * - If no Transfers[Id], rejects plugins with transferAt set (missing .transfer() in data model)\n * - Rejects duplicate plugin IDs (Id already in keyof Plugins)\n *\n * @param instance - PluginInstance created via factory.create({ pluginId, ... })\n * @param params - Per-property lambdas deriving plugin params from block RenderCtx\n *\n * @example\n * .plugin(mainTable, {\n * columns: (ctx) => ctx.outputs?.resolve(\"data\")?.getPColumns(),\n * sourceId: (ctx) => ctx.data.selectedSource,\n * })\n */\n public plugin<\n const PluginId extends string,\n PData extends PluginData,\n PParams extends PluginParams,\n POutputs extends PluginOutputs,\n PTransferData,\n PluginModelServices,\n PluginUiServices,\n >(\n instance: PluginInstanceClass<\n PluginId &\n (PluginId extends keyof Transfers\n ? Transfers[PluginId] extends PTransferData\n ? string\n : never\n : [PTransferData] extends [never]\n ? string\n : never) &\n (PluginId extends keyof Plugins ? never : string),\n PData,\n PParams,\n POutputs,\n PTransferData,\n PluginModelServices,\n PluginUiServices\n >,\n params?: ParamsInput<PParams, Args, Data>,\n ): BlockModelV3<\n Args,\n OutputsCfg,\n Data,\n Href,\n Plugins & {\n [K in PluginId]: PluginRecord<\n PData,\n PParams,\n POutputs,\n PluginModelServices,\n PluginUiServices\n >;\n },\n Omit<Transfers, PluginId>\n >;\n public plugin(\n instance: PluginInstanceClass,\n params?: ParamsInput<Record<string, unknown>, unknown, unknown>,\n ): BlockModelV3<\n Args,\n OutputsCfg,\n Data,\n Href,\n Record<string, PluginRecord>,\n Record<string, unknown>\n > {\n const pluginId = instance.id;\n const plugin = instance[CREATE_PLUGIN_MODEL]();\n const resolvedParams = (params ?? {}) as ParamsInputErased;\n\n if (pluginId in this.config.plugins) {\n throw new Error(`Plugin '${pluginId}' already registered`);\n }\n\n const registered: PluginRecord = {\n model: plugin,\n inputs: resolvedParams,\n };\n\n return new BlockModelV3({\n ...this.config,\n plugins: {\n ...this.config.plugins,\n [pluginId]: registered,\n },\n featureFlags: mergeFeatureFlags(this.config.featureFlags, plugin.featureFlags ?? {}),\n });\n }\n\n /** Renders all provided block settings into a pre-configured platforma API\n * instance, that can be used in frontend to interact with block data, and\n * other features provided by the platforma to the block.\n *\n * Type-level check: if there are unconsumed transfers (from `.transfer()` calls\n * in the migration chain), this method requires an impossible `never` argument,\n * producing a compile error. Register all transferred plugins via `.plugin(instance)`\n * before calling `.done()`.\n */\n public done(\n ..._: keyof Transfers extends never ? [] : [never]\n ): PlatformaExtended<\n PlatformaV3<\n Data,\n Args,\n InferOutputsFromLambdas<OutputsCfg>,\n Href,\n Plugins,\n BlockDefaultUiServices\n >\n > {\n if (this.config.argsFunction === undefined) throw new Error(\"Args rendering function not set.\");\n\n const apiVersion = 3;\n\n // Build plugin registry\n const { plugins } = this.config;\n const pluginRegistry: Record<string, PluginName> = {};\n const pluginHandles = Object.keys(plugins) as PluginHandle[];\n for (const handle of pluginHandles) {\n pluginRegistry[handle] = plugins[handle].model.name;\n }\n\n const { dataModel, argsFunction, prerunArgsFunction } = this.config;\n\n const mergedServiceNames = resolveRequiredServices(this.config.featureFlags);\n\n function getPlugin(handle: PluginHandle): PluginRecord {\n const plugin = plugins[handle];\n if (!plugin) throw new Error(`Plugin model not found for '${handle}'`);\n return plugin;\n }\n\n // Register ALL facade callbacks here, with dependencies captured via closures\n registerFacadeCallbacks({\n [BlockStorageFacadeCallbacks.StorageApplyUpdate]: applyStorageUpdate,\n [BlockStorageFacadeCallbacks.StorageDebugView]: getStorageDebugView,\n [BlockStorageFacadeCallbacks.StorageMigrate]: (currentStorageJson) =>\n migrateStorage(currentStorageJson, {\n migrateBlockData: (v) => dataModel.migrate(v),\n getPluginRegistry: () => pluginRegistry,\n migratePluginData: (handle, v) => getPlugin(handle).model.dataModel.migrate(v),\n createPluginData: (handle, transfer) => {\n if (transfer) return transfer;\n return getPlugin(handle).model.getDefaultData();\n },\n }),\n [BlockStorageFacadeCallbacks.StorageInitial]: () =>\n createInitialStorage({\n getDefaultBlockData: () => dataModel.getDefaultData(),\n getPluginRegistry: () => pluginRegistry,\n createPluginData: (handle) => getPlugin(handle).model.getDefaultData(),\n }),\n [BlockStorageFacadeCallbacks.ArgsDerive]: (storageJson) =>\n deriveArgsFromStorage(storageJson, argsFunction),\n [BlockStorageFacadeCallbacks.PrerunArgsDerive]: (storageJson) =>\n derivePrerunArgsFromStorage(storageJson, argsFunction, prerunArgsFunction),\n });\n\n // Register plugin input and output lambdas\n const pluginOutputs: Record<string, ConfigRenderLambda> = {};\n for (const handle of pluginHandles) {\n const { model, inputs } = plugins[handle];\n // Wrap plugin param lambdas: close over BlockRenderCtx creation\n const wrappedInputs: Record<string, () => unknown> = {};\n for (const [paramKey, paramFn] of Object.entries(inputs)) {\n wrappedInputs[paramKey] = () => paramFn(new BlockRenderCtx(mergedServiceNames));\n }\n\n // Register plugin outputs (in config pack, evaluated by middle layer)\n const outputs = model.outputs as Record<string, (ctx: PluginRenderCtx) => unknown>;\n const { outputFlags } = model;\n for (const [outputKey, outputFn] of Object.entries(outputs)) {\n const key = pluginOutputKey(handle, outputKey);\n pluginOutputs[key] = createAndRegisterRenderLambda({\n handle: key,\n lambda: () => outputFn(new PluginRenderCtx(handle, wrappedInputs, mergedServiceNames)),\n withStatus: outputFlags[outputKey]?.withStatus,\n });\n }\n }\n const allOutputs = { ...this.config.outputs, ...pluginOutputs };\n\n globalThis.platformaApiVersion = apiVersion;\n\n if (!isInUI()) {\n const blockConfig: BlockConfigContainer = {\n v4: {\n configVersion: 4,\n modelAPIVersion: BLOCK_STORAGE_FACADE_VERSION,\n sdkVersion: PlatformaSDKVersion,\n renderingMode: this.config.renderingMode,\n sections: this.config.sections,\n title: this.config.title,\n subtitle: this.config.subtitle,\n tags: this.config.tags,\n outputs: allOutputs,\n enrichmentTargets: this.config.enrichmentTargets,\n featureFlags: this.config.featureFlags,\n blockLifecycleCallbacks: { ...BlockStorageFacadeHandles },\n },\n\n // fields below are added to allow previous desktop versions read generated configs\n sdkVersion: PlatformaSDKVersion,\n renderingMode: this.config.renderingMode,\n sections: this.config.sections,\n outputs: Object.fromEntries(\n Object.entries(this.config.outputs).map(([key, value]) => [\n key,\n downgradeCfgOrLambda(value),\n ]),\n ),\n };\n // we are in the configuration rendering routine, not in actual UI\n return { config: blockConfig } as any;\n // normal operation inside the UI\n } else {\n return {\n ...getPlatformaInstance({\n sdkVersion: PlatformaSDKVersion,\n apiVersion,\n }),\n blockModelInfo: {\n outputs: Object.fromEntries(\n Object.entries(allOutputs).map(([key, value]) => [\n key,\n {\n withStatus: Boolean(isConfigLambda(value) && value.withStatus),\n },\n ]),\n ),\n pluginIds: pluginHandles,\n featureFlags: this.config.featureFlags,\n },\n } as any;\n }\n }\n}\n\n// Type tests for BlockModelV3\n\nexport type Expect<T extends true> = T;\n\nexport type Equal<X, Y> =\n (<T>() => T extends X ? 1 : 2) extends <T>() => T extends Y ? 1 : 2 ? true : false;\n\nexport type Merge<A, B> = {\n [K in keyof A | keyof B]: K extends keyof B ? B[K] : K extends keyof A ? A[K] : never;\n};\n\n// Helper types for testing\ntype _TestArgs = { inputFile: string; threshold: number };\ntype _TestData = { selectedTab: string };\ntype _TestOutputs = {\n result: ConfigRenderLambda<string>;\n count: ConfigRenderLambda<number>;\n};\n\n// Test: Merge type works correctly\ntype _MergeTest1 = Expect<Equal<Merge<{ a: 1 }, { b: 2 }>, { a: 1; b: 2 }>>;\ntype _MergeTest2 = Expect<Equal<Merge<{ a: 1 }, { a: 2 }>, { a: 2 }>>;\ntype _MergeTest3 = Expect<Equal<Merge<{ a: 1; b: 1 }, { b: 2; c: 3 }>, { a: 1; b: 2; c: 3 }>>;\n\n// Test: create() returns a BlockModelV3 instance\n// Note: Due to function overloads, ReturnType uses the last overload signature.\n// We verify the structure is correct using a simpler assignability test.\ntype _CreateResult = ReturnType<typeof BlockModelV3.create>;\ntype _CreateIsBlockModelV3 =\n _CreateResult extends BlockModelV3<infer _A, infer _O, infer _S> ? true : false;\ntype _CreateTest = Expect<_CreateIsBlockModelV3>;\n\n// Test: BlockModelV3Config interface structure (default generics)\ntype _ConfigTest = Expect<\n Equal<\n BlockModelV3Config<_TestOutputs, _TestData>,\n {\n renderingMode: BlockRenderingMode;\n argsFunction: ((data: unknown) => unknown) | undefined;\n prerunArgsFunction: ((data: unknown) => unknown) | undefined;\n dataModel: DataModel<_TestData, {}>;\n outputs: _TestOutputs;\n sections: ConfigRenderLambda;\n title: ConfigRenderLambda | undefined;\n subtitle: ConfigRenderLambda | undefined;\n tags: ConfigRenderLambda | undefined;\n enrichmentTargets: ConfigRenderLambda | undefined;\n featureFlags: BlockCodeKnownFeatureFlags;\n plugins: {};\n }\n >\n>;\n\n// Test: Default Href is '/'\ntype _HrefDefaultTest =\n BlockModelV3<_TestArgs, {}, _TestData> extends BlockModelV3<_TestArgs, {}, _TestData, \"/\">\n ? true\n : false;\ntype _VerifyHrefDefault = Expect<_HrefDefaultTest>;\n\n// Test: Custom Href can be specified\ntype _CustomHref = \"/settings\" | \"/main\";\ntype _HrefCustomBuilder = BlockModelV3<_TestArgs, {}, _TestData, _CustomHref>;\ntype _HrefCustomTest =\n _HrefCustomBuilder extends BlockModelV3<_TestArgs, {}, _TestData, _CustomHref> ? true : false;\ntype _VerifyHrefCustom = Expect<_HrefCustomTest>;\n\n// Test: Output type accumulation with & intersection\ntype _OutputsAccumulation = { a: ConfigRenderLambda<string> } & {\n b: ConfigRenderLambda<number>;\n};\ntype _VerifyOutputsHaveKeys = Expect<Equal<keyof _OutputsAccumulation, \"a\" | \"b\">>;\n\n// Test: Builder with all type parameters specified compiles\ntype _FullBuilder = BlockModelV3<_TestArgs, _TestOutputs, _TestData, \"/main\">;\ntype _FullBuilderTest =\n _FullBuilder extends BlockModelV3<_TestArgs, _TestOutputs, _TestData, \"/main\"> ? true : false;\ntype _VerifyFullBuilder = Expect<_FullBuilderTest>;\n\n// Test: InferOutputsFromLambdas maps outputs correctly\ntype _InferOutputsTest = InferOutputsFromLambdas<{\n myOutput: ConfigRenderLambda<number>;\n}>;\ntype _VerifyInferOutputs = Expect<\n Equal<_InferOutputsTest, { myOutput: OutputWithStatus<number> & { __unwrap: true } }>\n>;\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"block_model.cjs","names":["BLOCK_SERVICE_FLAGS","createAndRegisterRenderLambda","BlockRenderCtx","blockServiceNames","CREATE_PLUGIN_MODEL","BlockStorageFacadeCallbacks","applyStorageUpdate","getStorageDebugView","migrateStorage","createInitialStorage","deriveArgsFromStorage","derivePrerunArgsFromStorage","pluginOutputKey","PluginRenderCtx","isInUI","PlatformaSDKVersion","BlockStorageFacadeHandles","downgradeCfgOrLambda","getPlatformaInstance","isConfigLambda"],"sources":["../src/block_model.ts"],"sourcesContent":["import type {\n BlockRenderingMode,\n BlockSection,\n OutputWithStatus,\n PlRef,\n BlockCodeKnownFeatureFlags,\n BlockConfigContainer,\n} from \"@milaboratories/pl-model-common\";\nimport { resolveRequiredServices } from \"@milaboratories/pl-model-common\";\nimport { getPlatformaInstance, isInUI, createAndRegisterRenderLambda } from \"./internal\";\nimport type { DataModel } from \"./block_migrations\";\nimport type { PlatformaV3 } from \"./platforma\";\nimport type { BlockDefaultUiServices } from \"./services/service_resolve\";\nimport { blockServiceNames, BLOCK_SERVICE_FLAGS } from \"./services/block_services\";\nimport type { InferRenderFunctionReturn, RenderFunction } from \"./render\";\nimport { BlockRenderCtx, PluginRenderCtx } from \"./render\";\nimport type { PluginData, PluginModel, PluginOutputs, PluginParams } from \"./plugin_model\";\nimport { PluginInstance as PluginInstanceClass, CREATE_PLUGIN_MODEL } from \"./plugin_model\";\nimport { type PluginHandle, pluginOutputKey } from \"./plugin_handle\";\nimport type { RenderCtxBase } from \"./render\";\nimport { PlatformaSDKVersion } from \"./version\";\nimport {\n applyStorageUpdate,\n getStorageDebugView,\n migrateStorage,\n createInitialStorage,\n deriveArgsFromStorage,\n derivePrerunArgsFromStorage,\n} from \"./block_storage_callbacks\";\nimport { type PluginName } from \"./block_storage\";\nimport type {\n ConfigRenderLambda,\n DeriveHref,\n ConfigRenderLambdaFlags,\n InferOutputsFromLambdas,\n} from \"./bconfig\";\nimport { downgradeCfgOrLambda, isConfigLambda } from \"./bconfig\";\nimport type { PlatformaExtended } from \"./platforma\";\nimport {\n BLOCK_STORAGE_FACADE_VERSION,\n BlockStorageFacadeCallbacks,\n BlockStorageFacadeHandles,\n registerFacadeCallbacks,\n} from \"./block_storage_facade\";\n\ntype SectionsExpectedType = readonly BlockSection[];\n\ntype NoOb = Record<string, never>;\n\n/**\n * Per-property lambdas for deriving plugin params from block render context.\n * Each property is a function that receives the block's RenderCtxBase and returns the param value.\n */\nexport type ParamsInput<Params, BArgs = unknown, BData = unknown> = {\n [K in keyof Params]: (ctx: RenderCtxBase<BArgs, BData>) => Params[K];\n};\n\n/**\n * Type-erased version of ParamsInput for internal storage.\n */\ntype ParamsInputErased = Record<string, (ctx: RenderCtxBase) => unknown>;\n\n/**\n * Merges two feature flag objects with type-aware logic:\n * - `supports*` (boolean): OR — `true` if either side is `true`\n * - `requires*` (numeric): MAX — take the higher version requirement\n */\nfunction mergeFeatureFlags(\n base: BlockCodeKnownFeatureFlags,\n override: BlockCodeKnownFeatureFlags,\n): BlockCodeKnownFeatureFlags {\n const result: Record<string, boolean | number | undefined> = { ...base };\n for (const [key, value] of Object.entries(override)) {\n if (value === undefined) continue;\n const existing = result[key];\n if (typeof value === \"boolean\") {\n result[key] = (typeof existing === \"boolean\" && existing) || value;\n } else if (typeof value === \"number\") {\n result[key] = Math.max(typeof existing === \"number\" ? existing : 0, value);\n }\n }\n return result as BlockCodeKnownFeatureFlags;\n}\n\n/**\n * Plugin record: model + param derivation lambdas.\n * Type parameters are carried by PluginModel generic.\n */\nexport type PluginRecord<\n Data extends PluginData = PluginData,\n Params extends PluginParams = undefined,\n Outputs extends PluginOutputs = PluginOutputs,\n ModelServices = unknown,\n UiServices = unknown,\n> = {\n readonly model: PluginModel<Data, Params, Outputs, ModelServices, UiServices>;\n readonly inputs: ParamsInputErased;\n};\n\ninterface BlockModelV3Config<\n OutputsCfg extends Record<string, ConfigRenderLambda>,\n Data,\n Plugins extends Record<string, PluginRecord> = {},\n Transfers extends Record<string, unknown> = {},\n> {\n renderingMode: BlockRenderingMode;\n dataModel: DataModel<Data, Transfers>;\n outputs: OutputsCfg;\n sections: ConfigRenderLambda;\n title: ConfigRenderLambda | undefined;\n subtitle: ConfigRenderLambda | undefined;\n tags: ConfigRenderLambda | undefined;\n enrichmentTargets: ConfigRenderLambda | undefined;\n featureFlags: BlockCodeKnownFeatureFlags;\n argsFunction: ((data: unknown) => unknown) | undefined;\n prerunArgsFunction: ((data: unknown) => unknown) | undefined;\n plugins: Plugins;\n}\n\n/** Main entry point that each block should use in it's \"config\" module. Don't forget\n * to call {@link done()} at the end of configuration. Value returned by this builder must be\n * exported as constant with name \"platforma\" from the \"config\" module.\n * API version is 3 (for UI) and 2 (for model) */\nexport class BlockModelV3<\n Args,\n OutputsCfg extends Record<string, ConfigRenderLambda>,\n Data extends Record<string, unknown> = Record<string, unknown>,\n Href extends `/${string}` = \"/\",\n Plugins extends Record<string, PluginRecord> = {},\n Transfers extends Record<string, unknown> = {},\n> {\n private constructor(\n private readonly config: BlockModelV3Config<OutputsCfg, Data, Plugins, Transfers>,\n ) {}\n\n public static readonly FEATURE_FLAGS = {\n supportsLazyState: true,\n supportsPframeQueryRanking: true,\n requiresUIAPIVersion: 3,\n requiresModelAPIVersion: BLOCK_STORAGE_FACADE_VERSION,\n requiresCreatePTable: 2,\n ...BLOCK_SERVICE_FLAGS,\n } satisfies BlockCodeKnownFeatureFlags;\n\n /** @deprecated Use FEATURE_FLAGS */\n public static readonly INITIAL_BLOCK_FEATURE_FLAGS = BlockModelV3.FEATURE_FLAGS;\n\n /**\n * Creates a new BlockModelV3 builder with the specified data model.\n *\n * @example\n * const dataModel = new DataModelBuilder()\n * .from<BlockData>(\"v1\")\n * .init(() => ({ numbers: [], labels: [] }));\n *\n * BlockModelV3.create(dataModel)\n * .args((data) => ({ numbers: data.numbers }))\n * .sections(() => [{ type: 'link', href: '/', label: 'Main' }])\n * .done();\n *\n * @param dataModel The data model that defines initial data and migrations\n */\n public static create<\n Data extends Record<string, unknown>,\n Transfers extends Record<string, unknown> = {},\n >(dataModel: DataModel<Data, Transfers>): BlockModelV3<NoOb, {}, Data, \"/\", {}, Transfers> {\n return new BlockModelV3<NoOb, {}, Data, \"/\", {}, Transfers>({\n renderingMode: \"Heavy\",\n dataModel,\n outputs: {},\n sections: createAndRegisterRenderLambda({ handle: \"sections\", lambda: () => [] }, true),\n title: undefined,\n subtitle: undefined,\n tags: undefined,\n enrichmentTargets: undefined,\n featureFlags: { ...BlockModelV3.FEATURE_FLAGS },\n argsFunction: undefined,\n prerunArgsFunction: undefined,\n plugins: {},\n });\n }\n\n /**\n * Add output cell wrapped with additional status information to the configuration\n *\n * @param key output cell name, that can be later used to retrieve the rendered value\n * @param rf callback calculating output value using context, that allows to access\n * workflows outputs and interact with platforma drivers\n * @param flags additional flags that may alter lambda rendering procedure\n * */\n public output<const Key extends string, const RF extends RenderFunction<Args, Data, unknown>>(\n key: Key,\n rf: RF,\n flags: ConfigRenderLambdaFlags & { withStatus: true },\n ): BlockModelV3<\n Args,\n OutputsCfg & {\n [K in Key]: ConfigRenderLambda<InferRenderFunctionReturn<RF>> & {\n withStatus: true;\n };\n },\n Data,\n Href,\n Plugins,\n Transfers\n >;\n /**\n * Add output cell to the configuration\n *\n * @param key output cell name, that can be later used to retrieve the rendered value\n * @param rf callback calculating output value using context, that allows to access\n * workflows outputs and interact with platforma drivers\n * @param flags additional flags that may alter lambda rendering procedure\n * */\n public output<const Key extends string, const RF extends RenderFunction<Args, Data, unknown>>(\n key: Key,\n rf: RF,\n flags?: ConfigRenderLambdaFlags,\n ): BlockModelV3<\n Args,\n OutputsCfg & {\n [K in Key]: ConfigRenderLambda<InferRenderFunctionReturn<RF>>;\n },\n Data,\n Href,\n Plugins,\n Transfers\n >;\n public output(\n key: string,\n cfgOrRf: RenderFunction<Args, Data, unknown>,\n flags: ConfigRenderLambdaFlags = {},\n ): BlockModelV3<Args, OutputsCfg, Data, Href, Plugins, Transfers> {\n return new BlockModelV3({\n ...this.config,\n outputs: {\n ...this.config.outputs,\n [key]: createAndRegisterRenderLambda({\n handle: `block-output#${key}`,\n lambda: () => cfgOrRf(new BlockRenderCtx<Args, Data>(blockServiceNames)),\n ...flags,\n }),\n },\n });\n }\n\n /** Shortcut for {@link output} with retentive flag set to true. */\n public retentiveOutput<\n const Key extends string,\n const RF extends RenderFunction<Args, Data, unknown>,\n >(\n key: Key,\n rf: RF,\n ): BlockModelV3<\n Args,\n OutputsCfg & {\n [K in Key]: ConfigRenderLambda<InferRenderFunctionReturn<RF>>;\n },\n Data,\n Href,\n Plugins,\n Transfers\n > {\n return this.output(key, rf, { retentive: true });\n }\n\n /** Shortcut for {@link output} with withStatus flag set to true. */\n public outputWithStatus<\n const Key extends string,\n const RF extends RenderFunction<Args, Data, unknown>,\n >(key: Key, rf: RF) {\n return this.output(key, rf, { withStatus: true });\n }\n\n /**\n * Sets a function to derive block args from data.\n * This is called during setData to compute the args that will be used for block execution.\n *\n * @example\n * .args<BlockArgs>((data) => ({ numbers: data.numbers }))\n *\n * @example\n * .args<BlockArgs>((data) => {\n * if (data.numbers.length === 0) throw new Error('Numbers required'); // block not ready\n * return { numbers: data.numbers };\n * })\n */\n public args<A>(\n lambda: (data: Data) => A,\n ): BlockModelV3<A, OutputsCfg, Data, Href, Plugins, Transfers> {\n return new BlockModelV3<A, OutputsCfg, Data, Href, Plugins, Transfers>({\n ...this.config,\n argsFunction: lambda as (data: unknown) => unknown,\n });\n }\n\n /**\n * Sets a function to derive pre-run args from data (optional).\n * This is called during setData to compute the args that will be used for staging/pre-run phase.\n *\n * If not defined, defaults to using the args() function result.\n * If defined, uses its return value for the staging / prerun phase.\n *\n * The staging / prerun phase runs only if currentPrerunArgs differs from the executed\n * version of prerunArgs (same comparison logic as currentArgs vs prodArgs).\n *\n * @example\n * .prerunArgs((data) => ({ numbers: data.numbers }))\n *\n * @example\n * .prerunArgs((data) => {\n * // Return undefined to skip staging for this block\n * if (!data.isReady) return undefined;\n * return { numbers: data.numbers };\n * })\n */\n public prerunArgs(\n fn: (data: Data) => unknown,\n ): BlockModelV3<Args, OutputsCfg, Data, Href, Plugins, Transfers> {\n return new BlockModelV3<Args, OutputsCfg, Data, Href, Plugins, Transfers>({\n ...this.config,\n prerunArgsFunction: fn as (data: unknown) => unknown,\n });\n }\n\n /** Sets the lambda to generate list of sections in the left block overviews panel. */\n public sections<\n const Ret extends SectionsExpectedType,\n const RF extends RenderFunction<Args, Data, Ret>,\n >(rf: RF): BlockModelV3<Args, OutputsCfg, Data, DeriveHref<ReturnType<RF>>, Plugins, Transfers> {\n return new BlockModelV3<Args, OutputsCfg, Data, DeriveHref<ReturnType<RF>>, Plugins, Transfers>(\n {\n ...this.config,\n // Replace the default sections callback with the user-provided one\n sections: createAndRegisterRenderLambda(\n {\n handle: \"sections\",\n lambda: () => rf(new BlockRenderCtx<Args, Data>(blockServiceNames)),\n },\n true,\n ),\n },\n );\n }\n\n /** Sets a rendering function to derive block title, shown for the block in the left blocks-overview panel. */\n public title(\n rf: RenderFunction<Args, Data, string>,\n ): BlockModelV3<Args, OutputsCfg, Data, Href, Plugins, Transfers> {\n return new BlockModelV3<Args, OutputsCfg, Data, Href, Plugins, Transfers>({\n ...this.config,\n title: createAndRegisterRenderLambda({\n handle: \"title\",\n lambda: () => rf(new BlockRenderCtx<Args, Data>(blockServiceNames)),\n }),\n });\n }\n\n public subtitle(\n rf: RenderFunction<Args, Data, string>,\n ): BlockModelV3<Args, OutputsCfg, Data, Href, Plugins, Transfers> {\n return new BlockModelV3<Args, OutputsCfg, Data, Href, Plugins, Transfers>({\n ...this.config,\n subtitle: createAndRegisterRenderLambda({\n handle: \"subtitle\",\n lambda: () => rf(new BlockRenderCtx<Args, Data>(blockServiceNames)),\n }),\n });\n }\n\n public tags(\n rf: RenderFunction<Args, Data, string[]>,\n ): BlockModelV3<Args, OutputsCfg, Data, Href, Plugins, Transfers> {\n return new BlockModelV3<Args, OutputsCfg, Data, Href, Plugins, Transfers>({\n ...this.config,\n tags: createAndRegisterRenderLambda({\n handle: \"tags\",\n lambda: () => rf(new BlockRenderCtx<Args, Data>(blockServiceNames)),\n }),\n });\n }\n\n /** Sets or overrides feature flags for the block. */\n public withFeatureFlags(\n flags: Partial<BlockCodeKnownFeatureFlags>,\n ): BlockModelV3<Args, OutputsCfg, Data, Href, Plugins, Transfers> {\n return new BlockModelV3<Args, OutputsCfg, Data, Href, Plugins, Transfers>({\n ...this.config,\n featureFlags: { ...this.config.featureFlags, ...flags },\n });\n }\n\n /**\n * Defines how to derive list of upstream references this block is meant to enrich with its exports from block args.\n * Influences dependency graph construction.\n */\n public enriches(\n lambda: (args: Args) => PlRef[],\n ): BlockModelV3<Args, OutputsCfg, Data, Href, Plugins, Transfers> {\n return new BlockModelV3<Args, OutputsCfg, Data, Href, Plugins, Transfers>({\n ...this.config,\n enrichmentTargets: createAndRegisterRenderLambda({\n handle: \"enrichmentTargets\",\n lambda: lambda,\n }),\n });\n }\n\n /**\n * Registers a plugin instance with the block.\n * Consumes a transfer if one was defined for this plugin ID in the migration chain.\n *\n * Type checks:\n * - If Transfers[Id] exists, verifies it extends PTransferData (transfer type compatibility)\n * - If no Transfers[Id], rejects plugins with transferAt set (missing .transfer() in data model)\n * - Rejects duplicate plugin IDs (Id already in keyof Plugins)\n *\n * @param instance - PluginInstance created via factory.create({ pluginId, ... })\n * @param params - Per-property lambdas deriving plugin params from block RenderCtx\n *\n * @example\n * .plugin(mainTable, {\n * columns: (ctx) => ctx.outputs?.resolve(\"data\")?.getPColumns(),\n * sourceId: (ctx) => ctx.data.selectedSource,\n * })\n */\n public plugin<\n const PluginId extends string,\n PData extends PluginData,\n PParams extends PluginParams,\n POutputs extends PluginOutputs,\n PTransferData,\n PluginModelServices,\n PluginUiServices,\n >(\n instance: PluginInstanceClass<\n PluginId &\n (PluginId extends keyof Transfers\n ? Transfers[PluginId] extends PTransferData\n ? string\n : never\n : [PTransferData] extends [never]\n ? string\n : never) &\n (PluginId extends keyof Plugins ? never : string),\n PData,\n PParams,\n POutputs,\n PTransferData,\n PluginModelServices,\n PluginUiServices\n >,\n params?: ParamsInput<PParams, Args, Data>,\n ): BlockModelV3<\n Args,\n OutputsCfg,\n Data,\n Href,\n Plugins & {\n [K in PluginId]: PluginRecord<\n PData,\n PParams,\n POutputs,\n PluginModelServices,\n PluginUiServices\n >;\n },\n Omit<Transfers, PluginId>\n >;\n public plugin(\n instance: PluginInstanceClass,\n params?: ParamsInput<Record<string, unknown>, unknown, unknown>,\n ): BlockModelV3<\n Args,\n OutputsCfg,\n Data,\n Href,\n Record<string, PluginRecord>,\n Record<string, unknown>\n > {\n const pluginId = instance.id;\n const plugin = instance[CREATE_PLUGIN_MODEL]();\n const resolvedParams = (params ?? {}) as ParamsInputErased;\n\n if (pluginId in this.config.plugins) {\n throw new Error(`Plugin '${pluginId}' already registered`);\n }\n\n const registered: PluginRecord = {\n model: plugin,\n inputs: resolvedParams,\n };\n\n return new BlockModelV3({\n ...this.config,\n plugins: {\n ...this.config.plugins,\n [pluginId]: registered,\n },\n featureFlags: mergeFeatureFlags(this.config.featureFlags, plugin.featureFlags ?? {}),\n });\n }\n\n /** Renders all provided block settings into a pre-configured platforma API\n * instance, that can be used in frontend to interact with block data, and\n * other features provided by the platforma to the block.\n *\n * Type-level check: if there are unconsumed transfers (from `.transfer()` calls\n * in the migration chain), this method requires an impossible `never` argument,\n * producing a compile error. Register all transferred plugins via `.plugin(instance)`\n * before calling `.done()`.\n */\n public done(\n ..._: keyof Transfers extends never ? [] : [never]\n ): PlatformaExtended<\n PlatformaV3<\n Data,\n Args,\n InferOutputsFromLambdas<OutputsCfg>,\n Href,\n Plugins,\n BlockDefaultUiServices\n >\n > {\n if (this.config.argsFunction === undefined) throw new Error(\"Args rendering function not set.\");\n\n const apiVersion = 3;\n\n // Build plugin registry\n const { plugins } = this.config;\n const pluginRegistry: Record<string, PluginName> = {};\n const pluginHandles = Object.keys(plugins) as PluginHandle[];\n for (const handle of pluginHandles) {\n pluginRegistry[handle] = plugins[handle].model.name;\n }\n\n const { dataModel, argsFunction, prerunArgsFunction } = this.config;\n\n const mergedServiceNames = resolveRequiredServices(this.config.featureFlags);\n\n function getPlugin(handle: PluginHandle): PluginRecord {\n const plugin = plugins[handle];\n if (!plugin) throw new Error(`Plugin model not found for '${handle}'`);\n return plugin;\n }\n\n // Register ALL facade callbacks here, with dependencies captured via closures\n registerFacadeCallbacks({\n [BlockStorageFacadeCallbacks.StorageApplyUpdate]: applyStorageUpdate,\n [BlockStorageFacadeCallbacks.StorageDebugView]: getStorageDebugView,\n [BlockStorageFacadeCallbacks.StorageMigrate]: (currentStorageJson) =>\n migrateStorage(currentStorageJson, {\n migrateBlockData: (v) => dataModel.migrate(v),\n getPluginRegistry: () => pluginRegistry,\n migratePluginData: (handle, v) => getPlugin(handle).model.dataModel.migrate(v),\n createPluginData: (handle, transfer) => {\n if (transfer) return transfer;\n return getPlugin(handle).model.getDefaultData();\n },\n }),\n [BlockStorageFacadeCallbacks.StorageInitial]: () =>\n createInitialStorage({\n getDefaultBlockData: () => dataModel.getDefaultData(),\n getPluginRegistry: () => pluginRegistry,\n createPluginData: (handle) => getPlugin(handle).model.getDefaultData(),\n }),\n [BlockStorageFacadeCallbacks.ArgsDerive]: (storageJson) =>\n deriveArgsFromStorage(storageJson, argsFunction),\n [BlockStorageFacadeCallbacks.PrerunArgsDerive]: (storageJson) =>\n derivePrerunArgsFromStorage(storageJson, argsFunction, prerunArgsFunction),\n });\n\n // Register plugin input and output lambdas\n const pluginOutputs: Record<string, ConfigRenderLambda> = {};\n for (const handle of pluginHandles) {\n const { model, inputs } = plugins[handle];\n // Wrap plugin param lambdas: close over BlockRenderCtx creation\n const wrappedInputs: Record<string, () => unknown> = {};\n for (const [paramKey, paramFn] of Object.entries(inputs)) {\n wrappedInputs[paramKey] = () => paramFn(new BlockRenderCtx(mergedServiceNames));\n }\n\n // Register plugin outputs (in config pack, evaluated by middle layer)\n const outputs = model.outputs as Record<string, (ctx: PluginRenderCtx) => unknown>;\n const { outputFlags } = model;\n for (const [outputKey, outputFn] of Object.entries(outputs)) {\n const key = pluginOutputKey(handle, outputKey);\n pluginOutputs[key] = createAndRegisterRenderLambda({\n handle: key,\n lambda: () => outputFn(new PluginRenderCtx(handle, wrappedInputs, mergedServiceNames)),\n withStatus: outputFlags[outputKey]?.withStatus,\n });\n }\n }\n const allOutputs = { ...this.config.outputs, ...pluginOutputs };\n\n globalThis.platformaApiVersion = apiVersion;\n\n if (!isInUI()) {\n const blockConfig: BlockConfigContainer = {\n v4: {\n configVersion: 4,\n modelAPIVersion: BLOCK_STORAGE_FACADE_VERSION,\n sdkVersion: PlatformaSDKVersion,\n renderingMode: this.config.renderingMode,\n sections: this.config.sections,\n title: this.config.title,\n subtitle: this.config.subtitle,\n tags: this.config.tags,\n outputs: allOutputs,\n enrichmentTargets: this.config.enrichmentTargets,\n featureFlags: this.config.featureFlags,\n blockLifecycleCallbacks: { ...BlockStorageFacadeHandles },\n },\n\n // fields below are added to allow previous desktop versions read generated configs\n sdkVersion: PlatformaSDKVersion,\n renderingMode: this.config.renderingMode,\n sections: this.config.sections,\n outputs: Object.fromEntries(\n Object.entries(this.config.outputs).map(([key, value]) => [\n key,\n downgradeCfgOrLambda(value),\n ]),\n ),\n };\n // we are in the configuration rendering routine, not in actual UI\n return { config: blockConfig } as any;\n // normal operation inside the UI\n } else {\n return {\n ...getPlatformaInstance({\n sdkVersion: PlatformaSDKVersion,\n apiVersion,\n }),\n blockModelInfo: {\n outputs: Object.fromEntries(\n Object.entries(allOutputs).map(([key, value]) => [\n key,\n {\n withStatus: Boolean(isConfigLambda(value) && value.withStatus),\n },\n ]),\n ),\n pluginIds: pluginHandles,\n featureFlags: this.config.featureFlags,\n },\n } as any;\n }\n }\n}\n\n// Type tests for BlockModelV3\n\nexport type Expect<T extends true> = T;\n\nexport type Equal<X, Y> =\n (<T>() => T extends X ? 1 : 2) extends <T>() => T extends Y ? 1 : 2 ? true : false;\n\nexport type Merge<A, B> = {\n [K in keyof A | keyof B]: K extends keyof B ? B[K] : K extends keyof A ? A[K] : never;\n};\n\n// Helper types for testing\ntype _TestArgs = { inputFile: string; threshold: number };\ntype _TestData = { selectedTab: string };\ntype _TestOutputs = {\n result: ConfigRenderLambda<string>;\n count: ConfigRenderLambda<number>;\n};\n\n// Test: Merge type works correctly\ntype _MergeTest1 = Expect<Equal<Merge<{ a: 1 }, { b: 2 }>, { a: 1; b: 2 }>>;\ntype _MergeTest2 = Expect<Equal<Merge<{ a: 1 }, { a: 2 }>, { a: 2 }>>;\ntype _MergeTest3 = Expect<Equal<Merge<{ a: 1; b: 1 }, { b: 2; c: 3 }>, { a: 1; b: 2; c: 3 }>>;\n\n// Test: create() returns a BlockModelV3 instance\n// Note: Due to function overloads, ReturnType uses the last overload signature.\n// We verify the structure is correct using a simpler assignability test.\ntype _CreateResult = ReturnType<typeof BlockModelV3.create>;\ntype _CreateIsBlockModelV3 =\n _CreateResult extends BlockModelV3<infer _A, infer _O, infer _S> ? true : false;\ntype _CreateTest = Expect<_CreateIsBlockModelV3>;\n\n// Test: BlockModelV3Config interface structure (default generics)\ntype _ConfigTest = Expect<\n Equal<\n BlockModelV3Config<_TestOutputs, _TestData>,\n {\n renderingMode: BlockRenderingMode;\n argsFunction: ((data: unknown) => unknown) | undefined;\n prerunArgsFunction: ((data: unknown) => unknown) | undefined;\n dataModel: DataModel<_TestData, {}>;\n outputs: _TestOutputs;\n sections: ConfigRenderLambda;\n title: ConfigRenderLambda | undefined;\n subtitle: ConfigRenderLambda | undefined;\n tags: ConfigRenderLambda | undefined;\n enrichmentTargets: ConfigRenderLambda | undefined;\n featureFlags: BlockCodeKnownFeatureFlags;\n plugins: {};\n }\n >\n>;\n\n// Test: Default Href is '/'\ntype _HrefDefaultTest =\n BlockModelV3<_TestArgs, {}, _TestData> extends BlockModelV3<_TestArgs, {}, _TestData, \"/\">\n ? true\n : false;\ntype _VerifyHrefDefault = Expect<_HrefDefaultTest>;\n\n// Test: Custom Href can be specified\ntype _CustomHref = \"/settings\" | \"/main\";\ntype _HrefCustomBuilder = BlockModelV3<_TestArgs, {}, _TestData, _CustomHref>;\ntype _HrefCustomTest =\n _HrefCustomBuilder extends BlockModelV3<_TestArgs, {}, _TestData, _CustomHref> ? true : false;\ntype _VerifyHrefCustom = Expect<_HrefCustomTest>;\n\n// Test: Output type accumulation with & intersection\ntype _OutputsAccumulation = { a: ConfigRenderLambda<string> } & {\n b: ConfigRenderLambda<number>;\n};\ntype _VerifyOutputsHaveKeys = Expect<Equal<keyof _OutputsAccumulation, \"a\" | \"b\">>;\n\n// Test: Builder with all type parameters specified compiles\ntype _FullBuilder = BlockModelV3<_TestArgs, _TestOutputs, _TestData, \"/main\">;\ntype _FullBuilderTest =\n _FullBuilder extends BlockModelV3<_TestArgs, _TestOutputs, _TestData, \"/main\"> ? true : false;\ntype _VerifyFullBuilder = Expect<_FullBuilderTest>;\n\n// Test: InferOutputsFromLambdas maps outputs correctly\ntype _InferOutputsTest = InferOutputsFromLambdas<{\n myOutput: ConfigRenderLambda<number>;\n}>;\ntype _VerifyInferOutputs = Expect<\n Equal<_InferOutputsTest, { myOutput: OutputWithStatus<number> & { __unwrap: true } }>\n>;\n"],"mappings":"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"}
|
package/dist/block_model.d.ts
CHANGED
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
import { DataModel } from "./block_migrations.js";
|
|
2
2
|
import { ConfigRenderLambda, ConfigRenderLambdaFlags, InferOutputsFromLambdas } from "./bconfig/lambdas.js";
|
|
3
3
|
import { DeriveHref } from "./bconfig/util.js";
|
|
4
|
-
import "./bconfig/index.js";
|
|
5
4
|
import { BlockDefaultUiServices } from "./services/service_resolve.js";
|
|
6
5
|
import { InferRenderFunctionReturn, RenderCtxBase, RenderFunction } from "./render/api.js";
|
|
7
|
-
import "./render/index.js";
|
|
8
6
|
import { PluginData, PluginInstance, PluginModel, PluginOutputs, PluginParams } from "./plugin_model.js";
|
|
9
7
|
import { PlatformaExtended, PlatformaV3 } from "./platforma.js";
|
|
10
8
|
import { BlockCodeKnownFeatureFlags, BlockSection, PlRef } from "@milaboratories/pl-model-common";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"block_model.d.ts","names":[],"sources":["../src/block_model.ts"],"mappings":"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"}
|
package/dist/block_model.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { pluginOutputKey } from "./plugin_handle.js";
|
|
2
2
|
import { createAndRegisterRenderLambda, getPlatformaInstance, isInUI } from "./internal.js";
|
|
3
|
-
import {
|
|
3
|
+
import { BlockStorageFacadeCallbacks, BlockStorageFacadeHandles, registerFacadeCallbacks } from "./block_storage_facade.js";
|
|
4
4
|
import { BlockRenderCtx, PluginRenderCtx } from "./render/api.js";
|
|
5
5
|
import "./render/index.js";
|
|
6
6
|
import { PlatformaSDKVersion } from "./version.js";
|
|
@@ -11,7 +11,6 @@ import { BLOCK_SERVICE_FLAGS, blockServiceNames } from "./services/block_service
|
|
|
11
11
|
import { CREATE_PLUGIN_MODEL } from "./plugin_model.js";
|
|
12
12
|
import { applyStorageUpdate, createInitialStorage, deriveArgsFromStorage, derivePrerunArgsFromStorage, getStorageDebugView, migrateStorage } from "./block_storage_callbacks.js";
|
|
13
13
|
import { resolveRequiredServices } from "@milaboratories/pl-model-common";
|
|
14
|
-
|
|
15
14
|
//#region src/block_model.ts
|
|
16
15
|
/**
|
|
17
16
|
* Merges two feature flag objects with type-aware logic:
|
|
@@ -40,7 +39,7 @@ var BlockModelV3 = class BlockModelV3 {
|
|
|
40
39
|
supportsLazyState: true,
|
|
41
40
|
supportsPframeQueryRanking: true,
|
|
42
41
|
requiresUIAPIVersion: 3,
|
|
43
|
-
requiresModelAPIVersion:
|
|
42
|
+
requiresModelAPIVersion: 2,
|
|
44
43
|
requiresCreatePTable: 2,
|
|
45
44
|
...BLOCK_SERVICE_FLAGS
|
|
46
45
|
};
|
|
@@ -292,7 +291,7 @@ var BlockModelV3 = class BlockModelV3 {
|
|
|
292
291
|
if (!isInUI()) return { config: {
|
|
293
292
|
v4: {
|
|
294
293
|
configVersion: 4,
|
|
295
|
-
modelAPIVersion:
|
|
294
|
+
modelAPIVersion: 2,
|
|
296
295
|
sdkVersion: PlatformaSDKVersion,
|
|
297
296
|
renderingMode: this.config.renderingMode,
|
|
298
297
|
sections: this.config.sections,
|
|
@@ -322,7 +321,7 @@ var BlockModelV3 = class BlockModelV3 {
|
|
|
322
321
|
};
|
|
323
322
|
}
|
|
324
323
|
};
|
|
325
|
-
|
|
326
324
|
//#endregion
|
|
327
325
|
export { BlockModelV3 };
|
|
326
|
+
|
|
328
327
|
//# sourceMappingURL=block_model.js.map
|
package/dist/block_model.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"block_model.js","names":[],"sources":["../src/block_model.ts"],"sourcesContent":["import type {\n BlockRenderingMode,\n BlockSection,\n OutputWithStatus,\n PlRef,\n BlockCodeKnownFeatureFlags,\n BlockConfigContainer,\n} from \"@milaboratories/pl-model-common\";\nimport { resolveRequiredServices } from \"@milaboratories/pl-model-common\";\nimport { getPlatformaInstance, isInUI, createAndRegisterRenderLambda } from \"./internal\";\nimport type { DataModel } from \"./block_migrations\";\nimport type { PlatformaV3 } from \"./platforma\";\nimport type { BlockDefaultUiServices } from \"./services/service_resolve\";\nimport { blockServiceNames, BLOCK_SERVICE_FLAGS } from \"./services/block_services\";\nimport type { InferRenderFunctionReturn, RenderFunction } from \"./render\";\nimport { BlockRenderCtx, PluginRenderCtx } from \"./render\";\nimport type { PluginData, PluginModel, PluginOutputs, PluginParams } from \"./plugin_model\";\nimport { PluginInstance as PluginInstanceClass, CREATE_PLUGIN_MODEL } from \"./plugin_model\";\nimport { type PluginHandle, pluginOutputKey } from \"./plugin_handle\";\nimport type { RenderCtxBase } from \"./render\";\nimport { PlatformaSDKVersion } from \"./version\";\nimport {\n applyStorageUpdate,\n getStorageDebugView,\n migrateStorage,\n createInitialStorage,\n deriveArgsFromStorage,\n derivePrerunArgsFromStorage,\n} from \"./block_storage_callbacks\";\nimport { type PluginName } from \"./block_storage\";\nimport type {\n ConfigRenderLambda,\n DeriveHref,\n ConfigRenderLambdaFlags,\n InferOutputsFromLambdas,\n} from \"./bconfig\";\nimport { downgradeCfgOrLambda, isConfigLambda } from \"./bconfig\";\nimport type { PlatformaExtended } from \"./platforma\";\nimport {\n BLOCK_STORAGE_FACADE_VERSION,\n BlockStorageFacadeCallbacks,\n BlockStorageFacadeHandles,\n registerFacadeCallbacks,\n} from \"./block_storage_facade\";\n\ntype SectionsExpectedType = readonly BlockSection[];\n\ntype NoOb = Record<string, never>;\n\n/**\n * Per-property lambdas for deriving plugin params from block render context.\n * Each property is a function that receives the block's RenderCtxBase and returns the param value.\n */\nexport type ParamsInput<Params, BArgs = unknown, BData = unknown> = {\n [K in keyof Params]: (ctx: RenderCtxBase<BArgs, BData>) => Params[K];\n};\n\n/**\n * Type-erased version of ParamsInput for internal storage.\n */\ntype ParamsInputErased = Record<string, (ctx: RenderCtxBase) => unknown>;\n\n/**\n * Merges two feature flag objects with type-aware logic:\n * - `supports*` (boolean): OR — `true` if either side is `true`\n * - `requires*` (numeric): MAX — take the higher version requirement\n */\nfunction mergeFeatureFlags(\n base: BlockCodeKnownFeatureFlags,\n override: BlockCodeKnownFeatureFlags,\n): BlockCodeKnownFeatureFlags {\n const result: Record<string, boolean | number | undefined> = { ...base };\n for (const [key, value] of Object.entries(override)) {\n if (value === undefined) continue;\n const existing = result[key];\n if (typeof value === \"boolean\") {\n result[key] = (typeof existing === \"boolean\" && existing) || value;\n } else if (typeof value === \"number\") {\n result[key] = Math.max(typeof existing === \"number\" ? existing : 0, value);\n }\n }\n return result as BlockCodeKnownFeatureFlags;\n}\n\n/**\n * Plugin record: model + param derivation lambdas.\n * Type parameters are carried by PluginModel generic.\n */\nexport type PluginRecord<\n Data extends PluginData = PluginData,\n Params extends PluginParams = undefined,\n Outputs extends PluginOutputs = PluginOutputs,\n ModelServices = unknown,\n UiServices = unknown,\n> = {\n readonly model: PluginModel<Data, Params, Outputs, ModelServices, UiServices>;\n readonly inputs: ParamsInputErased;\n};\n\ninterface BlockModelV3Config<\n OutputsCfg extends Record<string, ConfigRenderLambda>,\n Data,\n Plugins extends Record<string, PluginRecord> = {},\n Transfers extends Record<string, unknown> = {},\n> {\n renderingMode: BlockRenderingMode;\n dataModel: DataModel<Data, Transfers>;\n outputs: OutputsCfg;\n sections: ConfigRenderLambda;\n title: ConfigRenderLambda | undefined;\n subtitle: ConfigRenderLambda | undefined;\n tags: ConfigRenderLambda | undefined;\n enrichmentTargets: ConfigRenderLambda | undefined;\n featureFlags: BlockCodeKnownFeatureFlags;\n argsFunction: ((data: unknown) => unknown) | undefined;\n prerunArgsFunction: ((data: unknown) => unknown) | undefined;\n plugins: Plugins;\n}\n\n/** Main entry point that each block should use in it's \"config\" module. Don't forget\n * to call {@link done()} at the end of configuration. Value returned by this builder must be\n * exported as constant with name \"platforma\" from the \"config\" module.\n * API version is 3 (for UI) and 2 (for model) */\nexport class BlockModelV3<\n Args,\n OutputsCfg extends Record<string, ConfigRenderLambda>,\n Data extends Record<string, unknown> = Record<string, unknown>,\n Href extends `/${string}` = \"/\",\n Plugins extends Record<string, PluginRecord> = {},\n Transfers extends Record<string, unknown> = {},\n> {\n private constructor(\n private readonly config: BlockModelV3Config<OutputsCfg, Data, Plugins, Transfers>,\n ) {}\n\n public static readonly FEATURE_FLAGS = {\n supportsLazyState: true,\n supportsPframeQueryRanking: true,\n requiresUIAPIVersion: 3,\n requiresModelAPIVersion: BLOCK_STORAGE_FACADE_VERSION,\n requiresCreatePTable: 2,\n ...BLOCK_SERVICE_FLAGS,\n } satisfies BlockCodeKnownFeatureFlags;\n\n /** @deprecated Use FEATURE_FLAGS */\n public static readonly INITIAL_BLOCK_FEATURE_FLAGS = BlockModelV3.FEATURE_FLAGS;\n\n /**\n * Creates a new BlockModelV3 builder with the specified data model.\n *\n * @example\n * const dataModel = new DataModelBuilder()\n * .from<BlockData>(\"v1\")\n * .init(() => ({ numbers: [], labels: [] }));\n *\n * BlockModelV3.create(dataModel)\n * .args((data) => ({ numbers: data.numbers }))\n * .sections(() => [{ type: 'link', href: '/', label: 'Main' }])\n * .done();\n *\n * @param dataModel The data model that defines initial data and migrations\n */\n public static create<\n Data extends Record<string, unknown>,\n Transfers extends Record<string, unknown> = {},\n >(dataModel: DataModel<Data, Transfers>): BlockModelV3<NoOb, {}, Data, \"/\", {}, Transfers> {\n return new BlockModelV3<NoOb, {}, Data, \"/\", {}, Transfers>({\n renderingMode: \"Heavy\",\n dataModel,\n outputs: {},\n sections: createAndRegisterRenderLambda({ handle: \"sections\", lambda: () => [] }, true),\n title: undefined,\n subtitle: undefined,\n tags: undefined,\n enrichmentTargets: undefined,\n featureFlags: { ...BlockModelV3.FEATURE_FLAGS },\n argsFunction: undefined,\n prerunArgsFunction: undefined,\n plugins: {},\n });\n }\n\n /**\n * Add output cell wrapped with additional status information to the configuration\n *\n * @param key output cell name, that can be later used to retrieve the rendered value\n * @param rf callback calculating output value using context, that allows to access\n * workflows outputs and interact with platforma drivers\n * @param flags additional flags that may alter lambda rendering procedure\n * */\n public output<const Key extends string, const RF extends RenderFunction<Args, Data, unknown>>(\n key: Key,\n rf: RF,\n flags: ConfigRenderLambdaFlags & { withStatus: true },\n ): BlockModelV3<\n Args,\n OutputsCfg & {\n [K in Key]: ConfigRenderLambda<InferRenderFunctionReturn<RF>> & {\n withStatus: true;\n };\n },\n Data,\n Href,\n Plugins,\n Transfers\n >;\n /**\n * Add output cell to the configuration\n *\n * @param key output cell name, that can be later used to retrieve the rendered value\n * @param rf callback calculating output value using context, that allows to access\n * workflows outputs and interact with platforma drivers\n * @param flags additional flags that may alter lambda rendering procedure\n * */\n public output<const Key extends string, const RF extends RenderFunction<Args, Data, unknown>>(\n key: Key,\n rf: RF,\n flags?: ConfigRenderLambdaFlags,\n ): BlockModelV3<\n Args,\n OutputsCfg & {\n [K in Key]: ConfigRenderLambda<InferRenderFunctionReturn<RF>>;\n },\n Data,\n Href,\n Plugins,\n Transfers\n >;\n public output(\n key: string,\n cfgOrRf: RenderFunction<Args, Data, unknown>,\n flags: ConfigRenderLambdaFlags = {},\n ): BlockModelV3<Args, OutputsCfg, Data, Href, Plugins, Transfers> {\n return new BlockModelV3({\n ...this.config,\n outputs: {\n ...this.config.outputs,\n [key]: createAndRegisterRenderLambda({\n handle: `block-output#${key}`,\n lambda: () => cfgOrRf(new BlockRenderCtx<Args, Data>(blockServiceNames)),\n ...flags,\n }),\n },\n });\n }\n\n /** Shortcut for {@link output} with retentive flag set to true. */\n public retentiveOutput<\n const Key extends string,\n const RF extends RenderFunction<Args, Data, unknown>,\n >(\n key: Key,\n rf: RF,\n ): BlockModelV3<\n Args,\n OutputsCfg & {\n [K in Key]: ConfigRenderLambda<InferRenderFunctionReturn<RF>>;\n },\n Data,\n Href,\n Plugins,\n Transfers\n > {\n return this.output(key, rf, { retentive: true });\n }\n\n /** Shortcut for {@link output} with withStatus flag set to true. */\n public outputWithStatus<\n const Key extends string,\n const RF extends RenderFunction<Args, Data, unknown>,\n >(key: Key, rf: RF) {\n return this.output(key, rf, { withStatus: true });\n }\n\n /**\n * Sets a function to derive block args from data.\n * This is called during setData to compute the args that will be used for block execution.\n *\n * @example\n * .args<BlockArgs>((data) => ({ numbers: data.numbers }))\n *\n * @example\n * .args<BlockArgs>((data) => {\n * if (data.numbers.length === 0) throw new Error('Numbers required'); // block not ready\n * return { numbers: data.numbers };\n * })\n */\n public args<A>(\n lambda: (data: Data) => A,\n ): BlockModelV3<A, OutputsCfg, Data, Href, Plugins, Transfers> {\n return new BlockModelV3<A, OutputsCfg, Data, Href, Plugins, Transfers>({\n ...this.config,\n argsFunction: lambda as (data: unknown) => unknown,\n });\n }\n\n /**\n * Sets a function to derive pre-run args from data (optional).\n * This is called during setData to compute the args that will be used for staging/pre-run phase.\n *\n * If not defined, defaults to using the args() function result.\n * If defined, uses its return value for the staging / prerun phase.\n *\n * The staging / prerun phase runs only if currentPrerunArgs differs from the executed\n * version of prerunArgs (same comparison logic as currentArgs vs prodArgs).\n *\n * @example\n * .prerunArgs((data) => ({ numbers: data.numbers }))\n *\n * @example\n * .prerunArgs((data) => {\n * // Return undefined to skip staging for this block\n * if (!data.isReady) return undefined;\n * return { numbers: data.numbers };\n * })\n */\n public prerunArgs(\n fn: (data: Data) => unknown,\n ): BlockModelV3<Args, OutputsCfg, Data, Href, Plugins, Transfers> {\n return new BlockModelV3<Args, OutputsCfg, Data, Href, Plugins, Transfers>({\n ...this.config,\n prerunArgsFunction: fn as (data: unknown) => unknown,\n });\n }\n\n /** Sets the lambda to generate list of sections in the left block overviews panel. */\n public sections<\n const Ret extends SectionsExpectedType,\n const RF extends RenderFunction<Args, Data, Ret>,\n >(rf: RF): BlockModelV3<Args, OutputsCfg, Data, DeriveHref<ReturnType<RF>>, Plugins, Transfers> {\n return new BlockModelV3<Args, OutputsCfg, Data, DeriveHref<ReturnType<RF>>, Plugins, Transfers>(\n {\n ...this.config,\n // Replace the default sections callback with the user-provided one\n sections: createAndRegisterRenderLambda(\n {\n handle: \"sections\",\n lambda: () => rf(new BlockRenderCtx<Args, Data>(blockServiceNames)),\n },\n true,\n ),\n },\n );\n }\n\n /** Sets a rendering function to derive block title, shown for the block in the left blocks-overview panel. */\n public title(\n rf: RenderFunction<Args, Data, string>,\n ): BlockModelV3<Args, OutputsCfg, Data, Href, Plugins, Transfers> {\n return new BlockModelV3<Args, OutputsCfg, Data, Href, Plugins, Transfers>({\n ...this.config,\n title: createAndRegisterRenderLambda({\n handle: \"title\",\n lambda: () => rf(new BlockRenderCtx<Args, Data>(blockServiceNames)),\n }),\n });\n }\n\n public subtitle(\n rf: RenderFunction<Args, Data, string>,\n ): BlockModelV3<Args, OutputsCfg, Data, Href, Plugins, Transfers> {\n return new BlockModelV3<Args, OutputsCfg, Data, Href, Plugins, Transfers>({\n ...this.config,\n subtitle: createAndRegisterRenderLambda({\n handle: \"subtitle\",\n lambda: () => rf(new BlockRenderCtx<Args, Data>(blockServiceNames)),\n }),\n });\n }\n\n public tags(\n rf: RenderFunction<Args, Data, string[]>,\n ): BlockModelV3<Args, OutputsCfg, Data, Href, Plugins, Transfers> {\n return new BlockModelV3<Args, OutputsCfg, Data, Href, Plugins, Transfers>({\n ...this.config,\n tags: createAndRegisterRenderLambda({\n handle: \"tags\",\n lambda: () => rf(new BlockRenderCtx<Args, Data>(blockServiceNames)),\n }),\n });\n }\n\n /** Sets or overrides feature flags for the block. */\n public withFeatureFlags(\n flags: Partial<BlockCodeKnownFeatureFlags>,\n ): BlockModelV3<Args, OutputsCfg, Data, Href, Plugins, Transfers> {\n return new BlockModelV3<Args, OutputsCfg, Data, Href, Plugins, Transfers>({\n ...this.config,\n featureFlags: { ...this.config.featureFlags, ...flags },\n });\n }\n\n /**\n * Defines how to derive list of upstream references this block is meant to enrich with its exports from block args.\n * Influences dependency graph construction.\n */\n public enriches(\n lambda: (args: Args) => PlRef[],\n ): BlockModelV3<Args, OutputsCfg, Data, Href, Plugins, Transfers> {\n return new BlockModelV3<Args, OutputsCfg, Data, Href, Plugins, Transfers>({\n ...this.config,\n enrichmentTargets: createAndRegisterRenderLambda({\n handle: \"enrichmentTargets\",\n lambda: lambda,\n }),\n });\n }\n\n /**\n * Registers a plugin instance with the block.\n * Consumes a transfer if one was defined for this plugin ID in the migration chain.\n *\n * Type checks:\n * - If Transfers[Id] exists, verifies it extends PTransferData (transfer type compatibility)\n * - If no Transfers[Id], rejects plugins with transferAt set (missing .transfer() in data model)\n * - Rejects duplicate plugin IDs (Id already in keyof Plugins)\n *\n * @param instance - PluginInstance created via factory.create({ pluginId, ... })\n * @param params - Per-property lambdas deriving plugin params from block RenderCtx\n *\n * @example\n * .plugin(mainTable, {\n * columns: (ctx) => ctx.outputs?.resolve(\"data\")?.getPColumns(),\n * sourceId: (ctx) => ctx.data.selectedSource,\n * })\n */\n public plugin<\n const PluginId extends string,\n PData extends PluginData,\n PParams extends PluginParams,\n POutputs extends PluginOutputs,\n PTransferData,\n PluginModelServices,\n PluginUiServices,\n >(\n instance: PluginInstanceClass<\n PluginId &\n (PluginId extends keyof Transfers\n ? Transfers[PluginId] extends PTransferData\n ? string\n : never\n : [PTransferData] extends [never]\n ? string\n : never) &\n (PluginId extends keyof Plugins ? never : string),\n PData,\n PParams,\n POutputs,\n PTransferData,\n PluginModelServices,\n PluginUiServices\n >,\n params?: ParamsInput<PParams, Args, Data>,\n ): BlockModelV3<\n Args,\n OutputsCfg,\n Data,\n Href,\n Plugins & {\n [K in PluginId]: PluginRecord<\n PData,\n PParams,\n POutputs,\n PluginModelServices,\n PluginUiServices\n >;\n },\n Omit<Transfers, PluginId>\n >;\n public plugin(\n instance: PluginInstanceClass,\n params?: ParamsInput<Record<string, unknown>, unknown, unknown>,\n ): BlockModelV3<\n Args,\n OutputsCfg,\n Data,\n Href,\n Record<string, PluginRecord>,\n Record<string, unknown>\n > {\n const pluginId = instance.id;\n const plugin = instance[CREATE_PLUGIN_MODEL]();\n const resolvedParams = (params ?? {}) as ParamsInputErased;\n\n if (pluginId in this.config.plugins) {\n throw new Error(`Plugin '${pluginId}' already registered`);\n }\n\n const registered: PluginRecord = {\n model: plugin,\n inputs: resolvedParams,\n };\n\n return new BlockModelV3({\n ...this.config,\n plugins: {\n ...this.config.plugins,\n [pluginId]: registered,\n },\n featureFlags: mergeFeatureFlags(this.config.featureFlags, plugin.featureFlags ?? {}),\n });\n }\n\n /** Renders all provided block settings into a pre-configured platforma API\n * instance, that can be used in frontend to interact with block data, and\n * other features provided by the platforma to the block.\n *\n * Type-level check: if there are unconsumed transfers (from `.transfer()` calls\n * in the migration chain), this method requires an impossible `never` argument,\n * producing a compile error. Register all transferred plugins via `.plugin(instance)`\n * before calling `.done()`.\n */\n public done(\n ..._: keyof Transfers extends never ? [] : [never]\n ): PlatformaExtended<\n PlatformaV3<\n Data,\n Args,\n InferOutputsFromLambdas<OutputsCfg>,\n Href,\n Plugins,\n BlockDefaultUiServices\n >\n > {\n if (this.config.argsFunction === undefined) throw new Error(\"Args rendering function not set.\");\n\n const apiVersion = 3;\n\n // Build plugin registry\n const { plugins } = this.config;\n const pluginRegistry: Record<string, PluginName> = {};\n const pluginHandles = Object.keys(plugins) as PluginHandle[];\n for (const handle of pluginHandles) {\n pluginRegistry[handle] = plugins[handle].model.name;\n }\n\n const { dataModel, argsFunction, prerunArgsFunction } = this.config;\n\n const mergedServiceNames = resolveRequiredServices(this.config.featureFlags);\n\n function getPlugin(handle: PluginHandle): PluginRecord {\n const plugin = plugins[handle];\n if (!plugin) throw new Error(`Plugin model not found for '${handle}'`);\n return plugin;\n }\n\n // Register ALL facade callbacks here, with dependencies captured via closures\n registerFacadeCallbacks({\n [BlockStorageFacadeCallbacks.StorageApplyUpdate]: applyStorageUpdate,\n [BlockStorageFacadeCallbacks.StorageDebugView]: getStorageDebugView,\n [BlockStorageFacadeCallbacks.StorageMigrate]: (currentStorageJson) =>\n migrateStorage(currentStorageJson, {\n migrateBlockData: (v) => dataModel.migrate(v),\n getPluginRegistry: () => pluginRegistry,\n migratePluginData: (handle, v) => getPlugin(handle).model.dataModel.migrate(v),\n createPluginData: (handle, transfer) => {\n if (transfer) return transfer;\n return getPlugin(handle).model.getDefaultData();\n },\n }),\n [BlockStorageFacadeCallbacks.StorageInitial]: () =>\n createInitialStorage({\n getDefaultBlockData: () => dataModel.getDefaultData(),\n getPluginRegistry: () => pluginRegistry,\n createPluginData: (handle) => getPlugin(handle).model.getDefaultData(),\n }),\n [BlockStorageFacadeCallbacks.ArgsDerive]: (storageJson) =>\n deriveArgsFromStorage(storageJson, argsFunction),\n [BlockStorageFacadeCallbacks.PrerunArgsDerive]: (storageJson) =>\n derivePrerunArgsFromStorage(storageJson, argsFunction, prerunArgsFunction),\n });\n\n // Register plugin input and output lambdas\n const pluginOutputs: Record<string, ConfigRenderLambda> = {};\n for (const handle of pluginHandles) {\n const { model, inputs } = plugins[handle];\n // Wrap plugin param lambdas: close over BlockRenderCtx creation\n const wrappedInputs: Record<string, () => unknown> = {};\n for (const [paramKey, paramFn] of Object.entries(inputs)) {\n wrappedInputs[paramKey] = () => paramFn(new BlockRenderCtx(mergedServiceNames));\n }\n\n // Register plugin outputs (in config pack, evaluated by middle layer)\n const outputs = model.outputs as Record<string, (ctx: PluginRenderCtx) => unknown>;\n const { outputFlags } = model;\n for (const [outputKey, outputFn] of Object.entries(outputs)) {\n const key = pluginOutputKey(handle, outputKey);\n pluginOutputs[key] = createAndRegisterRenderLambda({\n handle: key,\n lambda: () => outputFn(new PluginRenderCtx(handle, wrappedInputs, mergedServiceNames)),\n withStatus: outputFlags[outputKey]?.withStatus,\n });\n }\n }\n const allOutputs = { ...this.config.outputs, ...pluginOutputs };\n\n globalThis.platformaApiVersion = apiVersion;\n\n if (!isInUI()) {\n const blockConfig: BlockConfigContainer = {\n v4: {\n configVersion: 4,\n modelAPIVersion: BLOCK_STORAGE_FACADE_VERSION,\n sdkVersion: PlatformaSDKVersion,\n renderingMode: this.config.renderingMode,\n sections: this.config.sections,\n title: this.config.title,\n subtitle: this.config.subtitle,\n tags: this.config.tags,\n outputs: allOutputs,\n enrichmentTargets: this.config.enrichmentTargets,\n featureFlags: this.config.featureFlags,\n blockLifecycleCallbacks: { ...BlockStorageFacadeHandles },\n },\n\n // fields below are added to allow previous desktop versions read generated configs\n sdkVersion: PlatformaSDKVersion,\n renderingMode: this.config.renderingMode,\n sections: this.config.sections,\n outputs: Object.fromEntries(\n Object.entries(this.config.outputs).map(([key, value]) => [\n key,\n downgradeCfgOrLambda(value),\n ]),\n ),\n };\n // we are in the configuration rendering routine, not in actual UI\n return { config: blockConfig } as any;\n // normal operation inside the UI\n } else {\n return {\n ...getPlatformaInstance({\n sdkVersion: PlatformaSDKVersion,\n apiVersion,\n }),\n blockModelInfo: {\n outputs: Object.fromEntries(\n Object.entries(allOutputs).map(([key, value]) => [\n key,\n {\n withStatus: Boolean(isConfigLambda(value) && value.withStatus),\n },\n ]),\n ),\n pluginIds: pluginHandles,\n featureFlags: this.config.featureFlags,\n },\n } as any;\n }\n }\n}\n\n// Type tests for BlockModelV3\n\nexport type Expect<T extends true> = T;\n\nexport type Equal<X, Y> =\n (<T>() => T extends X ? 1 : 2) extends <T>() => T extends Y ? 1 : 2 ? true : false;\n\nexport type Merge<A, B> = {\n [K in keyof A | keyof B]: K extends keyof B ? B[K] : K extends keyof A ? A[K] : never;\n};\n\n// Helper types for testing\ntype _TestArgs = { inputFile: string; threshold: number };\ntype _TestData = { selectedTab: string };\ntype _TestOutputs = {\n result: ConfigRenderLambda<string>;\n count: ConfigRenderLambda<number>;\n};\n\n// Test: Merge type works correctly\ntype _MergeTest1 = Expect<Equal<Merge<{ a: 1 }, { b: 2 }>, { a: 1; b: 2 }>>;\ntype _MergeTest2 = Expect<Equal<Merge<{ a: 1 }, { a: 2 }>, { a: 2 }>>;\ntype _MergeTest3 = Expect<Equal<Merge<{ a: 1; b: 1 }, { b: 2; c: 3 }>, { a: 1; b: 2; c: 3 }>>;\n\n// Test: create() returns a BlockModelV3 instance\n// Note: Due to function overloads, ReturnType uses the last overload signature.\n// We verify the structure is correct using a simpler assignability test.\ntype _CreateResult = ReturnType<typeof BlockModelV3.create>;\ntype _CreateIsBlockModelV3 =\n _CreateResult extends BlockModelV3<infer _A, infer _O, infer _S> ? true : false;\ntype _CreateTest = Expect<_CreateIsBlockModelV3>;\n\n// Test: BlockModelV3Config interface structure (default generics)\ntype _ConfigTest = Expect<\n Equal<\n BlockModelV3Config<_TestOutputs, _TestData>,\n {\n renderingMode: BlockRenderingMode;\n argsFunction: ((data: unknown) => unknown) | undefined;\n prerunArgsFunction: ((data: unknown) => unknown) | undefined;\n dataModel: DataModel<_TestData, {}>;\n outputs: _TestOutputs;\n sections: ConfigRenderLambda;\n title: ConfigRenderLambda | undefined;\n subtitle: ConfigRenderLambda | undefined;\n tags: ConfigRenderLambda | undefined;\n enrichmentTargets: ConfigRenderLambda | undefined;\n featureFlags: BlockCodeKnownFeatureFlags;\n plugins: {};\n }\n >\n>;\n\n// Test: Default Href is '/'\ntype _HrefDefaultTest =\n BlockModelV3<_TestArgs, {}, _TestData> extends BlockModelV3<_TestArgs, {}, _TestData, \"/\">\n ? true\n : false;\ntype _VerifyHrefDefault = Expect<_HrefDefaultTest>;\n\n// Test: Custom Href can be specified\ntype _CustomHref = \"/settings\" | \"/main\";\ntype _HrefCustomBuilder = BlockModelV3<_TestArgs, {}, _TestData, _CustomHref>;\ntype _HrefCustomTest =\n _HrefCustomBuilder extends BlockModelV3<_TestArgs, {}, _TestData, _CustomHref> ? true : false;\ntype _VerifyHrefCustom = Expect<_HrefCustomTest>;\n\n// Test: Output type accumulation with & intersection\ntype _OutputsAccumulation = { a: ConfigRenderLambda<string> } & {\n b: ConfigRenderLambda<number>;\n};\ntype _VerifyOutputsHaveKeys = Expect<Equal<keyof _OutputsAccumulation, \"a\" | \"b\">>;\n\n// Test: Builder with all type parameters specified compiles\ntype _FullBuilder = BlockModelV3<_TestArgs, _TestOutputs, _TestData, \"/main\">;\ntype _FullBuilderTest =\n _FullBuilder extends BlockModelV3<_TestArgs, _TestOutputs, _TestData, \"/main\"> ? true : false;\ntype _VerifyFullBuilder = Expect<_FullBuilderTest>;\n\n// Test: InferOutputsFromLambdas maps outputs correctly\ntype _InferOutputsTest = InferOutputsFromLambdas<{\n myOutput: ConfigRenderLambda<number>;\n}>;\ntype _VerifyInferOutputs = Expect<\n Equal<_InferOutputsTest, { myOutput: OutputWithStatus<number> & { __unwrap: true } }>\n>;\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"block_model.js","names":[],"sources":["../src/block_model.ts"],"sourcesContent":["import type {\n BlockRenderingMode,\n BlockSection,\n OutputWithStatus,\n PlRef,\n BlockCodeKnownFeatureFlags,\n BlockConfigContainer,\n} from \"@milaboratories/pl-model-common\";\nimport { resolveRequiredServices } from \"@milaboratories/pl-model-common\";\nimport { getPlatformaInstance, isInUI, createAndRegisterRenderLambda } from \"./internal\";\nimport type { DataModel } from \"./block_migrations\";\nimport type { PlatformaV3 } from \"./platforma\";\nimport type { BlockDefaultUiServices } from \"./services/service_resolve\";\nimport { blockServiceNames, BLOCK_SERVICE_FLAGS } from \"./services/block_services\";\nimport type { InferRenderFunctionReturn, RenderFunction } from \"./render\";\nimport { BlockRenderCtx, PluginRenderCtx } from \"./render\";\nimport type { PluginData, PluginModel, PluginOutputs, PluginParams } from \"./plugin_model\";\nimport { PluginInstance as PluginInstanceClass, CREATE_PLUGIN_MODEL } from \"./plugin_model\";\nimport { type PluginHandle, pluginOutputKey } from \"./plugin_handle\";\nimport type { RenderCtxBase } from \"./render\";\nimport { PlatformaSDKVersion } from \"./version\";\nimport {\n applyStorageUpdate,\n getStorageDebugView,\n migrateStorage,\n createInitialStorage,\n deriveArgsFromStorage,\n derivePrerunArgsFromStorage,\n} from \"./block_storage_callbacks\";\nimport { type PluginName } from \"./block_storage\";\nimport type {\n ConfigRenderLambda,\n DeriveHref,\n ConfigRenderLambdaFlags,\n InferOutputsFromLambdas,\n} from \"./bconfig\";\nimport { downgradeCfgOrLambda, isConfigLambda } from \"./bconfig\";\nimport type { PlatformaExtended } from \"./platforma\";\nimport {\n BLOCK_STORAGE_FACADE_VERSION,\n BlockStorageFacadeCallbacks,\n BlockStorageFacadeHandles,\n registerFacadeCallbacks,\n} from \"./block_storage_facade\";\n\ntype SectionsExpectedType = readonly BlockSection[];\n\ntype NoOb = Record<string, never>;\n\n/**\n * Per-property lambdas for deriving plugin params from block render context.\n * Each property is a function that receives the block's RenderCtxBase and returns the param value.\n */\nexport type ParamsInput<Params, BArgs = unknown, BData = unknown> = {\n [K in keyof Params]: (ctx: RenderCtxBase<BArgs, BData>) => Params[K];\n};\n\n/**\n * Type-erased version of ParamsInput for internal storage.\n */\ntype ParamsInputErased = Record<string, (ctx: RenderCtxBase) => unknown>;\n\n/**\n * Merges two feature flag objects with type-aware logic:\n * - `supports*` (boolean): OR — `true` if either side is `true`\n * - `requires*` (numeric): MAX — take the higher version requirement\n */\nfunction mergeFeatureFlags(\n base: BlockCodeKnownFeatureFlags,\n override: BlockCodeKnownFeatureFlags,\n): BlockCodeKnownFeatureFlags {\n const result: Record<string, boolean | number | undefined> = { ...base };\n for (const [key, value] of Object.entries(override)) {\n if (value === undefined) continue;\n const existing = result[key];\n if (typeof value === \"boolean\") {\n result[key] = (typeof existing === \"boolean\" && existing) || value;\n } else if (typeof value === \"number\") {\n result[key] = Math.max(typeof existing === \"number\" ? existing : 0, value);\n }\n }\n return result as BlockCodeKnownFeatureFlags;\n}\n\n/**\n * Plugin record: model + param derivation lambdas.\n * Type parameters are carried by PluginModel generic.\n */\nexport type PluginRecord<\n Data extends PluginData = PluginData,\n Params extends PluginParams = undefined,\n Outputs extends PluginOutputs = PluginOutputs,\n ModelServices = unknown,\n UiServices = unknown,\n> = {\n readonly model: PluginModel<Data, Params, Outputs, ModelServices, UiServices>;\n readonly inputs: ParamsInputErased;\n};\n\ninterface BlockModelV3Config<\n OutputsCfg extends Record<string, ConfigRenderLambda>,\n Data,\n Plugins extends Record<string, PluginRecord> = {},\n Transfers extends Record<string, unknown> = {},\n> {\n renderingMode: BlockRenderingMode;\n dataModel: DataModel<Data, Transfers>;\n outputs: OutputsCfg;\n sections: ConfigRenderLambda;\n title: ConfigRenderLambda | undefined;\n subtitle: ConfigRenderLambda | undefined;\n tags: ConfigRenderLambda | undefined;\n enrichmentTargets: ConfigRenderLambda | undefined;\n featureFlags: BlockCodeKnownFeatureFlags;\n argsFunction: ((data: unknown) => unknown) | undefined;\n prerunArgsFunction: ((data: unknown) => unknown) | undefined;\n plugins: Plugins;\n}\n\n/** Main entry point that each block should use in it's \"config\" module. Don't forget\n * to call {@link done()} at the end of configuration. Value returned by this builder must be\n * exported as constant with name \"platforma\" from the \"config\" module.\n * API version is 3 (for UI) and 2 (for model) */\nexport class BlockModelV3<\n Args,\n OutputsCfg extends Record<string, ConfigRenderLambda>,\n Data extends Record<string, unknown> = Record<string, unknown>,\n Href extends `/${string}` = \"/\",\n Plugins extends Record<string, PluginRecord> = {},\n Transfers extends Record<string, unknown> = {},\n> {\n private constructor(\n private readonly config: BlockModelV3Config<OutputsCfg, Data, Plugins, Transfers>,\n ) {}\n\n public static readonly FEATURE_FLAGS = {\n supportsLazyState: true,\n supportsPframeQueryRanking: true,\n requiresUIAPIVersion: 3,\n requiresModelAPIVersion: BLOCK_STORAGE_FACADE_VERSION,\n requiresCreatePTable: 2,\n ...BLOCK_SERVICE_FLAGS,\n } satisfies BlockCodeKnownFeatureFlags;\n\n /** @deprecated Use FEATURE_FLAGS */\n public static readonly INITIAL_BLOCK_FEATURE_FLAGS = BlockModelV3.FEATURE_FLAGS;\n\n /**\n * Creates a new BlockModelV3 builder with the specified data model.\n *\n * @example\n * const dataModel = new DataModelBuilder()\n * .from<BlockData>(\"v1\")\n * .init(() => ({ numbers: [], labels: [] }));\n *\n * BlockModelV3.create(dataModel)\n * .args((data) => ({ numbers: data.numbers }))\n * .sections(() => [{ type: 'link', href: '/', label: 'Main' }])\n * .done();\n *\n * @param dataModel The data model that defines initial data and migrations\n */\n public static create<\n Data extends Record<string, unknown>,\n Transfers extends Record<string, unknown> = {},\n >(dataModel: DataModel<Data, Transfers>): BlockModelV3<NoOb, {}, Data, \"/\", {}, Transfers> {\n return new BlockModelV3<NoOb, {}, Data, \"/\", {}, Transfers>({\n renderingMode: \"Heavy\",\n dataModel,\n outputs: {},\n sections: createAndRegisterRenderLambda({ handle: \"sections\", lambda: () => [] }, true),\n title: undefined,\n subtitle: undefined,\n tags: undefined,\n enrichmentTargets: undefined,\n featureFlags: { ...BlockModelV3.FEATURE_FLAGS },\n argsFunction: undefined,\n prerunArgsFunction: undefined,\n plugins: {},\n });\n }\n\n /**\n * Add output cell wrapped with additional status information to the configuration\n *\n * @param key output cell name, that can be later used to retrieve the rendered value\n * @param rf callback calculating output value using context, that allows to access\n * workflows outputs and interact with platforma drivers\n * @param flags additional flags that may alter lambda rendering procedure\n * */\n public output<const Key extends string, const RF extends RenderFunction<Args, Data, unknown>>(\n key: Key,\n rf: RF,\n flags: ConfigRenderLambdaFlags & { withStatus: true },\n ): BlockModelV3<\n Args,\n OutputsCfg & {\n [K in Key]: ConfigRenderLambda<InferRenderFunctionReturn<RF>> & {\n withStatus: true;\n };\n },\n Data,\n Href,\n Plugins,\n Transfers\n >;\n /**\n * Add output cell to the configuration\n *\n * @param key output cell name, that can be later used to retrieve the rendered value\n * @param rf callback calculating output value using context, that allows to access\n * workflows outputs and interact with platforma drivers\n * @param flags additional flags that may alter lambda rendering procedure\n * */\n public output<const Key extends string, const RF extends RenderFunction<Args, Data, unknown>>(\n key: Key,\n rf: RF,\n flags?: ConfigRenderLambdaFlags,\n ): BlockModelV3<\n Args,\n OutputsCfg & {\n [K in Key]: ConfigRenderLambda<InferRenderFunctionReturn<RF>>;\n },\n Data,\n Href,\n Plugins,\n Transfers\n >;\n public output(\n key: string,\n cfgOrRf: RenderFunction<Args, Data, unknown>,\n flags: ConfigRenderLambdaFlags = {},\n ): BlockModelV3<Args, OutputsCfg, Data, Href, Plugins, Transfers> {\n return new BlockModelV3({\n ...this.config,\n outputs: {\n ...this.config.outputs,\n [key]: createAndRegisterRenderLambda({\n handle: `block-output#${key}`,\n lambda: () => cfgOrRf(new BlockRenderCtx<Args, Data>(blockServiceNames)),\n ...flags,\n }),\n },\n });\n }\n\n /** Shortcut for {@link output} with retentive flag set to true. */\n public retentiveOutput<\n const Key extends string,\n const RF extends RenderFunction<Args, Data, unknown>,\n >(\n key: Key,\n rf: RF,\n ): BlockModelV3<\n Args,\n OutputsCfg & {\n [K in Key]: ConfigRenderLambda<InferRenderFunctionReturn<RF>>;\n },\n Data,\n Href,\n Plugins,\n Transfers\n > {\n return this.output(key, rf, { retentive: true });\n }\n\n /** Shortcut for {@link output} with withStatus flag set to true. */\n public outputWithStatus<\n const Key extends string,\n const RF extends RenderFunction<Args, Data, unknown>,\n >(key: Key, rf: RF) {\n return this.output(key, rf, { withStatus: true });\n }\n\n /**\n * Sets a function to derive block args from data.\n * This is called during setData to compute the args that will be used for block execution.\n *\n * @example\n * .args<BlockArgs>((data) => ({ numbers: data.numbers }))\n *\n * @example\n * .args<BlockArgs>((data) => {\n * if (data.numbers.length === 0) throw new Error('Numbers required'); // block not ready\n * return { numbers: data.numbers };\n * })\n */\n public args<A>(\n lambda: (data: Data) => A,\n ): BlockModelV3<A, OutputsCfg, Data, Href, Plugins, Transfers> {\n return new BlockModelV3<A, OutputsCfg, Data, Href, Plugins, Transfers>({\n ...this.config,\n argsFunction: lambda as (data: unknown) => unknown,\n });\n }\n\n /**\n * Sets a function to derive pre-run args from data (optional).\n * This is called during setData to compute the args that will be used for staging/pre-run phase.\n *\n * If not defined, defaults to using the args() function result.\n * If defined, uses its return value for the staging / prerun phase.\n *\n * The staging / prerun phase runs only if currentPrerunArgs differs from the executed\n * version of prerunArgs (same comparison logic as currentArgs vs prodArgs).\n *\n * @example\n * .prerunArgs((data) => ({ numbers: data.numbers }))\n *\n * @example\n * .prerunArgs((data) => {\n * // Return undefined to skip staging for this block\n * if (!data.isReady) return undefined;\n * return { numbers: data.numbers };\n * })\n */\n public prerunArgs(\n fn: (data: Data) => unknown,\n ): BlockModelV3<Args, OutputsCfg, Data, Href, Plugins, Transfers> {\n return new BlockModelV3<Args, OutputsCfg, Data, Href, Plugins, Transfers>({\n ...this.config,\n prerunArgsFunction: fn as (data: unknown) => unknown,\n });\n }\n\n /** Sets the lambda to generate list of sections in the left block overviews panel. */\n public sections<\n const Ret extends SectionsExpectedType,\n const RF extends RenderFunction<Args, Data, Ret>,\n >(rf: RF): BlockModelV3<Args, OutputsCfg, Data, DeriveHref<ReturnType<RF>>, Plugins, Transfers> {\n return new BlockModelV3<Args, OutputsCfg, Data, DeriveHref<ReturnType<RF>>, Plugins, Transfers>(\n {\n ...this.config,\n // Replace the default sections callback with the user-provided one\n sections: createAndRegisterRenderLambda(\n {\n handle: \"sections\",\n lambda: () => rf(new BlockRenderCtx<Args, Data>(blockServiceNames)),\n },\n true,\n ),\n },\n );\n }\n\n /** Sets a rendering function to derive block title, shown for the block in the left blocks-overview panel. */\n public title(\n rf: RenderFunction<Args, Data, string>,\n ): BlockModelV3<Args, OutputsCfg, Data, Href, Plugins, Transfers> {\n return new BlockModelV3<Args, OutputsCfg, Data, Href, Plugins, Transfers>({\n ...this.config,\n title: createAndRegisterRenderLambda({\n handle: \"title\",\n lambda: () => rf(new BlockRenderCtx<Args, Data>(blockServiceNames)),\n }),\n });\n }\n\n public subtitle(\n rf: RenderFunction<Args, Data, string>,\n ): BlockModelV3<Args, OutputsCfg, Data, Href, Plugins, Transfers> {\n return new BlockModelV3<Args, OutputsCfg, Data, Href, Plugins, Transfers>({\n ...this.config,\n subtitle: createAndRegisterRenderLambda({\n handle: \"subtitle\",\n lambda: () => rf(new BlockRenderCtx<Args, Data>(blockServiceNames)),\n }),\n });\n }\n\n public tags(\n rf: RenderFunction<Args, Data, string[]>,\n ): BlockModelV3<Args, OutputsCfg, Data, Href, Plugins, Transfers> {\n return new BlockModelV3<Args, OutputsCfg, Data, Href, Plugins, Transfers>({\n ...this.config,\n tags: createAndRegisterRenderLambda({\n handle: \"tags\",\n lambda: () => rf(new BlockRenderCtx<Args, Data>(blockServiceNames)),\n }),\n });\n }\n\n /** Sets or overrides feature flags for the block. */\n public withFeatureFlags(\n flags: Partial<BlockCodeKnownFeatureFlags>,\n ): BlockModelV3<Args, OutputsCfg, Data, Href, Plugins, Transfers> {\n return new BlockModelV3<Args, OutputsCfg, Data, Href, Plugins, Transfers>({\n ...this.config,\n featureFlags: { ...this.config.featureFlags, ...flags },\n });\n }\n\n /**\n * Defines how to derive list of upstream references this block is meant to enrich with its exports from block args.\n * Influences dependency graph construction.\n */\n public enriches(\n lambda: (args: Args) => PlRef[],\n ): BlockModelV3<Args, OutputsCfg, Data, Href, Plugins, Transfers> {\n return new BlockModelV3<Args, OutputsCfg, Data, Href, Plugins, Transfers>({\n ...this.config,\n enrichmentTargets: createAndRegisterRenderLambda({\n handle: \"enrichmentTargets\",\n lambda: lambda,\n }),\n });\n }\n\n /**\n * Registers a plugin instance with the block.\n * Consumes a transfer if one was defined for this plugin ID in the migration chain.\n *\n * Type checks:\n * - If Transfers[Id] exists, verifies it extends PTransferData (transfer type compatibility)\n * - If no Transfers[Id], rejects plugins with transferAt set (missing .transfer() in data model)\n * - Rejects duplicate plugin IDs (Id already in keyof Plugins)\n *\n * @param instance - PluginInstance created via factory.create({ pluginId, ... })\n * @param params - Per-property lambdas deriving plugin params from block RenderCtx\n *\n * @example\n * .plugin(mainTable, {\n * columns: (ctx) => ctx.outputs?.resolve(\"data\")?.getPColumns(),\n * sourceId: (ctx) => ctx.data.selectedSource,\n * })\n */\n public plugin<\n const PluginId extends string,\n PData extends PluginData,\n PParams extends PluginParams,\n POutputs extends PluginOutputs,\n PTransferData,\n PluginModelServices,\n PluginUiServices,\n >(\n instance: PluginInstanceClass<\n PluginId &\n (PluginId extends keyof Transfers\n ? Transfers[PluginId] extends PTransferData\n ? string\n : never\n : [PTransferData] extends [never]\n ? string\n : never) &\n (PluginId extends keyof Plugins ? never : string),\n PData,\n PParams,\n POutputs,\n PTransferData,\n PluginModelServices,\n PluginUiServices\n >,\n params?: ParamsInput<PParams, Args, Data>,\n ): BlockModelV3<\n Args,\n OutputsCfg,\n Data,\n Href,\n Plugins & {\n [K in PluginId]: PluginRecord<\n PData,\n PParams,\n POutputs,\n PluginModelServices,\n PluginUiServices\n >;\n },\n Omit<Transfers, PluginId>\n >;\n public plugin(\n instance: PluginInstanceClass,\n params?: ParamsInput<Record<string, unknown>, unknown, unknown>,\n ): BlockModelV3<\n Args,\n OutputsCfg,\n Data,\n Href,\n Record<string, PluginRecord>,\n Record<string, unknown>\n > {\n const pluginId = instance.id;\n const plugin = instance[CREATE_PLUGIN_MODEL]();\n const resolvedParams = (params ?? {}) as ParamsInputErased;\n\n if (pluginId in this.config.plugins) {\n throw new Error(`Plugin '${pluginId}' already registered`);\n }\n\n const registered: PluginRecord = {\n model: plugin,\n inputs: resolvedParams,\n };\n\n return new BlockModelV3({\n ...this.config,\n plugins: {\n ...this.config.plugins,\n [pluginId]: registered,\n },\n featureFlags: mergeFeatureFlags(this.config.featureFlags, plugin.featureFlags ?? {}),\n });\n }\n\n /** Renders all provided block settings into a pre-configured platforma API\n * instance, that can be used in frontend to interact with block data, and\n * other features provided by the platforma to the block.\n *\n * Type-level check: if there are unconsumed transfers (from `.transfer()` calls\n * in the migration chain), this method requires an impossible `never` argument,\n * producing a compile error. Register all transferred plugins via `.plugin(instance)`\n * before calling `.done()`.\n */\n public done(\n ..._: keyof Transfers extends never ? [] : [never]\n ): PlatformaExtended<\n PlatformaV3<\n Data,\n Args,\n InferOutputsFromLambdas<OutputsCfg>,\n Href,\n Plugins,\n BlockDefaultUiServices\n >\n > {\n if (this.config.argsFunction === undefined) throw new Error(\"Args rendering function not set.\");\n\n const apiVersion = 3;\n\n // Build plugin registry\n const { plugins } = this.config;\n const pluginRegistry: Record<string, PluginName> = {};\n const pluginHandles = Object.keys(plugins) as PluginHandle[];\n for (const handle of pluginHandles) {\n pluginRegistry[handle] = plugins[handle].model.name;\n }\n\n const { dataModel, argsFunction, prerunArgsFunction } = this.config;\n\n const mergedServiceNames = resolveRequiredServices(this.config.featureFlags);\n\n function getPlugin(handle: PluginHandle): PluginRecord {\n const plugin = plugins[handle];\n if (!plugin) throw new Error(`Plugin model not found for '${handle}'`);\n return plugin;\n }\n\n // Register ALL facade callbacks here, with dependencies captured via closures\n registerFacadeCallbacks({\n [BlockStorageFacadeCallbacks.StorageApplyUpdate]: applyStorageUpdate,\n [BlockStorageFacadeCallbacks.StorageDebugView]: getStorageDebugView,\n [BlockStorageFacadeCallbacks.StorageMigrate]: (currentStorageJson) =>\n migrateStorage(currentStorageJson, {\n migrateBlockData: (v) => dataModel.migrate(v),\n getPluginRegistry: () => pluginRegistry,\n migratePluginData: (handle, v) => getPlugin(handle).model.dataModel.migrate(v),\n createPluginData: (handle, transfer) => {\n if (transfer) return transfer;\n return getPlugin(handle).model.getDefaultData();\n },\n }),\n [BlockStorageFacadeCallbacks.StorageInitial]: () =>\n createInitialStorage({\n getDefaultBlockData: () => dataModel.getDefaultData(),\n getPluginRegistry: () => pluginRegistry,\n createPluginData: (handle) => getPlugin(handle).model.getDefaultData(),\n }),\n [BlockStorageFacadeCallbacks.ArgsDerive]: (storageJson) =>\n deriveArgsFromStorage(storageJson, argsFunction),\n [BlockStorageFacadeCallbacks.PrerunArgsDerive]: (storageJson) =>\n derivePrerunArgsFromStorage(storageJson, argsFunction, prerunArgsFunction),\n });\n\n // Register plugin input and output lambdas\n const pluginOutputs: Record<string, ConfigRenderLambda> = {};\n for (const handle of pluginHandles) {\n const { model, inputs } = plugins[handle];\n // Wrap plugin param lambdas: close over BlockRenderCtx creation\n const wrappedInputs: Record<string, () => unknown> = {};\n for (const [paramKey, paramFn] of Object.entries(inputs)) {\n wrappedInputs[paramKey] = () => paramFn(new BlockRenderCtx(mergedServiceNames));\n }\n\n // Register plugin outputs (in config pack, evaluated by middle layer)\n const outputs = model.outputs as Record<string, (ctx: PluginRenderCtx) => unknown>;\n const { outputFlags } = model;\n for (const [outputKey, outputFn] of Object.entries(outputs)) {\n const key = pluginOutputKey(handle, outputKey);\n pluginOutputs[key] = createAndRegisterRenderLambda({\n handle: key,\n lambda: () => outputFn(new PluginRenderCtx(handle, wrappedInputs, mergedServiceNames)),\n withStatus: outputFlags[outputKey]?.withStatus,\n });\n }\n }\n const allOutputs = { ...this.config.outputs, ...pluginOutputs };\n\n globalThis.platformaApiVersion = apiVersion;\n\n if (!isInUI()) {\n const blockConfig: BlockConfigContainer = {\n v4: {\n configVersion: 4,\n modelAPIVersion: BLOCK_STORAGE_FACADE_VERSION,\n sdkVersion: PlatformaSDKVersion,\n renderingMode: this.config.renderingMode,\n sections: this.config.sections,\n title: this.config.title,\n subtitle: this.config.subtitle,\n tags: this.config.tags,\n outputs: allOutputs,\n enrichmentTargets: this.config.enrichmentTargets,\n featureFlags: this.config.featureFlags,\n blockLifecycleCallbacks: { ...BlockStorageFacadeHandles },\n },\n\n // fields below are added to allow previous desktop versions read generated configs\n sdkVersion: PlatformaSDKVersion,\n renderingMode: this.config.renderingMode,\n sections: this.config.sections,\n outputs: Object.fromEntries(\n Object.entries(this.config.outputs).map(([key, value]) => [\n key,\n downgradeCfgOrLambda(value),\n ]),\n ),\n };\n // we are in the configuration rendering routine, not in actual UI\n return { config: blockConfig } as any;\n // normal operation inside the UI\n } else {\n return {\n ...getPlatformaInstance({\n sdkVersion: PlatformaSDKVersion,\n apiVersion,\n }),\n blockModelInfo: {\n outputs: Object.fromEntries(\n Object.entries(allOutputs).map(([key, value]) => [\n key,\n {\n withStatus: Boolean(isConfigLambda(value) && value.withStatus),\n },\n ]),\n ),\n pluginIds: pluginHandles,\n featureFlags: this.config.featureFlags,\n },\n } as any;\n }\n }\n}\n\n// Type tests for BlockModelV3\n\nexport type Expect<T extends true> = T;\n\nexport type Equal<X, Y> =\n (<T>() => T extends X ? 1 : 2) extends <T>() => T extends Y ? 1 : 2 ? true : false;\n\nexport type Merge<A, B> = {\n [K in keyof A | keyof B]: K extends keyof B ? B[K] : K extends keyof A ? A[K] : never;\n};\n\n// Helper types for testing\ntype _TestArgs = { inputFile: string; threshold: number };\ntype _TestData = { selectedTab: string };\ntype _TestOutputs = {\n result: ConfigRenderLambda<string>;\n count: ConfigRenderLambda<number>;\n};\n\n// Test: Merge type works correctly\ntype _MergeTest1 = Expect<Equal<Merge<{ a: 1 }, { b: 2 }>, { a: 1; b: 2 }>>;\ntype _MergeTest2 = Expect<Equal<Merge<{ a: 1 }, { a: 2 }>, { a: 2 }>>;\ntype _MergeTest3 = Expect<Equal<Merge<{ a: 1; b: 1 }, { b: 2; c: 3 }>, { a: 1; b: 2; c: 3 }>>;\n\n// Test: create() returns a BlockModelV3 instance\n// Note: Due to function overloads, ReturnType uses the last overload signature.\n// We verify the structure is correct using a simpler assignability test.\ntype _CreateResult = ReturnType<typeof BlockModelV3.create>;\ntype _CreateIsBlockModelV3 =\n _CreateResult extends BlockModelV3<infer _A, infer _O, infer _S> ? true : false;\ntype _CreateTest = Expect<_CreateIsBlockModelV3>;\n\n// Test: BlockModelV3Config interface structure (default generics)\ntype _ConfigTest = Expect<\n Equal<\n BlockModelV3Config<_TestOutputs, _TestData>,\n {\n renderingMode: BlockRenderingMode;\n argsFunction: ((data: unknown) => unknown) | undefined;\n prerunArgsFunction: ((data: unknown) => unknown) | undefined;\n dataModel: DataModel<_TestData, {}>;\n outputs: _TestOutputs;\n sections: ConfigRenderLambda;\n title: ConfigRenderLambda | undefined;\n subtitle: ConfigRenderLambda | undefined;\n tags: ConfigRenderLambda | undefined;\n enrichmentTargets: ConfigRenderLambda | undefined;\n featureFlags: BlockCodeKnownFeatureFlags;\n plugins: {};\n }\n >\n>;\n\n// Test: Default Href is '/'\ntype _HrefDefaultTest =\n BlockModelV3<_TestArgs, {}, _TestData> extends BlockModelV3<_TestArgs, {}, _TestData, \"/\">\n ? true\n : false;\ntype _VerifyHrefDefault = Expect<_HrefDefaultTest>;\n\n// Test: Custom Href can be specified\ntype _CustomHref = \"/settings\" | \"/main\";\ntype _HrefCustomBuilder = BlockModelV3<_TestArgs, {}, _TestData, _CustomHref>;\ntype _HrefCustomTest =\n _HrefCustomBuilder extends BlockModelV3<_TestArgs, {}, _TestData, _CustomHref> ? true : false;\ntype _VerifyHrefCustom = Expect<_HrefCustomTest>;\n\n// Test: Output type accumulation with & intersection\ntype _OutputsAccumulation = { a: ConfigRenderLambda<string> } & {\n b: ConfigRenderLambda<number>;\n};\ntype _VerifyOutputsHaveKeys = Expect<Equal<keyof _OutputsAccumulation, \"a\" | \"b\">>;\n\n// Test: Builder with all type parameters specified compiles\ntype _FullBuilder = BlockModelV3<_TestArgs, _TestOutputs, _TestData, \"/main\">;\ntype _FullBuilderTest =\n _FullBuilder extends BlockModelV3<_TestArgs, _TestOutputs, _TestData, \"/main\"> ? true : false;\ntype _VerifyFullBuilder = Expect<_FullBuilderTest>;\n\n// Test: InferOutputsFromLambdas maps outputs correctly\ntype _InferOutputsTest = InferOutputsFromLambdas<{\n myOutput: ConfigRenderLambda<number>;\n}>;\ntype _VerifyInferOutputs = Expect<\n Equal<_InferOutputsTest, { myOutput: OutputWithStatus<number> & { __unwrap: true } }>\n>;\n"],"mappings":"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"}
|