@platforma-sdk/model 1.54.10 → 1.55.0

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.
Files changed (151) hide show
  1. package/dist/bconfig/normalization.cjs +8 -1
  2. package/dist/bconfig/normalization.cjs.map +1 -1
  3. package/dist/bconfig/normalization.d.ts.map +1 -1
  4. package/dist/bconfig/normalization.js +8 -1
  5. package/dist/bconfig/normalization.js.map +1 -1
  6. package/dist/block_api_v3.d.ts +2 -2
  7. package/dist/block_api_v3.d.ts.map +1 -1
  8. package/dist/block_migrations.cjs +246 -214
  9. package/dist/block_migrations.cjs.map +1 -1
  10. package/dist/block_migrations.d.ts +180 -158
  11. package/dist/block_migrations.d.ts.map +1 -1
  12. package/dist/block_migrations.js +247 -214
  13. package/dist/block_migrations.js.map +1 -1
  14. package/dist/block_model.cjs +85 -35
  15. package/dist/block_model.cjs.map +1 -1
  16. package/dist/block_model.d.ts +66 -38
  17. package/dist/block_model.d.ts.map +1 -1
  18. package/dist/block_model.js +86 -36
  19. package/dist/block_model.js.map +1 -1
  20. package/dist/{builder.cjs → block_model_legacy.cjs} +2 -2
  21. package/dist/block_model_legacy.cjs.map +1 -0
  22. package/dist/{builder.d.ts → block_model_legacy.d.ts} +1 -1
  23. package/dist/block_model_legacy.d.ts.map +1 -0
  24. package/dist/{builder.js → block_model_legacy.js} +2 -2
  25. package/dist/block_model_legacy.js.map +1 -0
  26. package/dist/block_state_patch.d.ts +11 -1
  27. package/dist/block_state_patch.d.ts.map +1 -1
  28. package/dist/block_storage.cjs +126 -109
  29. package/dist/block_storage.cjs.map +1 -1
  30. package/dist/block_storage.d.ts +109 -112
  31. package/dist/block_storage.d.ts.map +1 -1
  32. package/dist/block_storage.js +126 -101
  33. package/dist/block_storage.js.map +1 -1
  34. package/dist/block_storage_callbacks.cjs +227 -0
  35. package/dist/block_storage_callbacks.cjs.map +1 -0
  36. package/dist/block_storage_callbacks.d.ts +113 -0
  37. package/dist/block_storage_callbacks.d.ts.map +1 -0
  38. package/dist/block_storage_callbacks.js +218 -0
  39. package/dist/block_storage_callbacks.js.map +1 -0
  40. package/dist/block_storage_facade.cjs +104 -0
  41. package/dist/block_storage_facade.cjs.map +1 -0
  42. package/dist/block_storage_facade.d.ts +168 -0
  43. package/dist/block_storage_facade.d.ts.map +1 -0
  44. package/dist/block_storage_facade.js +99 -0
  45. package/dist/block_storage_facade.js.map +1 -0
  46. package/dist/components/PlDataTable/state-migration.cjs.map +1 -1
  47. package/dist/components/PlDataTable/state-migration.js.map +1 -1
  48. package/dist/components/PlDataTable/table.cjs +11 -2
  49. package/dist/components/PlDataTable/table.cjs.map +1 -1
  50. package/dist/components/PlDataTable/table.d.ts.map +1 -1
  51. package/dist/components/PlDataTable/table.js +12 -3
  52. package/dist/components/PlDataTable/table.js.map +1 -1
  53. package/dist/components/PlDataTable/v5.d.ts +7 -4
  54. package/dist/components/PlDataTable/v5.d.ts.map +1 -1
  55. package/dist/filters/converters/filterToQuery.cjs +3 -4
  56. package/dist/filters/converters/filterToQuery.cjs.map +1 -1
  57. package/dist/filters/converters/filterToQuery.d.ts +1 -1
  58. package/dist/filters/converters/filterToQuery.d.ts.map +1 -1
  59. package/dist/filters/converters/filterToQuery.js +3 -4
  60. package/dist/filters/converters/filterToQuery.js.map +1 -1
  61. package/dist/filters/distill.cjs.map +1 -1
  62. package/dist/filters/distill.d.ts +3 -2
  63. package/dist/filters/distill.d.ts.map +1 -1
  64. package/dist/filters/distill.js.map +1 -1
  65. package/dist/filters/traverse.cjs +7 -3
  66. package/dist/filters/traverse.cjs.map +1 -1
  67. package/dist/filters/traverse.d.ts +14 -12
  68. package/dist/filters/traverse.d.ts.map +1 -1
  69. package/dist/filters/traverse.js +7 -3
  70. package/dist/filters/traverse.js.map +1 -1
  71. package/dist/index.cjs +13 -14
  72. package/dist/index.cjs.map +1 -1
  73. package/dist/index.d.ts +8 -3
  74. package/dist/index.d.ts.map +1 -1
  75. package/dist/index.js +6 -4
  76. package/dist/index.js.map +1 -1
  77. package/dist/package.json.cjs +1 -1
  78. package/dist/package.json.js +1 -1
  79. package/dist/platforma.d.ts +11 -4
  80. package/dist/platforma.d.ts.map +1 -1
  81. package/dist/plugin_model.cjs +171 -0
  82. package/dist/plugin_model.cjs.map +1 -0
  83. package/dist/plugin_model.d.ts +162 -0
  84. package/dist/plugin_model.d.ts.map +1 -0
  85. package/dist/plugin_model.js +169 -0
  86. package/dist/plugin_model.js.map +1 -0
  87. package/dist/render/api.cjs +20 -21
  88. package/dist/render/api.cjs.map +1 -1
  89. package/dist/render/api.d.ts +8 -8
  90. package/dist/render/api.d.ts.map +1 -1
  91. package/dist/render/api.js +20 -21
  92. package/dist/render/api.js.map +1 -1
  93. package/dist/render/internal.cjs.map +1 -1
  94. package/dist/render/internal.d.ts +1 -1
  95. package/dist/render/internal.d.ts.map +1 -1
  96. package/dist/render/internal.js.map +1 -1
  97. package/dist/version.cjs +4 -0
  98. package/dist/version.cjs.map +1 -1
  99. package/dist/version.d.ts +4 -0
  100. package/dist/version.d.ts.map +1 -1
  101. package/dist/version.js +4 -1
  102. package/dist/version.js.map +1 -1
  103. package/package.json +6 -6
  104. package/src/bconfig/normalization.ts +8 -1
  105. package/src/block_api_v3.ts +2 -2
  106. package/src/block_migrations.test.ts +141 -171
  107. package/src/block_migrations.ts +300 -285
  108. package/src/block_model.ts +205 -95
  109. package/src/{builder.ts → block_model_legacy.ts} +1 -1
  110. package/src/block_state_patch.ts +13 -1
  111. package/src/block_storage.test.ts +283 -95
  112. package/src/block_storage.ts +199 -188
  113. package/src/block_storage_callbacks.ts +326 -0
  114. package/src/block_storage_facade.ts +199 -0
  115. package/src/components/PlDataTable/state-migration.ts +4 -4
  116. package/src/components/PlDataTable/table.ts +16 -3
  117. package/src/components/PlDataTable/v5.ts +9 -5
  118. package/src/filters/converters/filterToQuery.ts +8 -7
  119. package/src/filters/distill.ts +19 -11
  120. package/src/filters/traverse.ts +44 -24
  121. package/src/index.ts +7 -3
  122. package/src/platforma.ts +26 -7
  123. package/src/plugin_model.test.ts +168 -0
  124. package/src/plugin_model.ts +242 -0
  125. package/src/render/api.ts +26 -24
  126. package/src/render/internal.ts +1 -1
  127. package/src/typing.test.ts +1 -1
  128. package/src/version.ts +8 -0
  129. package/dist/block_storage_vm.cjs +0 -262
  130. package/dist/block_storage_vm.cjs.map +0 -1
  131. package/dist/block_storage_vm.d.ts +0 -59
  132. package/dist/block_storage_vm.d.ts.map +0 -1
  133. package/dist/block_storage_vm.js +0 -258
  134. package/dist/block_storage_vm.js.map +0 -1
  135. package/dist/branding.d.ts +0 -7
  136. package/dist/branding.d.ts.map +0 -1
  137. package/dist/builder.cjs.map +0 -1
  138. package/dist/builder.d.ts.map +0 -1
  139. package/dist/builder.js.map +0 -1
  140. package/dist/sdk_info.cjs +0 -10
  141. package/dist/sdk_info.cjs.map +0 -1
  142. package/dist/sdk_info.d.ts +0 -5
  143. package/dist/sdk_info.d.ts.map +0 -1
  144. package/dist/sdk_info.js +0 -8
  145. package/dist/sdk_info.js.map +0 -1
  146. package/dist/unionize.d.ts +0 -12
  147. package/dist/unionize.d.ts.map +0 -1
  148. package/src/block_storage_vm.ts +0 -346
  149. package/src/branding.ts +0 -4
  150. package/src/sdk_info.ts +0 -9
  151. package/src/unionize.ts +0 -12
@@ -8,6 +8,8 @@
8
8
  *
9
9
  * @module block_storage
10
10
  */
11
+ import type { Branded } from "@milaboratories/pl-model-common";
12
+ import type { DataMigrationResult, DataVersioned } from "./block_migrations";
11
13
  /**
12
14
  * Discriminator key for BlockStorage format detection.
13
15
  * This unique hash-based key identifies data as BlockStorage vs legacy formats.
@@ -28,26 +30,41 @@ export declare const DATA_MODEL_DEFAULT_VERSION = "__pl_v1_d4e8f2a1__";
28
30
  */
29
31
  export type BlockStorageSchemaVersion = "v1";
30
32
  /**
31
- * Plugin key type - keys starting with `@plugin/` are reserved for plugin data
33
+ * Branded type for plugin names - globally unique plugin type identifiers.
34
+ * Using a branded type enforces explicit casting (`as PluginName`) which makes
35
+ * it easy to find all plugin name definitions in the codebase and verify uniqueness.
32
36
  */
33
- export type PluginKey = `@plugin/${string}`;
37
+ export type PluginName = Branded<string, "PluginName">;
38
+ /**
39
+ * Plugin registry - maps pluginId (unique within a block) to pluginName (globally unique plugin type).
40
+ * Using a Record highlights that pluginIds must be unique within a block.
41
+ */
42
+ export type PluginRegistry = Record<string, PluginName>;
43
+ /**
44
+ * Versioned data - used for both block data and plugin data
45
+ */
46
+ export interface VersionedData<TData = unknown> {
47
+ /** Version of the data, used for migrations */
48
+ __dataVersion: string;
49
+ /** The persistent data */
50
+ __data: TData;
51
+ }
34
52
  /**
35
53
  * Core BlockStorage type that holds:
36
54
  * - __pl_a7f3e2b9__: Schema version (discriminator key identifies BlockStorage format)
37
55
  * - __dataVersion: Version key for block data migrations
38
56
  * - __data: The block's user-facing data (state)
39
- * - @plugin/*: Optional plugin-specific data
57
+ * - __pluginRegistry: Map from pluginId to pluginName (optional)
58
+ * - __plugins: Plugin-specific data keyed by pluginId (optional)
40
59
  */
41
60
  export type BlockStorage<TState = unknown> = {
42
61
  /** Schema version - the key itself is the discriminator */
43
62
  readonly [BLOCK_STORAGE_KEY]: BlockStorageSchemaVersion;
44
- /** Version of the block data, used for migrations */
45
- __dataVersion: string;
46
- /** The block's user-facing data (state) */
47
- __data: TState;
48
- } & {
49
- [K in PluginKey]?: unknown;
50
- };
63
+ /** Registry of plugins: pluginId -> pluginName */
64
+ __pluginRegistry?: PluginRegistry;
65
+ /** Plugin-specific data, keyed by pluginId */
66
+ __plugins?: Record<string, VersionedData<unknown>>;
67
+ } & VersionedData<TState>;
51
68
  /**
52
69
  * Type guard to check if a value is a valid BlockStorage object.
53
70
  * Checks for the discriminator key and valid schema version.
@@ -63,7 +80,7 @@ export declare function isBlockStorage(value: unknown): value is BlockStorage;
63
80
  export declare function createBlockStorage<TState = unknown>(initialData?: TState, version?: string): BlockStorage<TState>;
64
81
  /**
65
82
  * Normalizes raw storage data to BlockStorage format.
66
- * If the input is already a BlockStorage, returns it as-is.
83
+ * If the input is already a BlockStorage, returns it as-is (with defaults for missing fields).
67
84
  * If the input is legacy format (raw state), wraps it in BlockStorage structure.
68
85
  *
69
86
  * @param raw - Raw storage data (may be legacy format or BlockStorage)
@@ -91,8 +108,12 @@ export declare function getStorageData<TState>(storage: BlockStorage<TState>): T
91
108
  export declare function deriveDataFromStorage<TData = unknown>(rawStorage: unknown): TData;
92
109
  /** Payload for storage mutation operations. SDK defines specific operations. */
93
110
  export type MutateStoragePayload<T = unknown> = {
94
- operation: "update-data";
111
+ operation: "update-block-data";
95
112
  value: T;
113
+ } | {
114
+ operation: "update-plugin-data";
115
+ pluginId: string;
116
+ value: unknown;
96
117
  };
97
118
  /**
98
119
  * Updates the data in BlockStorage (immutable)
@@ -102,21 +123,6 @@ export type MutateStoragePayload<T = unknown> = {
102
123
  * @returns A new BlockStorage with updated data
103
124
  */
104
125
  export declare function updateStorageData<TValue = unknown>(storage: BlockStorage<TValue>, payload: MutateStoragePayload<TValue>): BlockStorage<TValue>;
105
- /**
106
- * Gets the data version from BlockStorage
107
- *
108
- * @param storage - The BlockStorage instance
109
- * @returns The data version key
110
- */
111
- export declare function getStorageDataVersion(storage: BlockStorage): string;
112
- /**
113
- * Updates the data version in BlockStorage (immutable)
114
- *
115
- * @param storage - The current BlockStorage
116
- * @param version - The new version key
117
- * @returns A new BlockStorage with updated version
118
- */
119
- export declare function updateStorageDataVersion<TState>(storage: BlockStorage<TState>, version: string): BlockStorage<TState>;
120
126
  /**
121
127
  * Storage debug view returned by __pl_storage_debugView callback.
122
128
  * Used by developer tools to display block storage info.
@@ -128,96 +134,87 @@ export interface StorageDebugView {
128
134
  data: unknown;
129
135
  }
130
136
  /**
131
- * Gets plugin-specific data from BlockStorage
132
- *
133
- * @param storage - The BlockStorage instance
134
- * @param pluginName - The plugin name (without `@plugin/` prefix)
135
- * @returns The plugin data or undefined if not set
136
- */
137
- export declare function getPluginData<TData = unknown>(storage: BlockStorage, pluginName: string): TData | undefined;
138
- /**
139
- * Sets plugin-specific data in BlockStorage (immutable)
140
- *
141
- * @param storage - The current BlockStorage
142
- * @param pluginName - The plugin name (without `@plugin/` prefix)
143
- * @param data - The plugin data to store
144
- * @returns A new BlockStorage with updated plugin data
145
- */
146
- export declare function setPluginData<TState>(storage: BlockStorage<TState>, pluginName: string, data: unknown): BlockStorage<TState>;
147
- /**
148
- * Removes plugin-specific data from BlockStorage (immutable)
149
- *
150
- * @param storage - The current BlockStorage
151
- * @param pluginName - The plugin name (without `@plugin/` prefix)
152
- * @returns A new BlockStorage with the plugin data removed
137
+ * Result of a successful atomic migration.
153
138
  */
154
- export declare function removePluginData<TState>(storage: BlockStorage<TState>, pluginName: string): BlockStorage<TState>;
155
- /**
156
- * Gets all plugin names that have data stored
157
- *
158
- * @param storage - The BlockStorage instance
159
- * @returns Array of plugin names (without `@plugin/` prefix)
160
- */
161
- export declare function getPluginNames(storage: BlockStorage): string[];
162
- /**
163
- * Gets a value from BlockStorage by key
164
- *
165
- * @param storage - The BlockStorage instance
166
- * @param key - The key to retrieve
167
- * @returns The value at the given key
168
- */
169
- export declare function getFromStorage<TState, K extends keyof BlockStorage<TState>>(storage: BlockStorage<TState>, key: K): BlockStorage<TState>[K];
170
- /**
171
- * Updates a value in BlockStorage by key (immutable)
172
- *
173
- * @param storage - The current BlockStorage
174
- * @param key - The key to update
175
- * @param value - The new value
176
- * @returns A new BlockStorage with the updated value
177
- */
178
- export declare function updateStorage<TState, K extends keyof BlockStorage<TState>>(storage: BlockStorage<TState>, key: K, value: BlockStorage<TState>[K]): BlockStorage<TState>;
179
- /**
180
- * Interface for model-configurable storage operations.
181
- * These handlers allow block models to customize how storage is managed.
182
- */
183
- export interface BlockStorageHandlers<TState = unknown> {
184
- /**
185
- * Called when setState is invoked - transforms the new state before storing.
186
- * Default behavior: replaces the state directly.
187
- *
188
- * @param currentStorage - The current BlockStorage
189
- * @param newState - The new state being set
190
- * @returns The updated BlockStorage
191
- */
192
- transformStateForStorage?: (currentStorage: BlockStorage<TState>, newState: TState) => BlockStorage<TState>;
193
- /**
194
- * Called when reading state for args derivation.
195
- * Default behavior: returns the state directly.
196
- *
197
- * @param storage - The current BlockStorage
198
- * @returns The state to use for args derivation
199
- */
200
- deriveStateForArgs?: (storage: BlockStorage<TState>) => TState;
201
- /**
202
- * Called during storage schema migration.
203
- * Default behavior: updates stateVersion only.
204
- *
205
- * @param oldStorage - The storage before migration
206
- * @param fromVersion - The version migrating from
207
- * @param toVersion - The version migrating to
208
- * @returns The migrated BlockStorage
209
- */
210
- migrateStorage?: (oldStorage: BlockStorage<TState>, fromVersion: string, toVersion: string) => BlockStorage<TState>;
139
+ export interface MigrationSuccess<TState> {
140
+ success: true;
141
+ /** The fully migrated storage - commit this to persist */
142
+ storage: BlockStorage<TState>;
211
143
  }
212
144
  /**
213
- * Default implementations of storage handlers
145
+ * Result of a failed atomic migration.
146
+ * The original storage is untouched - user must choose to abort or reset.
214
147
  */
215
- export declare const defaultBlockStorageHandlers: Required<BlockStorageHandlers<unknown>>;
148
+ export interface MigrationFailure {
149
+ success: false;
150
+ /** Description of what failed */
151
+ error: string;
152
+ /** Which step failed: 'block' or pluginId */
153
+ failedAt: string;
154
+ }
155
+ export type MigrationResult<TState> = MigrationSuccess<TState> | MigrationFailure;
156
+ /**
157
+ * Configuration for atomic block storage migration.
158
+ * Callbacks use DataVersioned format (the DataModel API format).
159
+ * Conversion to internal VersionedData format is handled by migrateBlockStorage().
160
+ */
161
+ export interface MigrateBlockStorageConfig {
162
+ /** Migrate block data from any version to latest */
163
+ migrateBlockData: (versioned: DataVersioned<unknown>) => DataMigrationResult<unknown>;
164
+ /** Migrate each plugin's data. Return undefined to remove the plugin. */
165
+ migratePluginData: (pluginId: string, versioned: DataVersioned<unknown>) => DataMigrationResult<unknown> | undefined;
166
+ /** The new plugin registry after migration (pluginId -> pluginName) */
167
+ newPluginRegistry: PluginRegistry;
168
+ /** Factory to create initial data for new plugins */
169
+ createPluginData: (pluginId: string) => DataVersioned<unknown>;
170
+ }
216
171
  /**
217
- * Merges custom handlers with defaults
172
+ * Performs atomic migration of block storage including block data and all plugins.
173
+ *
174
+ * Migration is atomic: either everything succeeds and a new storage is returned,
175
+ * or an error is returned and the original storage is completely untouched.
176
+ *
177
+ * Migration steps:
178
+ * 1. Migrate block data
179
+ * 2. For each plugin in newPluginRegistry:
180
+ * - If plugin exists with same name: migrate its data
181
+ * - Otherwise (new or type changed): create with initial data
182
+ * Plugins not in newPluginRegistry are dropped.
183
+ *
184
+ * If any step throws, migration fails and original storage is preserved.
185
+ * User can then choose to:
186
+ * - Abort: keep original storage, don't update block
187
+ * - Reset: call createBlockStorage() to start fresh
188
+ *
189
+ * @param storage - The original storage (will not be modified)
190
+ * @param config - Migration configuration
191
+ * @returns Migration result - either success with new storage, or failure with error info
192
+ *
193
+ * @example
194
+ * const result = migrateBlockStorage(storage, {
195
+ * migrateBlockData: (versioned) => blockDataModel.migrate(versioned),
196
+ * migratePluginData: (pluginId, versioned) => getPluginModel(pluginId).migrate(versioned),
197
+ * newPluginRegistry: { table1: 'dataTable' as PluginName },
198
+ * createPluginData: (pluginId) => getPluginModel(pluginId).getDefaultData(),
199
+ * });
200
+ *
201
+ * if (result.success) {
202
+ * commitStorage(result.storage);
203
+ * } else {
204
+ * const userChoice = await askUser(`Migration failed: ${result.error}. Reset data?`);
205
+ * if (userChoice === 'reset') {
206
+ * commitStorage(createBlockStorage(initialData, currentVersion));
207
+ * }
208
+ * // else: abort, keep original
209
+ * }
210
+ */
211
+ export declare function migrateBlockStorage(storage: BlockStorage<unknown>, config: MigrateBlockStorageConfig): MigrationResult<unknown>;
212
+ /**
213
+ * Gets plugin-specific data from BlockStorage (for UI)
218
214
  *
219
- * @param customHandlers - Custom handlers to merge
220
- * @returns Complete handlers with defaults for missing functions
215
+ * @param storage - The BlockStorage instance
216
+ * @param pluginId - The plugin instance id
217
+ * @returns The plugin data or undefined if not set
221
218
  */
222
- export declare function mergeBlockStorageHandlers<TState>(customHandlers?: BlockStorageHandlers<TState>): Required<BlockStorageHandlers<TState>>;
219
+ export declare function getPluginData<TData = unknown>(storage: BlockStorage, pluginId: string): TData | undefined;
223
220
  //# sourceMappingURL=block_storage.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"block_storage.d.ts","sourceRoot":"","sources":["../src/block_storage.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"block_storage.d.ts","sourceRoot":"","sources":["../src/block_storage.ts"],"names":[],"mappings":"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"}
@@ -53,11 +53,13 @@ function createBlockStorage(initialData = {}, version = DATA_MODEL_DEFAULT_VERSI
53
53
  [BLOCK_STORAGE_KEY]: BLOCK_STORAGE_SCHEMA_VERSION,
54
54
  __dataVersion: version,
55
55
  __data: initialData,
56
+ __pluginRegistry: {},
57
+ __plugins: {},
56
58
  };
57
59
  }
58
60
  /**
59
61
  * Normalizes raw storage data to BlockStorage format.
60
- * If the input is already a BlockStorage, returns it as-is.
62
+ * If the input is already a BlockStorage, returns it as-is (with defaults for missing fields).
61
63
  * If the input is legacy format (raw state), wraps it in BlockStorage structure.
62
64
  *
63
65
  * @param raw - Raw storage data (may be legacy format or BlockStorage)
@@ -72,6 +74,9 @@ function normalizeBlockStorage(raw) {
72
74
  __dataVersion: typeof storage.__dataVersion === "number"
73
75
  ? DATA_MODEL_DEFAULT_VERSION
74
76
  : storage.__dataVersion,
77
+ // Ensure plugin fields have defaults
78
+ __pluginRegistry: storage.__pluginRegistry ?? {},
79
+ __plugins: storage.__plugins ?? {},
75
80
  };
76
81
  }
77
82
  // Legacy format: raw is the state directly
@@ -114,124 +119,144 @@ function deriveDataFromStorage(rawStorage) {
114
119
  */
115
120
  function updateStorageData(storage, payload) {
116
121
  switch (payload.operation) {
117
- case "update-data":
122
+ case "update-block-data":
118
123
  return { ...storage, __data: payload.value };
124
+ case "update-plugin-data": {
125
+ const { pluginId, value } = payload;
126
+ const currentPlugins = storage.__plugins ?? {};
127
+ const existingEntry = currentPlugins[pluginId];
128
+ const version = existingEntry?.__dataVersion ?? DATA_MODEL_DEFAULT_VERSION;
129
+ return {
130
+ ...storage,
131
+ __plugins: {
132
+ ...currentPlugins,
133
+ [pluginId]: {
134
+ __dataVersion: version,
135
+ __data: value,
136
+ },
137
+ },
138
+ };
139
+ }
119
140
  default:
120
141
  throw new Error(`Unknown storage operation: ${payload.operation}`);
121
142
  }
122
143
  }
123
144
  /**
124
- * Gets the data version from BlockStorage
145
+ * Performs atomic migration of block storage including block data and all plugins.
125
146
  *
126
- * @param storage - The BlockStorage instance
127
- * @returns The data version key
128
- */
129
- function getStorageDataVersion(storage) {
130
- return storage.__dataVersion;
131
- }
132
- /**
133
- * Updates the data version in BlockStorage (immutable)
147
+ * Migration is atomic: either everything succeeds and a new storage is returned,
148
+ * or an error is returned and the original storage is completely untouched.
134
149
  *
135
- * @param storage - The current BlockStorage
136
- * @param version - The new version key
137
- * @returns A new BlockStorage with updated version
138
- */
139
- function updateStorageDataVersion(storage, version) {
140
- return { ...storage, __dataVersion: version };
141
- }
142
- // =============================================================================
143
- // Plugin Data Functions
144
- // =============================================================================
145
- /**
146
- * Gets plugin-specific data from BlockStorage
150
+ * Migration steps:
151
+ * 1. Migrate block data
152
+ * 2. For each plugin in newPluginRegistry:
153
+ * - If plugin exists with same name: migrate its data
154
+ * - Otherwise (new or type changed): create with initial data
155
+ * Plugins not in newPluginRegistry are dropped.
147
156
  *
148
- * @param storage - The BlockStorage instance
149
- * @param pluginName - The plugin name (without `@plugin/` prefix)
150
- * @returns The plugin data or undefined if not set
151
- */
152
- function getPluginData(storage, pluginName) {
153
- const key = `@plugin/${pluginName}`;
154
- return storage[key];
155
- }
156
- /**
157
- * Sets plugin-specific data in BlockStorage (immutable)
157
+ * If any step throws, migration fails and original storage is preserved.
158
+ * User can then choose to:
159
+ * - Abort: keep original storage, don't update block
160
+ * - Reset: call createBlockStorage() to start fresh
158
161
  *
159
- * @param storage - The current BlockStorage
160
- * @param pluginName - The plugin name (without `@plugin/` prefix)
161
- * @param data - The plugin data to store
162
- * @returns A new BlockStorage with updated plugin data
163
- */
164
- function setPluginData(storage, pluginName, data) {
165
- const key = `@plugin/${pluginName}`;
166
- return { ...storage, [key]: data };
167
- }
168
- /**
169
- * Removes plugin-specific data from BlockStorage (immutable)
162
+ * @param storage - The original storage (will not be modified)
163
+ * @param config - Migration configuration
164
+ * @returns Migration result - either success with new storage, or failure with error info
170
165
  *
171
- * @param storage - The current BlockStorage
172
- * @param pluginName - The plugin name (without `@plugin/` prefix)
173
- * @returns A new BlockStorage with the plugin data removed
174
- */
175
- function removePluginData(storage, pluginName) {
176
- const key = `@plugin/${pluginName}`;
177
- const { [key]: _, ...rest } = storage;
178
- return rest;
179
- }
180
- /**
181
- * Gets all plugin names that have data stored
166
+ * @example
167
+ * const result = migrateBlockStorage(storage, {
168
+ * migrateBlockData: (versioned) => blockDataModel.migrate(versioned),
169
+ * migratePluginData: (pluginId, versioned) => getPluginModel(pluginId).migrate(versioned),
170
+ * newPluginRegistry: { table1: 'dataTable' as PluginName },
171
+ * createPluginData: (pluginId) => getPluginModel(pluginId).getDefaultData(),
172
+ * });
182
173
  *
183
- * @param storage - The BlockStorage instance
184
- * @returns Array of plugin names (without `@plugin/` prefix)
174
+ * if (result.success) {
175
+ * commitStorage(result.storage);
176
+ * } else {
177
+ * const userChoice = await askUser(`Migration failed: ${result.error}. Reset data?`);
178
+ * if (userChoice === 'reset') {
179
+ * commitStorage(createBlockStorage(initialData, currentVersion));
180
+ * }
181
+ * // else: abort, keep original
182
+ * }
185
183
  */
186
- function getPluginNames(storage) {
187
- return Object.keys(storage)
188
- .filter((key) => key.startsWith("@plugin/"))
189
- .map((key) => key.slice("@plugin/".length));
184
+ function migrateBlockStorage(storage, config) {
185
+ const { migrateBlockData, migratePluginData, newPluginRegistry, createPluginData } = config;
186
+ // Step 1: Migrate block data
187
+ let migratedData;
188
+ let newVersion;
189
+ try {
190
+ const result = migrateBlockData({ version: storage.__dataVersion, data: storage.__data });
191
+ migratedData = result.data;
192
+ newVersion = result.version;
193
+ }
194
+ catch (error) {
195
+ return {
196
+ success: false,
197
+ error: error instanceof Error ? error.message : String(error),
198
+ failedAt: "block",
199
+ };
200
+ }
201
+ // Step 2: Migrate plugins
202
+ const oldPlugins = storage.__plugins ?? {};
203
+ const oldRegistry = storage.__pluginRegistry ?? {};
204
+ const newPlugins = {};
205
+ for (const [pluginId, pluginName] of Object.entries(newPluginRegistry)) {
206
+ const existingEntry = oldPlugins[pluginId];
207
+ const existingName = oldRegistry[pluginId];
208
+ try {
209
+ if (existingEntry && existingName === pluginName) {
210
+ // Plugin exists with same type - migrate its data
211
+ const migrated = migratePluginData(pluginId, {
212
+ version: existingEntry.__dataVersion,
213
+ data: existingEntry.__data,
214
+ });
215
+ if (migrated) {
216
+ newPlugins[pluginId] = { __dataVersion: migrated.version, __data: migrated.data };
217
+ }
218
+ // If undefined returned, plugin is intentionally removed
219
+ }
220
+ else {
221
+ // New plugin or type changed - create with initial data
222
+ const initial = createPluginData(pluginId);
223
+ newPlugins[pluginId] = { __dataVersion: initial.version, __data: initial.data };
224
+ }
225
+ }
226
+ catch (error) {
227
+ return {
228
+ success: false,
229
+ error: error instanceof Error ? error.message : String(error),
230
+ failedAt: pluginId,
231
+ };
232
+ }
233
+ }
234
+ // Step 3: Build final storage atomically
235
+ const migratedStorage = {
236
+ [BLOCK_STORAGE_KEY]: BLOCK_STORAGE_SCHEMA_VERSION,
237
+ __dataVersion: newVersion,
238
+ __data: migratedData,
239
+ __pluginRegistry: newPluginRegistry,
240
+ __plugins: newPlugins,
241
+ };
242
+ return {
243
+ success: true,
244
+ storage: migratedStorage,
245
+ };
190
246
  }
191
- // =============================================================================
192
- // Generic Storage Access
193
- // =============================================================================
194
247
  /**
195
- * Gets a value from BlockStorage by key
248
+ * Gets plugin-specific data from BlockStorage (for UI)
196
249
  *
197
250
  * @param storage - The BlockStorage instance
198
- * @param key - The key to retrieve
199
- * @returns The value at the given key
200
- */
201
- function getFromStorage(storage, key) {
202
- return storage[key];
203
- }
204
- /**
205
- * Updates a value in BlockStorage by key (immutable)
206
- *
207
- * @param storage - The current BlockStorage
208
- * @param key - The key to update
209
- * @param value - The new value
210
- * @returns A new BlockStorage with the updated value
211
- */
212
- function updateStorage(storage, key, value) {
213
- return { ...storage, [key]: value };
214
- }
215
- /**
216
- * Default implementations of storage handlers
217
- */
218
- const defaultBlockStorageHandlers = {
219
- transformStateForStorage: (storage, newState) => updateStorageData(storage, { operation: "update-data", value: newState }),
220
- deriveStateForArgs: (storage) => getStorageData(storage),
221
- migrateStorage: (storage, _fromVersion, toVersion) => updateStorageDataVersion(storage, toVersion),
222
- };
223
- /**
224
- * Merges custom handlers with defaults
225
- *
226
- * @param customHandlers - Custom handlers to merge
227
- * @returns Complete handlers with defaults for missing functions
251
+ * @param pluginId - The plugin instance id
252
+ * @returns The plugin data or undefined if not set
228
253
  */
229
- function mergeBlockStorageHandlers(customHandlers) {
230
- return {
231
- ...defaultBlockStorageHandlers,
232
- ...customHandlers,
233
- };
254
+ function getPluginData(storage, pluginId) {
255
+ const pluginEntry = storage.__plugins?.[pluginId];
256
+ if (!pluginEntry)
257
+ return undefined;
258
+ return pluginEntry.__data;
234
259
  }
235
260
 
236
- export { BLOCK_STORAGE_KEY, BLOCK_STORAGE_SCHEMA_VERSION, DATA_MODEL_DEFAULT_VERSION, createBlockStorage, defaultBlockStorageHandlers, deriveDataFromStorage, getFromStorage, getPluginData, getPluginNames, getStorageData, getStorageDataVersion, isBlockStorage, mergeBlockStorageHandlers, normalizeBlockStorage, removePluginData, setPluginData, updateStorage, updateStorageData, updateStorageDataVersion };
261
+ export { BLOCK_STORAGE_KEY, BLOCK_STORAGE_SCHEMA_VERSION, DATA_MODEL_DEFAULT_VERSION, createBlockStorage, deriveDataFromStorage, getPluginData, getStorageData, isBlockStorage, migrateBlockStorage, normalizeBlockStorage, updateStorageData };
237
262
  //# sourceMappingURL=block_storage.js.map