@platforma-sdk/model 1.54.13 → 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.
- package/dist/bconfig/normalization.cjs +8 -1
- package/dist/bconfig/normalization.cjs.map +1 -1
- package/dist/bconfig/normalization.d.ts.map +1 -1
- package/dist/bconfig/normalization.js +8 -1
- package/dist/bconfig/normalization.js.map +1 -1
- package/dist/block_api_v3.d.ts +2 -2
- package/dist/block_api_v3.d.ts.map +1 -1
- package/dist/block_migrations.cjs +246 -214
- package/dist/block_migrations.cjs.map +1 -1
- package/dist/block_migrations.d.ts +180 -158
- package/dist/block_migrations.d.ts.map +1 -1
- package/dist/block_migrations.js +247 -214
- package/dist/block_migrations.js.map +1 -1
- package/dist/block_model.cjs +85 -35
- package/dist/block_model.cjs.map +1 -1
- package/dist/block_model.d.ts +66 -38
- package/dist/block_model.d.ts.map +1 -1
- package/dist/block_model.js +86 -36
- package/dist/block_model.js.map +1 -1
- package/dist/{builder.cjs → block_model_legacy.cjs} +2 -2
- package/dist/block_model_legacy.cjs.map +1 -0
- package/dist/{builder.d.ts → block_model_legacy.d.ts} +1 -1
- package/dist/block_model_legacy.d.ts.map +1 -0
- package/dist/{builder.js → block_model_legacy.js} +2 -2
- package/dist/block_model_legacy.js.map +1 -0
- package/dist/block_state_patch.d.ts +11 -1
- package/dist/block_state_patch.d.ts.map +1 -1
- package/dist/block_storage.cjs +126 -109
- package/dist/block_storage.cjs.map +1 -1
- package/dist/block_storage.d.ts +109 -112
- package/dist/block_storage.d.ts.map +1 -1
- package/dist/block_storage.js +126 -101
- package/dist/block_storage.js.map +1 -1
- package/dist/block_storage_callbacks.cjs +227 -0
- package/dist/block_storage_callbacks.cjs.map +1 -0
- package/dist/block_storage_callbacks.d.ts +113 -0
- package/dist/block_storage_callbacks.d.ts.map +1 -0
- package/dist/block_storage_callbacks.js +218 -0
- package/dist/block_storage_callbacks.js.map +1 -0
- package/dist/block_storage_facade.cjs +104 -0
- package/dist/block_storage_facade.cjs.map +1 -0
- package/dist/block_storage_facade.d.ts +168 -0
- package/dist/block_storage_facade.d.ts.map +1 -0
- package/dist/block_storage_facade.js +99 -0
- package/dist/block_storage_facade.js.map +1 -0
- package/dist/index.cjs +13 -14
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +8 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -4
- package/dist/index.js.map +1 -1
- package/dist/package.json.cjs +1 -1
- package/dist/package.json.js +1 -1
- package/dist/platforma.d.ts +11 -4
- package/dist/platforma.d.ts.map +1 -1
- package/dist/plugin_model.cjs +171 -0
- package/dist/plugin_model.cjs.map +1 -0
- package/dist/plugin_model.d.ts +162 -0
- package/dist/plugin_model.d.ts.map +1 -0
- package/dist/plugin_model.js +169 -0
- package/dist/plugin_model.js.map +1 -0
- package/dist/render/api.cjs +20 -21
- package/dist/render/api.cjs.map +1 -1
- package/dist/render/api.d.ts +8 -8
- package/dist/render/api.d.ts.map +1 -1
- package/dist/render/api.js +20 -21
- package/dist/render/api.js.map +1 -1
- package/dist/render/internal.cjs.map +1 -1
- package/dist/render/internal.d.ts +1 -1
- package/dist/render/internal.d.ts.map +1 -1
- package/dist/render/internal.js.map +1 -1
- package/dist/version.cjs +4 -0
- package/dist/version.cjs.map +1 -1
- package/dist/version.d.ts +4 -0
- package/dist/version.d.ts.map +1 -1
- package/dist/version.js +4 -1
- package/dist/version.js.map +1 -1
- package/package.json +5 -5
- package/src/bconfig/normalization.ts +8 -1
- package/src/block_api_v3.ts +2 -2
- package/src/block_migrations.test.ts +141 -171
- package/src/block_migrations.ts +300 -285
- package/src/block_model.ts +205 -95
- package/src/{builder.ts → block_model_legacy.ts} +1 -1
- package/src/block_state_patch.ts +13 -1
- package/src/block_storage.test.ts +283 -95
- package/src/block_storage.ts +199 -188
- package/src/block_storage_callbacks.ts +326 -0
- package/src/block_storage_facade.ts +199 -0
- package/src/index.ts +7 -3
- package/src/platforma.ts +26 -7
- package/src/plugin_model.test.ts +168 -0
- package/src/plugin_model.ts +242 -0
- package/src/render/api.ts +26 -24
- package/src/render/internal.ts +1 -1
- package/src/typing.test.ts +1 -1
- package/src/version.ts +8 -0
- package/dist/block_storage_vm.cjs +0 -262
- package/dist/block_storage_vm.cjs.map +0 -1
- package/dist/block_storage_vm.d.ts +0 -59
- package/dist/block_storage_vm.d.ts.map +0 -1
- package/dist/block_storage_vm.js +0 -258
- package/dist/block_storage_vm.js.map +0 -1
- package/dist/branding.d.ts +0 -7
- package/dist/branding.d.ts.map +0 -1
- package/dist/builder.cjs.map +0 -1
- package/dist/builder.d.ts.map +0 -1
- package/dist/builder.js.map +0 -1
- package/dist/sdk_info.cjs +0 -10
- package/dist/sdk_info.cjs.map +0 -1
- package/dist/sdk_info.d.ts +0 -5
- package/dist/sdk_info.d.ts.map +0 -1
- package/dist/sdk_info.js +0 -8
- package/dist/sdk_info.js.map +0 -1
- package/dist/unionize.d.ts +0 -12
- package/dist/unionize.d.ts.map +0 -1
- package/src/block_storage_vm.ts +0 -346
- package/src/branding.ts +0 -4
- package/src/sdk_info.ts +0 -9
- package/src/unionize.ts +0 -12
package/dist/block_storage.d.ts
CHANGED
|
@@ -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
|
-
*
|
|
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
|
|
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
|
-
* -
|
|
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
|
-
/**
|
|
45
|
-
|
|
46
|
-
/**
|
|
47
|
-
|
|
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
|
-
*
|
|
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
|
|
155
|
-
|
|
156
|
-
|
|
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
|
-
*
|
|
145
|
+
* Result of a failed atomic migration.
|
|
146
|
+
* The original storage is untouched - user must choose to abort or reset.
|
|
214
147
|
*/
|
|
215
|
-
export
|
|
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
|
-
*
|
|
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
|
|
220
|
-
* @
|
|
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
|
|
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":"AAAA;;;;;;;;;GASG;
|
|
1
|
+
{"version":3,"file":"block_storage.d.ts","sourceRoot":"","sources":["../src/block_storage.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,iCAAiC,CAAC;AAC/D,OAAO,KAAK,EAAE,mBAAmB,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAM7E;;;GAGG;AACH,eAAO,MAAM,iBAAiB,oBAAoB,CAAC;AAEnD;;;GAGG;AACH,eAAO,MAAM,4BAA4B,OAAO,CAAC;AAEjD;;;GAGG;AACH,eAAO,MAAM,0BAA0B,uBAAuB,CAAC;AAE/D;;GAEG;AACH,MAAM,MAAM,yBAAyB,GAAG,IAAI,CAAC;AAE7C;;;;GAIG;AACH,MAAM,MAAM,UAAU,GAAG,OAAO,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;AAEvD;;;GAGG;AACH,MAAM,MAAM,cAAc,GAAG,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;AAExD;;GAEG;AACH,MAAM,WAAW,aAAa,CAAC,KAAK,GAAG,OAAO;IAC5C,+CAA+C;IAC/C,aAAa,EAAE,MAAM,CAAC;IACtB,0BAA0B;IAC1B,MAAM,EAAE,KAAK,CAAC;CACf;AAED;;;;;;;GAOG;AACH,MAAM,MAAM,YAAY,CAAC,MAAM,GAAG,OAAO,IAAI;IAC3C,2DAA2D;IAC3D,QAAQ,CAAC,CAAC,iBAAiB,CAAC,EAAE,yBAAyB,CAAC;IACxD,kDAAkD;IAClD,gBAAgB,CAAC,EAAE,cAAc,CAAC;IAClC,8CAA8C;IAC9C,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,OAAO,CAAC,CAAC,CAAC;CACpD,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC;AAE1B;;;GAGG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,YAAY,CAMpE;AAMD;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,GAAG,OAAO,EACjD,WAAW,GAAE,MAAqB,EAClC,OAAO,GAAE,MAAmC,GAC3C,YAAY,CAAC,MAAM,CAAC,CAQtB;AAED;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,GAAG,OAAO,EAAE,GAAG,EAAE,OAAO,GAAG,YAAY,CAAC,MAAM,CAAC,CAiB1F;AAMD;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,OAAO,EAAE,YAAY,CAAC,MAAM,CAAC,GAAG,MAAM,CAE5E;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,GAAG,OAAO,EAAE,UAAU,EAAE,OAAO,GAAG,KAAK,CAIjF;AAED,gFAAgF;AAChF,MAAM,MAAM,oBAAoB,CAAC,CAAC,GAAG,OAAO,IACxC;IAAE,SAAS,EAAE,mBAAmB,CAAC;IAAC,KAAK,EAAE,CAAC,CAAA;CAAE,GAC5C;IAAE,SAAS,EAAE,oBAAoB,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,OAAO,CAAA;CAAE,CAAC;AAE1E;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,GAAG,OAAO,EAChD,OAAO,EAAE,YAAY,CAAC,MAAM,CAAC,EAC7B,OAAO,EAAE,oBAAoB,CAAC,MAAM,CAAC,GACpC,YAAY,CAAC,MAAM,CAAC,CAuBtB;AAED;;;GAGG;AACH,MAAM,WAAW,gBAAgB;IAC/B,+BAA+B;IAC/B,WAAW,EAAE,MAAM,CAAC;IACpB,8CAA8C;IAC9C,IAAI,EAAE,OAAO,CAAC;CACf;AAMD;;GAEG;AACH,MAAM,WAAW,gBAAgB,CAAC,MAAM;IACtC,OAAO,EAAE,IAAI,CAAC;IACd,0DAA0D;IAC1D,OAAO,EAAE,YAAY,CAAC,MAAM,CAAC,CAAC;CAC/B;AAED;;;GAGG;AACH,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,KAAK,CAAC;IACf,iCAAiC;IACjC,KAAK,EAAE,MAAM,CAAC;IACd,6CAA6C;IAC7C,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,MAAM,eAAe,CAAC,MAAM,IAAI,gBAAgB,CAAC,MAAM,CAAC,GAAG,gBAAgB,CAAC;AAElF;;;;GAIG;AACH,MAAM,WAAW,yBAAyB;IACxC,oDAAoD;IACpD,gBAAgB,EAAE,CAAC,SAAS,EAAE,aAAa,CAAC,OAAO,CAAC,KAAK,mBAAmB,CAAC,OAAO,CAAC,CAAC;IACtF,yEAAyE;IACzE,iBAAiB,EAAE,CACjB,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,aAAa,CAAC,OAAO,CAAC,KAC9B,mBAAmB,CAAC,OAAO,CAAC,GAAG,SAAS,CAAC;IAC9C,uEAAuE;IACvE,iBAAiB,EAAE,cAAc,CAAC;IAClC,qDAAqD;IACrD,gBAAgB,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,aAAa,CAAC,OAAO,CAAC,CAAC;CAChE;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AACH,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,YAAY,CAAC,OAAO,CAAC,EAC9B,MAAM,EAAE,yBAAyB,GAChC,eAAe,CAAC,OAAO,CAAC,CAiE1B;AAED;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,KAAK,GAAG,OAAO,EAC3C,OAAO,EAAE,YAAY,EACrB,QAAQ,EAAE,MAAM,GACf,KAAK,GAAG,SAAS,CAInB"}
|
package/dist/block_storage.js
CHANGED
|
@@ -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
|
-
*
|
|
145
|
+
* Performs atomic migration of block storage including block data and all plugins.
|
|
125
146
|
*
|
|
126
|
-
*
|
|
127
|
-
*
|
|
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
|
-
*
|
|
136
|
-
*
|
|
137
|
-
*
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
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
|
-
*
|
|
149
|
-
*
|
|
150
|
-
*
|
|
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
|
|
160
|
-
* @param
|
|
161
|
-
* @
|
|
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
|
-
* @
|
|
172
|
-
*
|
|
173
|
-
*
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
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
|
-
*
|
|
184
|
-
*
|
|
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
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
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
|
|
248
|
+
* Gets plugin-specific data from BlockStorage (for UI)
|
|
196
249
|
*
|
|
197
250
|
* @param storage - The BlockStorage instance
|
|
198
|
-
* @param
|
|
199
|
-
* @returns The
|
|
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
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
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,
|
|
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
|