@milaboratories/pl-middle-layer 1.46.8 → 1.46.10

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.
@@ -69,21 +69,21 @@ function serializeBlockStorage(storage) {
69
69
  return JSON.stringify(storage);
70
70
  }
71
71
  /**
72
- * Checks if the storage needs migration based on version.
72
+ * Checks if the storage needs migration based on version key.
73
73
  *
74
74
  * @param storage - Current BlockStorage
75
- * @param targetVersion - Target schema version
75
+ * @param targetVersion - Target version key
76
76
  * @returns true if migration is needed
77
77
  */
78
78
  function needsMigration(storage, targetVersion) {
79
- return model.getStorageDataVersion(storage) < targetVersion;
79
+ return model.getStorageDataVersion(storage) !== targetVersion;
80
80
  }
81
81
  /**
82
82
  * Migrates BlockStorage from one version to another.
83
83
  *
84
84
  * @param storage - Current BlockStorage
85
- * @param fromVersion - Source version
86
- * @param toVersion - Target version
85
+ * @param fromVersion - Source version key
86
+ * @param toVersion - Target version key
87
87
  * @param handlers - Optional custom handlers
88
88
  * @returns Migrated BlockStorage
89
89
  */
@@ -116,7 +116,7 @@ function isLegacyV1V2Format(rawData) {
116
116
  * @returns BlockStorage with legacy data as state
117
117
  */
118
118
  function convertLegacyToBlockStorage(legacyData) {
119
- return model.createBlockStorage(legacyData, 1);
119
+ return model.createBlockStorage(legacyData);
120
120
  }
121
121
  /**
122
122
  * Smart parser that handles all storage formats:
@@ -1 +1 @@
1
- {"version":3,"file":"block_storage_helper.cjs","sources":["../../src/model/block_storage_helper.ts"],"sourcesContent":["/**\n * Block Storage Helper - Middle layer utilities for BlockStorage operations.\n *\n * This module provides the bridge between the SDK's BlockStorage abstraction\n * and the middle layer's storage operations. Block developers never interact\n * with this - they only see `state`.\n *\n * @module block_storage_helper\n */\n\nimport type {\n BlockStorage,\n BlockStorageHandlers,\n} from '@platforma-sdk/model';\nimport {\n BLOCK_STORAGE_KEY,\n BLOCK_STORAGE_SCHEMA_VERSION,\n createBlockStorage,\n defaultBlockStorageHandlers,\n getPluginData,\n getStorageData,\n getStorageDataVersion,\n isBlockStorage,\n normalizeBlockStorage,\n setPluginData,\n updateStorageData,\n updateStorageDataVersion,\n} from '@platforma-sdk/model';\n\n// Re-export types for convenience\nexport type { BlockStorage, BlockStorageHandlers };\n\n// Re-export utilities that middle layer needs\nexport {\n BLOCK_STORAGE_KEY,\n BLOCK_STORAGE_SCHEMA_VERSION,\n createBlockStorage,\n defaultBlockStorageHandlers,\n getPluginData,\n getStorageData,\n getStorageDataVersion,\n isBlockStorage,\n normalizeBlockStorage,\n setPluginData,\n updateStorageData,\n updateStorageDataVersion,\n};\n\n/**\n * Parses raw blockStorage data (from resource tree) into BlockStorage.\n * Handles both legacy format (raw state) and new format (BlockStorage).\n *\n * @param rawData - Raw data from blockStorage field (may be string or parsed object)\n * @returns Normalized BlockStorage object\n */\nexport function parseBlockStorage<TState = unknown>(rawData: unknown): BlockStorage<TState> {\n if (rawData === undefined || rawData === null) {\n return createBlockStorage<TState>({} as TState);\n }\n\n // If it's a string, parse it first\n if (typeof rawData === 'string') {\n try {\n const parsed = JSON.parse(rawData);\n return normalizeBlockStorage<TState>(parsed);\n } catch {\n // If parsing fails, treat the string as the state itself\n return createBlockStorage(rawData as unknown as TState);\n }\n }\n\n return normalizeBlockStorage<TState>(rawData);\n}\n\n/**\n * Extracts the user-facing data from BlockStorage.\n * This is what block developers see in their .args() callbacks.\n *\n * @param storage - The BlockStorage object\n * @returns The data value that developers work with\n */\nexport function extractDataForDeveloper<TState>(storage: BlockStorage<TState>): TState {\n return getStorageData(storage);\n}\n\n/**\n * Creates a new BlockStorage with updated state.\n * Used when setState is called from the frontend.\n *\n * @param currentStorage - Current BlockStorage (or undefined for new blocks)\n * @param newState - New state from developer\n * @param handlers - Optional custom handlers (defaults to standard handlers)\n * @returns Updated BlockStorage\n */\nexport function applyStateUpdate<TState>(\n currentStorage: BlockStorage<TState> | undefined,\n newState: TState,\n handlers: BlockStorageHandlers<TState> = defaultBlockStorageHandlers as BlockStorageHandlers<TState>,\n): BlockStorage<TState> {\n const storage = currentStorage ?? createBlockStorage<TState>({} as TState);\n const transform = handlers.transformStateForStorage ?? defaultBlockStorageHandlers.transformStateForStorage;\n return transform(storage, newState) as BlockStorage<TState>;\n}\n\n/**\n * Serializes BlockStorage for writing to the resource tree.\n *\n * @param storage - The BlockStorage to serialize\n * @returns JSON string\n */\nexport function serializeBlockStorage(storage: BlockStorage): string {\n return JSON.stringify(storage);\n}\n\n/**\n * Checks if the storage needs migration based on version.\n *\n * @param storage - Current BlockStorage\n * @param targetVersion - Target schema version\n * @returns true if migration is needed\n */\nexport function needsMigration(storage: BlockStorage, targetVersion: number): boolean {\n return getStorageDataVersion(storage) < targetVersion;\n}\n\n/**\n * Migrates BlockStorage from one version to another.\n *\n * @param storage - Current BlockStorage\n * @param fromVersion - Source version\n * @param toVersion - Target version\n * @param handlers - Optional custom handlers\n * @returns Migrated BlockStorage\n */\nexport function migrateBlockStorage<TState>(\n storage: BlockStorage<TState>,\n fromVersion: number,\n toVersion: number,\n handlers: BlockStorageHandlers<TState> = defaultBlockStorageHandlers as BlockStorageHandlers<TState>,\n): BlockStorage<TState> {\n const migrate = handlers.migrateStorage ?? defaultBlockStorageHandlers.migrateStorage;\n return migrate(storage, fromVersion, toVersion) as BlockStorage<TState>;\n}\n\n/**\n * V1/V2 legacy format - state stored as { args, uiState }\n */\nexport interface LegacyV1V2State {\n args?: unknown;\n uiState?: unknown;\n}\n\n/**\n * Checks if the raw data is in legacy V1/V2 format.\n * V1/V2 blocks stored { args, uiState } directly, not wrapped in BlockStorage.\n *\n * @param rawData - Raw data from blockStorage field\n * @returns true if data is in legacy format\n */\nexport function isLegacyV1V2Format(rawData: unknown): rawData is LegacyV1V2State {\n if (rawData === null || typeof rawData !== 'object') return false;\n // If it has the discriminator, it's BlockStorage format\n if (isBlockStorage(rawData)) return false;\n\n const obj = rawData as Record<string, unknown>;\n // Legacy format has 'args' and/or 'uiState' at top level, no discriminator\n return ('args' in obj || 'uiState' in obj);\n}\n\n/**\n * Converts legacy V1/V2 format to BlockStorage.\n * For backward compatibility with existing blocks.\n *\n * @param legacyData - Data in { args, uiState } format\n * @returns BlockStorage with legacy data as state\n */\nexport function convertLegacyToBlockStorage(legacyData: LegacyV1V2State): BlockStorage<LegacyV1V2State> {\n return createBlockStorage(legacyData, 1);\n}\n\n/**\n * Smart parser that handles all storage formats:\n * - New BlockStorage format\n * - Legacy V1/V2 format ({ args, uiState })\n * - Raw state (any other format)\n *\n * @param rawData - Raw data from blockStorage field\n * @returns Normalized BlockStorage\n */\nexport function parseBlockStorageSmart<TState = unknown>(rawData: unknown): BlockStorage<TState> {\n if (rawData === undefined || rawData === null) {\n return createBlockStorage<TState>({} as TState);\n }\n\n // If it's a string, parse it first\n let parsed = rawData;\n if (typeof rawData === 'string') {\n try {\n parsed = JSON.parse(rawData);\n } catch {\n // If parsing fails, treat the string as the state itself\n return createBlockStorage(rawData as unknown as TState);\n }\n }\n\n // Check for legacy V1/V2 format\n if (isLegacyV1V2Format(parsed)) {\n return convertLegacyToBlockStorage(parsed) as unknown as BlockStorage<TState>;\n }\n\n // Use standard normalization\n return normalizeBlockStorage<TState>(parsed);\n}\n"],"names":["createBlockStorage","normalizeBlockStorage","getStorageData","defaultBlockStorageHandlers","getStorageDataVersion","isBlockStorage"],"mappings":"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"}
1
+ {"version":3,"file":"block_storage_helper.cjs","sources":["../../src/model/block_storage_helper.ts"],"sourcesContent":["/**\n * Block Storage Helper - Middle layer utilities for BlockStorage operations.\n *\n * This module provides the bridge between the SDK's BlockStorage abstraction\n * and the middle layer's storage operations. Block developers never interact\n * with this - they only see `state`.\n *\n * @module block_storage_helper\n */\n\nimport type {\n BlockStorage,\n BlockStorageHandlers,\n} from '@platforma-sdk/model';\nimport {\n BLOCK_STORAGE_KEY,\n BLOCK_STORAGE_SCHEMA_VERSION,\n createBlockStorage,\n defaultBlockStorageHandlers,\n getPluginData,\n getStorageData,\n getStorageDataVersion,\n isBlockStorage,\n normalizeBlockStorage,\n setPluginData,\n updateStorageData,\n updateStorageDataVersion,\n} from '@platforma-sdk/model';\n\n// Re-export types for convenience\nexport type { BlockStorage, BlockStorageHandlers };\n\n// Re-export utilities that middle layer needs\nexport {\n BLOCK_STORAGE_KEY,\n BLOCK_STORAGE_SCHEMA_VERSION,\n createBlockStorage,\n defaultBlockStorageHandlers,\n getPluginData,\n getStorageData,\n getStorageDataVersion,\n isBlockStorage,\n normalizeBlockStorage,\n setPluginData,\n updateStorageData,\n updateStorageDataVersion,\n};\n\n/**\n * Parses raw blockStorage data (from resource tree) into BlockStorage.\n * Handles both legacy format (raw state) and new format (BlockStorage).\n *\n * @param rawData - Raw data from blockStorage field (may be string or parsed object)\n * @returns Normalized BlockStorage object\n */\nexport function parseBlockStorage<TState = unknown>(rawData: unknown): BlockStorage<TState> {\n if (rawData === undefined || rawData === null) {\n return createBlockStorage<TState>({} as TState);\n }\n\n // If it's a string, parse it first\n if (typeof rawData === 'string') {\n try {\n const parsed = JSON.parse(rawData);\n return normalizeBlockStorage<TState>(parsed);\n } catch {\n // If parsing fails, treat the string as the state itself\n return createBlockStorage(rawData as unknown as TState);\n }\n }\n\n return normalizeBlockStorage<TState>(rawData);\n}\n\n/**\n * Extracts the user-facing data from BlockStorage.\n * This is what block developers see in their .args() callbacks.\n *\n * @param storage - The BlockStorage object\n * @returns The data value that developers work with\n */\nexport function extractDataForDeveloper<TState>(storage: BlockStorage<TState>): TState {\n return getStorageData(storage);\n}\n\n/**\n * Creates a new BlockStorage with updated state.\n * Used when setState is called from the frontend.\n *\n * @param currentStorage - Current BlockStorage (or undefined for new blocks)\n * @param newState - New state from developer\n * @param handlers - Optional custom handlers (defaults to standard handlers)\n * @returns Updated BlockStorage\n */\nexport function applyStateUpdate<TState>(\n currentStorage: BlockStorage<TState> | undefined,\n newState: TState,\n handlers: BlockStorageHandlers<TState> = defaultBlockStorageHandlers as BlockStorageHandlers<TState>,\n): BlockStorage<TState> {\n const storage = currentStorage ?? createBlockStorage<TState>({} as TState);\n const transform = handlers.transformStateForStorage ?? defaultBlockStorageHandlers.transformStateForStorage;\n return transform(storage, newState) as BlockStorage<TState>;\n}\n\n/**\n * Serializes BlockStorage for writing to the resource tree.\n *\n * @param storage - The BlockStorage to serialize\n * @returns JSON string\n */\nexport function serializeBlockStorage(storage: BlockStorage): string {\n return JSON.stringify(storage);\n}\n\n/**\n * Checks if the storage needs migration based on version key.\n *\n * @param storage - Current BlockStorage\n * @param targetVersion - Target version key\n * @returns true if migration is needed\n */\nexport function needsMigration(storage: BlockStorage, targetVersion: string): boolean {\n return getStorageDataVersion(storage) !== targetVersion;\n}\n\n/**\n * Migrates BlockStorage from one version to another.\n *\n * @param storage - Current BlockStorage\n * @param fromVersion - Source version key\n * @param toVersion - Target version key\n * @param handlers - Optional custom handlers\n * @returns Migrated BlockStorage\n */\nexport function migrateBlockStorage<TState>(\n storage: BlockStorage<TState>,\n fromVersion: string,\n toVersion: string,\n handlers: BlockStorageHandlers<TState> = defaultBlockStorageHandlers as BlockStorageHandlers<TState>,\n): BlockStorage<TState> {\n const migrate = handlers.migrateStorage ?? defaultBlockStorageHandlers.migrateStorage;\n return migrate(storage, fromVersion, toVersion) as BlockStorage<TState>;\n}\n\n/**\n * V1/V2 legacy format - state stored as { args, uiState }\n */\nexport interface LegacyV1V2State {\n args?: unknown;\n uiState?: unknown;\n}\n\n/**\n * Checks if the raw data is in legacy V1/V2 format.\n * V1/V2 blocks stored { args, uiState } directly, not wrapped in BlockStorage.\n *\n * @param rawData - Raw data from blockStorage field\n * @returns true if data is in legacy format\n */\nexport function isLegacyV1V2Format(rawData: unknown): rawData is LegacyV1V2State {\n if (rawData === null || typeof rawData !== 'object') return false;\n // If it has the discriminator, it's BlockStorage format\n if (isBlockStorage(rawData)) return false;\n\n const obj = rawData as Record<string, unknown>;\n // Legacy format has 'args' and/or 'uiState' at top level, no discriminator\n return ('args' in obj || 'uiState' in obj);\n}\n\n/**\n * Converts legacy V1/V2 format to BlockStorage.\n * For backward compatibility with existing blocks.\n *\n * @param legacyData - Data in { args, uiState } format\n * @returns BlockStorage with legacy data as state\n */\nexport function convertLegacyToBlockStorage(legacyData: LegacyV1V2State): BlockStorage<LegacyV1V2State> {\n return createBlockStorage(legacyData);\n}\n\n/**\n * Smart parser that handles all storage formats:\n * - New BlockStorage format\n * - Legacy V1/V2 format ({ args, uiState })\n * - Raw state (any other format)\n *\n * @param rawData - Raw data from blockStorage field\n * @returns Normalized BlockStorage\n */\nexport function parseBlockStorageSmart<TState = unknown>(rawData: unknown): BlockStorage<TState> {\n if (rawData === undefined || rawData === null) {\n return createBlockStorage<TState>({} as TState);\n }\n\n // If it's a string, parse it first\n let parsed = rawData;\n if (typeof rawData === 'string') {\n try {\n parsed = JSON.parse(rawData);\n } catch {\n // If parsing fails, treat the string as the state itself\n return createBlockStorage(rawData as unknown as TState);\n }\n }\n\n // Check for legacy V1/V2 format\n if (isLegacyV1V2Format(parsed)) {\n return convertLegacyToBlockStorage(parsed) as unknown as BlockStorage<TState>;\n }\n\n // Use standard normalization\n return normalizeBlockStorage<TState>(parsed);\n}\n"],"names":["createBlockStorage","normalizeBlockStorage","getStorageData","defaultBlockStorageHandlers","getStorageDataVersion","isBlockStorage"],"mappings":"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"}
@@ -45,23 +45,23 @@ export declare function applyStateUpdate<TState>(currentStorage: BlockStorage<TS
45
45
  */
46
46
  export declare function serializeBlockStorage(storage: BlockStorage): string;
47
47
  /**
48
- * Checks if the storage needs migration based on version.
48
+ * Checks if the storage needs migration based on version key.
49
49
  *
50
50
  * @param storage - Current BlockStorage
51
- * @param targetVersion - Target schema version
51
+ * @param targetVersion - Target version key
52
52
  * @returns true if migration is needed
53
53
  */
54
- export declare function needsMigration(storage: BlockStorage, targetVersion: number): boolean;
54
+ export declare function needsMigration(storage: BlockStorage, targetVersion: string): boolean;
55
55
  /**
56
56
  * Migrates BlockStorage from one version to another.
57
57
  *
58
58
  * @param storage - Current BlockStorage
59
- * @param fromVersion - Source version
60
- * @param toVersion - Target version
59
+ * @param fromVersion - Source version key
60
+ * @param toVersion - Target version key
61
61
  * @param handlers - Optional custom handlers
62
62
  * @returns Migrated BlockStorage
63
63
  */
64
- export declare function migrateBlockStorage<TState>(storage: BlockStorage<TState>, fromVersion: number, toVersion: number, handlers?: BlockStorageHandlers<TState>): BlockStorage<TState>;
64
+ export declare function migrateBlockStorage<TState>(storage: BlockStorage<TState>, fromVersion: string, toVersion: string, handlers?: BlockStorageHandlers<TState>): BlockStorage<TState>;
65
65
  /**
66
66
  * V1/V2 legacy format - state stored as { args, uiState }
67
67
  */
@@ -68,21 +68,21 @@ function serializeBlockStorage(storage) {
68
68
  return JSON.stringify(storage);
69
69
  }
70
70
  /**
71
- * Checks if the storage needs migration based on version.
71
+ * Checks if the storage needs migration based on version key.
72
72
  *
73
73
  * @param storage - Current BlockStorage
74
- * @param targetVersion - Target schema version
74
+ * @param targetVersion - Target version key
75
75
  * @returns true if migration is needed
76
76
  */
77
77
  function needsMigration(storage, targetVersion) {
78
- return getStorageDataVersion(storage) < targetVersion;
78
+ return getStorageDataVersion(storage) !== targetVersion;
79
79
  }
80
80
  /**
81
81
  * Migrates BlockStorage from one version to another.
82
82
  *
83
83
  * @param storage - Current BlockStorage
84
- * @param fromVersion - Source version
85
- * @param toVersion - Target version
84
+ * @param fromVersion - Source version key
85
+ * @param toVersion - Target version key
86
86
  * @param handlers - Optional custom handlers
87
87
  * @returns Migrated BlockStorage
88
88
  */
@@ -115,7 +115,7 @@ function isLegacyV1V2Format(rawData) {
115
115
  * @returns BlockStorage with legacy data as state
116
116
  */
117
117
  function convertLegacyToBlockStorage(legacyData) {
118
- return createBlockStorage(legacyData, 1);
118
+ return createBlockStorage(legacyData);
119
119
  }
120
120
  /**
121
121
  * Smart parser that handles all storage formats:
@@ -1 +1 @@
1
- {"version":3,"file":"block_storage_helper.js","sources":["../../src/model/block_storage_helper.ts"],"sourcesContent":["/**\n * Block Storage Helper - Middle layer utilities for BlockStorage operations.\n *\n * This module provides the bridge between the SDK's BlockStorage abstraction\n * and the middle layer's storage operations. Block developers never interact\n * with this - they only see `state`.\n *\n * @module block_storage_helper\n */\n\nimport type {\n BlockStorage,\n BlockStorageHandlers,\n} from '@platforma-sdk/model';\nimport {\n BLOCK_STORAGE_KEY,\n BLOCK_STORAGE_SCHEMA_VERSION,\n createBlockStorage,\n defaultBlockStorageHandlers,\n getPluginData,\n getStorageData,\n getStorageDataVersion,\n isBlockStorage,\n normalizeBlockStorage,\n setPluginData,\n updateStorageData,\n updateStorageDataVersion,\n} from '@platforma-sdk/model';\n\n// Re-export types for convenience\nexport type { BlockStorage, BlockStorageHandlers };\n\n// Re-export utilities that middle layer needs\nexport {\n BLOCK_STORAGE_KEY,\n BLOCK_STORAGE_SCHEMA_VERSION,\n createBlockStorage,\n defaultBlockStorageHandlers,\n getPluginData,\n getStorageData,\n getStorageDataVersion,\n isBlockStorage,\n normalizeBlockStorage,\n setPluginData,\n updateStorageData,\n updateStorageDataVersion,\n};\n\n/**\n * Parses raw blockStorage data (from resource tree) into BlockStorage.\n * Handles both legacy format (raw state) and new format (BlockStorage).\n *\n * @param rawData - Raw data from blockStorage field (may be string or parsed object)\n * @returns Normalized BlockStorage object\n */\nexport function parseBlockStorage<TState = unknown>(rawData: unknown): BlockStorage<TState> {\n if (rawData === undefined || rawData === null) {\n return createBlockStorage<TState>({} as TState);\n }\n\n // If it's a string, parse it first\n if (typeof rawData === 'string') {\n try {\n const parsed = JSON.parse(rawData);\n return normalizeBlockStorage<TState>(parsed);\n } catch {\n // If parsing fails, treat the string as the state itself\n return createBlockStorage(rawData as unknown as TState);\n }\n }\n\n return normalizeBlockStorage<TState>(rawData);\n}\n\n/**\n * Extracts the user-facing data from BlockStorage.\n * This is what block developers see in their .args() callbacks.\n *\n * @param storage - The BlockStorage object\n * @returns The data value that developers work with\n */\nexport function extractDataForDeveloper<TState>(storage: BlockStorage<TState>): TState {\n return getStorageData(storage);\n}\n\n/**\n * Creates a new BlockStorage with updated state.\n * Used when setState is called from the frontend.\n *\n * @param currentStorage - Current BlockStorage (or undefined for new blocks)\n * @param newState - New state from developer\n * @param handlers - Optional custom handlers (defaults to standard handlers)\n * @returns Updated BlockStorage\n */\nexport function applyStateUpdate<TState>(\n currentStorage: BlockStorage<TState> | undefined,\n newState: TState,\n handlers: BlockStorageHandlers<TState> = defaultBlockStorageHandlers as BlockStorageHandlers<TState>,\n): BlockStorage<TState> {\n const storage = currentStorage ?? createBlockStorage<TState>({} as TState);\n const transform = handlers.transformStateForStorage ?? defaultBlockStorageHandlers.transformStateForStorage;\n return transform(storage, newState) as BlockStorage<TState>;\n}\n\n/**\n * Serializes BlockStorage for writing to the resource tree.\n *\n * @param storage - The BlockStorage to serialize\n * @returns JSON string\n */\nexport function serializeBlockStorage(storage: BlockStorage): string {\n return JSON.stringify(storage);\n}\n\n/**\n * Checks if the storage needs migration based on version.\n *\n * @param storage - Current BlockStorage\n * @param targetVersion - Target schema version\n * @returns true if migration is needed\n */\nexport function needsMigration(storage: BlockStorage, targetVersion: number): boolean {\n return getStorageDataVersion(storage) < targetVersion;\n}\n\n/**\n * Migrates BlockStorage from one version to another.\n *\n * @param storage - Current BlockStorage\n * @param fromVersion - Source version\n * @param toVersion - Target version\n * @param handlers - Optional custom handlers\n * @returns Migrated BlockStorage\n */\nexport function migrateBlockStorage<TState>(\n storage: BlockStorage<TState>,\n fromVersion: number,\n toVersion: number,\n handlers: BlockStorageHandlers<TState> = defaultBlockStorageHandlers as BlockStorageHandlers<TState>,\n): BlockStorage<TState> {\n const migrate = handlers.migrateStorage ?? defaultBlockStorageHandlers.migrateStorage;\n return migrate(storage, fromVersion, toVersion) as BlockStorage<TState>;\n}\n\n/**\n * V1/V2 legacy format - state stored as { args, uiState }\n */\nexport interface LegacyV1V2State {\n args?: unknown;\n uiState?: unknown;\n}\n\n/**\n * Checks if the raw data is in legacy V1/V2 format.\n * V1/V2 blocks stored { args, uiState } directly, not wrapped in BlockStorage.\n *\n * @param rawData - Raw data from blockStorage field\n * @returns true if data is in legacy format\n */\nexport function isLegacyV1V2Format(rawData: unknown): rawData is LegacyV1V2State {\n if (rawData === null || typeof rawData !== 'object') return false;\n // If it has the discriminator, it's BlockStorage format\n if (isBlockStorage(rawData)) return false;\n\n const obj = rawData as Record<string, unknown>;\n // Legacy format has 'args' and/or 'uiState' at top level, no discriminator\n return ('args' in obj || 'uiState' in obj);\n}\n\n/**\n * Converts legacy V1/V2 format to BlockStorage.\n * For backward compatibility with existing blocks.\n *\n * @param legacyData - Data in { args, uiState } format\n * @returns BlockStorage with legacy data as state\n */\nexport function convertLegacyToBlockStorage(legacyData: LegacyV1V2State): BlockStorage<LegacyV1V2State> {\n return createBlockStorage(legacyData, 1);\n}\n\n/**\n * Smart parser that handles all storage formats:\n * - New BlockStorage format\n * - Legacy V1/V2 format ({ args, uiState })\n * - Raw state (any other format)\n *\n * @param rawData - Raw data from blockStorage field\n * @returns Normalized BlockStorage\n */\nexport function parseBlockStorageSmart<TState = unknown>(rawData: unknown): BlockStorage<TState> {\n if (rawData === undefined || rawData === null) {\n return createBlockStorage<TState>({} as TState);\n }\n\n // If it's a string, parse it first\n let parsed = rawData;\n if (typeof rawData === 'string') {\n try {\n parsed = JSON.parse(rawData);\n } catch {\n // If parsing fails, treat the string as the state itself\n return createBlockStorage(rawData as unknown as TState);\n }\n }\n\n // Check for legacy V1/V2 format\n if (isLegacyV1V2Format(parsed)) {\n return convertLegacyToBlockStorage(parsed) as unknown as BlockStorage<TState>;\n }\n\n // Use standard normalization\n return normalizeBlockStorage<TState>(parsed);\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"block_storage_helper.js","sources":["../../src/model/block_storage_helper.ts"],"sourcesContent":["/**\n * Block Storage Helper - Middle layer utilities for BlockStorage operations.\n *\n * This module provides the bridge between the SDK's BlockStorage abstraction\n * and the middle layer's storage operations. Block developers never interact\n * with this - they only see `state`.\n *\n * @module block_storage_helper\n */\n\nimport type {\n BlockStorage,\n BlockStorageHandlers,\n} from '@platforma-sdk/model';\nimport {\n BLOCK_STORAGE_KEY,\n BLOCK_STORAGE_SCHEMA_VERSION,\n createBlockStorage,\n defaultBlockStorageHandlers,\n getPluginData,\n getStorageData,\n getStorageDataVersion,\n isBlockStorage,\n normalizeBlockStorage,\n setPluginData,\n updateStorageData,\n updateStorageDataVersion,\n} from '@platforma-sdk/model';\n\n// Re-export types for convenience\nexport type { BlockStorage, BlockStorageHandlers };\n\n// Re-export utilities that middle layer needs\nexport {\n BLOCK_STORAGE_KEY,\n BLOCK_STORAGE_SCHEMA_VERSION,\n createBlockStorage,\n defaultBlockStorageHandlers,\n getPluginData,\n getStorageData,\n getStorageDataVersion,\n isBlockStorage,\n normalizeBlockStorage,\n setPluginData,\n updateStorageData,\n updateStorageDataVersion,\n};\n\n/**\n * Parses raw blockStorage data (from resource tree) into BlockStorage.\n * Handles both legacy format (raw state) and new format (BlockStorage).\n *\n * @param rawData - Raw data from blockStorage field (may be string or parsed object)\n * @returns Normalized BlockStorage object\n */\nexport function parseBlockStorage<TState = unknown>(rawData: unknown): BlockStorage<TState> {\n if (rawData === undefined || rawData === null) {\n return createBlockStorage<TState>({} as TState);\n }\n\n // If it's a string, parse it first\n if (typeof rawData === 'string') {\n try {\n const parsed = JSON.parse(rawData);\n return normalizeBlockStorage<TState>(parsed);\n } catch {\n // If parsing fails, treat the string as the state itself\n return createBlockStorage(rawData as unknown as TState);\n }\n }\n\n return normalizeBlockStorage<TState>(rawData);\n}\n\n/**\n * Extracts the user-facing data from BlockStorage.\n * This is what block developers see in their .args() callbacks.\n *\n * @param storage - The BlockStorage object\n * @returns The data value that developers work with\n */\nexport function extractDataForDeveloper<TState>(storage: BlockStorage<TState>): TState {\n return getStorageData(storage);\n}\n\n/**\n * Creates a new BlockStorage with updated state.\n * Used when setState is called from the frontend.\n *\n * @param currentStorage - Current BlockStorage (or undefined for new blocks)\n * @param newState - New state from developer\n * @param handlers - Optional custom handlers (defaults to standard handlers)\n * @returns Updated BlockStorage\n */\nexport function applyStateUpdate<TState>(\n currentStorage: BlockStorage<TState> | undefined,\n newState: TState,\n handlers: BlockStorageHandlers<TState> = defaultBlockStorageHandlers as BlockStorageHandlers<TState>,\n): BlockStorage<TState> {\n const storage = currentStorage ?? createBlockStorage<TState>({} as TState);\n const transform = handlers.transformStateForStorage ?? defaultBlockStorageHandlers.transformStateForStorage;\n return transform(storage, newState) as BlockStorage<TState>;\n}\n\n/**\n * Serializes BlockStorage for writing to the resource tree.\n *\n * @param storage - The BlockStorage to serialize\n * @returns JSON string\n */\nexport function serializeBlockStorage(storage: BlockStorage): string {\n return JSON.stringify(storage);\n}\n\n/**\n * Checks if the storage needs migration based on version key.\n *\n * @param storage - Current BlockStorage\n * @param targetVersion - Target version key\n * @returns true if migration is needed\n */\nexport function needsMigration(storage: BlockStorage, targetVersion: string): boolean {\n return getStorageDataVersion(storage) !== targetVersion;\n}\n\n/**\n * Migrates BlockStorage from one version to another.\n *\n * @param storage - Current BlockStorage\n * @param fromVersion - Source version key\n * @param toVersion - Target version key\n * @param handlers - Optional custom handlers\n * @returns Migrated BlockStorage\n */\nexport function migrateBlockStorage<TState>(\n storage: BlockStorage<TState>,\n fromVersion: string,\n toVersion: string,\n handlers: BlockStorageHandlers<TState> = defaultBlockStorageHandlers as BlockStorageHandlers<TState>,\n): BlockStorage<TState> {\n const migrate = handlers.migrateStorage ?? defaultBlockStorageHandlers.migrateStorage;\n return migrate(storage, fromVersion, toVersion) as BlockStorage<TState>;\n}\n\n/**\n * V1/V2 legacy format - state stored as { args, uiState }\n */\nexport interface LegacyV1V2State {\n args?: unknown;\n uiState?: unknown;\n}\n\n/**\n * Checks if the raw data is in legacy V1/V2 format.\n * V1/V2 blocks stored { args, uiState } directly, not wrapped in BlockStorage.\n *\n * @param rawData - Raw data from blockStorage field\n * @returns true if data is in legacy format\n */\nexport function isLegacyV1V2Format(rawData: unknown): rawData is LegacyV1V2State {\n if (rawData === null || typeof rawData !== 'object') return false;\n // If it has the discriminator, it's BlockStorage format\n if (isBlockStorage(rawData)) return false;\n\n const obj = rawData as Record<string, unknown>;\n // Legacy format has 'args' and/or 'uiState' at top level, no discriminator\n return ('args' in obj || 'uiState' in obj);\n}\n\n/**\n * Converts legacy V1/V2 format to BlockStorage.\n * For backward compatibility with existing blocks.\n *\n * @param legacyData - Data in { args, uiState } format\n * @returns BlockStorage with legacy data as state\n */\nexport function convertLegacyToBlockStorage(legacyData: LegacyV1V2State): BlockStorage<LegacyV1V2State> {\n return createBlockStorage(legacyData);\n}\n\n/**\n * Smart parser that handles all storage formats:\n * - New BlockStorage format\n * - Legacy V1/V2 format ({ args, uiState })\n * - Raw state (any other format)\n *\n * @param rawData - Raw data from blockStorage field\n * @returns Normalized BlockStorage\n */\nexport function parseBlockStorageSmart<TState = unknown>(rawData: unknown): BlockStorage<TState> {\n if (rawData === undefined || rawData === null) {\n return createBlockStorage<TState>({} as TState);\n }\n\n // If it's a string, parse it first\n let parsed = rawData;\n if (typeof rawData === 'string') {\n try {\n parsed = JSON.parse(rawData);\n } catch {\n // If parsing fails, treat the string as the state itself\n return createBlockStorage(rawData as unknown as TState);\n }\n }\n\n // Check for legacy V1/V2 format\n if (isLegacyV1V2Format(parsed)) {\n return convertLegacyToBlockStorage(parsed) as unknown as BlockStorage<TState>;\n }\n\n // Use standard normalization\n return normalizeBlockStorage<TState>(parsed);\n}\n"],"names":[],"mappings":";;;AAAA;;;;;;;;AAQG;AAwCH;;;;;;AAMG;AACG,SAAU,iBAAiB,CAAmB,OAAgB,EAAA;IAClE,IAAI,OAAO,KAAK,SAAS,IAAI,OAAO,KAAK,IAAI,EAAE;AAC7C,QAAA,OAAO,kBAAkB,CAAS,EAAY,CAAC;IACjD;;AAGA,IAAA,IAAI,OAAO,OAAO,KAAK,QAAQ,EAAE;AAC/B,QAAA,IAAI;YACF,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC;AAClC,YAAA,OAAO,qBAAqB,CAAS,MAAM,CAAC;QAC9C;AAAE,QAAA,MAAM;;AAEN,YAAA,OAAO,kBAAkB,CAAC,OAA4B,CAAC;QACzD;IACF;AAEA,IAAA,OAAO,qBAAqB,CAAS,OAAO,CAAC;AAC/C;AAEA;;;;;;AAMG;AACG,SAAU,uBAAuB,CAAS,OAA6B,EAAA;AAC3E,IAAA,OAAO,cAAc,CAAC,OAAO,CAAC;AAChC;AAEA;;;;;;;;AAQG;AACG,SAAU,gBAAgB,CAC9B,cAAgD,EAChD,QAAgB,EAChB,WAAyC,2BAA2D,EAAA;IAEpG,MAAM,OAAO,GAAG,cAAc,IAAI,kBAAkB,CAAS,EAAY,CAAC;IAC1E,MAAM,SAAS,GAAG,QAAQ,CAAC,wBAAwB,IAAI,2BAA2B,CAAC,wBAAwB;AAC3G,IAAA,OAAO,SAAS,CAAC,OAAO,EAAE,QAAQ,CAAyB;AAC7D;AAEA;;;;;AAKG;AACG,SAAU,qBAAqB,CAAC,OAAqB,EAAA;AACzD,IAAA,OAAO,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC;AAChC;AAEA;;;;;;AAMG;AACG,SAAU,cAAc,CAAC,OAAqB,EAAE,aAAqB,EAAA;AACzE,IAAA,OAAO,qBAAqB,CAAC,OAAO,CAAC,KAAK,aAAa;AACzD;AAEA;;;;;;;;AAQG;AACG,SAAU,mBAAmB,CACjC,OAA6B,EAC7B,WAAmB,EACnB,SAAiB,EACjB,QAAA,GAAyC,2BAA2D,EAAA;IAEpG,MAAM,OAAO,GAAG,QAAQ,CAAC,cAAc,IAAI,2BAA2B,CAAC,cAAc;IACrF,OAAO,OAAO,CAAC,OAAO,EAAE,WAAW,EAAE,SAAS,CAAyB;AACzE;AAUA;;;;;;AAMG;AACG,SAAU,kBAAkB,CAAC,OAAgB,EAAA;AACjD,IAAA,IAAI,OAAO,KAAK,IAAI,IAAI,OAAO,OAAO,KAAK,QAAQ;AAAE,QAAA,OAAO,KAAK;;IAEjE,IAAI,cAAc,CAAC,OAAO,CAAC;AAAE,QAAA,OAAO,KAAK;IAEzC,MAAM,GAAG,GAAG,OAAkC;;IAE9C,QAAQ,MAAM,IAAI,GAAG,IAAI,SAAS,IAAI,GAAG;AAC3C;AAEA;;;;;;AAMG;AACG,SAAU,2BAA2B,CAAC,UAA2B,EAAA;AACrE,IAAA,OAAO,kBAAkB,CAAC,UAAU,CAAC;AACvC;AAEA;;;;;;;;AAQG;AACG,SAAU,sBAAsB,CAAmB,OAAgB,EAAA;IACvE,IAAI,OAAO,KAAK,SAAS,IAAI,OAAO,KAAK,IAAI,EAAE;AAC7C,QAAA,OAAO,kBAAkB,CAAS,EAAY,CAAC;IACjD;;IAGA,IAAI,MAAM,GAAG,OAAO;AACpB,IAAA,IAAI,OAAO,OAAO,KAAK,QAAQ,EAAE;AAC/B,QAAA,IAAI;AACF,YAAA,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC;QAC9B;AAAE,QAAA,MAAM;;AAEN,YAAA,OAAO,kBAAkB,CAAC,OAA4B,CAAC;QACzD;IACF;;AAGA,IAAA,IAAI,kBAAkB,CAAC,MAAM,CAAC,EAAE;AAC9B,QAAA,OAAO,2BAA2B,CAAC,MAAM,CAAoC;IAC/E;;AAGA,IAAA,OAAO,qBAAqB,CAAS,MAAM,CAAC;AAC9C;;;;"}
@@ -145,7 +145,7 @@ class ProjectHelper {
145
145
  *
146
146
  * @param blockConfig Block configuration
147
147
  * @param rawStorageJson Raw storage as JSON string (or undefined)
148
- * @returns Storage debug view as JSON string (e.g., '{"dataVersion": 1}')
148
+ * @returns Storage debug view as JSON string (e.g., '{"dataVersion": "v1"}')
149
149
  */
150
150
  getStorageDebugViewInVM(blockConfig, rawStorageJson) {
151
151
  try {
@@ -164,7 +164,7 @@ class ProjectHelper {
164
164
  * Runs block state migrations via VM-based transformation.
165
165
  * This calls the model's `__pl_storage_migrate` callback which:
166
166
  * - Normalizes current storage to get state and version
167
- * - Calculates target version from number of registered migrations
167
+ * - Applies DataModel upgrade to reach target version key
168
168
  * - Runs all necessary migrations sequentially
169
169
  * - Returns new storage with updated state and version
170
170
  *
@@ -1 +1 @@
1
- {"version":3,"file":"project_helper.cjs","sources":["../../src/model/project_helper.ts"],"sourcesContent":["import type { ResultOrError, BlockConfig, PlRef, ConfigRenderLambda, StorageDebugView } from '@platforma-sdk/model';\nimport type { StringifiedJson } from '@milaboratories/pl-model-common';\nimport { extractCodeWithInfo, ensureError } from '@platforma-sdk/model';\nimport { LRUCache } from 'lru-cache';\nimport type { QuickJSWASMModule } from 'quickjs-emscripten';\nimport { executeSingleLambda } from '../js_render';\nimport type { ResourceId } from '@milaboratories/pl-client';\n\ntype EnrichmentTargetsRequest = {\n blockConfig: () => BlockConfig;\n args: () => unknown;\n};\n\ntype EnrichmentTargetsValue = {\n value: PlRef[] | undefined;\n};\n\n/**\n * Result of VM-based storage migration.\n * Returned by migrateStorageInVM().\n *\n * - Error result: { error: string } - serious failure (no context, etc.)\n * - Success result: { newStorageJson: string, info: string, warn?: string } - migration succeeded or reset to initial\n */\nexport type MigrationResult =\n | { error: string }\n | { error?: undefined; newStorageJson: string; info: string; warn?: string };\n\n// Internal lambda handles for storage operations (registered by SDK's block_storage_vm.ts)\n// All callbacks are prefixed with `__pl_` to indicate internal SDK use\nconst STORAGE_APPLY_UPDATE_HANDLE: ConfigRenderLambda = { __renderLambda: true, handle: '__pl_storage_applyUpdate' };\nconst STORAGE_DEBUG_VIEW_HANDLE: ConfigRenderLambda = { __renderLambda: true, handle: '__pl_storage_debugView' };\nconst STORAGE_MIGRATE_HANDLE: ConfigRenderLambda = { __renderLambda: true, handle: '__pl_storage_migrate' };\nconst ARGS_DERIVE_HANDLE: ConfigRenderLambda = { __renderLambda: true, handle: '__pl_args_derive' };\nconst PRERUN_ARGS_DERIVE_HANDLE: ConfigRenderLambda = { __renderLambda: true, handle: '__pl_prerunArgs_derive' };\n// Registered by DataModel.registerCallbacks()\nconst INITIAL_STORAGE_HANDLE: ConfigRenderLambda = { __renderLambda: true, handle: '__pl_storage_initial' };\n\n/**\n * Result of args derivation from storage.\n * Returned by __pl_args_derive and __pl_prerunArgs_derive VM callbacks.\n */\ntype ArgsDeriveResult =\n | { error: string }\n | { error?: undefined; value: unknown };\n\nexport class ProjectHelper {\n private readonly enrichmentTargetsCache = new LRUCache<string, EnrichmentTargetsValue, EnrichmentTargetsRequest>({\n max: 256,\n memoMethod: (_key, _value, { context }) => {\n return { value: this.calculateEnrichmentTargets(context) };\n },\n });\n\n constructor(private readonly quickJs: QuickJSWASMModule) {}\n\n // =============================================================================\n // Args Derivation from Storage (V3+)\n // =============================================================================\n\n /**\n * Derives args directly from storage JSON using VM callback.\n * The VM extracts data from storage and calls the block's args() function.\n *\n * This allows the middle layer to work only with storage JSON,\n * without needing to know the underlying data structure.\n *\n * @param blockConfig The block configuration (provides the model code)\n * @param storageJson Storage as JSON string\n * @returns The derived args object, or error if derivation fails\n */\n public deriveArgsFromStorage(blockConfig: BlockConfig, storageJson: string): ResultOrError<unknown> {\n if (blockConfig.modelAPIVersion !== 2) {\n return { error: new Error('deriveArgsFromStorage is only supported for model API version 2') };\n }\n\n try {\n const result = executeSingleLambda(\n this.quickJs,\n ARGS_DERIVE_HANDLE,\n extractCodeWithInfo(blockConfig),\n storageJson,\n ) as ArgsDeriveResult;\n\n if (result.error !== undefined) {\n return { error: new Error(result.error) };\n }\n return { value: result.value };\n } catch (e) {\n return { error: new Error('Args derivation from storage failed', { cause: ensureError(e) }) };\n }\n }\n\n /**\n * Derives prerunArgs directly from storage JSON using VM callback.\n * Falls back to args() if prerunArgs is not defined in the block model.\n *\n * @param blockConfig The block configuration (provides the model code)\n * @param storageJson Storage as JSON string\n * @returns The derived prerunArgs, or undefined if derivation fails\n */\n public derivePrerunArgsFromStorage(blockConfig: BlockConfig, storageJson: string): unknown {\n if (blockConfig.modelAPIVersion !== 2) {\n throw new Error('derivePrerunArgsFromStorage is only supported for model API version 2');\n }\n\n try {\n const result = executeSingleLambda(\n this.quickJs,\n PRERUN_ARGS_DERIVE_HANDLE,\n extractCodeWithInfo(blockConfig),\n storageJson,\n ) as ArgsDeriveResult;\n\n if (result.error !== undefined) {\n // Return undefined if derivation fails (skip block in staging)\n return undefined;\n }\n return result.value;\n } catch {\n // Return undefined if derivation fails (skip block in staging)\n return undefined;\n }\n }\n\n private calculateEnrichmentTargets(req: EnrichmentTargetsRequest): PlRef[] | undefined {\n const blockConfig = req.blockConfig();\n if (blockConfig.enrichmentTargets === undefined) return undefined;\n const args = req.args();\n const result = executeSingleLambda(this.quickJs, blockConfig.enrichmentTargets, extractCodeWithInfo(blockConfig), args) as PlRef[];\n return result;\n }\n\n public getEnrichmentTargets(blockConfig: () => BlockConfig, args: () => unknown, key?: { argsRid: ResourceId; blockPackRid: ResourceId }): PlRef[] | undefined {\n const req = { blockConfig, args };\n if (key === undefined)\n return this.calculateEnrichmentTargets(req);\n const cacheKey = `${key.argsRid}:${key.blockPackRid}`;\n return this.enrichmentTargetsCache.memo(cacheKey, { context: req }).value;\n }\n\n // =============================================================================\n // VM-based Storage Operations\n // =============================================================================\n\n /**\n * Creates initial BlockStorage for a new block using VM-based transformation.\n * This calls the '__pl_storage_initial' callback registered by DataModel which:\n * - Gets initial data from DataModel.getDefaultData()\n * - Creates BlockStorage with correct version\n *\n * @param blockConfig The block configuration (provides the model code)\n * @returns Initial storage as JSON string\n * @throws Error if storage creation fails\n */\n public getInitialStorageInVM(blockConfig: BlockConfig): string {\n try {\n const result = executeSingleLambda(\n this.quickJs,\n INITIAL_STORAGE_HANDLE,\n extractCodeWithInfo(blockConfig),\n ) as string;\n return result;\n } catch (e) {\n console.error('[ProjectHelper.getInitialStorageInVM] Initial storage creation failed:', e);\n throw new Error(`Block initial storage creation failed: ${e}`);\n }\n }\n\n /**\n * Applies a state update using VM-based transformation.\n * This calls the model's `__pl_storage_applyUpdate` callback which:\n * - Normalizes current storage\n * - Updates state while preserving other fields (version, plugins)\n * - Returns the updated storage as JSON string\n *\n * @param blockConfig The block configuration (provides the model code)\n * @param currentStorageJson Current storage as JSON string (must be defined)\n * @param newState New state from developer\n * @returns Updated storage as JSON string\n * @throws Error if storage update fails\n */\n public applyStorageUpdateInVM(blockConfig: BlockConfig, currentStorageJson: string, payload: { operation: string; value: unknown }): string {\n try {\n const result = executeSingleLambda(\n this.quickJs,\n STORAGE_APPLY_UPDATE_HANDLE,\n extractCodeWithInfo(blockConfig),\n currentStorageJson,\n payload,\n ) as string;\n return result;\n } catch (e) {\n console.error('[ProjectHelper.applyStorageUpdateInVM] Storage update failed:', e);\n throw new Error(`Block storage update failed: ${e}`);\n }\n }\n\n /**\n * Gets storage debug view from raw storage data by calling the VM's __pl_storage_debugView callback.\n * Returns structured debug info about the storage (e.g., dataVersion).\n *\n * @param blockConfig Block configuration\n * @param rawStorageJson Raw storage as JSON string (or undefined)\n * @returns Storage debug view as JSON string (e.g., '{\"dataVersion\": 1}')\n */\n public getStorageDebugViewInVM(blockConfig: BlockConfig, rawStorageJson: string | undefined): StringifiedJson<StorageDebugView> | undefined {\n try {\n const result = executeSingleLambda(\n this.quickJs,\n STORAGE_DEBUG_VIEW_HANDLE,\n extractCodeWithInfo(blockConfig),\n rawStorageJson,\n ) as StringifiedJson<StorageDebugView>;\n return result;\n } catch (e) {\n console.error('[ProjectHelper.getStorageDebugViewInVM] Get storage debug view failed:', e);\n return undefined;\n }\n }\n\n // =============================================================================\n // Block State Migrations\n // =============================================================================\n\n /**\n * Runs block state migrations via VM-based transformation.\n * This calls the model's `__pl_storage_migrate` callback which:\n * - Normalizes current storage to get state and version\n * - Calculates target version from number of registered migrations\n * - Runs all necessary migrations sequentially\n * - Returns new storage with updated state and version\n *\n * The middle layer doesn't need to know about dataVersion or storage internals.\n * All migration logic is encapsulated in the model.\n *\n * @param blockConfig The NEW block configuration (provides the model code with migrations)\n * @param currentStorageJson Current storage as JSON string (or undefined)\n * @returns MigrationResult with new storage or skip/error info\n */\n public migrateStorageInVM(blockConfig: BlockConfig, currentStorageJson: string | undefined): MigrationResult {\n try {\n const result = executeSingleLambda(\n this.quickJs,\n STORAGE_MIGRATE_HANDLE,\n extractCodeWithInfo(blockConfig),\n currentStorageJson,\n ) as MigrationResult;\n return result;\n } catch (e) {\n console.error('[ProjectHelper.migrateStorageInVM] Migration failed:', e);\n return { error: `VM execution failed: ${e}` };\n }\n }\n}\n"],"names":["LRUCache","executeSingleLambda","extractCodeWithInfo","ensureError"],"mappings":"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"}
1
+ {"version":3,"file":"project_helper.cjs","sources":["../../src/model/project_helper.ts"],"sourcesContent":["import type { ResultOrError, BlockConfig, PlRef, ConfigRenderLambda, StorageDebugView } from '@platforma-sdk/model';\nimport type { StringifiedJson } from '@milaboratories/pl-model-common';\nimport { extractCodeWithInfo, ensureError } from '@platforma-sdk/model';\nimport { LRUCache } from 'lru-cache';\nimport type { QuickJSWASMModule } from 'quickjs-emscripten';\nimport { executeSingleLambda } from '../js_render';\nimport type { ResourceId } from '@milaboratories/pl-client';\n\ntype EnrichmentTargetsRequest = {\n blockConfig: () => BlockConfig;\n args: () => unknown;\n};\n\ntype EnrichmentTargetsValue = {\n value: PlRef[] | undefined;\n};\n\n/**\n * Result of VM-based storage migration.\n * Returned by migrateStorageInVM().\n *\n * - Error result: { error: string } - serious failure (no context, etc.)\n * - Success result: { newStorageJson: string, info: string, warn?: string } - migration succeeded or reset to initial\n */\nexport type MigrationResult =\n | { error: string }\n | { error?: undefined; newStorageJson: string; info: string; warn?: string };\n\n// Internal lambda handles for storage operations (registered by SDK's block_storage_vm.ts)\n// All callbacks are prefixed with `__pl_` to indicate internal SDK use\nconst STORAGE_APPLY_UPDATE_HANDLE: ConfigRenderLambda = { __renderLambda: true, handle: '__pl_storage_applyUpdate' };\nconst STORAGE_DEBUG_VIEW_HANDLE: ConfigRenderLambda = { __renderLambda: true, handle: '__pl_storage_debugView' };\nconst STORAGE_MIGRATE_HANDLE: ConfigRenderLambda = { __renderLambda: true, handle: '__pl_storage_migrate' };\nconst ARGS_DERIVE_HANDLE: ConfigRenderLambda = { __renderLambda: true, handle: '__pl_args_derive' };\nconst PRERUN_ARGS_DERIVE_HANDLE: ConfigRenderLambda = { __renderLambda: true, handle: '__pl_prerunArgs_derive' };\n// Registered by DataModel.registerCallbacks()\nconst INITIAL_STORAGE_HANDLE: ConfigRenderLambda = { __renderLambda: true, handle: '__pl_storage_initial' };\n\n/**\n * Result of args derivation from storage.\n * Returned by __pl_args_derive and __pl_prerunArgs_derive VM callbacks.\n */\ntype ArgsDeriveResult =\n | { error: string }\n | { error?: undefined; value: unknown };\n\nexport class ProjectHelper {\n private readonly enrichmentTargetsCache = new LRUCache<string, EnrichmentTargetsValue, EnrichmentTargetsRequest>({\n max: 256,\n memoMethod: (_key, _value, { context }) => {\n return { value: this.calculateEnrichmentTargets(context) };\n },\n });\n\n constructor(private readonly quickJs: QuickJSWASMModule) {}\n\n // =============================================================================\n // Args Derivation from Storage (V3+)\n // =============================================================================\n\n /**\n * Derives args directly from storage JSON using VM callback.\n * The VM extracts data from storage and calls the block's args() function.\n *\n * This allows the middle layer to work only with storage JSON,\n * without needing to know the underlying data structure.\n *\n * @param blockConfig The block configuration (provides the model code)\n * @param storageJson Storage as JSON string\n * @returns The derived args object, or error if derivation fails\n */\n public deriveArgsFromStorage(blockConfig: BlockConfig, storageJson: string): ResultOrError<unknown> {\n if (blockConfig.modelAPIVersion !== 2) {\n return { error: new Error('deriveArgsFromStorage is only supported for model API version 2') };\n }\n\n try {\n const result = executeSingleLambda(\n this.quickJs,\n ARGS_DERIVE_HANDLE,\n extractCodeWithInfo(blockConfig),\n storageJson,\n ) as ArgsDeriveResult;\n\n if (result.error !== undefined) {\n return { error: new Error(result.error) };\n }\n return { value: result.value };\n } catch (e) {\n return { error: new Error('Args derivation from storage failed', { cause: ensureError(e) }) };\n }\n }\n\n /**\n * Derives prerunArgs directly from storage JSON using VM callback.\n * Falls back to args() if prerunArgs is not defined in the block model.\n *\n * @param blockConfig The block configuration (provides the model code)\n * @param storageJson Storage as JSON string\n * @returns The derived prerunArgs, or undefined if derivation fails\n */\n public derivePrerunArgsFromStorage(blockConfig: BlockConfig, storageJson: string): unknown {\n if (blockConfig.modelAPIVersion !== 2) {\n throw new Error('derivePrerunArgsFromStorage is only supported for model API version 2');\n }\n\n try {\n const result = executeSingleLambda(\n this.quickJs,\n PRERUN_ARGS_DERIVE_HANDLE,\n extractCodeWithInfo(blockConfig),\n storageJson,\n ) as ArgsDeriveResult;\n\n if (result.error !== undefined) {\n // Return undefined if derivation fails (skip block in staging)\n return undefined;\n }\n return result.value;\n } catch {\n // Return undefined if derivation fails (skip block in staging)\n return undefined;\n }\n }\n\n private calculateEnrichmentTargets(req: EnrichmentTargetsRequest): PlRef[] | undefined {\n const blockConfig = req.blockConfig();\n if (blockConfig.enrichmentTargets === undefined) return undefined;\n const args = req.args();\n const result = executeSingleLambda(this.quickJs, blockConfig.enrichmentTargets, extractCodeWithInfo(blockConfig), args) as PlRef[];\n return result;\n }\n\n public getEnrichmentTargets(blockConfig: () => BlockConfig, args: () => unknown, key?: { argsRid: ResourceId; blockPackRid: ResourceId }): PlRef[] | undefined {\n const req = { blockConfig, args };\n if (key === undefined)\n return this.calculateEnrichmentTargets(req);\n const cacheKey = `${key.argsRid}:${key.blockPackRid}`;\n return this.enrichmentTargetsCache.memo(cacheKey, { context: req }).value;\n }\n\n // =============================================================================\n // VM-based Storage Operations\n // =============================================================================\n\n /**\n * Creates initial BlockStorage for a new block using VM-based transformation.\n * This calls the '__pl_storage_initial' callback registered by DataModel which:\n * - Gets initial data from DataModel.getDefaultData()\n * - Creates BlockStorage with correct version\n *\n * @param blockConfig The block configuration (provides the model code)\n * @returns Initial storage as JSON string\n * @throws Error if storage creation fails\n */\n public getInitialStorageInVM(blockConfig: BlockConfig): string {\n try {\n const result = executeSingleLambda(\n this.quickJs,\n INITIAL_STORAGE_HANDLE,\n extractCodeWithInfo(blockConfig),\n ) as string;\n return result;\n } catch (e) {\n console.error('[ProjectHelper.getInitialStorageInVM] Initial storage creation failed:', e);\n throw new Error(`Block initial storage creation failed: ${e}`);\n }\n }\n\n /**\n * Applies a state update using VM-based transformation.\n * This calls the model's `__pl_storage_applyUpdate` callback which:\n * - Normalizes current storage\n * - Updates state while preserving other fields (version, plugins)\n * - Returns the updated storage as JSON string\n *\n * @param blockConfig The block configuration (provides the model code)\n * @param currentStorageJson Current storage as JSON string (must be defined)\n * @param newState New state from developer\n * @returns Updated storage as JSON string\n * @throws Error if storage update fails\n */\n public applyStorageUpdateInVM(blockConfig: BlockConfig, currentStorageJson: string, payload: { operation: string; value: unknown }): string {\n try {\n const result = executeSingleLambda(\n this.quickJs,\n STORAGE_APPLY_UPDATE_HANDLE,\n extractCodeWithInfo(blockConfig),\n currentStorageJson,\n payload,\n ) as string;\n return result;\n } catch (e) {\n console.error('[ProjectHelper.applyStorageUpdateInVM] Storage update failed:', e);\n throw new Error(`Block storage update failed: ${e}`);\n }\n }\n\n /**\n * Gets storage debug view from raw storage data by calling the VM's __pl_storage_debugView callback.\n * Returns structured debug info about the storage (e.g., dataVersion).\n *\n * @param blockConfig Block configuration\n * @param rawStorageJson Raw storage as JSON string (or undefined)\n * @returns Storage debug view as JSON string (e.g., '{\"dataVersion\": \"v1\"}')\n */\n public getStorageDebugViewInVM(blockConfig: BlockConfig, rawStorageJson: string | undefined): StringifiedJson<StorageDebugView> | undefined {\n try {\n const result = executeSingleLambda(\n this.quickJs,\n STORAGE_DEBUG_VIEW_HANDLE,\n extractCodeWithInfo(blockConfig),\n rawStorageJson,\n ) as StringifiedJson<StorageDebugView>;\n return result;\n } catch (e) {\n console.error('[ProjectHelper.getStorageDebugViewInVM] Get storage debug view failed:', e);\n return undefined;\n }\n }\n\n // =============================================================================\n // Block State Migrations\n // =============================================================================\n\n /**\n * Runs block state migrations via VM-based transformation.\n * This calls the model's `__pl_storage_migrate` callback which:\n * - Normalizes current storage to get state and version\n * - Applies DataModel upgrade to reach target version key\n * - Runs all necessary migrations sequentially\n * - Returns new storage with updated state and version\n *\n * The middle layer doesn't need to know about dataVersion or storage internals.\n * All migration logic is encapsulated in the model.\n *\n * @param blockConfig The NEW block configuration (provides the model code with migrations)\n * @param currentStorageJson Current storage as JSON string (or undefined)\n * @returns MigrationResult with new storage or skip/error info\n */\n public migrateStorageInVM(blockConfig: BlockConfig, currentStorageJson: string | undefined): MigrationResult {\n try {\n const result = executeSingleLambda(\n this.quickJs,\n STORAGE_MIGRATE_HANDLE,\n extractCodeWithInfo(blockConfig),\n currentStorageJson,\n ) as MigrationResult;\n return result;\n } catch (e) {\n console.error('[ProjectHelper.migrateStorageInVM] Migration failed:', e);\n return { error: `VM execution failed: ${e}` };\n }\n }\n}\n"],"names":["LRUCache","executeSingleLambda","extractCodeWithInfo","ensureError"],"mappings":"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"}
@@ -81,14 +81,14 @@ export declare class ProjectHelper {
81
81
  *
82
82
  * @param blockConfig Block configuration
83
83
  * @param rawStorageJson Raw storage as JSON string (or undefined)
84
- * @returns Storage debug view as JSON string (e.g., '{"dataVersion": 1}')
84
+ * @returns Storage debug view as JSON string (e.g., '{"dataVersion": "v1"}')
85
85
  */
86
86
  getStorageDebugViewInVM(blockConfig: BlockConfig, rawStorageJson: string | undefined): StringifiedJson<StorageDebugView> | undefined;
87
87
  /**
88
88
  * Runs block state migrations via VM-based transformation.
89
89
  * This calls the model's `__pl_storage_migrate` callback which:
90
90
  * - Normalizes current storage to get state and version
91
- * - Calculates target version from number of registered migrations
91
+ * - Applies DataModel upgrade to reach target version key
92
92
  * - Runs all necessary migrations sequentially
93
93
  * - Returns new storage with updated state and version
94
94
  *
@@ -143,7 +143,7 @@ class ProjectHelper {
143
143
  *
144
144
  * @param blockConfig Block configuration
145
145
  * @param rawStorageJson Raw storage as JSON string (or undefined)
146
- * @returns Storage debug view as JSON string (e.g., '{"dataVersion": 1}')
146
+ * @returns Storage debug view as JSON string (e.g., '{"dataVersion": "v1"}')
147
147
  */
148
148
  getStorageDebugViewInVM(blockConfig, rawStorageJson) {
149
149
  try {
@@ -162,7 +162,7 @@ class ProjectHelper {
162
162
  * Runs block state migrations via VM-based transformation.
163
163
  * This calls the model's `__pl_storage_migrate` callback which:
164
164
  * - Normalizes current storage to get state and version
165
- * - Calculates target version from number of registered migrations
165
+ * - Applies DataModel upgrade to reach target version key
166
166
  * - Runs all necessary migrations sequentially
167
167
  * - Returns new storage with updated state and version
168
168
  *
@@ -1 +1 @@
1
- {"version":3,"file":"project_helper.js","sources":["../../src/model/project_helper.ts"],"sourcesContent":["import type { ResultOrError, BlockConfig, PlRef, ConfigRenderLambda, StorageDebugView } from '@platforma-sdk/model';\nimport type { StringifiedJson } from '@milaboratories/pl-model-common';\nimport { extractCodeWithInfo, ensureError } from '@platforma-sdk/model';\nimport { LRUCache } from 'lru-cache';\nimport type { QuickJSWASMModule } from 'quickjs-emscripten';\nimport { executeSingleLambda } from '../js_render';\nimport type { ResourceId } from '@milaboratories/pl-client';\n\ntype EnrichmentTargetsRequest = {\n blockConfig: () => BlockConfig;\n args: () => unknown;\n};\n\ntype EnrichmentTargetsValue = {\n value: PlRef[] | undefined;\n};\n\n/**\n * Result of VM-based storage migration.\n * Returned by migrateStorageInVM().\n *\n * - Error result: { error: string } - serious failure (no context, etc.)\n * - Success result: { newStorageJson: string, info: string, warn?: string } - migration succeeded or reset to initial\n */\nexport type MigrationResult =\n | { error: string }\n | { error?: undefined; newStorageJson: string; info: string; warn?: string };\n\n// Internal lambda handles for storage operations (registered by SDK's block_storage_vm.ts)\n// All callbacks are prefixed with `__pl_` to indicate internal SDK use\nconst STORAGE_APPLY_UPDATE_HANDLE: ConfigRenderLambda = { __renderLambda: true, handle: '__pl_storage_applyUpdate' };\nconst STORAGE_DEBUG_VIEW_HANDLE: ConfigRenderLambda = { __renderLambda: true, handle: '__pl_storage_debugView' };\nconst STORAGE_MIGRATE_HANDLE: ConfigRenderLambda = { __renderLambda: true, handle: '__pl_storage_migrate' };\nconst ARGS_DERIVE_HANDLE: ConfigRenderLambda = { __renderLambda: true, handle: '__pl_args_derive' };\nconst PRERUN_ARGS_DERIVE_HANDLE: ConfigRenderLambda = { __renderLambda: true, handle: '__pl_prerunArgs_derive' };\n// Registered by DataModel.registerCallbacks()\nconst INITIAL_STORAGE_HANDLE: ConfigRenderLambda = { __renderLambda: true, handle: '__pl_storage_initial' };\n\n/**\n * Result of args derivation from storage.\n * Returned by __pl_args_derive and __pl_prerunArgs_derive VM callbacks.\n */\ntype ArgsDeriveResult =\n | { error: string }\n | { error?: undefined; value: unknown };\n\nexport class ProjectHelper {\n private readonly enrichmentTargetsCache = new LRUCache<string, EnrichmentTargetsValue, EnrichmentTargetsRequest>({\n max: 256,\n memoMethod: (_key, _value, { context }) => {\n return { value: this.calculateEnrichmentTargets(context) };\n },\n });\n\n constructor(private readonly quickJs: QuickJSWASMModule) {}\n\n // =============================================================================\n // Args Derivation from Storage (V3+)\n // =============================================================================\n\n /**\n * Derives args directly from storage JSON using VM callback.\n * The VM extracts data from storage and calls the block's args() function.\n *\n * This allows the middle layer to work only with storage JSON,\n * without needing to know the underlying data structure.\n *\n * @param blockConfig The block configuration (provides the model code)\n * @param storageJson Storage as JSON string\n * @returns The derived args object, or error if derivation fails\n */\n public deriveArgsFromStorage(blockConfig: BlockConfig, storageJson: string): ResultOrError<unknown> {\n if (blockConfig.modelAPIVersion !== 2) {\n return { error: new Error('deriveArgsFromStorage is only supported for model API version 2') };\n }\n\n try {\n const result = executeSingleLambda(\n this.quickJs,\n ARGS_DERIVE_HANDLE,\n extractCodeWithInfo(blockConfig),\n storageJson,\n ) as ArgsDeriveResult;\n\n if (result.error !== undefined) {\n return { error: new Error(result.error) };\n }\n return { value: result.value };\n } catch (e) {\n return { error: new Error('Args derivation from storage failed', { cause: ensureError(e) }) };\n }\n }\n\n /**\n * Derives prerunArgs directly from storage JSON using VM callback.\n * Falls back to args() if prerunArgs is not defined in the block model.\n *\n * @param blockConfig The block configuration (provides the model code)\n * @param storageJson Storage as JSON string\n * @returns The derived prerunArgs, or undefined if derivation fails\n */\n public derivePrerunArgsFromStorage(blockConfig: BlockConfig, storageJson: string): unknown {\n if (blockConfig.modelAPIVersion !== 2) {\n throw new Error('derivePrerunArgsFromStorage is only supported for model API version 2');\n }\n\n try {\n const result = executeSingleLambda(\n this.quickJs,\n PRERUN_ARGS_DERIVE_HANDLE,\n extractCodeWithInfo(blockConfig),\n storageJson,\n ) as ArgsDeriveResult;\n\n if (result.error !== undefined) {\n // Return undefined if derivation fails (skip block in staging)\n return undefined;\n }\n return result.value;\n } catch {\n // Return undefined if derivation fails (skip block in staging)\n return undefined;\n }\n }\n\n private calculateEnrichmentTargets(req: EnrichmentTargetsRequest): PlRef[] | undefined {\n const blockConfig = req.blockConfig();\n if (blockConfig.enrichmentTargets === undefined) return undefined;\n const args = req.args();\n const result = executeSingleLambda(this.quickJs, blockConfig.enrichmentTargets, extractCodeWithInfo(blockConfig), args) as PlRef[];\n return result;\n }\n\n public getEnrichmentTargets(blockConfig: () => BlockConfig, args: () => unknown, key?: { argsRid: ResourceId; blockPackRid: ResourceId }): PlRef[] | undefined {\n const req = { blockConfig, args };\n if (key === undefined)\n return this.calculateEnrichmentTargets(req);\n const cacheKey = `${key.argsRid}:${key.blockPackRid}`;\n return this.enrichmentTargetsCache.memo(cacheKey, { context: req }).value;\n }\n\n // =============================================================================\n // VM-based Storage Operations\n // =============================================================================\n\n /**\n * Creates initial BlockStorage for a new block using VM-based transformation.\n * This calls the '__pl_storage_initial' callback registered by DataModel which:\n * - Gets initial data from DataModel.getDefaultData()\n * - Creates BlockStorage with correct version\n *\n * @param blockConfig The block configuration (provides the model code)\n * @returns Initial storage as JSON string\n * @throws Error if storage creation fails\n */\n public getInitialStorageInVM(blockConfig: BlockConfig): string {\n try {\n const result = executeSingleLambda(\n this.quickJs,\n INITIAL_STORAGE_HANDLE,\n extractCodeWithInfo(blockConfig),\n ) as string;\n return result;\n } catch (e) {\n console.error('[ProjectHelper.getInitialStorageInVM] Initial storage creation failed:', e);\n throw new Error(`Block initial storage creation failed: ${e}`);\n }\n }\n\n /**\n * Applies a state update using VM-based transformation.\n * This calls the model's `__pl_storage_applyUpdate` callback which:\n * - Normalizes current storage\n * - Updates state while preserving other fields (version, plugins)\n * - Returns the updated storage as JSON string\n *\n * @param blockConfig The block configuration (provides the model code)\n * @param currentStorageJson Current storage as JSON string (must be defined)\n * @param newState New state from developer\n * @returns Updated storage as JSON string\n * @throws Error if storage update fails\n */\n public applyStorageUpdateInVM(blockConfig: BlockConfig, currentStorageJson: string, payload: { operation: string; value: unknown }): string {\n try {\n const result = executeSingleLambda(\n this.quickJs,\n STORAGE_APPLY_UPDATE_HANDLE,\n extractCodeWithInfo(blockConfig),\n currentStorageJson,\n payload,\n ) as string;\n return result;\n } catch (e) {\n console.error('[ProjectHelper.applyStorageUpdateInVM] Storage update failed:', e);\n throw new Error(`Block storage update failed: ${e}`);\n }\n }\n\n /**\n * Gets storage debug view from raw storage data by calling the VM's __pl_storage_debugView callback.\n * Returns structured debug info about the storage (e.g., dataVersion).\n *\n * @param blockConfig Block configuration\n * @param rawStorageJson Raw storage as JSON string (or undefined)\n * @returns Storage debug view as JSON string (e.g., '{\"dataVersion\": 1}')\n */\n public getStorageDebugViewInVM(blockConfig: BlockConfig, rawStorageJson: string | undefined): StringifiedJson<StorageDebugView> | undefined {\n try {\n const result = executeSingleLambda(\n this.quickJs,\n STORAGE_DEBUG_VIEW_HANDLE,\n extractCodeWithInfo(blockConfig),\n rawStorageJson,\n ) as StringifiedJson<StorageDebugView>;\n return result;\n } catch (e) {\n console.error('[ProjectHelper.getStorageDebugViewInVM] Get storage debug view failed:', e);\n return undefined;\n }\n }\n\n // =============================================================================\n // Block State Migrations\n // =============================================================================\n\n /**\n * Runs block state migrations via VM-based transformation.\n * This calls the model's `__pl_storage_migrate` callback which:\n * - Normalizes current storage to get state and version\n * - Calculates target version from number of registered migrations\n * - Runs all necessary migrations sequentially\n * - Returns new storage with updated state and version\n *\n * The middle layer doesn't need to know about dataVersion or storage internals.\n * All migration logic is encapsulated in the model.\n *\n * @param blockConfig The NEW block configuration (provides the model code with migrations)\n * @param currentStorageJson Current storage as JSON string (or undefined)\n * @returns MigrationResult with new storage or skip/error info\n */\n public migrateStorageInVM(blockConfig: BlockConfig, currentStorageJson: string | undefined): MigrationResult {\n try {\n const result = executeSingleLambda(\n this.quickJs,\n STORAGE_MIGRATE_HANDLE,\n extractCodeWithInfo(blockConfig),\n currentStorageJson,\n ) as MigrationResult;\n return result;\n } catch (e) {\n console.error('[ProjectHelper.migrateStorageInVM] Migration failed:', e);\n return { error: `VM execution failed: ${e}` };\n }\n }\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"project_helper.js","sources":["../../src/model/project_helper.ts"],"sourcesContent":["import type { ResultOrError, BlockConfig, PlRef, ConfigRenderLambda, StorageDebugView } from '@platforma-sdk/model';\nimport type { StringifiedJson } from '@milaboratories/pl-model-common';\nimport { extractCodeWithInfo, ensureError } from '@platforma-sdk/model';\nimport { LRUCache } from 'lru-cache';\nimport type { QuickJSWASMModule } from 'quickjs-emscripten';\nimport { executeSingleLambda } from '../js_render';\nimport type { ResourceId } from '@milaboratories/pl-client';\n\ntype EnrichmentTargetsRequest = {\n blockConfig: () => BlockConfig;\n args: () => unknown;\n};\n\ntype EnrichmentTargetsValue = {\n value: PlRef[] | undefined;\n};\n\n/**\n * Result of VM-based storage migration.\n * Returned by migrateStorageInVM().\n *\n * - Error result: { error: string } - serious failure (no context, etc.)\n * - Success result: { newStorageJson: string, info: string, warn?: string } - migration succeeded or reset to initial\n */\nexport type MigrationResult =\n | { error: string }\n | { error?: undefined; newStorageJson: string; info: string; warn?: string };\n\n// Internal lambda handles for storage operations (registered by SDK's block_storage_vm.ts)\n// All callbacks are prefixed with `__pl_` to indicate internal SDK use\nconst STORAGE_APPLY_UPDATE_HANDLE: ConfigRenderLambda = { __renderLambda: true, handle: '__pl_storage_applyUpdate' };\nconst STORAGE_DEBUG_VIEW_HANDLE: ConfigRenderLambda = { __renderLambda: true, handle: '__pl_storage_debugView' };\nconst STORAGE_MIGRATE_HANDLE: ConfigRenderLambda = { __renderLambda: true, handle: '__pl_storage_migrate' };\nconst ARGS_DERIVE_HANDLE: ConfigRenderLambda = { __renderLambda: true, handle: '__pl_args_derive' };\nconst PRERUN_ARGS_DERIVE_HANDLE: ConfigRenderLambda = { __renderLambda: true, handle: '__pl_prerunArgs_derive' };\n// Registered by DataModel.registerCallbacks()\nconst INITIAL_STORAGE_HANDLE: ConfigRenderLambda = { __renderLambda: true, handle: '__pl_storage_initial' };\n\n/**\n * Result of args derivation from storage.\n * Returned by __pl_args_derive and __pl_prerunArgs_derive VM callbacks.\n */\ntype ArgsDeriveResult =\n | { error: string }\n | { error?: undefined; value: unknown };\n\nexport class ProjectHelper {\n private readonly enrichmentTargetsCache = new LRUCache<string, EnrichmentTargetsValue, EnrichmentTargetsRequest>({\n max: 256,\n memoMethod: (_key, _value, { context }) => {\n return { value: this.calculateEnrichmentTargets(context) };\n },\n });\n\n constructor(private readonly quickJs: QuickJSWASMModule) {}\n\n // =============================================================================\n // Args Derivation from Storage (V3+)\n // =============================================================================\n\n /**\n * Derives args directly from storage JSON using VM callback.\n * The VM extracts data from storage and calls the block's args() function.\n *\n * This allows the middle layer to work only with storage JSON,\n * without needing to know the underlying data structure.\n *\n * @param blockConfig The block configuration (provides the model code)\n * @param storageJson Storage as JSON string\n * @returns The derived args object, or error if derivation fails\n */\n public deriveArgsFromStorage(blockConfig: BlockConfig, storageJson: string): ResultOrError<unknown> {\n if (blockConfig.modelAPIVersion !== 2) {\n return { error: new Error('deriveArgsFromStorage is only supported for model API version 2') };\n }\n\n try {\n const result = executeSingleLambda(\n this.quickJs,\n ARGS_DERIVE_HANDLE,\n extractCodeWithInfo(blockConfig),\n storageJson,\n ) as ArgsDeriveResult;\n\n if (result.error !== undefined) {\n return { error: new Error(result.error) };\n }\n return { value: result.value };\n } catch (e) {\n return { error: new Error('Args derivation from storage failed', { cause: ensureError(e) }) };\n }\n }\n\n /**\n * Derives prerunArgs directly from storage JSON using VM callback.\n * Falls back to args() if prerunArgs is not defined in the block model.\n *\n * @param blockConfig The block configuration (provides the model code)\n * @param storageJson Storage as JSON string\n * @returns The derived prerunArgs, or undefined if derivation fails\n */\n public derivePrerunArgsFromStorage(blockConfig: BlockConfig, storageJson: string): unknown {\n if (blockConfig.modelAPIVersion !== 2) {\n throw new Error('derivePrerunArgsFromStorage is only supported for model API version 2');\n }\n\n try {\n const result = executeSingleLambda(\n this.quickJs,\n PRERUN_ARGS_DERIVE_HANDLE,\n extractCodeWithInfo(blockConfig),\n storageJson,\n ) as ArgsDeriveResult;\n\n if (result.error !== undefined) {\n // Return undefined if derivation fails (skip block in staging)\n return undefined;\n }\n return result.value;\n } catch {\n // Return undefined if derivation fails (skip block in staging)\n return undefined;\n }\n }\n\n private calculateEnrichmentTargets(req: EnrichmentTargetsRequest): PlRef[] | undefined {\n const blockConfig = req.blockConfig();\n if (blockConfig.enrichmentTargets === undefined) return undefined;\n const args = req.args();\n const result = executeSingleLambda(this.quickJs, blockConfig.enrichmentTargets, extractCodeWithInfo(blockConfig), args) as PlRef[];\n return result;\n }\n\n public getEnrichmentTargets(blockConfig: () => BlockConfig, args: () => unknown, key?: { argsRid: ResourceId; blockPackRid: ResourceId }): PlRef[] | undefined {\n const req = { blockConfig, args };\n if (key === undefined)\n return this.calculateEnrichmentTargets(req);\n const cacheKey = `${key.argsRid}:${key.blockPackRid}`;\n return this.enrichmentTargetsCache.memo(cacheKey, { context: req }).value;\n }\n\n // =============================================================================\n // VM-based Storage Operations\n // =============================================================================\n\n /**\n * Creates initial BlockStorage for a new block using VM-based transformation.\n * This calls the '__pl_storage_initial' callback registered by DataModel which:\n * - Gets initial data from DataModel.getDefaultData()\n * - Creates BlockStorage with correct version\n *\n * @param blockConfig The block configuration (provides the model code)\n * @returns Initial storage as JSON string\n * @throws Error if storage creation fails\n */\n public getInitialStorageInVM(blockConfig: BlockConfig): string {\n try {\n const result = executeSingleLambda(\n this.quickJs,\n INITIAL_STORAGE_HANDLE,\n extractCodeWithInfo(blockConfig),\n ) as string;\n return result;\n } catch (e) {\n console.error('[ProjectHelper.getInitialStorageInVM] Initial storage creation failed:', e);\n throw new Error(`Block initial storage creation failed: ${e}`);\n }\n }\n\n /**\n * Applies a state update using VM-based transformation.\n * This calls the model's `__pl_storage_applyUpdate` callback which:\n * - Normalizes current storage\n * - Updates state while preserving other fields (version, plugins)\n * - Returns the updated storage as JSON string\n *\n * @param blockConfig The block configuration (provides the model code)\n * @param currentStorageJson Current storage as JSON string (must be defined)\n * @param newState New state from developer\n * @returns Updated storage as JSON string\n * @throws Error if storage update fails\n */\n public applyStorageUpdateInVM(blockConfig: BlockConfig, currentStorageJson: string, payload: { operation: string; value: unknown }): string {\n try {\n const result = executeSingleLambda(\n this.quickJs,\n STORAGE_APPLY_UPDATE_HANDLE,\n extractCodeWithInfo(blockConfig),\n currentStorageJson,\n payload,\n ) as string;\n return result;\n } catch (e) {\n console.error('[ProjectHelper.applyStorageUpdateInVM] Storage update failed:', e);\n throw new Error(`Block storage update failed: ${e}`);\n }\n }\n\n /**\n * Gets storage debug view from raw storage data by calling the VM's __pl_storage_debugView callback.\n * Returns structured debug info about the storage (e.g., dataVersion).\n *\n * @param blockConfig Block configuration\n * @param rawStorageJson Raw storage as JSON string (or undefined)\n * @returns Storage debug view as JSON string (e.g., '{\"dataVersion\": \"v1\"}')\n */\n public getStorageDebugViewInVM(blockConfig: BlockConfig, rawStorageJson: string | undefined): StringifiedJson<StorageDebugView> | undefined {\n try {\n const result = executeSingleLambda(\n this.quickJs,\n STORAGE_DEBUG_VIEW_HANDLE,\n extractCodeWithInfo(blockConfig),\n rawStorageJson,\n ) as StringifiedJson<StorageDebugView>;\n return result;\n } catch (e) {\n console.error('[ProjectHelper.getStorageDebugViewInVM] Get storage debug view failed:', e);\n return undefined;\n }\n }\n\n // =============================================================================\n // Block State Migrations\n // =============================================================================\n\n /**\n * Runs block state migrations via VM-based transformation.\n * This calls the model's `__pl_storage_migrate` callback which:\n * - Normalizes current storage to get state and version\n * - Applies DataModel upgrade to reach target version key\n * - Runs all necessary migrations sequentially\n * - Returns new storage with updated state and version\n *\n * The middle layer doesn't need to know about dataVersion or storage internals.\n * All migration logic is encapsulated in the model.\n *\n * @param blockConfig The NEW block configuration (provides the model code with migrations)\n * @param currentStorageJson Current storage as JSON string (or undefined)\n * @returns MigrationResult with new storage or skip/error info\n */\n public migrateStorageInVM(blockConfig: BlockConfig, currentStorageJson: string | undefined): MigrationResult {\n try {\n const result = executeSingleLambda(\n this.quickJs,\n STORAGE_MIGRATE_HANDLE,\n extractCodeWithInfo(blockConfig),\n currentStorageJson,\n ) as MigrationResult;\n return result;\n } catch (e) {\n console.error('[ProjectHelper.migrateStorageInVM] Migration failed:', e);\n return { error: `VM execution failed: ${e}` };\n }\n }\n}\n"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@milaboratories/pl-middle-layer",
3
- "version": "1.46.8",
3
+ "version": "1.46.10",
4
4
  "description": "Pl Middle Layer",
5
5
  "engines": {
6
6
  "node": ">=22.19.0"
@@ -33,22 +33,22 @@
33
33
  "zod": "~3.23.8",
34
34
  "remeda": "^2.28.0",
35
35
  "@milaboratories/pl-http": "1.2.0",
36
- "@milaboratories/resolve-helper": "1.1.1",
37
36
  "@milaboratories/computable": "2.8.2",
38
- "@platforma-sdk/block-tools": "2.6.33",
39
- "@milaboratories/pl-drivers": "1.11.42",
37
+ "@platforma-sdk/block-tools": "2.6.35",
38
+ "@milaboratories/resolve-helper": "1.1.1",
40
39
  "@milaboratories/pl-client": "2.16.24",
40
+ "@milaboratories/pl-drivers": "1.11.42",
41
+ "@milaboratories/pl-model-middle-layer": "1.10.4",
41
42
  "@milaboratories/pl-model-backend": "1.1.41",
42
- "@milaboratories/pl-tree": "1.8.32",
43
43
  "@milaboratories/pl-model-common": "1.24.1",
44
- "@milaboratories/pl-model-middle-layer": "1.10.2",
45
- "@milaboratories/ts-helpers": "1.7.0",
46
- "@platforma-sdk/model": "1.53.0",
47
- "@milaboratories/pl-errors": "1.1.56",
44
+ "@milaboratories/pl-tree": "1.8.32",
45
+ "@platforma-sdk/model": "1.53.2",
48
46
  "@platforma-sdk/workflow-tengo": "5.8.1",
49
47
  "@milaboratories/pl-config": "1.7.11",
48
+ "@milaboratories/ts-helpers": "1.7.0",
49
+ "@milaboratories/pl-errors": "1.1.56",
50
50
  "@milaboratories/pl-deployments": "2.15.5",
51
- "@milaboratories/pf-driver": "1.0.28"
51
+ "@milaboratories/pf-driver": "1.0.30"
52
52
  },
53
53
  "devDependencies": {
54
54
  "semver": "^7.7.2",
@@ -60,9 +60,9 @@
60
60
  "@types/node": "~24.5.2",
61
61
  "tslib": "~2.7.0",
62
62
  "@milaboratories/build-configs": "1.4.0",
63
- "@milaboratories/ts-configs": "1.2.0",
64
63
  "@milaboratories/eslint-config": "1.0.5",
65
- "@milaboratories/ts-builder": "1.2.4"
64
+ "@milaboratories/ts-builder": "1.2.4",
65
+ "@milaboratories/ts-configs": "1.2.0"
66
66
  },
67
67
  "scripts": {
68
68
  "type-check": "ts-builder types --target node",
@@ -113,29 +113,29 @@ export function serializeBlockStorage(storage: BlockStorage): string {
113
113
  }
114
114
 
115
115
  /**
116
- * Checks if the storage needs migration based on version.
116
+ * Checks if the storage needs migration based on version key.
117
117
  *
118
118
  * @param storage - Current BlockStorage
119
- * @param targetVersion - Target schema version
119
+ * @param targetVersion - Target version key
120
120
  * @returns true if migration is needed
121
121
  */
122
- export function needsMigration(storage: BlockStorage, targetVersion: number): boolean {
123
- return getStorageDataVersion(storage) < targetVersion;
122
+ export function needsMigration(storage: BlockStorage, targetVersion: string): boolean {
123
+ return getStorageDataVersion(storage) !== targetVersion;
124
124
  }
125
125
 
126
126
  /**
127
127
  * Migrates BlockStorage from one version to another.
128
128
  *
129
129
  * @param storage - Current BlockStorage
130
- * @param fromVersion - Source version
131
- * @param toVersion - Target version
130
+ * @param fromVersion - Source version key
131
+ * @param toVersion - Target version key
132
132
  * @param handlers - Optional custom handlers
133
133
  * @returns Migrated BlockStorage
134
134
  */
135
135
  export function migrateBlockStorage<TState>(
136
136
  storage: BlockStorage<TState>,
137
- fromVersion: number,
138
- toVersion: number,
137
+ fromVersion: string,
138
+ toVersion: string,
139
139
  handlers: BlockStorageHandlers<TState> = defaultBlockStorageHandlers as BlockStorageHandlers<TState>,
140
140
  ): BlockStorage<TState> {
141
141
  const migrate = handlers.migrateStorage ?? defaultBlockStorageHandlers.migrateStorage;
@@ -175,7 +175,7 @@ export function isLegacyV1V2Format(rawData: unknown): rawData is LegacyV1V2State
175
175
  * @returns BlockStorage with legacy data as state
176
176
  */
177
177
  export function convertLegacyToBlockStorage(legacyData: LegacyV1V2State): BlockStorage<LegacyV1V2State> {
178
- return createBlockStorage(legacyData, 1);
178
+ return createBlockStorage(legacyData);
179
179
  }
180
180
 
181
181
  /**
@@ -202,7 +202,7 @@ export class ProjectHelper {
202
202
  *
203
203
  * @param blockConfig Block configuration
204
204
  * @param rawStorageJson Raw storage as JSON string (or undefined)
205
- * @returns Storage debug view as JSON string (e.g., '{"dataVersion": 1}')
205
+ * @returns Storage debug view as JSON string (e.g., '{"dataVersion": "v1"}')
206
206
  */
207
207
  public getStorageDebugViewInVM(blockConfig: BlockConfig, rawStorageJson: string | undefined): StringifiedJson<StorageDebugView> | undefined {
208
208
  try {
@@ -227,7 +227,7 @@ export class ProjectHelper {
227
227
  * Runs block state migrations via VM-based transformation.
228
228
  * This calls the model's `__pl_storage_migrate` callback which:
229
229
  * - Normalizes current storage to get state and version
230
- * - Calculates target version from number of registered migrations
230
+ * - Applies DataModel upgrade to reach target version key
231
231
  * - Runs all necessary migrations sequentially
232
232
  * - Returns new storage with updated state and version
233
233
  *