@platforma-sdk/model 1.58.5 → 1.58.9
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 +43 -0
- package/dist/_virtual/_rolldown/runtime.js +18 -0
- package/dist/annotations/converter.cjs +15 -20
- package/dist/annotations/converter.cjs.map +1 -1
- package/dist/annotations/converter.d.ts +6 -2
- package/dist/annotations/converter.js +14 -18
- package/dist/annotations/converter.js.map +1 -1
- package/dist/annotations/index.cjs +1 -0
- package/dist/annotations/index.d.ts +2 -3
- package/dist/annotations/index.js +1 -0
- package/dist/annotations/types.d.ts +21 -16
- package/dist/bconfig/index.cjs +2 -0
- package/dist/bconfig/index.d.ts +5 -6
- package/dist/bconfig/index.js +2 -0
- package/dist/bconfig/lambdas.d.ts +52 -52
- package/dist/bconfig/normalization.cjs +13 -18
- package/dist/bconfig/normalization.cjs.map +1 -1
- package/dist/bconfig/normalization.d.ts +10 -6
- package/dist/bconfig/normalization.js +12 -16
- package/dist/bconfig/normalization.js.map +1 -1
- package/dist/bconfig/types.cjs +4 -3
- package/dist/bconfig/types.cjs.map +1 -1
- package/dist/bconfig/types.d.ts +10 -5
- package/dist/bconfig/types.js +4 -2
- package/dist/bconfig/types.js.map +1 -1
- package/dist/bconfig/util.d.ts +7 -4
- package/dist/bconfig/v3.d.ts +10 -6
- package/dist/block_api_v1.d.ts +62 -58
- package/dist/block_api_v2.d.ts +51 -47
- package/dist/block_api_v3.d.ts +33 -29
- package/dist/block_migrations.cjs +481 -413
- package/dist/block_migrations.cjs.map +1 -1
- package/dist/block_migrations.d.ts +258 -204
- package/dist/block_migrations.js +482 -408
- package/dist/block_migrations.js.map +1 -1
- package/dist/block_model.cjs +312 -343
- package/dist/block_model.cjs.map +1 -1
- package/dist/block_model.d.ts +143 -147
- package/dist/block_model.js +312 -341
- package/dist/block_model.js.map +1 -1
- package/dist/block_model_legacy.cjs +231 -255
- package/dist/block_model_legacy.cjs.map +1 -1
- package/dist/block_model_legacy.d.ts +108 -106
- package/dist/block_model_legacy.js +231 -253
- package/dist/block_model_legacy.js.map +1 -1
- package/dist/block_state_patch.d.ts +10 -10
- package/dist/block_state_util.cjs +15 -19
- package/dist/block_state_util.cjs.map +1 -1
- package/dist/block_state_util.d.ts +14 -13
- package/dist/block_state_util.js +15 -18
- package/dist/block_state_util.js.map +1 -1
- package/dist/block_storage.cjs +233 -238
- package/dist/block_storage.cjs.map +1 -1
- package/dist/block_storage.d.ts +62 -78
- package/dist/block_storage.js +234 -237
- package/dist/block_storage.js.map +1 -1
- package/dist/block_storage_callbacks.cjs +156 -195
- package/dist/block_storage_callbacks.cjs.map +1 -1
- package/dist/block_storage_callbacks.js +156 -192
- package/dist/block_storage_callbacks.js.map +1 -1
- package/dist/block_storage_facade.cjs +29 -85
- package/dist/block_storage_facade.cjs.map +1 -1
- package/dist/block_storage_facade.d.ts +83 -126
- package/dist/block_storage_facade.js +29 -83
- package/dist/block_storage_facade.js.map +1 -1
- package/dist/components/PFrameForGraphs.cjs +26 -24
- package/dist/components/PFrameForGraphs.cjs.map +1 -1
- package/dist/components/PFrameForGraphs.d.ts +12 -7
- package/dist/components/PFrameForGraphs.js +25 -22
- package/dist/components/PFrameForGraphs.js.map +1 -1
- package/dist/components/PlAnnotations/filter.d.ts +62 -79
- package/dist/components/PlAnnotations/filters_ui.cjs +135 -171
- package/dist/components/PlAnnotations/filters_ui.cjs.map +1 -1
- package/dist/components/PlAnnotations/filters_ui.d.ts +48 -46
- package/dist/components/PlAnnotations/filters_ui.js +135 -170
- package/dist/components/PlAnnotations/filters_ui.js.map +1 -1
- package/dist/components/PlAnnotations/index.d.ts +2 -3
- package/dist/components/PlDataTable/index.cjs +2 -0
- package/dist/components/PlDataTable/index.d.ts +3 -5
- package/dist/components/PlDataTable/index.js +2 -0
- package/dist/components/PlDataTable/labels.cjs +59 -81
- package/dist/components/PlDataTable/labels.cjs.map +1 -1
- package/dist/components/PlDataTable/labels.js +58 -79
- package/dist/components/PlDataTable/labels.js.map +1 -1
- package/dist/components/PlDataTable/state-migration.cjs +186 -144
- package/dist/components/PlDataTable/state-migration.cjs.map +1 -1
- package/dist/components/PlDataTable/state-migration.d.ts +85 -82
- package/dist/components/PlDataTable/state-migration.js +185 -142
- package/dist/components/PlDataTable/state-migration.js.map +1 -1
- package/dist/components/PlDataTable/table.cjs +172 -194
- package/dist/components/PlDataTable/table.cjs.map +1 -1
- package/dist/components/PlDataTable/table.d.ts +16 -12
- package/dist/components/PlDataTable/table.js +171 -192
- package/dist/components/PlDataTable/table.js.map +1 -1
- package/dist/components/PlDataTable/v4.d.ts +84 -119
- package/dist/components/PlDataTable/v5.d.ts +80 -103
- package/dist/components/PlMultiSequenceAlignment.cjs +27 -29
- package/dist/components/PlMultiSequenceAlignment.cjs.map +1 -1
- package/dist/components/PlMultiSequenceAlignment.d.ts +36 -27
- package/dist/components/PlMultiSequenceAlignment.js +26 -27
- package/dist/components/PlMultiSequenceAlignment.js.map +1 -1
- package/dist/components/PlSelectionModel.cjs +7 -6
- package/dist/components/PlSelectionModel.cjs.map +1 -1
- package/dist/components/PlSelectionModel.d.ts +10 -8
- package/dist/components/PlSelectionModel.js +7 -5
- package/dist/components/PlSelectionModel.js.map +1 -1
- package/dist/components/index.cjs +8 -0
- package/dist/components/index.d.ts +11 -6
- package/dist/components/index.js +8 -0
- package/dist/config/actions.cjs +138 -171
- package/dist/config/actions.cjs.map +1 -1
- package/dist/config/actions.d.ts +47 -47
- package/dist/config/actions.js +146 -178
- package/dist/config/actions.js.map +1 -1
- package/dist/config/actions_kinds.d.ts +114 -121
- package/dist/config/index.cjs +1 -0
- package/dist/config/index.d.ts +6 -7
- package/dist/config/index.js +1 -0
- package/dist/config/model.d.ts +131 -127
- package/dist/config/model_meta.d.ts +4 -1
- package/dist/config/type_engine.d.ts +22 -21
- package/dist/config/type_util.d.ts +12 -10
- package/dist/env_value.cjs +5 -6
- package/dist/env_value.cjs.map +1 -1
- package/dist/env_value.d.ts +4 -1
- package/dist/env_value.js +5 -5
- package/dist/env_value.js.map +1 -1
- package/dist/filters/converters/filterToQuery.cjs +273 -239
- package/dist/filters/converters/filterToQuery.cjs.map +1 -1
- package/dist/filters/converters/filterToQuery.d.ts +6 -2
- package/dist/filters/converters/filterToQuery.js +272 -237
- package/dist/filters/converters/filterToQuery.js.map +1 -1
- package/dist/filters/converters/filterUiToExpressionImpl.cjs +56 -85
- package/dist/filters/converters/filterUiToExpressionImpl.cjs.map +1 -1
- package/dist/filters/converters/filterUiToExpressionImpl.d.ts +8 -4
- package/dist/filters/converters/filterUiToExpressionImpl.js +55 -83
- package/dist/filters/converters/filterUiToExpressionImpl.js.map +1 -1
- package/dist/filters/converters/index.cjs +2 -0
- package/dist/filters/converters/index.d.ts +2 -3
- package/dist/filters/converters/index.js +2 -0
- package/dist/filters/distill.cjs +59 -60
- package/dist/filters/distill.cjs.map +1 -1
- package/dist/filters/distill.d.ts +6 -3
- package/dist/filters/distill.js +58 -58
- package/dist/filters/distill.js.map +1 -1
- package/dist/filters/index.cjs +4 -0
- package/dist/filters/index.d.ts +5 -4
- package/dist/filters/index.js +4 -0
- package/dist/filters/traverse.cjs +31 -40
- package/dist/filters/traverse.cjs.map +1 -1
- package/dist/filters/traverse.js +31 -39
- package/dist/filters/traverse.js.map +1 -1
- package/dist/filters/types.d.ts +10 -7
- package/dist/index.cjs +193 -187
- package/dist/index.d.ts +61 -28
- package/dist/index.js +49 -41
- package/dist/internal.cjs +48 -62
- package/dist/internal.cjs.map +1 -1
- package/dist/internal.js +49 -60
- package/dist/internal.js.map +1 -1
- package/dist/package.cjs +12 -0
- package/dist/package.cjs.map +1 -0
- package/dist/package.js +6 -0
- package/dist/package.js.map +1 -0
- package/dist/pframe.cjs +32 -37
- package/dist/pframe.cjs.map +1 -1
- package/dist/pframe.d.ts +14 -10
- package/dist/pframe.js +32 -35
- package/dist/pframe.js.map +1 -1
- package/dist/pframe_utils/axes.cjs +81 -114
- package/dist/pframe_utils/axes.cjs.map +1 -1
- package/dist/pframe_utils/axes.d.ts +10 -13
- package/dist/pframe_utils/axes.js +80 -112
- package/dist/pframe_utils/axes.js.map +1 -1
- package/dist/pframe_utils/columns.cjs +61 -81
- package/dist/pframe_utils/columns.cjs.map +1 -1
- package/dist/pframe_utils/columns.d.ts +15 -6
- package/dist/pframe_utils/columns.js +60 -79
- package/dist/pframe_utils/columns.js.map +1 -1
- package/dist/pframe_utils/index.cjs +232 -253
- package/dist/pframe_utils/index.cjs.map +1 -1
- package/dist/pframe_utils/index.d.ts +39 -35
- package/dist/pframe_utils/index.js +231 -251
- package/dist/pframe_utils/index.js.map +1 -1
- package/dist/platforma.d.ts +48 -46
- package/dist/plugin_handle.cjs +6 -14
- package/dist/plugin_handle.cjs.map +1 -1
- package/dist/plugin_handle.d.ts +20 -25
- package/dist/plugin_handle.js +6 -13
- package/dist/plugin_handle.js.map +1 -1
- package/dist/plugin_model.cjs +364 -163
- package/dist/plugin_model.cjs.map +1 -1
- package/dist/plugin_model.d.ts +280 -129
- package/dist/plugin_model.js +362 -163
- package/dist/plugin_model.js.map +1 -1
- package/dist/raw_globals.cjs +10 -22
- package/dist/raw_globals.cjs.map +1 -1
- package/dist/raw_globals.d.ts +8 -5
- package/dist/raw_globals.js +10 -20
- package/dist/raw_globals.js.map +1 -1
- package/dist/ref_util.cjs +14 -13
- package/dist/ref_util.cjs.map +1 -1
- package/dist/ref_util.d.ts +18 -12
- package/dist/ref_util.js +14 -11
- package/dist/ref_util.js.map +1 -1
- package/dist/render/accessor.cjs +213 -226
- package/dist/render/accessor.cjs.map +1 -1
- package/dist/render/accessor.d.ts +115 -120
- package/dist/render/accessor.js +212 -224
- package/dist/render/accessor.js.map +1 -1
- package/dist/render/api.cjs +478 -580
- package/dist/render/api.cjs.map +1 -1
- package/dist/render/api.d.ts +207 -209
- package/dist/render/api.js +476 -578
- package/dist/render/api.js.map +1 -1
- package/dist/render/future.cjs +28 -32
- package/dist/render/future.cjs.map +1 -1
- package/dist/render/future.d.ts +15 -11
- package/dist/render/future.js +28 -30
- package/dist/render/future.js.map +1 -1
- package/dist/render/index.cjs +8 -0
- package/dist/render/index.d.ts +10 -8
- package/dist/render/index.js +8 -0
- package/dist/render/internal.cjs +33 -29
- package/dist/render/internal.cjs.map +1 -1
- package/dist/render/internal.d.ts +78 -72
- package/dist/render/internal.js +29 -26
- package/dist/render/internal.js.map +1 -1
- package/dist/render/traversal_ops.d.ts +42 -43
- package/dist/render/util/axis_filtering.cjs +63 -86
- package/dist/render/util/axis_filtering.cjs.map +1 -1
- package/dist/render/util/axis_filtering.d.ts +10 -7
- package/dist/render/util/axis_filtering.js +63 -85
- package/dist/render/util/axis_filtering.js.map +1 -1
- package/dist/render/util/column_collection.cjs +266 -321
- package/dist/render/util/column_collection.cjs.map +1 -1
- package/dist/render/util/column_collection.d.ts +47 -47
- package/dist/render/util/column_collection.js +264 -319
- package/dist/render/util/column_collection.js.map +1 -1
- package/dist/render/util/index.cjs +4 -0
- package/dist/render/util/index.d.ts +4 -5
- package/dist/render/util/index.js +4 -0
- package/dist/render/util/label.cjs +129 -163
- package/dist/render/util/label.cjs.map +1 -1
- package/dist/render/util/label.d.ts +45 -46
- package/dist/render/util/label.js +128 -161
- package/dist/render/util/label.js.map +1 -1
- package/dist/render/util/pcolumn_data.cjs +315 -375
- package/dist/render/util/pcolumn_data.cjs.map +1 -1
- package/dist/render/util/pcolumn_data.d.ts +33 -32
- package/dist/render/util/pcolumn_data.js +314 -373
- package/dist/render/util/pcolumn_data.js.map +1 -1
- package/dist/render/util/pframe_upgraders.cjs +37 -42
- package/dist/render/util/pframe_upgraders.cjs.map +1 -1
- package/dist/render/util/pframe_upgraders.js +37 -41
- package/dist/render/util/pframe_upgraders.js.map +1 -1
- package/dist/render/util/split_selectors.d.ts +13 -9
- package/dist/version.cjs +6 -8
- package/dist/version.cjs.map +1 -1
- package/dist/version.d.ts +7 -4
- package/dist/version.js +5 -5
- package/dist/version.js.map +1 -1
- package/package.json +10 -4
- package/src/block_migrations.test.ts +184 -14
- package/src/block_migrations.ts +185 -30
- package/src/block_model.ts +111 -66
- package/src/block_storage.test.ts +147 -3
- package/src/block_storage.ts +43 -8
- package/src/block_storage_callbacks.ts +9 -4
- package/src/env_value.ts +0 -2
- package/src/index.ts +12 -11
- package/src/internal.ts +0 -1
- package/src/platforma.ts +4 -4
- package/src/plugin_handle.ts +1 -1
- package/src/plugin_model.test.ts +217 -21
- package/src/plugin_model.ts +450 -55
- package/src/raw_globals.ts +0 -1
- package/dist/annotations/converter.d.ts.map +0 -1
- package/dist/annotations/index.d.ts.map +0 -1
- package/dist/annotations/types.d.ts.map +0 -1
- package/dist/bconfig/index.d.ts.map +0 -1
- package/dist/bconfig/lambdas.d.ts.map +0 -1
- package/dist/bconfig/normalization.d.ts.map +0 -1
- package/dist/bconfig/types.d.ts.map +0 -1
- package/dist/bconfig/util.d.ts.map +0 -1
- package/dist/bconfig/v3.d.ts.map +0 -1
- package/dist/block_api_v1.d.ts.map +0 -1
- package/dist/block_api_v2.d.ts.map +0 -1
- package/dist/block_api_v3.d.ts.map +0 -1
- package/dist/block_migrations.d.ts.map +0 -1
- package/dist/block_model.d.ts.map +0 -1
- package/dist/block_model_legacy.d.ts.map +0 -1
- package/dist/block_state_patch.d.ts.map +0 -1
- package/dist/block_state_util.d.ts.map +0 -1
- package/dist/block_storage.d.ts.map +0 -1
- package/dist/block_storage_callbacks.d.ts +0 -115
- package/dist/block_storage_callbacks.d.ts.map +0 -1
- package/dist/block_storage_facade.d.ts.map +0 -1
- package/dist/components/PFrameForGraphs.d.ts.map +0 -1
- package/dist/components/PlAnnotations/filter.d.ts.map +0 -1
- package/dist/components/PlAnnotations/filters_ui.d.ts.map +0 -1
- package/dist/components/PlAnnotations/index.d.ts.map +0 -1
- package/dist/components/PlAnnotations/types.d.ts +0 -3
- package/dist/components/PlAnnotations/types.d.ts.map +0 -1
- package/dist/components/PlDataTable/index.d.ts.map +0 -1
- package/dist/components/PlDataTable/labels.d.ts +0 -7
- package/dist/components/PlDataTable/labels.d.ts.map +0 -1
- package/dist/components/PlDataTable/state-migration.d.ts.map +0 -1
- package/dist/components/PlDataTable/table.d.ts.map +0 -1
- package/dist/components/PlDataTable/v4.d.ts.map +0 -1
- package/dist/components/PlDataTable/v5.d.ts.map +0 -1
- package/dist/components/PlMultiSequenceAlignment.d.ts.map +0 -1
- package/dist/components/PlSelectionModel.d.ts.map +0 -1
- package/dist/components/index.d.ts.map +0 -1
- package/dist/config/actions.d.ts.map +0 -1
- package/dist/config/actions_kinds.d.ts.map +0 -1
- package/dist/config/index.d.ts.map +0 -1
- package/dist/config/model.d.ts.map +0 -1
- package/dist/config/model_meta.d.ts.map +0 -1
- package/dist/config/type_engine.d.ts.map +0 -1
- package/dist/config/type_util.d.ts.map +0 -1
- package/dist/env_value.d.ts.map +0 -1
- package/dist/filters/converters/filterToQuery.d.ts.map +0 -1
- package/dist/filters/converters/filterUiToExpressionImpl.d.ts.map +0 -1
- package/dist/filters/converters/index.d.ts.map +0 -1
- package/dist/filters/distill.d.ts.map +0 -1
- package/dist/filters/index.d.ts.map +0 -1
- package/dist/filters/traverse.d.ts +0 -27
- package/dist/filters/traverse.d.ts.map +0 -1
- package/dist/filters/types.d.ts.map +0 -1
- package/dist/index.cjs.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/internal.d.ts +0 -36
- package/dist/internal.d.ts.map +0 -1
- package/dist/package.json.cjs +0 -6
- package/dist/package.json.cjs.map +0 -1
- package/dist/package.json.js +0 -4
- package/dist/package.json.js.map +0 -1
- package/dist/pframe.d.ts.map +0 -1
- package/dist/pframe_utils/axes.d.ts.map +0 -1
- package/dist/pframe_utils/columns.d.ts.map +0 -1
- package/dist/pframe_utils/index.d.ts.map +0 -1
- package/dist/pframe_utils/querySpec.d.ts +0 -2
- package/dist/pframe_utils/querySpec.d.ts.map +0 -1
- package/dist/platforma.d.ts.map +0 -1
- package/dist/plugin_handle.d.ts.map +0 -1
- package/dist/plugin_model.d.ts.map +0 -1
- package/dist/raw_globals.d.ts.map +0 -1
- package/dist/ref_util.d.ts.map +0 -1
- package/dist/render/accessor.d.ts.map +0 -1
- package/dist/render/api.d.ts.map +0 -1
- package/dist/render/future.d.ts.map +0 -1
- package/dist/render/index.d.ts.map +0 -1
- package/dist/render/internal.d.ts.map +0 -1
- package/dist/render/traversal_ops.d.ts.map +0 -1
- package/dist/render/util/axis_filtering.d.ts.map +0 -1
- package/dist/render/util/column_collection.d.ts.map +0 -1
- package/dist/render/util/index.d.ts.map +0 -1
- package/dist/render/util/label.d.ts.map +0 -1
- package/dist/render/util/pcolumn_data.d.ts.map +0 -1
- package/dist/render/util/pframe_upgraders.d.ts +0 -3
- package/dist/render/util/pframe_upgraders.d.ts.map +0 -1
- package/dist/render/util/split_selectors.d.ts.map +0 -1
- package/dist/version.d.ts.map +0 -1
package/src/block_model.ts
CHANGED
|
@@ -12,6 +12,7 @@ import type { PlatformaV3 } from "./platforma";
|
|
|
12
12
|
import type { InferRenderFunctionReturn, RenderFunction } from "./render";
|
|
13
13
|
import { BlockRenderCtx, PluginRenderCtx } from "./render";
|
|
14
14
|
import type { PluginData, PluginModel, PluginOutputs, PluginParams } from "./plugin_model";
|
|
15
|
+
import { PluginInstance as PluginInstanceClass, CREATE_PLUGIN_MODEL } from "./plugin_model";
|
|
15
16
|
import { type PluginHandle, pluginOutputKey } from "./plugin_handle";
|
|
16
17
|
import type { RenderCtxBase } from "./render";
|
|
17
18
|
import { PlatformaSDKVersion } from "./version";
|
|
@@ -79,10 +80,10 @@ function mergeFeatureFlags(
|
|
|
79
80
|
}
|
|
80
81
|
|
|
81
82
|
/**
|
|
82
|
-
*
|
|
83
|
+
* Plugin record: model + param derivation lambdas.
|
|
83
84
|
* Type parameters are carried by PluginModel generic.
|
|
84
85
|
*/
|
|
85
|
-
export type
|
|
86
|
+
export type PluginRecord<
|
|
86
87
|
Data extends PluginData = PluginData,
|
|
87
88
|
Params extends PluginParams = undefined,
|
|
88
89
|
Outputs extends PluginOutputs = PluginOutputs,
|
|
@@ -94,10 +95,11 @@ export type PluginInstance<
|
|
|
94
95
|
interface BlockModelV3Config<
|
|
95
96
|
OutputsCfg extends Record<string, ConfigRenderLambda>,
|
|
96
97
|
Data,
|
|
97
|
-
Plugins extends Record<string,
|
|
98
|
+
Plugins extends Record<string, PluginRecord> = {},
|
|
99
|
+
Transfers extends Record<string, unknown> = {},
|
|
98
100
|
> {
|
|
99
101
|
renderingMode: BlockRenderingMode;
|
|
100
|
-
dataModel: DataModel<Data>;
|
|
102
|
+
dataModel: DataModel<Data, Transfers>;
|
|
101
103
|
outputs: OutputsCfg;
|
|
102
104
|
sections: ConfigRenderLambda;
|
|
103
105
|
title: ConfigRenderLambda | undefined;
|
|
@@ -119,9 +121,12 @@ export class BlockModelV3<
|
|
|
119
121
|
OutputsCfg extends Record<string, ConfigRenderLambda>,
|
|
120
122
|
Data extends Record<string, unknown> = Record<string, unknown>,
|
|
121
123
|
Href extends `/${string}` = "/",
|
|
122
|
-
Plugins extends Record<string,
|
|
124
|
+
Plugins extends Record<string, PluginRecord> = {},
|
|
125
|
+
Transfers extends Record<string, unknown> = {},
|
|
123
126
|
> {
|
|
124
|
-
private constructor(
|
|
127
|
+
private constructor(
|
|
128
|
+
private readonly config: BlockModelV3Config<OutputsCfg, Data, Plugins, Transfers>,
|
|
129
|
+
) {}
|
|
125
130
|
|
|
126
131
|
public static readonly INITIAL_BLOCK_FEATURE_FLAGS: BlockCodeKnownFeatureFlags = {
|
|
127
132
|
supportsLazyState: true,
|
|
@@ -145,10 +150,11 @@ export class BlockModelV3<
|
|
|
145
150
|
*
|
|
146
151
|
* @param dataModel The data model that defines initial data and migrations
|
|
147
152
|
*/
|
|
148
|
-
public static create<
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
153
|
+
public static create<
|
|
154
|
+
Data extends Record<string, unknown>,
|
|
155
|
+
Transfers extends Record<string, unknown> = {},
|
|
156
|
+
>(dataModel: DataModel<Data, Transfers>): BlockModelV3<NoOb, {}, Data, "/", {}, Transfers> {
|
|
157
|
+
return new BlockModelV3<NoOb, {}, Data, "/", {}, Transfers>({
|
|
152
158
|
renderingMode: "Heavy",
|
|
153
159
|
dataModel,
|
|
154
160
|
outputs: {},
|
|
@@ -185,7 +191,8 @@ export class BlockModelV3<
|
|
|
185
191
|
},
|
|
186
192
|
Data,
|
|
187
193
|
Href,
|
|
188
|
-
Plugins
|
|
194
|
+
Plugins,
|
|
195
|
+
Transfers
|
|
189
196
|
>;
|
|
190
197
|
/**
|
|
191
198
|
* Add output cell to the configuration
|
|
@@ -206,13 +213,14 @@ export class BlockModelV3<
|
|
|
206
213
|
},
|
|
207
214
|
Data,
|
|
208
215
|
Href,
|
|
209
|
-
Plugins
|
|
216
|
+
Plugins,
|
|
217
|
+
Transfers
|
|
210
218
|
>;
|
|
211
219
|
public output(
|
|
212
220
|
key: string,
|
|
213
221
|
cfgOrRf: RenderFunction<Args, Data, unknown>,
|
|
214
222
|
flags: ConfigRenderLambdaFlags = {},
|
|
215
|
-
): BlockModelV3<Args, OutputsCfg, Data, Href, Plugins> {
|
|
223
|
+
): BlockModelV3<Args, OutputsCfg, Data, Href, Plugins, Transfers> {
|
|
216
224
|
return new BlockModelV3({
|
|
217
225
|
...this.config,
|
|
218
226
|
outputs: {
|
|
@@ -240,7 +248,8 @@ export class BlockModelV3<
|
|
|
240
248
|
},
|
|
241
249
|
Data,
|
|
242
250
|
Href,
|
|
243
|
-
Plugins
|
|
251
|
+
Plugins,
|
|
252
|
+
Transfers
|
|
244
253
|
> {
|
|
245
254
|
return this.output(key, rf, { retentive: true });
|
|
246
255
|
}
|
|
@@ -266,10 +275,10 @@ export class BlockModelV3<
|
|
|
266
275
|
* return { numbers: data.numbers };
|
|
267
276
|
* })
|
|
268
277
|
*/
|
|
269
|
-
public args<
|
|
270
|
-
lambda: (data: Data) =>
|
|
271
|
-
): BlockModelV3<
|
|
272
|
-
return new BlockModelV3<
|
|
278
|
+
public args<A>(
|
|
279
|
+
lambda: (data: Data) => A,
|
|
280
|
+
): BlockModelV3<A, OutputsCfg, Data, Href, Plugins, Transfers> {
|
|
281
|
+
return new BlockModelV3<A, OutputsCfg, Data, Href, Plugins, Transfers>({
|
|
273
282
|
...this.config,
|
|
274
283
|
argsFunction: lambda as (data: unknown) => unknown,
|
|
275
284
|
});
|
|
@@ -297,8 +306,8 @@ export class BlockModelV3<
|
|
|
297
306
|
*/
|
|
298
307
|
public prerunArgs(
|
|
299
308
|
fn: (data: Data) => unknown,
|
|
300
|
-
): BlockModelV3<Args, OutputsCfg, Data, Href, Plugins> {
|
|
301
|
-
return new BlockModelV3<Args, OutputsCfg, Data, Href, Plugins>({
|
|
309
|
+
): BlockModelV3<Args, OutputsCfg, Data, Href, Plugins, Transfers> {
|
|
310
|
+
return new BlockModelV3<Args, OutputsCfg, Data, Href, Plugins, Transfers>({
|
|
302
311
|
...this.config,
|
|
303
312
|
prerunArgsFunction: fn as (data: unknown) => unknown,
|
|
304
313
|
});
|
|
@@ -308,22 +317,24 @@ export class BlockModelV3<
|
|
|
308
317
|
public sections<
|
|
309
318
|
const Ret extends SectionsExpectedType,
|
|
310
319
|
const RF extends RenderFunction<Args, Data, Ret>,
|
|
311
|
-
>(rf: RF): BlockModelV3<Args, OutputsCfg, Data, DeriveHref<ReturnType<RF>>, Plugins> {
|
|
312
|
-
return new BlockModelV3<Args, OutputsCfg, Data, DeriveHref<ReturnType<RF>>, Plugins>(
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
+
>(rf: RF): BlockModelV3<Args, OutputsCfg, Data, DeriveHref<ReturnType<RF>>, Plugins, Transfers> {
|
|
321
|
+
return new BlockModelV3<Args, OutputsCfg, Data, DeriveHref<ReturnType<RF>>, Plugins, Transfers>(
|
|
322
|
+
{
|
|
323
|
+
...this.config,
|
|
324
|
+
// Replace the default sections callback with the user-provided one
|
|
325
|
+
sections: createAndRegisterRenderLambda(
|
|
326
|
+
{ handle: "sections", lambda: () => rf(new BlockRenderCtx<Args, Data>()) },
|
|
327
|
+
true,
|
|
328
|
+
),
|
|
329
|
+
},
|
|
330
|
+
);
|
|
320
331
|
}
|
|
321
332
|
|
|
322
333
|
/** Sets a rendering function to derive block title, shown for the block in the left blocks-overview panel. */
|
|
323
334
|
public title(
|
|
324
335
|
rf: RenderFunction<Args, Data, string>,
|
|
325
|
-
): BlockModelV3<Args, OutputsCfg, Data, Href, Plugins> {
|
|
326
|
-
return new BlockModelV3<Args, OutputsCfg, Data, Href, Plugins>({
|
|
336
|
+
): BlockModelV3<Args, OutputsCfg, Data, Href, Plugins, Transfers> {
|
|
337
|
+
return new BlockModelV3<Args, OutputsCfg, Data, Href, Plugins, Transfers>({
|
|
327
338
|
...this.config,
|
|
328
339
|
title: createAndRegisterRenderLambda({
|
|
329
340
|
handle: "title",
|
|
@@ -334,8 +345,8 @@ export class BlockModelV3<
|
|
|
334
345
|
|
|
335
346
|
public subtitle(
|
|
336
347
|
rf: RenderFunction<Args, Data, string>,
|
|
337
|
-
): BlockModelV3<Args, OutputsCfg, Data, Href, Plugins> {
|
|
338
|
-
return new BlockModelV3<Args, OutputsCfg, Data, Href, Plugins>({
|
|
348
|
+
): BlockModelV3<Args, OutputsCfg, Data, Href, Plugins, Transfers> {
|
|
349
|
+
return new BlockModelV3<Args, OutputsCfg, Data, Href, Plugins, Transfers>({
|
|
339
350
|
...this.config,
|
|
340
351
|
subtitle: createAndRegisterRenderLambda({
|
|
341
352
|
handle: "subtitle",
|
|
@@ -346,8 +357,8 @@ export class BlockModelV3<
|
|
|
346
357
|
|
|
347
358
|
public tags(
|
|
348
359
|
rf: RenderFunction<Args, Data, string[]>,
|
|
349
|
-
): BlockModelV3<Args, OutputsCfg, Data, Href, Plugins> {
|
|
350
|
-
return new BlockModelV3<Args, OutputsCfg, Data, Href, Plugins>({
|
|
360
|
+
): BlockModelV3<Args, OutputsCfg, Data, Href, Plugins, Transfers> {
|
|
361
|
+
return new BlockModelV3<Args, OutputsCfg, Data, Href, Plugins, Transfers>({
|
|
351
362
|
...this.config,
|
|
352
363
|
tags: createAndRegisterRenderLambda({
|
|
353
364
|
handle: "tags",
|
|
@@ -359,8 +370,8 @@ export class BlockModelV3<
|
|
|
359
370
|
/** Sets or overrides feature flags for the block. */
|
|
360
371
|
public withFeatureFlags(
|
|
361
372
|
flags: Partial<BlockCodeKnownFeatureFlags>,
|
|
362
|
-
): BlockModelV3<Args, OutputsCfg, Data, Href, Plugins> {
|
|
363
|
-
return new BlockModelV3<Args, OutputsCfg, Data, Href, Plugins>({
|
|
373
|
+
): BlockModelV3<Args, OutputsCfg, Data, Href, Plugins, Transfers> {
|
|
374
|
+
return new BlockModelV3<Args, OutputsCfg, Data, Href, Plugins, Transfers>({
|
|
364
375
|
...this.config,
|
|
365
376
|
featureFlags: { ...this.config.featureFlags, ...flags },
|
|
366
377
|
});
|
|
@@ -372,8 +383,8 @@ export class BlockModelV3<
|
|
|
372
383
|
*/
|
|
373
384
|
public enriches(
|
|
374
385
|
lambda: (args: Args) => PlRef[],
|
|
375
|
-
): BlockModelV3<Args, OutputsCfg, Data, Href, Plugins> {
|
|
376
|
-
return new BlockModelV3<Args, OutputsCfg, Data, Href, Plugins>({
|
|
386
|
+
): BlockModelV3<Args, OutputsCfg, Data, Href, Plugins, Transfers> {
|
|
387
|
+
return new BlockModelV3<Args, OutputsCfg, Data, Href, Plugins, Transfers>({
|
|
377
388
|
...this.config,
|
|
378
389
|
enrichmentTargets: createAndRegisterRenderLambda({
|
|
379
390
|
handle: "enrichmentTargets",
|
|
@@ -384,16 +395,18 @@ export class BlockModelV3<
|
|
|
384
395
|
|
|
385
396
|
/**
|
|
386
397
|
* Registers a plugin instance with the block.
|
|
398
|
+
* Consumes a transfer if one was defined for this plugin ID in the migration chain.
|
|
387
399
|
*
|
|
388
|
-
*
|
|
389
|
-
*
|
|
400
|
+
* Type checks:
|
|
401
|
+
* - If Transfers[Id] exists, verifies it extends PTransferData (transfer type compatibility)
|
|
402
|
+
* - If no Transfers[Id], rejects plugins with transferAt set (missing .transfer() in data model)
|
|
403
|
+
* - Rejects duplicate plugin IDs (Id already in keyof Plugins)
|
|
390
404
|
*
|
|
391
|
-
* @param
|
|
392
|
-
* @param plugin - Configured PluginModel instance (created via factory.create(config))
|
|
405
|
+
* @param instance - PluginInstance created via factory.create({ pluginId, ... })
|
|
393
406
|
* @param params - Per-property lambdas deriving plugin params from block RenderCtx
|
|
394
407
|
*
|
|
395
408
|
* @example
|
|
396
|
-
* .plugin(
|
|
409
|
+
* .plugin(mainTable, {
|
|
397
410
|
* columns: (ctx) => ctx.outputs?.resolve("data")?.getPColumns(),
|
|
398
411
|
* sourceId: (ctx) => ctx.data.selectedSource,
|
|
399
412
|
* })
|
|
@@ -403,32 +416,61 @@ export class BlockModelV3<
|
|
|
403
416
|
PData extends PluginData,
|
|
404
417
|
PParams extends PluginParams,
|
|
405
418
|
POutputs extends PluginOutputs,
|
|
419
|
+
PTransferData,
|
|
406
420
|
>(
|
|
407
|
-
|
|
408
|
-
|
|
421
|
+
instance: PluginInstanceClass<
|
|
422
|
+
PluginId &
|
|
423
|
+
(PluginId extends keyof Transfers
|
|
424
|
+
? Transfers[PluginId] extends PTransferData
|
|
425
|
+
? string
|
|
426
|
+
: never
|
|
427
|
+
: [PTransferData] extends [never]
|
|
428
|
+
? string
|
|
429
|
+
: never) &
|
|
430
|
+
(PluginId extends keyof Plugins ? never : string),
|
|
431
|
+
PData,
|
|
432
|
+
PParams,
|
|
433
|
+
POutputs,
|
|
434
|
+
PTransferData
|
|
435
|
+
>,
|
|
409
436
|
params?: ParamsInput<PParams, Args, Data>,
|
|
410
437
|
): BlockModelV3<
|
|
411
438
|
Args,
|
|
412
439
|
OutputsCfg,
|
|
413
440
|
Data,
|
|
414
441
|
Href,
|
|
415
|
-
Plugins & { [K in PluginId]:
|
|
442
|
+
Plugins & { [K in PluginId]: PluginRecord<PData, PParams, POutputs> },
|
|
443
|
+
Omit<Transfers, PluginId>
|
|
444
|
+
>;
|
|
445
|
+
public plugin(
|
|
446
|
+
instance: PluginInstanceClass,
|
|
447
|
+
params?: ParamsInput<Record<string, unknown>, unknown, unknown>,
|
|
448
|
+
): BlockModelV3<
|
|
449
|
+
Args,
|
|
450
|
+
OutputsCfg,
|
|
451
|
+
Data,
|
|
452
|
+
Href,
|
|
453
|
+
Record<string, PluginRecord>,
|
|
454
|
+
Record<string, unknown>
|
|
416
455
|
> {
|
|
417
|
-
|
|
456
|
+
const pluginId = instance.id;
|
|
457
|
+
const plugin = instance[CREATE_PLUGIN_MODEL]();
|
|
458
|
+
const resolvedParams = (params ?? {}) as ParamsInputErased;
|
|
459
|
+
|
|
418
460
|
if (pluginId in this.config.plugins) {
|
|
419
461
|
throw new Error(`Plugin '${pluginId}' already registered`);
|
|
420
462
|
}
|
|
421
463
|
|
|
422
|
-
const
|
|
464
|
+
const registered: PluginRecord = {
|
|
423
465
|
model: plugin,
|
|
424
|
-
inputs:
|
|
466
|
+
inputs: resolvedParams,
|
|
425
467
|
};
|
|
426
468
|
|
|
427
469
|
return new BlockModelV3({
|
|
428
470
|
...this.config,
|
|
429
471
|
plugins: {
|
|
430
472
|
...this.config.plugins,
|
|
431
|
-
[pluginId]:
|
|
473
|
+
[pluginId]: registered,
|
|
432
474
|
},
|
|
433
475
|
featureFlags: mergeFeatureFlags(this.config.featureFlags, plugin.featureFlags ?? {}),
|
|
434
476
|
});
|
|
@@ -436,16 +478,16 @@ export class BlockModelV3<
|
|
|
436
478
|
|
|
437
479
|
/** Renders all provided block settings into a pre-configured platforma API
|
|
438
480
|
* instance, that can be used in frontend to interact with block data, and
|
|
439
|
-
* other features provided by the platforma to the block.
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
481
|
+
* other features provided by the platforma to the block.
|
|
482
|
+
*
|
|
483
|
+
* Type-level check: if there are unconsumed transfers (from `.transfer()` calls
|
|
484
|
+
* in the migration chain), this method requires an impossible `never` argument,
|
|
485
|
+
* producing a compile error. Register all transferred plugins via `.plugin(instance)`
|
|
486
|
+
* before calling `.done()`.
|
|
487
|
+
*/
|
|
488
|
+
public done(
|
|
489
|
+
..._: keyof Transfers extends never ? [] : [never]
|
|
490
|
+
): PlatformaExtended<
|
|
449
491
|
PlatformaV3<Data, Args, InferOutputsFromLambdas<OutputsCfg>, Href, Plugins>
|
|
450
492
|
> {
|
|
451
493
|
if (this.config.argsFunction === undefined) throw new Error("Args rendering function not set.");
|
|
@@ -462,7 +504,7 @@ export class BlockModelV3<
|
|
|
462
504
|
|
|
463
505
|
const { dataModel, argsFunction, prerunArgsFunction } = this.config;
|
|
464
506
|
|
|
465
|
-
function getPlugin(handle: PluginHandle):
|
|
507
|
+
function getPlugin(handle: PluginHandle): PluginRecord {
|
|
466
508
|
const plugin = plugins[handle];
|
|
467
509
|
if (!plugin) throw new Error(`Plugin model not found for '${handle}'`);
|
|
468
510
|
return plugin;
|
|
@@ -477,13 +519,16 @@ export class BlockModelV3<
|
|
|
477
519
|
migrateBlockData: (v) => dataModel.migrate(v),
|
|
478
520
|
getPluginRegistry: () => pluginRegistry,
|
|
479
521
|
migratePluginData: (handle, v) => getPlugin(handle).model.dataModel.migrate(v),
|
|
480
|
-
createPluginData: (handle) =>
|
|
522
|
+
createPluginData: (handle, transfer) => {
|
|
523
|
+
if (transfer) return transfer;
|
|
524
|
+
return getPlugin(handle).model.getDefaultData();
|
|
525
|
+
},
|
|
481
526
|
}),
|
|
482
527
|
[BlockStorageFacadeCallbacks.StorageInitial]: () =>
|
|
483
528
|
createInitialStorage({
|
|
484
529
|
getDefaultBlockData: () => dataModel.getDefaultData(),
|
|
485
530
|
getPluginRegistry: () => pluginRegistry,
|
|
486
|
-
createPluginData: (handle) => getPlugin(handle).model.
|
|
531
|
+
createPluginData: (handle) => getPlugin(handle).model.getDefaultData(),
|
|
487
532
|
}),
|
|
488
533
|
[BlockStorageFacadeCallbacks.ArgsDerive]: (storageJson) =>
|
|
489
534
|
deriveArgsFromStorage(storageJson, argsFunction),
|
|
@@ -600,7 +645,7 @@ type _CreateIsBlockModelV3 =
|
|
|
600
645
|
_CreateResult extends BlockModelV3<infer _A, infer _O, infer _S> ? true : false;
|
|
601
646
|
type _CreateTest = Expect<_CreateIsBlockModelV3>;
|
|
602
647
|
|
|
603
|
-
// Test: BlockModelV3Config interface structure
|
|
648
|
+
// Test: BlockModelV3Config interface structure (default generics)
|
|
604
649
|
type _ConfigTest = Expect<
|
|
605
650
|
Equal<
|
|
606
651
|
BlockModelV3Config<_TestOutputs, _TestData>,
|
|
@@ -608,7 +653,7 @@ type _ConfigTest = Expect<
|
|
|
608
653
|
renderingMode: BlockRenderingMode;
|
|
609
654
|
argsFunction: ((data: unknown) => unknown) | undefined;
|
|
610
655
|
prerunArgsFunction: ((data: unknown) => unknown) | undefined;
|
|
611
|
-
dataModel: DataModel<_TestData>;
|
|
656
|
+
dataModel: DataModel<_TestData, {}>;
|
|
612
657
|
outputs: _TestOutputs;
|
|
613
658
|
sections: ConfigRenderLambda;
|
|
614
659
|
title: ConfigRenderLambda | undefined;
|
|
@@ -14,6 +14,7 @@ import {
|
|
|
14
14
|
type PluginName,
|
|
15
15
|
type PluginRegistry,
|
|
16
16
|
} from "./block_storage";
|
|
17
|
+
import { DataUnrecoverableError } from "./block_migrations";
|
|
17
18
|
import type { PluginHandle } from "./plugin_handle";
|
|
18
19
|
|
|
19
20
|
describe("BlockStorage", () => {
|
|
@@ -284,7 +285,7 @@ describe("BlockStorage", () => {
|
|
|
284
285
|
const result = migrateBlockStorage(storage, {
|
|
285
286
|
migrateBlockData: (versioned) => {
|
|
286
287
|
const d = versioned.data as { count: number };
|
|
287
|
-
return { data: { count: d.count + 1 }, version: "v2" };
|
|
288
|
+
return { data: { count: d.count + 1 }, version: "v2", transfers: {} };
|
|
288
289
|
},
|
|
289
290
|
migratePluginData: (_pluginId, _versioned) => ({
|
|
290
291
|
version: "v2",
|
|
@@ -338,6 +339,7 @@ describe("BlockStorage", () => {
|
|
|
338
339
|
migrateBlockData: (versioned) => ({
|
|
339
340
|
data: versioned.data as { count: number },
|
|
340
341
|
version: "v2",
|
|
342
|
+
transfers: {},
|
|
341
343
|
}),
|
|
342
344
|
migratePluginData: (pluginId) => {
|
|
343
345
|
throw new Error(`Plugin ${pluginId} migration failed`);
|
|
@@ -353,7 +355,7 @@ describe("BlockStorage", () => {
|
|
|
353
355
|
}
|
|
354
356
|
});
|
|
355
357
|
|
|
356
|
-
it("should
|
|
358
|
+
it("should pass DATA_MODEL_LEGACY_VERSION when plugin type changes (upgradeLegacy handles it)", () => {
|
|
357
359
|
const storage = createTestStorage();
|
|
358
360
|
const newRegistry: PluginRegistry = { plugin1: "typeB" as PluginName }; // Different type
|
|
359
361
|
|
|
@@ -361,9 +363,43 @@ describe("BlockStorage", () => {
|
|
|
361
363
|
migrateBlockData: (versioned) => ({
|
|
362
364
|
data: versioned.data as { count: number },
|
|
363
365
|
version: "v2",
|
|
366
|
+
transfers: {},
|
|
367
|
+
}),
|
|
368
|
+
migratePluginData: (_handle, versioned) => {
|
|
369
|
+
// Version should be reset to DATA_MODEL_LEGACY_VERSION
|
|
370
|
+
expect(versioned.version).toBe(DATA_MODEL_LEGACY_VERSION);
|
|
371
|
+
return {
|
|
372
|
+
version: "upgraded",
|
|
373
|
+
data: { upgraded: true, from: versioned.data },
|
|
374
|
+
};
|
|
375
|
+
},
|
|
376
|
+
newPluginRegistry: newRegistry,
|
|
377
|
+
createPluginData: () => {
|
|
378
|
+
throw new Error("Should not be called when upgradeLegacy succeeds");
|
|
379
|
+
},
|
|
380
|
+
});
|
|
381
|
+
|
|
382
|
+
expect(result.success).toBe(true);
|
|
383
|
+
if (result.success) {
|
|
384
|
+
expect(result.storage.__plugins?.plugin1).toEqual({
|
|
385
|
+
__dataVersion: "upgraded",
|
|
386
|
+
__data: { upgraded: true, from: { value: "old" } },
|
|
387
|
+
});
|
|
388
|
+
}
|
|
389
|
+
});
|
|
390
|
+
|
|
391
|
+
it("should fall back to createPluginData when plugin type changes and no upgradeLegacy", () => {
|
|
392
|
+
const storage = createTestStorage();
|
|
393
|
+
const newRegistry: PluginRegistry = { plugin1: "typeB" as PluginName }; // Different type
|
|
394
|
+
|
|
395
|
+
const result = migrateBlockStorage(storage, {
|
|
396
|
+
migrateBlockData: (versioned) => ({
|
|
397
|
+
data: versioned.data as { count: number },
|
|
398
|
+
version: "v2",
|
|
399
|
+
transfers: {},
|
|
364
400
|
}),
|
|
365
401
|
migratePluginData: () => {
|
|
366
|
-
throw new
|
|
402
|
+
throw new DataUnrecoverableError(DATA_MODEL_LEGACY_VERSION);
|
|
367
403
|
},
|
|
368
404
|
newPluginRegistry: newRegistry,
|
|
369
405
|
createPluginData: (pluginId) => ({
|
|
@@ -389,6 +425,7 @@ describe("BlockStorage", () => {
|
|
|
389
425
|
migrateBlockData: (versioned) => ({
|
|
390
426
|
data: versioned.data as { count: number },
|
|
391
427
|
version: "v2",
|
|
428
|
+
transfers: {},
|
|
392
429
|
}),
|
|
393
430
|
migratePluginData: () => {
|
|
394
431
|
throw new Error("Should not be called for new plugin");
|
|
@@ -417,6 +454,7 @@ describe("BlockStorage", () => {
|
|
|
417
454
|
migrateBlockData: (versioned) => ({
|
|
418
455
|
data: versioned.data as { count: number },
|
|
419
456
|
version: "v2",
|
|
457
|
+
transfers: {},
|
|
420
458
|
}),
|
|
421
459
|
migratePluginData: () => {
|
|
422
460
|
throw new Error("Should not be called for dropped plugin");
|
|
@@ -442,6 +480,7 @@ describe("BlockStorage", () => {
|
|
|
442
480
|
migrateBlockData: (versioned) => ({
|
|
443
481
|
data: versioned.data as { count: number },
|
|
444
482
|
version: "v2",
|
|
483
|
+
transfers: {},
|
|
445
484
|
}),
|
|
446
485
|
migratePluginData: () => undefined, // Remove plugin
|
|
447
486
|
newPluginRegistry: newRegistry,
|
|
@@ -453,5 +492,110 @@ describe("BlockStorage", () => {
|
|
|
453
492
|
expect(result.storage.__plugins).toEqual({});
|
|
454
493
|
}
|
|
455
494
|
});
|
|
495
|
+
|
|
496
|
+
it("should pass transfer data to createPluginData for new plugins", () => {
|
|
497
|
+
const storage = createBlockStorage({ count: 1, tableState: "expanded" }, "v1");
|
|
498
|
+
const newRegistry: PluginRegistry = { table1: "dataTable" as PluginName };
|
|
499
|
+
|
|
500
|
+
const result = migrateBlockStorage(storage, {
|
|
501
|
+
migrateBlockData: (versioned) => ({
|
|
502
|
+
data: { count: (versioned.data as any).count },
|
|
503
|
+
version: "v2",
|
|
504
|
+
transfers: {
|
|
505
|
+
table1: { version: "__legacy__", data: { state: (versioned.data as any).tableState } },
|
|
506
|
+
},
|
|
507
|
+
}),
|
|
508
|
+
migratePluginData: () => {
|
|
509
|
+
throw new Error("Should not be called for new plugin");
|
|
510
|
+
},
|
|
511
|
+
newPluginRegistry: newRegistry,
|
|
512
|
+
createPluginData: (_handle, transfer) => {
|
|
513
|
+
// Transfer should be passed through
|
|
514
|
+
if (transfer) {
|
|
515
|
+
return { version: "v1", data: { upgraded: true, fromState: transfer.data } };
|
|
516
|
+
}
|
|
517
|
+
return { version: "v1", data: { upgraded: false } };
|
|
518
|
+
},
|
|
519
|
+
});
|
|
520
|
+
|
|
521
|
+
expect(result.success).toBe(true);
|
|
522
|
+
if (result.success) {
|
|
523
|
+
expect(result.storage.__plugins?.table1).toEqual({
|
|
524
|
+
__dataVersion: "v1",
|
|
525
|
+
__data: { upgraded: true, fromState: { state: "expanded" } },
|
|
526
|
+
});
|
|
527
|
+
}
|
|
528
|
+
});
|
|
529
|
+
|
|
530
|
+
it("should not pass transfer to existing plugin with same type (uses migration instead)", () => {
|
|
531
|
+
const storage = createTestStorage(); // has plugin1 of typeA
|
|
532
|
+
const newRegistry: PluginRegistry = { plugin1: "typeA" as PluginName };
|
|
533
|
+
|
|
534
|
+
const result = migrateBlockStorage(storage, {
|
|
535
|
+
migrateBlockData: (versioned) => ({
|
|
536
|
+
data: versioned.data,
|
|
537
|
+
version: "v2",
|
|
538
|
+
transfers: {
|
|
539
|
+
plugin1: { version: "__legacy__", data: { should: "be ignored" } },
|
|
540
|
+
},
|
|
541
|
+
}),
|
|
542
|
+
migratePluginData: (_handle, versioned) => ({
|
|
543
|
+
version: "v2",
|
|
544
|
+
data: { migrated: true, from: versioned.data },
|
|
545
|
+
}),
|
|
546
|
+
newPluginRegistry: newRegistry,
|
|
547
|
+
createPluginData: () => {
|
|
548
|
+
throw new Error("Should not be called — existing plugin migrates");
|
|
549
|
+
},
|
|
550
|
+
});
|
|
551
|
+
|
|
552
|
+
expect(result.success).toBe(true);
|
|
553
|
+
if (result.success) {
|
|
554
|
+
expect(result.storage.__plugins?.plugin1).toEqual({
|
|
555
|
+
__dataVersion: "v2",
|
|
556
|
+
__data: { migrated: true, from: { value: "old" } },
|
|
557
|
+
});
|
|
558
|
+
}
|
|
559
|
+
});
|
|
560
|
+
|
|
561
|
+
it("should handle multiple plugins: one transferred, one fresh", () => {
|
|
562
|
+
const storage = createBlockStorage({ count: 1 }, "v1");
|
|
563
|
+
const newRegistry: PluginRegistry = {
|
|
564
|
+
transferred: "typeT" as PluginName,
|
|
565
|
+
fresh: "typeF" as PluginName,
|
|
566
|
+
};
|
|
567
|
+
|
|
568
|
+
const result = migrateBlockStorage(storage, {
|
|
569
|
+
migrateBlockData: (versioned) => ({
|
|
570
|
+
data: versioned.data,
|
|
571
|
+
version: "v2",
|
|
572
|
+
transfers: {
|
|
573
|
+
transferred: { version: "__legacy__", data: { legacy: true } },
|
|
574
|
+
},
|
|
575
|
+
}),
|
|
576
|
+
migratePluginData: () => {
|
|
577
|
+
throw new Error("No existing plugins to migrate");
|
|
578
|
+
},
|
|
579
|
+
newPluginRegistry: newRegistry,
|
|
580
|
+
createPluginData: (_handle, transfer) => {
|
|
581
|
+
if (transfer) {
|
|
582
|
+
return { version: "v1", data: { fromTransfer: transfer.data } };
|
|
583
|
+
}
|
|
584
|
+
return { version: "v1", data: { default: true } };
|
|
585
|
+
},
|
|
586
|
+
});
|
|
587
|
+
|
|
588
|
+
expect(result.success).toBe(true);
|
|
589
|
+
if (result.success) {
|
|
590
|
+
expect(result.storage.__plugins?.transferred).toEqual({
|
|
591
|
+
__dataVersion: "v1",
|
|
592
|
+
__data: { fromTransfer: { legacy: true } },
|
|
593
|
+
});
|
|
594
|
+
expect(result.storage.__plugins?.fresh).toEqual({
|
|
595
|
+
__dataVersion: "v1",
|
|
596
|
+
__data: { default: true },
|
|
597
|
+
});
|
|
598
|
+
}
|
|
599
|
+
});
|
|
456
600
|
});
|
|
457
601
|
});
|
package/src/block_storage.ts
CHANGED
|
@@ -10,7 +10,11 @@
|
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
12
|
import type { Branded } from "@milaboratories/pl-model-common";
|
|
13
|
-
import
|
|
13
|
+
import {
|
|
14
|
+
type DataVersioned,
|
|
15
|
+
type TransferRecord,
|
|
16
|
+
isDataUnrecoverableError,
|
|
17
|
+
} from "./block_migrations";
|
|
14
18
|
import type { PluginHandle, PluginFactoryLike, InferFactoryData } from "./plugin_handle";
|
|
15
19
|
|
|
16
20
|
// =============================================================================
|
|
@@ -258,8 +262,10 @@ export type MigrationResult<TState> = MigrationSuccess<TState> | MigrationFailur
|
|
|
258
262
|
* Conversion to internal VersionedData format is handled by migrateBlockStorage().
|
|
259
263
|
*/
|
|
260
264
|
export interface MigrateBlockStorageConfig {
|
|
261
|
-
/** Migrate block data from any version to latest.
|
|
262
|
-
migrateBlockData: (versioned: DataVersioned<unknown>) => DataVersioned<unknown
|
|
265
|
+
/** Migrate block data from any version to latest. Returns migrated data and transfers. */
|
|
266
|
+
migrateBlockData: (versioned: DataVersioned<unknown>) => DataVersioned<unknown> & {
|
|
267
|
+
transfers: TransferRecord;
|
|
268
|
+
};
|
|
263
269
|
/** Migrate each plugin's data. Return undefined to remove the plugin. Throws on failure. */
|
|
264
270
|
migratePluginData: (
|
|
265
271
|
handle: PluginHandle,
|
|
@@ -267,8 +273,12 @@ export interface MigrateBlockStorageConfig {
|
|
|
267
273
|
) => DataVersioned<unknown> | undefined;
|
|
268
274
|
/** The new plugin registry after migration (pluginId -> pluginName) */
|
|
269
275
|
newPluginRegistry: PluginRegistry;
|
|
270
|
-
/** Factory to create initial data for new plugins
|
|
271
|
-
|
|
276
|
+
/** Factory to create initial data for new plugins. Transfer is provided when a
|
|
277
|
+
* .transfer() was defined for this plugin in the block's migration chain. */
|
|
278
|
+
createPluginData: (
|
|
279
|
+
handle: PluginHandle,
|
|
280
|
+
transfer?: DataVersioned<unknown>,
|
|
281
|
+
) => DataVersioned<unknown>;
|
|
272
282
|
}
|
|
273
283
|
|
|
274
284
|
/**
|
|
@@ -317,13 +327,15 @@ export function migrateBlockStorage(
|
|
|
317
327
|
): MigrationResult<unknown> {
|
|
318
328
|
const { migrateBlockData, migratePluginData, newPluginRegistry, createPluginData } = config;
|
|
319
329
|
|
|
320
|
-
// Step 1: Migrate block data
|
|
330
|
+
// Step 1: Migrate block data and collect transfers
|
|
321
331
|
let migratedData: unknown;
|
|
322
332
|
let newVersion: string;
|
|
333
|
+
let transfers: TransferRecord;
|
|
323
334
|
try {
|
|
324
335
|
const result = migrateBlockData({ version: storage.__dataVersion, data: storage.__data });
|
|
325
336
|
migratedData = result.data;
|
|
326
337
|
newVersion = result.version;
|
|
338
|
+
transfers = result.transfers;
|
|
327
339
|
} catch (error) {
|
|
328
340
|
return {
|
|
329
341
|
success: false,
|
|
@@ -353,9 +365,32 @@ export function migrateBlockStorage(
|
|
|
353
365
|
newPlugins[handle] = { __dataVersion: migrated.version, __data: migrated.data };
|
|
354
366
|
}
|
|
355
367
|
// If undefined returned, plugin is intentionally removed
|
|
368
|
+
} else if (existingEntry) {
|
|
369
|
+
// Plugin type changed — pass old data with DATA_MODEL_LEGACY_VERSION.
|
|
370
|
+
// If the new plugin has upgradeLegacy(), it migrates the old data.
|
|
371
|
+
// If not, defaultRecover throws DataUnrecoverableError → fall back to init.
|
|
372
|
+
let recovered = false;
|
|
373
|
+
try {
|
|
374
|
+
const migrated = migratePluginData(handle, {
|
|
375
|
+
version: DATA_MODEL_LEGACY_VERSION,
|
|
376
|
+
data: existingEntry.__data,
|
|
377
|
+
});
|
|
378
|
+
if (migrated) {
|
|
379
|
+
newPlugins[handle] = { __dataVersion: migrated.version, __data: migrated.data };
|
|
380
|
+
recovered = true;
|
|
381
|
+
}
|
|
382
|
+
} catch (recoverError) {
|
|
383
|
+
if (!isDataUnrecoverableError(recoverError)) throw recoverError;
|
|
384
|
+
}
|
|
385
|
+
if (!recovered) {
|
|
386
|
+
const transfer = transfers[handle];
|
|
387
|
+
const initial = createPluginData(handle, transfer);
|
|
388
|
+
newPlugins[handle] = { __dataVersion: initial.version, __data: initial.data };
|
|
389
|
+
}
|
|
356
390
|
} else {
|
|
357
|
-
// New plugin
|
|
358
|
-
const
|
|
391
|
+
// New plugin - create with initial data, passing transfer if available
|
|
392
|
+
const transfer = transfers[handle];
|
|
393
|
+
const initial = createPluginData(handle, transfer);
|
|
359
394
|
newPlugins[handle] = { __dataVersion: initial.version, __data: initial.data };
|
|
360
395
|
}
|
|
361
396
|
} catch (error) {
|