@platforma-sdk/model 1.58.0 → 1.58.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/dist/block_migrations.cjs +60 -77
  2. package/dist/block_migrations.cjs.map +1 -1
  3. package/dist/block_migrations.d.ts +35 -32
  4. package/dist/block_migrations.d.ts.map +1 -1
  5. package/dist/block_migrations.js +60 -78
  6. package/dist/block_migrations.js.map +1 -1
  7. package/dist/block_model.cjs +1 -1
  8. package/dist/block_model.cjs.map +1 -1
  9. package/dist/block_model.d.ts +1 -1
  10. package/dist/block_model.js +1 -1
  11. package/dist/block_model.js.map +1 -1
  12. package/dist/block_storage.cjs +6 -6
  13. package/dist/block_storage.cjs.map +1 -1
  14. package/dist/block_storage.d.ts +7 -7
  15. package/dist/block_storage.d.ts.map +1 -1
  16. package/dist/block_storage.js +6 -6
  17. package/dist/block_storage.js.map +1 -1
  18. package/dist/block_storage_callbacks.cjs +1 -0
  19. package/dist/block_storage_callbacks.cjs.map +1 -1
  20. package/dist/block_storage_callbacks.d.ts +4 -3
  21. package/dist/block_storage_callbacks.d.ts.map +1 -1
  22. package/dist/block_storage_callbacks.js +1 -0
  23. package/dist/block_storage_callbacks.js.map +1 -1
  24. package/dist/index.cjs +1 -3
  25. package/dist/index.cjs.map +1 -1
  26. package/dist/index.d.ts +2 -2
  27. package/dist/index.d.ts.map +1 -1
  28. package/dist/index.js +2 -2
  29. package/dist/package.json.cjs +1 -1
  30. package/dist/package.json.js +1 -1
  31. package/dist/plugin_model.cjs +2 -2
  32. package/dist/plugin_model.cjs.map +1 -1
  33. package/dist/plugin_model.d.ts +2 -2
  34. package/dist/plugin_model.js +2 -2
  35. package/dist/plugin_model.js.map +1 -1
  36. package/package.json +5 -5
  37. package/src/block_migrations.test.ts +109 -12
  38. package/src/block_migrations.ts +63 -87
  39. package/src/block_model.ts +1 -1
  40. package/src/block_storage.test.ts +8 -8
  41. package/src/block_storage.ts +10 -10
  42. package/src/block_storage_callbacks.ts +4 -3
  43. package/src/index.ts +22 -1
  44. package/src/plugin_model.test.ts +2 -2
  45. package/src/plugin_model.ts +2 -2
@@ -11,12 +11,12 @@
11
11
  import { BLOCK_STORAGE_KEY, BLOCK_STORAGE_SCHEMA_VERSION, type BlockStorage, type MutateStoragePayload, type StorageDebugView, type PluginRegistry } from "./block_storage";
12
12
  import type { PluginHandle } from "./plugin_handle";
13
13
  import { type StringifiedJson } from "@milaboratories/pl-model-common";
14
- import type { DataMigrationResult, DataVersioned } from "./block_migrations";
14
+ import type { DataVersioned } from "./block_migrations";
15
15
  /** Dependencies for storage migration */
16
16
  export interface MigrationHooks {
17
- migrateBlockData: (versioned: DataVersioned<unknown>) => DataMigrationResult<unknown>;
17
+ migrateBlockData: (versioned: DataVersioned<unknown>) => DataVersioned<unknown>;
18
18
  getPluginRegistry: () => PluginRegistry;
19
- migratePluginData: (handle: PluginHandle, versioned: DataVersioned<unknown>) => DataMigrationResult<unknown> | undefined;
19
+ migratePluginData: (handle: PluginHandle, versioned: DataVersioned<unknown>) => DataVersioned<unknown> | undefined;
20
20
  createPluginData: (handle: PluginHandle) => DataVersioned<unknown>;
21
21
  }
22
22
  /** Dependencies for initial storage creation */
@@ -79,6 +79,7 @@ export declare function migrateStorage(currentStorageJson: string | undefined, h
79
79
  *
80
80
  * @param hooks - Dependencies for creating initial block and plugin data
81
81
  * @returns Initial storage as branded JSON string
82
+ * @throws If initialDataFn or createPluginData throws
82
83
  */
83
84
  export declare function createInitialStorage(hooks: InitialStorageHooks): StringifiedJson<BlockStorage>;
84
85
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"block_storage_callbacks.d.ts","sourceRoot":"","sources":["../src/block_storage_callbacks.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"block_storage_callbacks.d.ts","sourceRoot":"","sources":["../src/block_storage_callbacks.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EACL,iBAAiB,EACjB,4BAA4B,EAC5B,KAAK,YAAY,EACjB,KAAK,oBAAoB,EACzB,KAAK,gBAAgB,EACrB,KAAK,cAAc,EAQpB,MAAM,iBAAiB,CAAC;AACzB,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAEpD,OAAO,EAAiB,KAAK,eAAe,EAAE,MAAM,iCAAiC,CAAC;AACtF,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAMxD,yCAAyC;AACzC,MAAM,WAAW,cAAc;IAC7B,gBAAgB,EAAE,CAAC,SAAS,EAAE,aAAa,CAAC,OAAO,CAAC,KAAK,aAAa,CAAC,OAAO,CAAC,CAAC;IAChF,iBAAiB,EAAE,MAAM,cAAc,CAAC;IACxC,iBAAiB,EAAE,CACjB,MAAM,EAAE,YAAY,EACpB,SAAS,EAAE,aAAa,CAAC,OAAO,CAAC,KAC9B,aAAa,CAAC,OAAO,CAAC,GAAG,SAAS,CAAC;IACxC,gBAAgB,EAAE,CAAC,MAAM,EAAE,YAAY,KAAK,aAAa,CAAC,OAAO,CAAC,CAAC;CACpE;AAED,gDAAgD;AAChD,MAAM,WAAW,mBAAmB;IAClC,mBAAmB,EAAE,MAAM,aAAa,CAAC,OAAO,CAAC,CAAC;IAClD,iBAAiB,EAAE,MAAM,cAAc,CAAC;IACxC,gBAAgB,EAAE,CAAC,MAAM,EAAE,YAAY,KAAK,aAAa,CAAC,OAAO,CAAC,CAAC;CACpE;AAED;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACrC,yCAAyC;IACzC,OAAO,EAAE,YAAY,CAAC;IACtB,+CAA+C;IAC/C,IAAI,EAAE,OAAO,CAAC;CACf;AAiDD;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAChC,kBAAkB,EAAE,MAAM,EAC1B,OAAO,EAAE,oBAAoB,GAC5B,eAAe,CAAC,YAAY,CAAC,CAO/B;AAkBD;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,UAAU,EAAE,OAAO,GAAG,eAAe,CAAC,gBAAgB,CAAC,CAO1F;AAMD;;;;;;GAMG;AACH,MAAM,MAAM,eAAe,GACvB;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,GACjB;IAAE,KAAK,CAAC,EAAE,SAAS,CAAC;IAAC,cAAc,EAAE,eAAe,CAAC,YAAY,CAAC,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAEvF;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAC5B,kBAAkB,EAAE,MAAM,GAAG,SAAS,EACtC,KAAK,EAAE,cAAc,GACpB,eAAe,CAgCjB;AAMD;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,mBAAmB,GAAG,eAAe,CAAC,YAAY,CAAC,CAkB9F;AAMD;;;GAGG;AACH,MAAM,MAAM,gBAAgB,GAAG;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,KAAK,CAAC,EAAE,SAAS,CAAC;IAAC,KAAK,EAAE,OAAO,CAAA;CAAE,CAAC;AAEzF;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,CACnC,WAAW,EAAE,MAAM,EACnB,YAAY,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,OAAO,GACvC,gBAAgB,CAYlB;AAED;;;;;;;;GAQG;AACH,wBAAgB,2BAA2B,CACzC,WAAW,EAAE,MAAM,EACnB,YAAY,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,OAAO,EACxC,kBAAkB,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,OAAO,GAC9C,gBAAgB,CAuBlB;AAGD,OAAO,EAAE,iBAAiB,EAAE,4BAA4B,EAAE,CAAC"}
@@ -141,6 +141,7 @@ function migrateStorage(currentStorageJson, hooks) {
141
141
  *
142
142
  * @param hooks - Dependencies for creating initial block and plugin data
143
143
  * @returns Initial storage as branded JSON string
144
+ * @throws If initialDataFn or createPluginData throws
144
145
  */
145
146
  function createInitialStorage(hooks) {
146
147
  const blockDefault = hooks.getDefaultBlockData();
@@ -1 +1 @@
1
- {"version":3,"file":"block_storage_callbacks.js","sources":["../src/block_storage_callbacks.ts"],"sourcesContent":["/**\n * BlockStorage Callback Implementations - wired to facade callbacks in BlockModelV3._done().\n *\n * Provides pure functions for storage operations (migration, initialization,\n * args derivation, updates, debug views). Each function takes its dependencies\n * explicitly as parameters.\n *\n * @module block_storage_callbacks\n * @internal\n */\n\nimport {\n BLOCK_STORAGE_KEY,\n BLOCK_STORAGE_SCHEMA_VERSION,\n type BlockStorage,\n type MutateStoragePayload,\n type StorageDebugView,\n type PluginRegistry,\n type VersionedData,\n createBlockStorage,\n getStorageData,\n isBlockStorage,\n migrateBlockStorage,\n normalizeBlockStorage,\n updateStorageData,\n} from \"./block_storage\";\nimport type { PluginHandle } from \"./plugin_handle\";\n\nimport { stringifyJson, type StringifiedJson } from \"@milaboratories/pl-model-common\";\nimport type { DataMigrationResult, DataVersioned } from \"./block_migrations\";\n\n// =============================================================================\n// Hook interfaces for dependency injection\n// =============================================================================\n\n/** Dependencies for storage migration */\nexport interface MigrationHooks {\n migrateBlockData: (versioned: DataVersioned<unknown>) => DataMigrationResult<unknown>;\n getPluginRegistry: () => PluginRegistry;\n migratePluginData: (\n handle: PluginHandle,\n versioned: DataVersioned<unknown>,\n ) => DataMigrationResult<unknown> | undefined;\n createPluginData: (handle: PluginHandle) => DataVersioned<unknown>;\n}\n\n/** Dependencies for initial storage creation */\nexport interface InitialStorageHooks {\n getDefaultBlockData: () => DataVersioned<unknown>;\n getPluginRegistry: () => PluginRegistry;\n createPluginData: (handle: PluginHandle) => DataVersioned<unknown>;\n}\n\n/**\n * Result of storage normalization\n */\nexport interface NormalizeStorageResult {\n /** The normalized BlockStorage object */\n storage: BlockStorage;\n /** The extracted data (what developers see) */\n data: unknown;\n}\n\n/**\n * Normalizes raw storage data and extracts state.\n * Handles all formats:\n * - New BlockStorage format (has discriminator)\n * - Legacy V1/V2 format ({ args, uiState })\n * - Raw V3 state (any other format)\n *\n * @param rawStorage - Raw data from blockStorage field (may be JSON string or object)\n * @returns Object with normalized storage and extracted state\n */\nfunction normalizeStorage(rawStorage: unknown): NormalizeStorageResult {\n // Handle undefined/null\n if (rawStorage === undefined || rawStorage === null) {\n const storage = createBlockStorage({});\n return { storage, data: {} };\n }\n\n // Parse JSON string if needed\n let parsed = rawStorage;\n if (typeof rawStorage === \"string\") {\n try {\n parsed = JSON.parse(rawStorage);\n } catch {\n // If parsing fails, treat string as the data\n const storage = createBlockStorage(rawStorage);\n return { storage, data: rawStorage };\n }\n }\n\n // Check for BlockStorage format (has discriminator)\n if (isBlockStorage(parsed)) {\n const storage = normalizeBlockStorage(parsed);\n return { storage, data: getStorageData(storage) };\n }\n\n // Check for legacy V1/V2 format: { args, uiState }\n if (isLegacyModelV1ApiFormat(parsed)) {\n // For legacy format, the whole object IS the data\n const storage = createBlockStorage(parsed);\n return { storage, data: parsed };\n }\n\n // Raw V3 data - wrap it\n const storage = createBlockStorage(parsed);\n return { storage, data: parsed };\n}\n\n/**\n * Applies a state update to existing storage.\n * Used when setData is called from the frontend.\n *\n * @param currentStorageJson - Current storage as JSON string (must be defined)\n * @param payload - Update payload with operation type and value\n * @returns Updated storage as StringifiedJson<BlockStorage>\n */\nexport function applyStorageUpdate(\n currentStorageJson: string,\n payload: MutateStoragePayload,\n): StringifiedJson<BlockStorage> {\n const { storage: currentStorage } = normalizeStorage(currentStorageJson);\n\n // Update data while preserving other storage fields (version, plugins)\n const updatedStorage = updateStorageData(currentStorage, payload);\n\n return stringifyJson(updatedStorage);\n}\n\n/**\n * Checks if data is in legacy Model API v1 format.\n * Legacy format has { args, uiState? } at top level without the BlockStorage discriminator.\n */\nfunction isLegacyModelV1ApiFormat(data: unknown): data is { args?: unknown } {\n if (data === null || typeof data !== \"object\") return false;\n if (isBlockStorage(data)) return false;\n\n const obj = data as Record<string, unknown>;\n return \"args\" in obj;\n}\n\n// =============================================================================\n// Facade Callback Implementations\n// =============================================================================\n\n/**\n * Gets storage debug view from raw storage data.\n * Returns structured debug info about the storage state.\n *\n * @param rawStorage - Raw data from blockStorage field (may be JSON string or object)\n * @returns JSON string with storage debug view\n */\nexport function getStorageDebugView(rawStorage: unknown): StringifiedJson<StorageDebugView> {\n const { storage } = normalizeStorage(rawStorage);\n const debugView: StorageDebugView = {\n dataVersion: storage.__dataVersion,\n data: storage.__data,\n };\n return stringifyJson(debugView);\n}\n\n// =============================================================================\n// Migration Support\n// =============================================================================\n\n/**\n * Result of storage migration.\n * Returned by __pl_storage_migrate callback.\n *\n * - Error result: { error: string } - serious failure (no context, etc.)\n * - Success result: { newStorageJson: StringifiedJson<BlockStorage>, info: string } - migration succeeded\n */\nexport type MigrationResult =\n | { error: string }\n | { error?: undefined; newStorageJson: StringifiedJson<BlockStorage>; info: string };\n\n/**\n * Runs storage migration using the provided hooks.\n * This is the main entry point for the middle layer to trigger migrations.\n *\n * @param currentStorageJson - Current storage as JSON string (or undefined)\n * @param hooks - Migration dependencies (block/plugin data migration and creation functions)\n * @returns MigrationResult\n */\nexport function migrateStorage(\n currentStorageJson: string | undefined,\n hooks: MigrationHooks,\n): MigrationResult {\n // Normalize current storage\n const { storage: currentStorage } = normalizeStorage(currentStorageJson);\n\n const newPluginRegistry = hooks.getPluginRegistry();\n\n // Perform atomic migration of block + all plugins\n const migrationResult = migrateBlockStorage(currentStorage, {\n migrateBlockData: hooks.migrateBlockData,\n migratePluginData: hooks.migratePluginData,\n newPluginRegistry,\n createPluginData: hooks.createPluginData,\n });\n\n if (!migrationResult.success) {\n return {\n error: `Migration failed at '${migrationResult.failedAt}': ${migrationResult.error}`,\n };\n }\n\n // Build info message\n const oldVersion = currentStorage.__dataVersion;\n const newVersion = migrationResult.storage.__dataVersion;\n const info =\n oldVersion === newVersion\n ? `No migration needed (${oldVersion})`\n : `Migrated ${oldVersion} -> ${newVersion}`;\n\n return {\n newStorageJson: stringifyJson(migrationResult.storage),\n info,\n };\n}\n\n// =============================================================================\n// Initial Storage Creation\n// =============================================================================\n\n/**\n * Creates complete initial storage (block data + all plugin data) atomically.\n *\n * @param hooks - Dependencies for creating initial block and plugin data\n * @returns Initial storage as branded JSON string\n */\nexport function createInitialStorage(hooks: InitialStorageHooks): StringifiedJson<BlockStorage> {\n const blockDefault = hooks.getDefaultBlockData();\n const pluginRegistry = hooks.getPluginRegistry();\n\n const plugins: Record<PluginHandle, VersionedData<unknown>> = {};\n for (const handle of Object.keys(pluginRegistry) as PluginHandle[]) {\n const initial = hooks.createPluginData(handle);\n plugins[handle] = { __dataVersion: initial.version, __data: initial.data };\n }\n\n const storage: BlockStorage = {\n [BLOCK_STORAGE_KEY]: BLOCK_STORAGE_SCHEMA_VERSION,\n __dataVersion: blockDefault.version,\n __data: blockDefault.data,\n __pluginRegistry: pluginRegistry,\n __plugins: plugins,\n };\n return stringifyJson(storage);\n}\n\n// =============================================================================\n// Args Derivation from Storage\n// =============================================================================\n\n/**\n * Result of args derivation from storage.\n * Returned by __pl_args_derive and __pl_prerunArgs_derive callbacks.\n */\nexport type ArgsDeriveResult = { error: string } | { error?: undefined; value: unknown };\n\n/**\n * Derives args from storage using the provided args function.\n * This extracts data from storage and passes it to the block's args() function.\n *\n * @param storageJson - Storage as JSON string\n * @param argsFunction - The block's args derivation function\n * @returns ArgsDeriveResult with derived args or error\n */\nexport function deriveArgsFromStorage(\n storageJson: string,\n argsFunction: (data: unknown) => unknown,\n): ArgsDeriveResult {\n // Extract data from storage\n const { data } = normalizeStorage(storageJson);\n\n // Call the args function with extracted data\n try {\n const result = argsFunction(data);\n return { value: result };\n } catch (e) {\n const errorMsg = e instanceof Error ? e.message : String(e);\n return { error: `args() threw: ${errorMsg}` };\n }\n}\n\n/**\n * Derives prerunArgs from storage.\n * Uses prerunArgsFunction if provided, otherwise falls back to argsFunction.\n *\n * @param storageJson - Storage as JSON string\n * @param argsFunction - The block's args derivation function (fallback)\n * @param prerunArgsFunction - Optional prerun args derivation function\n * @returns ArgsDeriveResult with derived prerunArgs or error\n */\nexport function derivePrerunArgsFromStorage(\n storageJson: string,\n argsFunction: (data: unknown) => unknown,\n prerunArgsFunction?: (data: unknown) => unknown,\n): ArgsDeriveResult {\n // Extract data from storage\n const { data } = normalizeStorage(storageJson);\n\n // Try prerunArgs function first if available\n if (prerunArgsFunction) {\n try {\n const result = prerunArgsFunction(data);\n return { value: result };\n } catch (e) {\n const errorMsg = e instanceof Error ? e.message : String(e);\n return { error: `prerunArgs() threw: ${errorMsg}` };\n }\n }\n\n // Fall back to args function\n try {\n const result = argsFunction(data);\n return { value: result };\n } catch (e) {\n const errorMsg = e instanceof Error ? e.message : String(e);\n return { error: `args() threw (fallback): ${errorMsg}` };\n }\n}\n\n// Export discriminator key and schema version for external checks\nexport { BLOCK_STORAGE_KEY, BLOCK_STORAGE_SCHEMA_VERSION };\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"block_storage_callbacks.js","sources":["../src/block_storage_callbacks.ts"],"sourcesContent":["/**\n * BlockStorage Callback Implementations - wired to facade callbacks in BlockModelV3._done().\n *\n * Provides pure functions for storage operations (migration, initialization,\n * args derivation, updates, debug views). Each function takes its dependencies\n * explicitly as parameters.\n *\n * @module block_storage_callbacks\n * @internal\n */\n\nimport {\n BLOCK_STORAGE_KEY,\n BLOCK_STORAGE_SCHEMA_VERSION,\n type BlockStorage,\n type MutateStoragePayload,\n type StorageDebugView,\n type PluginRegistry,\n type VersionedData,\n createBlockStorage,\n getStorageData,\n isBlockStorage,\n migrateBlockStorage,\n normalizeBlockStorage,\n updateStorageData,\n} from \"./block_storage\";\nimport type { PluginHandle } from \"./plugin_handle\";\n\nimport { stringifyJson, type StringifiedJson } from \"@milaboratories/pl-model-common\";\nimport type { DataVersioned } from \"./block_migrations\";\n\n// =============================================================================\n// Hook interfaces for dependency injection\n// =============================================================================\n\n/** Dependencies for storage migration */\nexport interface MigrationHooks {\n migrateBlockData: (versioned: DataVersioned<unknown>) => DataVersioned<unknown>;\n getPluginRegistry: () => PluginRegistry;\n migratePluginData: (\n handle: PluginHandle,\n versioned: DataVersioned<unknown>,\n ) => DataVersioned<unknown> | undefined;\n createPluginData: (handle: PluginHandle) => DataVersioned<unknown>;\n}\n\n/** Dependencies for initial storage creation */\nexport interface InitialStorageHooks {\n getDefaultBlockData: () => DataVersioned<unknown>;\n getPluginRegistry: () => PluginRegistry;\n createPluginData: (handle: PluginHandle) => DataVersioned<unknown>;\n}\n\n/**\n * Result of storage normalization\n */\nexport interface NormalizeStorageResult {\n /** The normalized BlockStorage object */\n storage: BlockStorage;\n /** The extracted data (what developers see) */\n data: unknown;\n}\n\n/**\n * Normalizes raw storage data and extracts state.\n * Handles all formats:\n * - New BlockStorage format (has discriminator)\n * - Legacy V1/V2 format ({ args, uiState })\n * - Raw V3 state (any other format)\n *\n * @param rawStorage - Raw data from blockStorage field (may be JSON string or object)\n * @returns Object with normalized storage and extracted state\n */\nfunction normalizeStorage(rawStorage: unknown): NormalizeStorageResult {\n // Handle undefined/null\n if (rawStorage === undefined || rawStorage === null) {\n const storage = createBlockStorage({});\n return { storage, data: {} };\n }\n\n // Parse JSON string if needed\n let parsed = rawStorage;\n if (typeof rawStorage === \"string\") {\n try {\n parsed = JSON.parse(rawStorage);\n } catch {\n // If parsing fails, treat string as the data\n const storage = createBlockStorage(rawStorage);\n return { storage, data: rawStorage };\n }\n }\n\n // Check for BlockStorage format (has discriminator)\n if (isBlockStorage(parsed)) {\n const storage = normalizeBlockStorage(parsed);\n return { storage, data: getStorageData(storage) };\n }\n\n // Check for legacy V1/V2 format: { args, uiState }\n if (isLegacyModelV1ApiFormat(parsed)) {\n // For legacy format, the whole object IS the data\n const storage = createBlockStorage(parsed);\n return { storage, data: parsed };\n }\n\n // Raw V3 data - wrap it\n const storage = createBlockStorage(parsed);\n return { storage, data: parsed };\n}\n\n/**\n * Applies a state update to existing storage.\n * Used when setData is called from the frontend.\n *\n * @param currentStorageJson - Current storage as JSON string (must be defined)\n * @param payload - Update payload with operation type and value\n * @returns Updated storage as StringifiedJson<BlockStorage>\n */\nexport function applyStorageUpdate(\n currentStorageJson: string,\n payload: MutateStoragePayload,\n): StringifiedJson<BlockStorage> {\n const { storage: currentStorage } = normalizeStorage(currentStorageJson);\n\n // Update data while preserving other storage fields (version, plugins)\n const updatedStorage = updateStorageData(currentStorage, payload);\n\n return stringifyJson(updatedStorage);\n}\n\n/**\n * Checks if data is in legacy Model API v1 format.\n * Legacy format has { args, uiState? } at top level without the BlockStorage discriminator.\n */\nfunction isLegacyModelV1ApiFormat(data: unknown): data is { args?: unknown } {\n if (data === null || typeof data !== \"object\") return false;\n if (isBlockStorage(data)) return false;\n\n const obj = data as Record<string, unknown>;\n return \"args\" in obj;\n}\n\n// =============================================================================\n// Facade Callback Implementations\n// =============================================================================\n\n/**\n * Gets storage debug view from raw storage data.\n * Returns structured debug info about the storage state.\n *\n * @param rawStorage - Raw data from blockStorage field (may be JSON string or object)\n * @returns JSON string with storage debug view\n */\nexport function getStorageDebugView(rawStorage: unknown): StringifiedJson<StorageDebugView> {\n const { storage } = normalizeStorage(rawStorage);\n const debugView: StorageDebugView = {\n dataVersion: storage.__dataVersion,\n data: storage.__data,\n };\n return stringifyJson(debugView);\n}\n\n// =============================================================================\n// Migration Support\n// =============================================================================\n\n/**\n * Result of storage migration.\n * Returned by __pl_storage_migrate callback.\n *\n * - Error result: { error: string } - serious failure (no context, etc.)\n * - Success result: { newStorageJson: StringifiedJson<BlockStorage>, info: string } - migration succeeded\n */\nexport type MigrationResult =\n | { error: string }\n | { error?: undefined; newStorageJson: StringifiedJson<BlockStorage>; info: string };\n\n/**\n * Runs storage migration using the provided hooks.\n * This is the main entry point for the middle layer to trigger migrations.\n *\n * @param currentStorageJson - Current storage as JSON string (or undefined)\n * @param hooks - Migration dependencies (block/plugin data migration and creation functions)\n * @returns MigrationResult\n */\nexport function migrateStorage(\n currentStorageJson: string | undefined,\n hooks: MigrationHooks,\n): MigrationResult {\n // Normalize current storage\n const { storage: currentStorage } = normalizeStorage(currentStorageJson);\n\n const newPluginRegistry = hooks.getPluginRegistry();\n\n // Perform atomic migration of block + all plugins\n const migrationResult = migrateBlockStorage(currentStorage, {\n migrateBlockData: hooks.migrateBlockData,\n migratePluginData: hooks.migratePluginData,\n newPluginRegistry,\n createPluginData: hooks.createPluginData,\n });\n\n if (!migrationResult.success) {\n return {\n error: `Migration failed at '${migrationResult.failedAt}': ${migrationResult.error}`,\n };\n }\n\n // Build info message\n const oldVersion = currentStorage.__dataVersion;\n const newVersion = migrationResult.storage.__dataVersion;\n const info =\n oldVersion === newVersion\n ? `No migration needed (${oldVersion})`\n : `Migrated ${oldVersion} -> ${newVersion}`;\n\n return {\n newStorageJson: stringifyJson(migrationResult.storage),\n info,\n };\n}\n\n// =============================================================================\n// Initial Storage Creation\n// =============================================================================\n\n/**\n * Creates complete initial storage (block data + all plugin data) atomically.\n *\n * @param hooks - Dependencies for creating initial block and plugin data\n * @returns Initial storage as branded JSON string\n * @throws If initialDataFn or createPluginData throws\n */\nexport function createInitialStorage(hooks: InitialStorageHooks): StringifiedJson<BlockStorage> {\n const blockDefault = hooks.getDefaultBlockData();\n const pluginRegistry = hooks.getPluginRegistry();\n\n const plugins: Record<PluginHandle, VersionedData<unknown>> = {};\n for (const handle of Object.keys(pluginRegistry) as PluginHandle[]) {\n const initial = hooks.createPluginData(handle);\n plugins[handle] = { __dataVersion: initial.version, __data: initial.data };\n }\n\n const storage: BlockStorage = {\n [BLOCK_STORAGE_KEY]: BLOCK_STORAGE_SCHEMA_VERSION,\n __dataVersion: blockDefault.version,\n __data: blockDefault.data,\n __pluginRegistry: pluginRegistry,\n __plugins: plugins,\n };\n return stringifyJson(storage);\n}\n\n// =============================================================================\n// Args Derivation from Storage\n// =============================================================================\n\n/**\n * Result of args derivation from storage.\n * Returned by __pl_args_derive and __pl_prerunArgs_derive callbacks.\n */\nexport type ArgsDeriveResult = { error: string } | { error?: undefined; value: unknown };\n\n/**\n * Derives args from storage using the provided args function.\n * This extracts data from storage and passes it to the block's args() function.\n *\n * @param storageJson - Storage as JSON string\n * @param argsFunction - The block's args derivation function\n * @returns ArgsDeriveResult with derived args or error\n */\nexport function deriveArgsFromStorage(\n storageJson: string,\n argsFunction: (data: unknown) => unknown,\n): ArgsDeriveResult {\n // Extract data from storage\n const { data } = normalizeStorage(storageJson);\n\n // Call the args function with extracted data\n try {\n const result = argsFunction(data);\n return { value: result };\n } catch (e) {\n const errorMsg = e instanceof Error ? e.message : String(e);\n return { error: `args() threw: ${errorMsg}` };\n }\n}\n\n/**\n * Derives prerunArgs from storage.\n * Uses prerunArgsFunction if provided, otherwise falls back to argsFunction.\n *\n * @param storageJson - Storage as JSON string\n * @param argsFunction - The block's args derivation function (fallback)\n * @param prerunArgsFunction - Optional prerun args derivation function\n * @returns ArgsDeriveResult with derived prerunArgs or error\n */\nexport function derivePrerunArgsFromStorage(\n storageJson: string,\n argsFunction: (data: unknown) => unknown,\n prerunArgsFunction?: (data: unknown) => unknown,\n): ArgsDeriveResult {\n // Extract data from storage\n const { data } = normalizeStorage(storageJson);\n\n // Try prerunArgs function first if available\n if (prerunArgsFunction) {\n try {\n const result = prerunArgsFunction(data);\n return { value: result };\n } catch (e) {\n const errorMsg = e instanceof Error ? e.message : String(e);\n return { error: `prerunArgs() threw: ${errorMsg}` };\n }\n }\n\n // Fall back to args function\n try {\n const result = argsFunction(data);\n return { value: result };\n } catch (e) {\n const errorMsg = e instanceof Error ? e.message : String(e);\n return { error: `args() threw (fallback): ${errorMsg}` };\n }\n}\n\n// Export discriminator key and schema version for external checks\nexport { BLOCK_STORAGE_KEY, BLOCK_STORAGE_SCHEMA_VERSION };\n"],"names":[],"mappings":"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"}
package/dist/index.cjs CHANGED
@@ -48,9 +48,6 @@ exports.wrapOutputs = block_state_util.wrapOutputs;
48
48
  exports.isPluginOutputKey = plugin_handle.isPluginOutputKey;
49
49
  exports.pluginOutputKey = plugin_handle.pluginOutputKey;
50
50
  exports.pluginOutputPrefix = plugin_handle.pluginOutputPrefix;
51
- exports.BLOCK_STORAGE_KEY = block_storage.BLOCK_STORAGE_KEY;
52
- exports.BLOCK_STORAGE_SCHEMA_VERSION = block_storage.BLOCK_STORAGE_SCHEMA_VERSION;
53
- exports.DATA_MODEL_DEFAULT_VERSION = block_storage.DATA_MODEL_DEFAULT_VERSION;
54
51
  exports.createBlockStorage = block_storage.createBlockStorage;
55
52
  exports.deriveDataFromStorage = block_storage.deriveDataFromStorage;
56
53
  exports.getPluginData = block_storage.getPluginData;
@@ -65,6 +62,7 @@ exports.BlockStorageFacadeHandles = block_storage_facade.BlockStorageFacadeHandl
65
62
  exports.registerFacadeCallbacks = block_storage_facade.registerFacadeCallbacks;
66
63
  exports.BlockModel = block_model_legacy.BlockModel;
67
64
  exports.BlockModelV3 = block_model.BlockModelV3;
65
+ exports.DataMigrationError = block_migrations.DataMigrationError;
68
66
  exports.DataModel = block_migrations.DataModel;
69
67
  exports.DataModelBuilder = block_migrations.DataModelBuilder;
70
68
  exports.DataUnrecoverableError = block_migrations.DataUnrecoverableError;
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"index.cjs","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
package/dist/index.d.ts CHANGED
@@ -1,12 +1,12 @@
1
1
  export * from "./block_state_patch";
2
2
  export * from "./block_state_util";
3
3
  export * from "./plugin_handle";
4
- export * from "./block_storage";
4
+ export { type BlockStorageSchemaVersion, type PluginName, type PluginRegistry, type VersionedData, type BlockStorage, isBlockStorage, createBlockStorage, normalizeBlockStorage, getStorageData, deriveDataFromStorage, type MutateStoragePayload, updateStorageData, type StorageDebugView, type MigrationSuccess, type MigrationFailure, type MigrationResult, type MigrateBlockStorageConfig, migrateBlockStorage, getPluginData, } from "./block_storage";
5
5
  export * from "./block_storage_facade";
6
6
  export * from "./block_model_legacy";
7
7
  export { BlockModelV3 } from "./block_model";
8
8
  export type { PluginInstance, ParamsInput } from "./block_model";
9
- export { DataModel, DataModelBuilder, DataUnrecoverableError, isDataUnrecoverableError, defaultRecover, makeDataVersioned, } from "./block_migrations";
9
+ export { DataModel, DataModelBuilder, DataMigrationError, DataUnrecoverableError, isDataUnrecoverableError, defaultRecover, makeDataVersioned, } from "./block_migrations";
10
10
  export type { LegacyV1State } from "./block_migrations";
11
11
  export * from "./plugin_model";
12
12
  export * from "./bconfig";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,qBAAqB,CAAC;AACpC,cAAc,oBAAoB,CAAC;AACnC,cAAc,iBAAiB,CAAC;AAChC,cAAc,iBAAiB,CAAC;AAChC,cAAc,wBAAwB,CAAC;AACvC,cAAc,sBAAsB,CAAC;AACrC,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAC7C,YAAY,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AACjE,OAAO,EACL,SAAS,EACT,gBAAgB,EAChB,sBAAsB,EACtB,wBAAwB,EACxB,cAAc,EACd,iBAAiB,GAClB,MAAM,oBAAoB,CAAC;AAC5B,YAAY,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACxD,cAAc,gBAAgB,CAAC;AAC/B,cAAc,WAAW,CAAC;AAC1B,cAAc,cAAc,CAAC;AAC7B,cAAc,UAAU,CAAC;AACzB,cAAc,UAAU,CAAC;AACzB,cAAc,aAAa,CAAC;AAC5B,cAAc,YAAY,CAAC;AAC3B,cAAc,UAAU,CAAC;AACzB,cAAc,WAAW,CAAC;AAC1B,cAAc,eAAe,CAAC;AAC9B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,WAAW,CAAC;AAC1B,cAAc,eAAe,CAAC;AAC9B,cAAc,gBAAgB,CAAC;AAG/B,cAAc,iCAAiC,CAAC;AAChD,cAAc,+BAA+B,CAAC;AAE9C,OAAO,KAAK,gBAAgB,MAAM,mBAAmB,CAAC;AACtD,OAAO,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,qBAAqB,CAAC;AACpC,cAAc,oBAAoB,CAAC;AACnC,cAAc,iBAAiB,CAAC;AAChC,OAAO,EACL,KAAK,yBAAyB,EAC9B,KAAK,UAAU,EACf,KAAK,cAAc,EACnB,KAAK,aAAa,EAClB,KAAK,YAAY,EACjB,cAAc,EACd,kBAAkB,EAClB,qBAAqB,EACrB,cAAc,EACd,qBAAqB,EACrB,KAAK,oBAAoB,EACzB,iBAAiB,EACjB,KAAK,gBAAgB,EACrB,KAAK,gBAAgB,EACrB,KAAK,gBAAgB,EACrB,KAAK,eAAe,EACpB,KAAK,yBAAyB,EAC9B,mBAAmB,EACnB,aAAa,GACd,MAAM,iBAAiB,CAAC;AACzB,cAAc,wBAAwB,CAAC;AACvC,cAAc,sBAAsB,CAAC;AACrC,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAC7C,YAAY,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AACjE,OAAO,EACL,SAAS,EACT,gBAAgB,EAChB,kBAAkB,EAClB,sBAAsB,EACtB,wBAAwB,EACxB,cAAc,EACd,iBAAiB,GAClB,MAAM,oBAAoB,CAAC;AAC5B,YAAY,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACxD,cAAc,gBAAgB,CAAC;AAC/B,cAAc,WAAW,CAAC;AAC1B,cAAc,cAAc,CAAC;AAC7B,cAAc,UAAU,CAAC;AACzB,cAAc,UAAU,CAAC;AACzB,cAAc,aAAa,CAAC;AAC5B,cAAc,YAAY,CAAC;AAC3B,cAAc,UAAU,CAAC;AACzB,cAAc,WAAW,CAAC;AAC1B,cAAc,eAAe,CAAC;AAC9B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,WAAW,CAAC;AAC1B,cAAc,eAAe,CAAC;AAC9B,cAAc,gBAAgB,CAAC;AAG/B,cAAc,iCAAiC,CAAC;AAChD,cAAc,+BAA+B,CAAC;AAE9C,OAAO,KAAK,gBAAgB,MAAM,mBAAmB,CAAC;AACtD,OAAO,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC"}
package/dist/index.js CHANGED
@@ -1,10 +1,10 @@
1
1
  export { OutputError, readOutput, wrapOutputs } from './block_state_util.js';
2
2
  export { isPluginOutputKey, pluginOutputKey, pluginOutputPrefix } from './plugin_handle.js';
3
- export { BLOCK_STORAGE_KEY, BLOCK_STORAGE_SCHEMA_VERSION, DATA_MODEL_DEFAULT_VERSION, createBlockStorage, deriveDataFromStorage, getPluginData, getStorageData, isBlockStorage, migrateBlockStorage, normalizeBlockStorage, updateStorageData } from './block_storage.js';
3
+ export { createBlockStorage, deriveDataFromStorage, getPluginData, getStorageData, isBlockStorage, migrateBlockStorage, normalizeBlockStorage, updateStorageData } from './block_storage.js';
4
4
  export { BLOCK_STORAGE_FACADE_VERSION, BlockStorageFacadeCallbacks, BlockStorageFacadeHandles, registerFacadeCallbacks } from './block_storage_facade.js';
5
5
  export { BlockModel } from './block_model_legacy.js';
6
6
  export { BlockModelV3 } from './block_model.js';
7
- export { DataModel, DataModelBuilder, DataUnrecoverableError, defaultRecover, isDataUnrecoverableError, makeDataVersioned } from './block_migrations.js';
7
+ export { DataMigrationError, DataModel, DataModelBuilder, DataUnrecoverableError, defaultRecover, isDataUnrecoverableError, makeDataVersioned } from './block_migrations.js';
8
8
  export { PluginModel } from './plugin_model.js';
9
9
  export { downgradeCfgOrLambda, extractConfig } from './bconfig/normalization.js';
10
10
  export { isConfigLambda } from './bconfig/types.js';
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var version = "1.58.0";
3
+ var version = "1.58.1";
4
4
 
5
5
  exports.version = version;
6
6
  //# sourceMappingURL=package.json.cjs.map
@@ -1,4 +1,4 @@
1
- var version = "1.58.0";
1
+ var version = "1.58.1";
2
2
 
3
3
  export { version };
4
4
  //# sourceMappingURL=package.json.js.map
@@ -45,7 +45,7 @@ class PluginModel {
45
45
  * @returns PluginModelBuilder for chaining output definitions
46
46
  *
47
47
  * @example
48
- * const dataModelChain = new DataModelBuilder().from<MyData>(DATA_MODEL_DEFAULT_VERSION);
48
+ * const dataModelChain = new DataModelBuilder().from<MyData>("v1");
49
49
  *
50
50
  * const myPlugin = PluginModel.define({
51
51
  * name: 'myPlugin' as PluginName,
@@ -90,7 +90,7 @@ class PluginModelFactory {
90
90
  * @typeParam Outputs - Accumulated output types
91
91
  *
92
92
  * @example
93
- * const dataModelChain = new DataModelBuilder().from<TableData>(DATA_MODEL_DEFAULT_VERSION);
93
+ * const dataModelChain = new DataModelBuilder().from<TableData>("v1");
94
94
  *
95
95
  * const dataTable = PluginModel.define<TableData, TableParams, TableConfig>({
96
96
  * name: 'dataTable' as PluginName,
@@ -1 +1 @@
1
- {"version":3,"file":"plugin_model.cjs","sources":["../src/plugin_model.ts"],"sourcesContent":["/**\n * PluginModel - Builder for creating plugin types with data model and outputs.\n *\n * Plugins are UI components with their own model logic and persistent state.\n * Block developers register plugin instances via BlockModelV3.plugin() method.\n *\n * @module plugin_model\n */\n\nimport type { BlockCodeKnownFeatureFlags } from \"@milaboratories/pl-model-common\";\nimport type { DataModel } from \"./block_migrations\";\nimport type { PluginName } from \"./block_storage\";\nimport type { PluginFactoryLike } from \"./plugin_handle\";\nimport type { PluginRenderCtx } from \"./render\";\n\n/** Symbol for internal builder creation method */\nconst FROM_BUILDER = Symbol(\"fromBuilder\");\n\nexport type PluginData = Record<string, unknown>;\nexport type PluginParams = undefined | Record<string, unknown>;\nexport type PluginOutputs = Record<string, unknown>;\nexport type PluginConfig = undefined | Record<string, unknown>;\n\n/**\n * Configured plugin instance returned by PluginModelFactory.create().\n * Contains the plugin's name, data model, and output definitions.\n */\nexport class PluginModel<\n Data extends PluginData = PluginData,\n Params extends PluginParams = undefined,\n Outputs extends PluginOutputs = PluginOutputs,\n> {\n /** Globally unique plugin name */\n readonly name: PluginName;\n /** Data model instance for this plugin */\n readonly dataModel: DataModel<Data>;\n /** Output definitions - functions that compute outputs from plugin context */\n readonly outputs: {\n [K in keyof Outputs]: (ctx: PluginRenderCtx<PluginFactoryLike<Data, Params>>) => Outputs[K];\n };\n /** Feature flags declared by this plugin */\n readonly featureFlags?: BlockCodeKnownFeatureFlags;\n\n private constructor(options: {\n name: PluginName;\n dataModel: DataModel<Data>;\n outputs: {\n [K in keyof Outputs]: (ctx: PluginRenderCtx<PluginFactoryLike<Data, Params>>) => Outputs[K];\n };\n featureFlags?: BlockCodeKnownFeatureFlags;\n }) {\n this.name = options.name;\n this.dataModel = options.dataModel;\n this.outputs = options.outputs;\n this.featureFlags = options.featureFlags;\n }\n\n /**\n * Internal method for creating PluginModel from factory.\n * Uses Symbol key to prevent external access.\n * @internal\n */\n static [FROM_BUILDER]<\n Data extends PluginData,\n Params extends PluginParams,\n Outputs extends PluginOutputs,\n >(options: {\n name: PluginName;\n dataModel: DataModel<Data>;\n outputs: {\n [K in keyof Outputs]: (ctx: PluginRenderCtx<PluginFactoryLike<Data, Params>>) => Outputs[K];\n };\n featureFlags?: BlockCodeKnownFeatureFlags;\n }): PluginModel<Data, Params, Outputs> {\n return new PluginModel<Data, Params, Outputs>(options);\n }\n\n /**\n * Creates a new PluginModelBuilder for building plugin definitions.\n *\n * @param options.name - Globally unique plugin name\n * @param options.data - Factory function that creates the data model from config\n * @returns PluginModelBuilder for chaining output definitions\n *\n * @example\n * const dataModelChain = new DataModelBuilder().from<MyData>(DATA_MODEL_DEFAULT_VERSION);\n *\n * const myPlugin = PluginModel.define({\n * name: 'myPlugin' as PluginName,\n * data: (cfg) => dataModelChain.init(() => ({ value: cfg.defaultValue })),\n * })\n * .output('computed', (ctx) => ctx.data.value * ctx.params.multiplier)\n * .build();\n */\n static define<\n Data extends PluginData,\n Params extends PluginParams,\n Config extends PluginConfig,\n >(options: {\n name: PluginName;\n data: (config?: Config) => DataModel<Data>;\n featureFlags?: BlockCodeKnownFeatureFlags;\n }): PluginModelBuilder<Data, Params, {}, Config> {\n return PluginModelBuilder[FROM_BUILDER](options);\n }\n}\n\n/** Plugin factory returned by PluginModelBuilder.build(). */\nexport interface PluginFactory<\n Data extends PluginData = PluginData,\n Params extends PluginParams = undefined,\n Outputs extends PluginOutputs = PluginOutputs,\n Config extends PluginConfig = undefined,\n> extends PluginFactoryLike {\n create(config?: Config): PluginModel<Data, Params, Outputs>;\n /**\n * @internal Phantom field for structural type extraction.\n * Enables InferFactoryData/InferFactoryOutputs to work via PluginFactoryLike.\n */\n readonly __types?: { data: Data; params: Params; outputs: Outputs; config: Config };\n}\n\nclass PluginModelFactory<\n Data extends PluginData = PluginData,\n Params extends PluginParams = undefined,\n Outputs extends PluginOutputs = PluginOutputs,\n Config extends PluginConfig = undefined,\n> implements PluginFactory<Data, Params, Outputs, Config> {\n private readonly name: PluginName;\n private readonly data: (config?: Config) => DataModel<Data>;\n private readonly outputs: {\n [K in keyof Outputs]: (ctx: PluginRenderCtx<PluginFactoryLike<Data, Params>>) => Outputs[K];\n };\n private readonly featureFlags?: BlockCodeKnownFeatureFlags;\n\n constructor(options: {\n name: PluginName;\n data: (config?: Config) => DataModel<Data>;\n outputs: {\n [K in keyof Outputs]: (ctx: PluginRenderCtx<PluginFactoryLike<Data, Params>>) => Outputs[K];\n };\n featureFlags?: BlockCodeKnownFeatureFlags;\n }) {\n this.name = options.name;\n this.data = options.data;\n this.outputs = options.outputs;\n this.featureFlags = options.featureFlags;\n }\n\n /** Create a configured PluginModel instance */\n create(config?: Config): PluginModel<Data, Params, Outputs> {\n return PluginModel[FROM_BUILDER]<Data, Params, Outputs>({\n name: this.name,\n dataModel: this.data(config),\n outputs: this.outputs,\n featureFlags: this.featureFlags,\n });\n }\n}\n\n/**\n * Builder for creating PluginType with type-safe output definitions.\n *\n * Use `PluginModel.define()` to create a builder instance.\n *\n * @typeParam Data - Plugin's persistent data type\n * @typeParam Params - Params derived from block's RenderCtx (optional)\n * @typeParam Config - Static configuration passed to plugin factory (optional)\n * @typeParam Outputs - Accumulated output types\n *\n * @example\n * const dataModelChain = new DataModelBuilder().from<TableData>(DATA_MODEL_DEFAULT_VERSION);\n *\n * const dataTable = PluginModel.define<TableData, TableParams, TableConfig>({\n * name: 'dataTable' as PluginName,\n * data: (cfg) => {\n * return dataModelChain.init(() => ({ state: createInitialState(cfg.ops) }));\n * },\n * })\n * .output('model', (ctx) => createTableModel(ctx))\n * .build();\n */\nclass PluginModelBuilder<\n Data extends PluginData = PluginData,\n Params extends PluginParams = undefined,\n Outputs extends PluginOutputs = PluginOutputs,\n Config extends PluginConfig = undefined,\n> {\n private readonly name: PluginName;\n private readonly data: (config?: Config) => DataModel<Data>;\n private readonly outputs: {\n [K in keyof Outputs]: (ctx: PluginRenderCtx<PluginFactoryLike<Data, Params>>) => Outputs[K];\n };\n private readonly featureFlags?: BlockCodeKnownFeatureFlags;\n\n private constructor(options: {\n name: PluginName;\n data: (config?: Config) => DataModel<Data>;\n outputs?: {\n [K in keyof Outputs]: (ctx: PluginRenderCtx<PluginFactoryLike<Data, Params>>) => Outputs[K];\n };\n featureFlags?: BlockCodeKnownFeatureFlags;\n }) {\n this.name = options.name;\n this.data = options.data;\n this.outputs =\n options.outputs ??\n ({} as {\n [K in keyof Outputs]: (ctx: PluginRenderCtx<PluginFactoryLike<Data, Params>>) => Outputs[K];\n });\n this.featureFlags = options.featureFlags;\n }\n\n /**\n * Internal method for creating PluginModelBuilder.\n * Uses Symbol key to prevent external access.\n * @internal\n */\n static [FROM_BUILDER]<\n Data extends PluginData,\n Params extends PluginParams,\n Outputs extends PluginOutputs,\n Config extends PluginConfig,\n >(options: {\n name: PluginName;\n data: (config?: Config) => DataModel<Data>;\n outputs?: {\n [K in keyof Outputs]: (ctx: PluginRenderCtx<PluginFactoryLike<Data, Params>>) => Outputs[K];\n };\n featureFlags?: BlockCodeKnownFeatureFlags;\n }): PluginModelBuilder<Data, Params, Outputs, Config> {\n return new PluginModelBuilder(options);\n }\n\n /**\n * Adds an output to the plugin.\n *\n * @param key - Output name\n * @param fn - Function that computes the output value from plugin context\n * @returns PluginModel with the new output added\n *\n * @example\n * .output('model', (ctx) => createModel(ctx.params.columns, ctx.data.state))\n * .output('isReady', (ctx) => ctx.params.columns !== undefined)\n */\n output<const Key extends string, T>(\n key: Key,\n fn: (ctx: PluginRenderCtx<PluginFactoryLike<Data, Params>>) => T,\n ): PluginModelBuilder<Data, Params, Outputs & { [K in Key]: T }, Config> {\n return new PluginModelBuilder<Data, Params, Outputs & { [K in Key]: T }, Config>({\n name: this.name,\n data: this.data,\n featureFlags: this.featureFlags,\n outputs: {\n ...this.outputs,\n [key]: fn,\n } as {\n [K in keyof (Outputs & { [P in Key]: T })]: (\n ctx: PluginRenderCtx<PluginFactoryLike<Data, Params>>,\n ) => (Outputs & { [P in Key]: T })[K];\n },\n });\n }\n\n /**\n * Finalizes the plugin definition and returns a ConfigurablePluginModel.\n *\n * @returns Callable plugin factory that accepts config and returns PluginModel\n *\n * @example\n * const myPlugin = new PluginModelBuilder('myPlugin', () => dataModel)\n * .output('value', (ctx) => ctx.data.value)\n * .build();\n *\n * // Later, call create() with config to get a configured instance:\n * const configured = myPlugin.create({ defaultValue: 'test' });\n */\n build(): PluginFactory<Data, Params, Outputs, Config> {\n return new PluginModelFactory<Data, Params, Outputs, Config>({\n name: this.name,\n data: this.data,\n outputs: this.outputs,\n featureFlags: this.featureFlags,\n });\n }\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"plugin_model.cjs","sources":["../src/plugin_model.ts"],"sourcesContent":["/**\n * PluginModel - Builder for creating plugin types with data model and outputs.\n *\n * Plugins are UI components with their own model logic and persistent state.\n * Block developers register plugin instances via BlockModelV3.plugin() method.\n *\n * @module plugin_model\n */\n\nimport type { BlockCodeKnownFeatureFlags } from \"@milaboratories/pl-model-common\";\nimport type { DataModel } from \"./block_migrations\";\nimport type { PluginName } from \"./block_storage\";\nimport type { PluginFactoryLike } from \"./plugin_handle\";\nimport type { PluginRenderCtx } from \"./render\";\n\n/** Symbol for internal builder creation method */\nconst FROM_BUILDER = Symbol(\"fromBuilder\");\n\nexport type PluginData = Record<string, unknown>;\nexport type PluginParams = undefined | Record<string, unknown>;\nexport type PluginOutputs = Record<string, unknown>;\nexport type PluginConfig = undefined | Record<string, unknown>;\n\n/**\n * Configured plugin instance returned by PluginModelFactory.create().\n * Contains the plugin's name, data model, and output definitions.\n */\nexport class PluginModel<\n Data extends PluginData = PluginData,\n Params extends PluginParams = undefined,\n Outputs extends PluginOutputs = PluginOutputs,\n> {\n /** Globally unique plugin name */\n readonly name: PluginName;\n /** Data model instance for this plugin */\n readonly dataModel: DataModel<Data>;\n /** Output definitions - functions that compute outputs from plugin context */\n readonly outputs: {\n [K in keyof Outputs]: (ctx: PluginRenderCtx<PluginFactoryLike<Data, Params>>) => Outputs[K];\n };\n /** Feature flags declared by this plugin */\n readonly featureFlags?: BlockCodeKnownFeatureFlags;\n\n private constructor(options: {\n name: PluginName;\n dataModel: DataModel<Data>;\n outputs: {\n [K in keyof Outputs]: (ctx: PluginRenderCtx<PluginFactoryLike<Data, Params>>) => Outputs[K];\n };\n featureFlags?: BlockCodeKnownFeatureFlags;\n }) {\n this.name = options.name;\n this.dataModel = options.dataModel;\n this.outputs = options.outputs;\n this.featureFlags = options.featureFlags;\n }\n\n /**\n * Internal method for creating PluginModel from factory.\n * Uses Symbol key to prevent external access.\n * @internal\n */\n static [FROM_BUILDER]<\n Data extends PluginData,\n Params extends PluginParams,\n Outputs extends PluginOutputs,\n >(options: {\n name: PluginName;\n dataModel: DataModel<Data>;\n outputs: {\n [K in keyof Outputs]: (ctx: PluginRenderCtx<PluginFactoryLike<Data, Params>>) => Outputs[K];\n };\n featureFlags?: BlockCodeKnownFeatureFlags;\n }): PluginModel<Data, Params, Outputs> {\n return new PluginModel<Data, Params, Outputs>(options);\n }\n\n /**\n * Creates a new PluginModelBuilder for building plugin definitions.\n *\n * @param options.name - Globally unique plugin name\n * @param options.data - Factory function that creates the data model from config\n * @returns PluginModelBuilder for chaining output definitions\n *\n * @example\n * const dataModelChain = new DataModelBuilder().from<MyData>(\"v1\");\n *\n * const myPlugin = PluginModel.define({\n * name: 'myPlugin' as PluginName,\n * data: (cfg) => dataModelChain.init(() => ({ value: cfg.defaultValue })),\n * })\n * .output('computed', (ctx) => ctx.data.value * ctx.params.multiplier)\n * .build();\n */\n static define<\n Data extends PluginData,\n Params extends PluginParams,\n Config extends PluginConfig,\n >(options: {\n name: PluginName;\n data: (config?: Config) => DataModel<Data>;\n featureFlags?: BlockCodeKnownFeatureFlags;\n }): PluginModelBuilder<Data, Params, {}, Config> {\n return PluginModelBuilder[FROM_BUILDER](options);\n }\n}\n\n/** Plugin factory returned by PluginModelBuilder.build(). */\nexport interface PluginFactory<\n Data extends PluginData = PluginData,\n Params extends PluginParams = undefined,\n Outputs extends PluginOutputs = PluginOutputs,\n Config extends PluginConfig = undefined,\n> extends PluginFactoryLike {\n create(config?: Config): PluginModel<Data, Params, Outputs>;\n /**\n * @internal Phantom field for structural type extraction.\n * Enables InferFactoryData/InferFactoryOutputs to work via PluginFactoryLike.\n */\n readonly __types?: { data: Data; params: Params; outputs: Outputs; config: Config };\n}\n\nclass PluginModelFactory<\n Data extends PluginData = PluginData,\n Params extends PluginParams = undefined,\n Outputs extends PluginOutputs = PluginOutputs,\n Config extends PluginConfig = undefined,\n> implements PluginFactory<Data, Params, Outputs, Config> {\n private readonly name: PluginName;\n private readonly data: (config?: Config) => DataModel<Data>;\n private readonly outputs: {\n [K in keyof Outputs]: (ctx: PluginRenderCtx<PluginFactoryLike<Data, Params>>) => Outputs[K];\n };\n private readonly featureFlags?: BlockCodeKnownFeatureFlags;\n\n constructor(options: {\n name: PluginName;\n data: (config?: Config) => DataModel<Data>;\n outputs: {\n [K in keyof Outputs]: (ctx: PluginRenderCtx<PluginFactoryLike<Data, Params>>) => Outputs[K];\n };\n featureFlags?: BlockCodeKnownFeatureFlags;\n }) {\n this.name = options.name;\n this.data = options.data;\n this.outputs = options.outputs;\n this.featureFlags = options.featureFlags;\n }\n\n /** Create a configured PluginModel instance */\n create(config?: Config): PluginModel<Data, Params, Outputs> {\n return PluginModel[FROM_BUILDER]<Data, Params, Outputs>({\n name: this.name,\n dataModel: this.data(config),\n outputs: this.outputs,\n featureFlags: this.featureFlags,\n });\n }\n}\n\n/**\n * Builder for creating PluginType with type-safe output definitions.\n *\n * Use `PluginModel.define()` to create a builder instance.\n *\n * @typeParam Data - Plugin's persistent data type\n * @typeParam Params - Params derived from block's RenderCtx (optional)\n * @typeParam Config - Static configuration passed to plugin factory (optional)\n * @typeParam Outputs - Accumulated output types\n *\n * @example\n * const dataModelChain = new DataModelBuilder().from<TableData>(\"v1\");\n *\n * const dataTable = PluginModel.define<TableData, TableParams, TableConfig>({\n * name: 'dataTable' as PluginName,\n * data: (cfg) => {\n * return dataModelChain.init(() => ({ state: createInitialState(cfg.ops) }));\n * },\n * })\n * .output('model', (ctx) => createTableModel(ctx))\n * .build();\n */\nclass PluginModelBuilder<\n Data extends PluginData = PluginData,\n Params extends PluginParams = undefined,\n Outputs extends PluginOutputs = PluginOutputs,\n Config extends PluginConfig = undefined,\n> {\n private readonly name: PluginName;\n private readonly data: (config?: Config) => DataModel<Data>;\n private readonly outputs: {\n [K in keyof Outputs]: (ctx: PluginRenderCtx<PluginFactoryLike<Data, Params>>) => Outputs[K];\n };\n private readonly featureFlags?: BlockCodeKnownFeatureFlags;\n\n private constructor(options: {\n name: PluginName;\n data: (config?: Config) => DataModel<Data>;\n outputs?: {\n [K in keyof Outputs]: (ctx: PluginRenderCtx<PluginFactoryLike<Data, Params>>) => Outputs[K];\n };\n featureFlags?: BlockCodeKnownFeatureFlags;\n }) {\n this.name = options.name;\n this.data = options.data;\n this.outputs =\n options.outputs ??\n ({} as {\n [K in keyof Outputs]: (ctx: PluginRenderCtx<PluginFactoryLike<Data, Params>>) => Outputs[K];\n });\n this.featureFlags = options.featureFlags;\n }\n\n /**\n * Internal method for creating PluginModelBuilder.\n * Uses Symbol key to prevent external access.\n * @internal\n */\n static [FROM_BUILDER]<\n Data extends PluginData,\n Params extends PluginParams,\n Outputs extends PluginOutputs,\n Config extends PluginConfig,\n >(options: {\n name: PluginName;\n data: (config?: Config) => DataModel<Data>;\n outputs?: {\n [K in keyof Outputs]: (ctx: PluginRenderCtx<PluginFactoryLike<Data, Params>>) => Outputs[K];\n };\n featureFlags?: BlockCodeKnownFeatureFlags;\n }): PluginModelBuilder<Data, Params, Outputs, Config> {\n return new PluginModelBuilder(options);\n }\n\n /**\n * Adds an output to the plugin.\n *\n * @param key - Output name\n * @param fn - Function that computes the output value from plugin context\n * @returns PluginModel with the new output added\n *\n * @example\n * .output('model', (ctx) => createModel(ctx.params.columns, ctx.data.state))\n * .output('isReady', (ctx) => ctx.params.columns !== undefined)\n */\n output<const Key extends string, T>(\n key: Key,\n fn: (ctx: PluginRenderCtx<PluginFactoryLike<Data, Params>>) => T,\n ): PluginModelBuilder<Data, Params, Outputs & { [K in Key]: T }, Config> {\n return new PluginModelBuilder<Data, Params, Outputs & { [K in Key]: T }, Config>({\n name: this.name,\n data: this.data,\n featureFlags: this.featureFlags,\n outputs: {\n ...this.outputs,\n [key]: fn,\n } as {\n [K in keyof (Outputs & { [P in Key]: T })]: (\n ctx: PluginRenderCtx<PluginFactoryLike<Data, Params>>,\n ) => (Outputs & { [P in Key]: T })[K];\n },\n });\n }\n\n /**\n * Finalizes the plugin definition and returns a ConfigurablePluginModel.\n *\n * @returns Callable plugin factory that accepts config and returns PluginModel\n *\n * @example\n * const myPlugin = new PluginModelBuilder('myPlugin', () => dataModel)\n * .output('value', (ctx) => ctx.data.value)\n * .build();\n *\n * // Later, call create() with config to get a configured instance:\n * const configured = myPlugin.create({ defaultValue: 'test' });\n */\n build(): PluginFactory<Data, Params, Outputs, Config> {\n return new PluginModelFactory<Data, Params, Outputs, Config>({\n name: this.name,\n data: this.data,\n outputs: this.outputs,\n featureFlags: this.featureFlags,\n });\n }\n}\n"],"names":[],"mappings":"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"}
@@ -54,7 +54,7 @@ export declare class PluginModel<Data extends PluginData = PluginData, Params ex
54
54
  * @returns PluginModelBuilder for chaining output definitions
55
55
  *
56
56
  * @example
57
- * const dataModelChain = new DataModelBuilder().from<MyData>(DATA_MODEL_DEFAULT_VERSION);
57
+ * const dataModelChain = new DataModelBuilder().from<MyData>("v1");
58
58
  *
59
59
  * const myPlugin = PluginModel.define({
60
60
  * name: 'myPlugin' as PluginName,
@@ -94,7 +94,7 @@ export interface PluginFactory<Data extends PluginData = PluginData, Params exte
94
94
  * @typeParam Outputs - Accumulated output types
95
95
  *
96
96
  * @example
97
- * const dataModelChain = new DataModelBuilder().from<TableData>(DATA_MODEL_DEFAULT_VERSION);
97
+ * const dataModelChain = new DataModelBuilder().from<TableData>("v1");
98
98
  *
99
99
  * const dataTable = PluginModel.define<TableData, TableParams, TableConfig>({
100
100
  * name: 'dataTable' as PluginName,
@@ -43,7 +43,7 @@ class PluginModel {
43
43
  * @returns PluginModelBuilder for chaining output definitions
44
44
  *
45
45
  * @example
46
- * const dataModelChain = new DataModelBuilder().from<MyData>(DATA_MODEL_DEFAULT_VERSION);
46
+ * const dataModelChain = new DataModelBuilder().from<MyData>("v1");
47
47
  *
48
48
  * const myPlugin = PluginModel.define({
49
49
  * name: 'myPlugin' as PluginName,
@@ -88,7 +88,7 @@ class PluginModelFactory {
88
88
  * @typeParam Outputs - Accumulated output types
89
89
  *
90
90
  * @example
91
- * const dataModelChain = new DataModelBuilder().from<TableData>(DATA_MODEL_DEFAULT_VERSION);
91
+ * const dataModelChain = new DataModelBuilder().from<TableData>("v1");
92
92
  *
93
93
  * const dataTable = PluginModel.define<TableData, TableParams, TableConfig>({
94
94
  * name: 'dataTable' as PluginName,
@@ -1 +1 @@
1
- {"version":3,"file":"plugin_model.js","sources":["../src/plugin_model.ts"],"sourcesContent":["/**\n * PluginModel - Builder for creating plugin types with data model and outputs.\n *\n * Plugins are UI components with their own model logic and persistent state.\n * Block developers register plugin instances via BlockModelV3.plugin() method.\n *\n * @module plugin_model\n */\n\nimport type { BlockCodeKnownFeatureFlags } from \"@milaboratories/pl-model-common\";\nimport type { DataModel } from \"./block_migrations\";\nimport type { PluginName } from \"./block_storage\";\nimport type { PluginFactoryLike } from \"./plugin_handle\";\nimport type { PluginRenderCtx } from \"./render\";\n\n/** Symbol for internal builder creation method */\nconst FROM_BUILDER = Symbol(\"fromBuilder\");\n\nexport type PluginData = Record<string, unknown>;\nexport type PluginParams = undefined | Record<string, unknown>;\nexport type PluginOutputs = Record<string, unknown>;\nexport type PluginConfig = undefined | Record<string, unknown>;\n\n/**\n * Configured plugin instance returned by PluginModelFactory.create().\n * Contains the plugin's name, data model, and output definitions.\n */\nexport class PluginModel<\n Data extends PluginData = PluginData,\n Params extends PluginParams = undefined,\n Outputs extends PluginOutputs = PluginOutputs,\n> {\n /** Globally unique plugin name */\n readonly name: PluginName;\n /** Data model instance for this plugin */\n readonly dataModel: DataModel<Data>;\n /** Output definitions - functions that compute outputs from plugin context */\n readonly outputs: {\n [K in keyof Outputs]: (ctx: PluginRenderCtx<PluginFactoryLike<Data, Params>>) => Outputs[K];\n };\n /** Feature flags declared by this plugin */\n readonly featureFlags?: BlockCodeKnownFeatureFlags;\n\n private constructor(options: {\n name: PluginName;\n dataModel: DataModel<Data>;\n outputs: {\n [K in keyof Outputs]: (ctx: PluginRenderCtx<PluginFactoryLike<Data, Params>>) => Outputs[K];\n };\n featureFlags?: BlockCodeKnownFeatureFlags;\n }) {\n this.name = options.name;\n this.dataModel = options.dataModel;\n this.outputs = options.outputs;\n this.featureFlags = options.featureFlags;\n }\n\n /**\n * Internal method for creating PluginModel from factory.\n * Uses Symbol key to prevent external access.\n * @internal\n */\n static [FROM_BUILDER]<\n Data extends PluginData,\n Params extends PluginParams,\n Outputs extends PluginOutputs,\n >(options: {\n name: PluginName;\n dataModel: DataModel<Data>;\n outputs: {\n [K in keyof Outputs]: (ctx: PluginRenderCtx<PluginFactoryLike<Data, Params>>) => Outputs[K];\n };\n featureFlags?: BlockCodeKnownFeatureFlags;\n }): PluginModel<Data, Params, Outputs> {\n return new PluginModel<Data, Params, Outputs>(options);\n }\n\n /**\n * Creates a new PluginModelBuilder for building plugin definitions.\n *\n * @param options.name - Globally unique plugin name\n * @param options.data - Factory function that creates the data model from config\n * @returns PluginModelBuilder for chaining output definitions\n *\n * @example\n * const dataModelChain = new DataModelBuilder().from<MyData>(DATA_MODEL_DEFAULT_VERSION);\n *\n * const myPlugin = PluginModel.define({\n * name: 'myPlugin' as PluginName,\n * data: (cfg) => dataModelChain.init(() => ({ value: cfg.defaultValue })),\n * })\n * .output('computed', (ctx) => ctx.data.value * ctx.params.multiplier)\n * .build();\n */\n static define<\n Data extends PluginData,\n Params extends PluginParams,\n Config extends PluginConfig,\n >(options: {\n name: PluginName;\n data: (config?: Config) => DataModel<Data>;\n featureFlags?: BlockCodeKnownFeatureFlags;\n }): PluginModelBuilder<Data, Params, {}, Config> {\n return PluginModelBuilder[FROM_BUILDER](options);\n }\n}\n\n/** Plugin factory returned by PluginModelBuilder.build(). */\nexport interface PluginFactory<\n Data extends PluginData = PluginData,\n Params extends PluginParams = undefined,\n Outputs extends PluginOutputs = PluginOutputs,\n Config extends PluginConfig = undefined,\n> extends PluginFactoryLike {\n create(config?: Config): PluginModel<Data, Params, Outputs>;\n /**\n * @internal Phantom field for structural type extraction.\n * Enables InferFactoryData/InferFactoryOutputs to work via PluginFactoryLike.\n */\n readonly __types?: { data: Data; params: Params; outputs: Outputs; config: Config };\n}\n\nclass PluginModelFactory<\n Data extends PluginData = PluginData,\n Params extends PluginParams = undefined,\n Outputs extends PluginOutputs = PluginOutputs,\n Config extends PluginConfig = undefined,\n> implements PluginFactory<Data, Params, Outputs, Config> {\n private readonly name: PluginName;\n private readonly data: (config?: Config) => DataModel<Data>;\n private readonly outputs: {\n [K in keyof Outputs]: (ctx: PluginRenderCtx<PluginFactoryLike<Data, Params>>) => Outputs[K];\n };\n private readonly featureFlags?: BlockCodeKnownFeatureFlags;\n\n constructor(options: {\n name: PluginName;\n data: (config?: Config) => DataModel<Data>;\n outputs: {\n [K in keyof Outputs]: (ctx: PluginRenderCtx<PluginFactoryLike<Data, Params>>) => Outputs[K];\n };\n featureFlags?: BlockCodeKnownFeatureFlags;\n }) {\n this.name = options.name;\n this.data = options.data;\n this.outputs = options.outputs;\n this.featureFlags = options.featureFlags;\n }\n\n /** Create a configured PluginModel instance */\n create(config?: Config): PluginModel<Data, Params, Outputs> {\n return PluginModel[FROM_BUILDER]<Data, Params, Outputs>({\n name: this.name,\n dataModel: this.data(config),\n outputs: this.outputs,\n featureFlags: this.featureFlags,\n });\n }\n}\n\n/**\n * Builder for creating PluginType with type-safe output definitions.\n *\n * Use `PluginModel.define()` to create a builder instance.\n *\n * @typeParam Data - Plugin's persistent data type\n * @typeParam Params - Params derived from block's RenderCtx (optional)\n * @typeParam Config - Static configuration passed to plugin factory (optional)\n * @typeParam Outputs - Accumulated output types\n *\n * @example\n * const dataModelChain = new DataModelBuilder().from<TableData>(DATA_MODEL_DEFAULT_VERSION);\n *\n * const dataTable = PluginModel.define<TableData, TableParams, TableConfig>({\n * name: 'dataTable' as PluginName,\n * data: (cfg) => {\n * return dataModelChain.init(() => ({ state: createInitialState(cfg.ops) }));\n * },\n * })\n * .output('model', (ctx) => createTableModel(ctx))\n * .build();\n */\nclass PluginModelBuilder<\n Data extends PluginData = PluginData,\n Params extends PluginParams = undefined,\n Outputs extends PluginOutputs = PluginOutputs,\n Config extends PluginConfig = undefined,\n> {\n private readonly name: PluginName;\n private readonly data: (config?: Config) => DataModel<Data>;\n private readonly outputs: {\n [K in keyof Outputs]: (ctx: PluginRenderCtx<PluginFactoryLike<Data, Params>>) => Outputs[K];\n };\n private readonly featureFlags?: BlockCodeKnownFeatureFlags;\n\n private constructor(options: {\n name: PluginName;\n data: (config?: Config) => DataModel<Data>;\n outputs?: {\n [K in keyof Outputs]: (ctx: PluginRenderCtx<PluginFactoryLike<Data, Params>>) => Outputs[K];\n };\n featureFlags?: BlockCodeKnownFeatureFlags;\n }) {\n this.name = options.name;\n this.data = options.data;\n this.outputs =\n options.outputs ??\n ({} as {\n [K in keyof Outputs]: (ctx: PluginRenderCtx<PluginFactoryLike<Data, Params>>) => Outputs[K];\n });\n this.featureFlags = options.featureFlags;\n }\n\n /**\n * Internal method for creating PluginModelBuilder.\n * Uses Symbol key to prevent external access.\n * @internal\n */\n static [FROM_BUILDER]<\n Data extends PluginData,\n Params extends PluginParams,\n Outputs extends PluginOutputs,\n Config extends PluginConfig,\n >(options: {\n name: PluginName;\n data: (config?: Config) => DataModel<Data>;\n outputs?: {\n [K in keyof Outputs]: (ctx: PluginRenderCtx<PluginFactoryLike<Data, Params>>) => Outputs[K];\n };\n featureFlags?: BlockCodeKnownFeatureFlags;\n }): PluginModelBuilder<Data, Params, Outputs, Config> {\n return new PluginModelBuilder(options);\n }\n\n /**\n * Adds an output to the plugin.\n *\n * @param key - Output name\n * @param fn - Function that computes the output value from plugin context\n * @returns PluginModel with the new output added\n *\n * @example\n * .output('model', (ctx) => createModel(ctx.params.columns, ctx.data.state))\n * .output('isReady', (ctx) => ctx.params.columns !== undefined)\n */\n output<const Key extends string, T>(\n key: Key,\n fn: (ctx: PluginRenderCtx<PluginFactoryLike<Data, Params>>) => T,\n ): PluginModelBuilder<Data, Params, Outputs & { [K in Key]: T }, Config> {\n return new PluginModelBuilder<Data, Params, Outputs & { [K in Key]: T }, Config>({\n name: this.name,\n data: this.data,\n featureFlags: this.featureFlags,\n outputs: {\n ...this.outputs,\n [key]: fn,\n } as {\n [K in keyof (Outputs & { [P in Key]: T })]: (\n ctx: PluginRenderCtx<PluginFactoryLike<Data, Params>>,\n ) => (Outputs & { [P in Key]: T })[K];\n },\n });\n }\n\n /**\n * Finalizes the plugin definition and returns a ConfigurablePluginModel.\n *\n * @returns Callable plugin factory that accepts config and returns PluginModel\n *\n * @example\n * const myPlugin = new PluginModelBuilder('myPlugin', () => dataModel)\n * .output('value', (ctx) => ctx.data.value)\n * .build();\n *\n * // Later, call create() with config to get a configured instance:\n * const configured = myPlugin.create({ defaultValue: 'test' });\n */\n build(): PluginFactory<Data, Params, Outputs, Config> {\n return new PluginModelFactory<Data, Params, Outputs, Config>({\n name: this.name,\n data: this.data,\n outputs: this.outputs,\n featureFlags: this.featureFlags,\n });\n }\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"plugin_model.js","sources":["../src/plugin_model.ts"],"sourcesContent":["/**\n * PluginModel - Builder for creating plugin types with data model and outputs.\n *\n * Plugins are UI components with their own model logic and persistent state.\n * Block developers register plugin instances via BlockModelV3.plugin() method.\n *\n * @module plugin_model\n */\n\nimport type { BlockCodeKnownFeatureFlags } from \"@milaboratories/pl-model-common\";\nimport type { DataModel } from \"./block_migrations\";\nimport type { PluginName } from \"./block_storage\";\nimport type { PluginFactoryLike } from \"./plugin_handle\";\nimport type { PluginRenderCtx } from \"./render\";\n\n/** Symbol for internal builder creation method */\nconst FROM_BUILDER = Symbol(\"fromBuilder\");\n\nexport type PluginData = Record<string, unknown>;\nexport type PluginParams = undefined | Record<string, unknown>;\nexport type PluginOutputs = Record<string, unknown>;\nexport type PluginConfig = undefined | Record<string, unknown>;\n\n/**\n * Configured plugin instance returned by PluginModelFactory.create().\n * Contains the plugin's name, data model, and output definitions.\n */\nexport class PluginModel<\n Data extends PluginData = PluginData,\n Params extends PluginParams = undefined,\n Outputs extends PluginOutputs = PluginOutputs,\n> {\n /** Globally unique plugin name */\n readonly name: PluginName;\n /** Data model instance for this plugin */\n readonly dataModel: DataModel<Data>;\n /** Output definitions - functions that compute outputs from plugin context */\n readonly outputs: {\n [K in keyof Outputs]: (ctx: PluginRenderCtx<PluginFactoryLike<Data, Params>>) => Outputs[K];\n };\n /** Feature flags declared by this plugin */\n readonly featureFlags?: BlockCodeKnownFeatureFlags;\n\n private constructor(options: {\n name: PluginName;\n dataModel: DataModel<Data>;\n outputs: {\n [K in keyof Outputs]: (ctx: PluginRenderCtx<PluginFactoryLike<Data, Params>>) => Outputs[K];\n };\n featureFlags?: BlockCodeKnownFeatureFlags;\n }) {\n this.name = options.name;\n this.dataModel = options.dataModel;\n this.outputs = options.outputs;\n this.featureFlags = options.featureFlags;\n }\n\n /**\n * Internal method for creating PluginModel from factory.\n * Uses Symbol key to prevent external access.\n * @internal\n */\n static [FROM_BUILDER]<\n Data extends PluginData,\n Params extends PluginParams,\n Outputs extends PluginOutputs,\n >(options: {\n name: PluginName;\n dataModel: DataModel<Data>;\n outputs: {\n [K in keyof Outputs]: (ctx: PluginRenderCtx<PluginFactoryLike<Data, Params>>) => Outputs[K];\n };\n featureFlags?: BlockCodeKnownFeatureFlags;\n }): PluginModel<Data, Params, Outputs> {\n return new PluginModel<Data, Params, Outputs>(options);\n }\n\n /**\n * Creates a new PluginModelBuilder for building plugin definitions.\n *\n * @param options.name - Globally unique plugin name\n * @param options.data - Factory function that creates the data model from config\n * @returns PluginModelBuilder for chaining output definitions\n *\n * @example\n * const dataModelChain = new DataModelBuilder().from<MyData>(\"v1\");\n *\n * const myPlugin = PluginModel.define({\n * name: 'myPlugin' as PluginName,\n * data: (cfg) => dataModelChain.init(() => ({ value: cfg.defaultValue })),\n * })\n * .output('computed', (ctx) => ctx.data.value * ctx.params.multiplier)\n * .build();\n */\n static define<\n Data extends PluginData,\n Params extends PluginParams,\n Config extends PluginConfig,\n >(options: {\n name: PluginName;\n data: (config?: Config) => DataModel<Data>;\n featureFlags?: BlockCodeKnownFeatureFlags;\n }): PluginModelBuilder<Data, Params, {}, Config> {\n return PluginModelBuilder[FROM_BUILDER](options);\n }\n}\n\n/** Plugin factory returned by PluginModelBuilder.build(). */\nexport interface PluginFactory<\n Data extends PluginData = PluginData,\n Params extends PluginParams = undefined,\n Outputs extends PluginOutputs = PluginOutputs,\n Config extends PluginConfig = undefined,\n> extends PluginFactoryLike {\n create(config?: Config): PluginModel<Data, Params, Outputs>;\n /**\n * @internal Phantom field for structural type extraction.\n * Enables InferFactoryData/InferFactoryOutputs to work via PluginFactoryLike.\n */\n readonly __types?: { data: Data; params: Params; outputs: Outputs; config: Config };\n}\n\nclass PluginModelFactory<\n Data extends PluginData = PluginData,\n Params extends PluginParams = undefined,\n Outputs extends PluginOutputs = PluginOutputs,\n Config extends PluginConfig = undefined,\n> implements PluginFactory<Data, Params, Outputs, Config> {\n private readonly name: PluginName;\n private readonly data: (config?: Config) => DataModel<Data>;\n private readonly outputs: {\n [K in keyof Outputs]: (ctx: PluginRenderCtx<PluginFactoryLike<Data, Params>>) => Outputs[K];\n };\n private readonly featureFlags?: BlockCodeKnownFeatureFlags;\n\n constructor(options: {\n name: PluginName;\n data: (config?: Config) => DataModel<Data>;\n outputs: {\n [K in keyof Outputs]: (ctx: PluginRenderCtx<PluginFactoryLike<Data, Params>>) => Outputs[K];\n };\n featureFlags?: BlockCodeKnownFeatureFlags;\n }) {\n this.name = options.name;\n this.data = options.data;\n this.outputs = options.outputs;\n this.featureFlags = options.featureFlags;\n }\n\n /** Create a configured PluginModel instance */\n create(config?: Config): PluginModel<Data, Params, Outputs> {\n return PluginModel[FROM_BUILDER]<Data, Params, Outputs>({\n name: this.name,\n dataModel: this.data(config),\n outputs: this.outputs,\n featureFlags: this.featureFlags,\n });\n }\n}\n\n/**\n * Builder for creating PluginType with type-safe output definitions.\n *\n * Use `PluginModel.define()` to create a builder instance.\n *\n * @typeParam Data - Plugin's persistent data type\n * @typeParam Params - Params derived from block's RenderCtx (optional)\n * @typeParam Config - Static configuration passed to plugin factory (optional)\n * @typeParam Outputs - Accumulated output types\n *\n * @example\n * const dataModelChain = new DataModelBuilder().from<TableData>(\"v1\");\n *\n * const dataTable = PluginModel.define<TableData, TableParams, TableConfig>({\n * name: 'dataTable' as PluginName,\n * data: (cfg) => {\n * return dataModelChain.init(() => ({ state: createInitialState(cfg.ops) }));\n * },\n * })\n * .output('model', (ctx) => createTableModel(ctx))\n * .build();\n */\nclass PluginModelBuilder<\n Data extends PluginData = PluginData,\n Params extends PluginParams = undefined,\n Outputs extends PluginOutputs = PluginOutputs,\n Config extends PluginConfig = undefined,\n> {\n private readonly name: PluginName;\n private readonly data: (config?: Config) => DataModel<Data>;\n private readonly outputs: {\n [K in keyof Outputs]: (ctx: PluginRenderCtx<PluginFactoryLike<Data, Params>>) => Outputs[K];\n };\n private readonly featureFlags?: BlockCodeKnownFeatureFlags;\n\n private constructor(options: {\n name: PluginName;\n data: (config?: Config) => DataModel<Data>;\n outputs?: {\n [K in keyof Outputs]: (ctx: PluginRenderCtx<PluginFactoryLike<Data, Params>>) => Outputs[K];\n };\n featureFlags?: BlockCodeKnownFeatureFlags;\n }) {\n this.name = options.name;\n this.data = options.data;\n this.outputs =\n options.outputs ??\n ({} as {\n [K in keyof Outputs]: (ctx: PluginRenderCtx<PluginFactoryLike<Data, Params>>) => Outputs[K];\n });\n this.featureFlags = options.featureFlags;\n }\n\n /**\n * Internal method for creating PluginModelBuilder.\n * Uses Symbol key to prevent external access.\n * @internal\n */\n static [FROM_BUILDER]<\n Data extends PluginData,\n Params extends PluginParams,\n Outputs extends PluginOutputs,\n Config extends PluginConfig,\n >(options: {\n name: PluginName;\n data: (config?: Config) => DataModel<Data>;\n outputs?: {\n [K in keyof Outputs]: (ctx: PluginRenderCtx<PluginFactoryLike<Data, Params>>) => Outputs[K];\n };\n featureFlags?: BlockCodeKnownFeatureFlags;\n }): PluginModelBuilder<Data, Params, Outputs, Config> {\n return new PluginModelBuilder(options);\n }\n\n /**\n * Adds an output to the plugin.\n *\n * @param key - Output name\n * @param fn - Function that computes the output value from plugin context\n * @returns PluginModel with the new output added\n *\n * @example\n * .output('model', (ctx) => createModel(ctx.params.columns, ctx.data.state))\n * .output('isReady', (ctx) => ctx.params.columns !== undefined)\n */\n output<const Key extends string, T>(\n key: Key,\n fn: (ctx: PluginRenderCtx<PluginFactoryLike<Data, Params>>) => T,\n ): PluginModelBuilder<Data, Params, Outputs & { [K in Key]: T }, Config> {\n return new PluginModelBuilder<Data, Params, Outputs & { [K in Key]: T }, Config>({\n name: this.name,\n data: this.data,\n featureFlags: this.featureFlags,\n outputs: {\n ...this.outputs,\n [key]: fn,\n } as {\n [K in keyof (Outputs & { [P in Key]: T })]: (\n ctx: PluginRenderCtx<PluginFactoryLike<Data, Params>>,\n ) => (Outputs & { [P in Key]: T })[K];\n },\n });\n }\n\n /**\n * Finalizes the plugin definition and returns a ConfigurablePluginModel.\n *\n * @returns Callable plugin factory that accepts config and returns PluginModel\n *\n * @example\n * const myPlugin = new PluginModelBuilder('myPlugin', () => dataModel)\n * .output('value', (ctx) => ctx.data.value)\n * .build();\n *\n * // Later, call create() with config to get a configured instance:\n * const configured = myPlugin.create({ defaultValue: 'test' });\n */\n build(): PluginFactory<Data, Params, Outputs, Config> {\n return new PluginModelFactory<Data, Params, Outputs, Config>({\n name: this.name,\n data: this.data,\n outputs: this.outputs,\n featureFlags: this.featureFlags,\n });\n }\n}\n"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@platforma-sdk/model",
3
- "version": "1.58.0",
3
+ "version": "1.58.1",
4
4
  "description": "Platforma.bio SDK / Block Model",
5
5
  "files": [
6
6
  "./dist/**/*",
@@ -25,9 +25,9 @@
25
25
  "utility-types": "^3.11.0",
26
26
  "zod": "~3.23.8",
27
27
  "@milaboratories/helpers": "1.13.5",
28
+ "@milaboratories/pl-error-like": "1.12.8",
28
29
  "@milaboratories/pl-model-common": "1.25.0",
29
- "@milaboratories/ptabler-expression-js": "1.1.22",
30
- "@milaboratories/pl-error-like": "1.12.8"
30
+ "@milaboratories/ptabler-expression-js": "1.1.22"
31
31
  },
32
32
  "devDependencies": {
33
33
  "@vitest/coverage-istanbul": "^4.0.16",
@@ -35,8 +35,8 @@
35
35
  "typescript": "~5.6.3",
36
36
  "vitest": "^4.0.16",
37
37
  "@milaboratories/build-configs": "1.5.0",
38
- "@milaboratories/ts-builder": "1.2.11",
39
- "@milaboratories/ts-configs": "1.2.1"
38
+ "@milaboratories/ts-configs": "1.2.1",
39
+ "@milaboratories/ts-builder": "1.2.11"
40
40
  },
41
41
  "scripts": {
42
42
  "build": "ts-builder build --target node",
@@ -1,5 +1,6 @@
1
1
  import { describe, expect, it } from "vitest";
2
2
  import { DataModelBuilder, defaultRecover, makeDataVersioned } from "./block_migrations";
3
+ import { DATA_MODEL_LEGACY_VERSION } from "./block_storage";
3
4
 
4
5
  describe("makeDataVersioned", () => {
5
6
  it("creates correct DataVersioned shape", () => {
@@ -18,7 +19,6 @@ describe("DataModel migrations", () => {
18
19
  const result = dataModel.migrate(makeDataVersioned("legacy", { count: 42 }));
19
20
  expect(result.version).toBe("v2");
20
21
  expect(result.data).toStrictEqual({ count: 0, label: "" });
21
- expect(result.warning).toBe(`Unknown version 'legacy'`);
22
22
  });
23
23
 
24
24
  it("throws at build time on duplicate version key", () => {
@@ -33,7 +33,7 @@ describe("DataModel migrations", () => {
33
33
  ).toThrow("Duplicate version 'v1' in migration chain");
34
34
  });
35
35
 
36
- it("returns initial data on migration failure", () => {
36
+ it("throws on migration failure", () => {
37
37
  const dataModel = new DataModelBuilder()
38
38
  .from<{ numbers: number[] }>("v1")
39
39
  .migrate<{ numbers: number[]; label: string }>("v2", (v1) => {
@@ -42,10 +42,9 @@ describe("DataModel migrations", () => {
42
42
  })
43
43
  .init(() => ({ numbers: [], label: "" }));
44
44
 
45
- const result = dataModel.migrate(makeDataVersioned("v1", { numbers: [666] }));
46
- expect(result.version).toBe("v2");
47
- expect(result.data).toStrictEqual({ numbers: [], label: "" });
48
- expect(result.warning).toBe(`Migration v1→v2 failed: Forbidden number`);
45
+ expect(() => dataModel.migrate(makeDataVersioned("v1", { numbers: [666] }))).toThrow(
46
+ "Forbidden number",
47
+ );
49
48
  });
50
49
 
51
50
  describe("recover()", () => {
@@ -70,7 +69,6 @@ describe("DataModel migrations", () => {
70
69
  const result = dataModel.migrate(makeDataVersioned("legacy", { count: 5 }));
71
70
  expect(result.version).toBe("v2");
72
71
  expect(result.data).toStrictEqual({ count: 5, label: "default" });
73
- expect(result.warning).toBeUndefined();
74
72
  });
75
73
 
76
74
  it("recover() between migrations — recovered data goes through subsequent migrations", () => {
@@ -97,7 +95,6 @@ describe("DataModel migrations", () => {
97
95
  const result = dataModel.migrate(makeDataVersioned("legacy", { count: 7 }));
98
96
  expect(result.version).toBe("v3");
99
97
  expect(result.data).toStrictEqual({ count: 7, label: "recovered", description: "added" });
100
- expect(result.warning).toBeUndefined();
101
98
  });
102
99
 
103
100
  it("recover() at the end of chain — recovered data is the final type", () => {
@@ -122,10 +119,9 @@ describe("DataModel migrations", () => {
122
119
  const result = dataModel.migrate(makeDataVersioned("legacy", { count: 9 }));
123
120
  expect(result.version).toBe("v2");
124
121
  expect(result.data).toStrictEqual({ count: 9, label: "recovered" });
125
- expect(result.warning).toBeUndefined();
126
122
  });
127
123
 
128
- it("recover() delegates to defaultRecover for truly unknown versions", () => {
124
+ it("recover() delegates to defaultRecover for truly unknown versions — resets to initial data", () => {
129
125
  const dataModel = new DataModelBuilder()
130
126
  .from<{ count: number }>("v1")
131
127
  .migrate<{ count: number; label: string }>("v2", (v1) => ({ ...v1, label: "" }))
@@ -135,7 +131,6 @@ describe("DataModel migrations", () => {
135
131
  const result = dataModel.migrate(makeDataVersioned("unknown", { count: 7 }));
136
132
  expect(result.version).toBe("v2");
137
133
  expect(result.data).toStrictEqual({ count: 0, label: "" });
138
- expect(result.warning).toBe(`Unknown version 'unknown'`);
139
134
  });
140
135
 
141
136
  it("migration failure after recover() resets to initial data", () => {
@@ -164,7 +159,6 @@ describe("DataModel migrations", () => {
164
159
  const result = dataModel.migrate(makeDataVersioned("legacy", { count: 7 }));
165
160
  expect(result.version).toBe("v3");
166
161
  expect(result.data).toStrictEqual({ count: 0, label: "", description: "" });
167
- expect(result.warning).toBe("Migration v2→v3 failed: v3 failed");
168
162
  });
169
163
 
170
164
  it("recover() cannot be called twice — enforced by type (no recover() on WithRecover)", () => {
@@ -172,4 +166,107 @@ describe("DataModel migrations", () => {
172
166
  // Verified by the absence of recover() in DataModelMigrationChainWithRecover.
173
167
  });
174
168
  });
169
+
170
+ describe("upgradeLegacy()", () => {
171
+ type LegacyArgs = { inputFile: string; threshold: number };
172
+ type LegacyUiState = { selectedTab: string };
173
+ type BlockData = { inputFile: string; threshold: number; selectedTab: string };
174
+
175
+ it("upgrades legacy { args, uiState } data with custom initial version", () => {
176
+ const dataModel = new DataModelBuilder()
177
+ .from<BlockData>("v1")
178
+ .upgradeLegacy<LegacyArgs, LegacyUiState>(({ args, uiState }) => ({
179
+ inputFile: args.inputFile,
180
+ threshold: args.threshold,
181
+ selectedTab: uiState.selectedTab,
182
+ }))
183
+ .init(() => ({ inputFile: "", threshold: 0, selectedTab: "main" }));
184
+
185
+ // Legacy data arrives at DATA_MODEL_LEGACY_VERSION (how normalizeBlockStorage wraps it)
186
+ const result = dataModel.migrate(
187
+ makeDataVersioned(DATA_MODEL_LEGACY_VERSION, {
188
+ args: { inputFile: "test.fa", threshold: 5 },
189
+ uiState: { selectedTab: "results" },
190
+ }),
191
+ );
192
+ expect(result.version).toBe("v1");
193
+ expect(result.data).toStrictEqual({
194
+ inputFile: "test.fa",
195
+ threshold: 5,
196
+ selectedTab: "results",
197
+ });
198
+ });
199
+
200
+ it("passes through non-legacy data at custom initial version unchanged", () => {
201
+ const dataModel = new DataModelBuilder()
202
+ .from<BlockData>("v1")
203
+ .upgradeLegacy<LegacyArgs, LegacyUiState>(({ args, uiState }) => ({
204
+ inputFile: args.inputFile,
205
+ threshold: args.threshold,
206
+ selectedTab: uiState.selectedTab,
207
+ }))
208
+ .init(() => ({ inputFile: "", threshold: 0, selectedTab: "main" }));
209
+
210
+ // Non-legacy data at the user's version passes through unchanged
211
+ const result = dataModel.migrate(
212
+ makeDataVersioned("v1", {
213
+ inputFile: "existing.fa",
214
+ threshold: 10,
215
+ selectedTab: "overview",
216
+ }),
217
+ );
218
+ expect(result.version).toBe("v1");
219
+ expect(result.data).toStrictEqual({
220
+ inputFile: "existing.fa",
221
+ threshold: 10,
222
+ selectedTab: "overview",
223
+ });
224
+ });
225
+
226
+ it("upgrades legacy data and runs subsequent migrations", () => {
227
+ type BlockDataV2 = BlockData & { description: string };
228
+
229
+ const dataModel = new DataModelBuilder()
230
+ .from<BlockData>("v1")
231
+ .upgradeLegacy<LegacyArgs, LegacyUiState>(({ args, uiState }) => ({
232
+ inputFile: args.inputFile,
233
+ threshold: args.threshold,
234
+ selectedTab: uiState.selectedTab,
235
+ }))
236
+ .migrate<BlockDataV2>("v2", (v1) => ({ ...v1, description: "auto" }))
237
+ .init(() => ({ inputFile: "", threshold: 0, selectedTab: "main", description: "" }));
238
+
239
+ const result = dataModel.migrate(
240
+ makeDataVersioned(DATA_MODEL_LEGACY_VERSION, {
241
+ args: { inputFile: "test.fa", threshold: 3 },
242
+ uiState: { selectedTab: "tab1" },
243
+ }),
244
+ );
245
+ expect(result.version).toBe("v2");
246
+ expect(result.data).toStrictEqual({
247
+ inputFile: "test.fa",
248
+ threshold: 3,
249
+ selectedTab: "tab1",
250
+ description: "auto",
251
+ });
252
+ });
253
+
254
+ it("throws when legacy upgrade fails", () => {
255
+ const dataModel = new DataModelBuilder()
256
+ .from<BlockData>("v1")
257
+ .upgradeLegacy<LegacyArgs, LegacyUiState>(() => {
258
+ throw new Error("bad legacy data");
259
+ })
260
+ .init(() => ({ inputFile: "", threshold: 0, selectedTab: "main" }));
261
+
262
+ expect(() =>
263
+ dataModel.migrate(
264
+ makeDataVersioned(DATA_MODEL_LEGACY_VERSION, {
265
+ args: { inputFile: "test.fa", threshold: 5 },
266
+ uiState: { selectedTab: "results" },
267
+ }),
268
+ ),
269
+ ).toThrow("bad legacy data");
270
+ });
271
+ });
175
272
  });