@platforma-sdk/model 1.54.10 → 1.55.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (151) hide show
  1. package/dist/bconfig/normalization.cjs +8 -1
  2. package/dist/bconfig/normalization.cjs.map +1 -1
  3. package/dist/bconfig/normalization.d.ts.map +1 -1
  4. package/dist/bconfig/normalization.js +8 -1
  5. package/dist/bconfig/normalization.js.map +1 -1
  6. package/dist/block_api_v3.d.ts +2 -2
  7. package/dist/block_api_v3.d.ts.map +1 -1
  8. package/dist/block_migrations.cjs +246 -214
  9. package/dist/block_migrations.cjs.map +1 -1
  10. package/dist/block_migrations.d.ts +180 -158
  11. package/dist/block_migrations.d.ts.map +1 -1
  12. package/dist/block_migrations.js +247 -214
  13. package/dist/block_migrations.js.map +1 -1
  14. package/dist/block_model.cjs +85 -35
  15. package/dist/block_model.cjs.map +1 -1
  16. package/dist/block_model.d.ts +66 -38
  17. package/dist/block_model.d.ts.map +1 -1
  18. package/dist/block_model.js +86 -36
  19. package/dist/block_model.js.map +1 -1
  20. package/dist/{builder.cjs → block_model_legacy.cjs} +2 -2
  21. package/dist/block_model_legacy.cjs.map +1 -0
  22. package/dist/{builder.d.ts → block_model_legacy.d.ts} +1 -1
  23. package/dist/block_model_legacy.d.ts.map +1 -0
  24. package/dist/{builder.js → block_model_legacy.js} +2 -2
  25. package/dist/block_model_legacy.js.map +1 -0
  26. package/dist/block_state_patch.d.ts +11 -1
  27. package/dist/block_state_patch.d.ts.map +1 -1
  28. package/dist/block_storage.cjs +126 -109
  29. package/dist/block_storage.cjs.map +1 -1
  30. package/dist/block_storage.d.ts +109 -112
  31. package/dist/block_storage.d.ts.map +1 -1
  32. package/dist/block_storage.js +126 -101
  33. package/dist/block_storage.js.map +1 -1
  34. package/dist/block_storage_callbacks.cjs +227 -0
  35. package/dist/block_storage_callbacks.cjs.map +1 -0
  36. package/dist/block_storage_callbacks.d.ts +113 -0
  37. package/dist/block_storage_callbacks.d.ts.map +1 -0
  38. package/dist/block_storage_callbacks.js +218 -0
  39. package/dist/block_storage_callbacks.js.map +1 -0
  40. package/dist/block_storage_facade.cjs +104 -0
  41. package/dist/block_storage_facade.cjs.map +1 -0
  42. package/dist/block_storage_facade.d.ts +168 -0
  43. package/dist/block_storage_facade.d.ts.map +1 -0
  44. package/dist/block_storage_facade.js +99 -0
  45. package/dist/block_storage_facade.js.map +1 -0
  46. package/dist/components/PlDataTable/state-migration.cjs.map +1 -1
  47. package/dist/components/PlDataTable/state-migration.js.map +1 -1
  48. package/dist/components/PlDataTable/table.cjs +11 -2
  49. package/dist/components/PlDataTable/table.cjs.map +1 -1
  50. package/dist/components/PlDataTable/table.d.ts.map +1 -1
  51. package/dist/components/PlDataTable/table.js +12 -3
  52. package/dist/components/PlDataTable/table.js.map +1 -1
  53. package/dist/components/PlDataTable/v5.d.ts +7 -4
  54. package/dist/components/PlDataTable/v5.d.ts.map +1 -1
  55. package/dist/filters/converters/filterToQuery.cjs +3 -4
  56. package/dist/filters/converters/filterToQuery.cjs.map +1 -1
  57. package/dist/filters/converters/filterToQuery.d.ts +1 -1
  58. package/dist/filters/converters/filterToQuery.d.ts.map +1 -1
  59. package/dist/filters/converters/filterToQuery.js +3 -4
  60. package/dist/filters/converters/filterToQuery.js.map +1 -1
  61. package/dist/filters/distill.cjs.map +1 -1
  62. package/dist/filters/distill.d.ts +3 -2
  63. package/dist/filters/distill.d.ts.map +1 -1
  64. package/dist/filters/distill.js.map +1 -1
  65. package/dist/filters/traverse.cjs +7 -3
  66. package/dist/filters/traverse.cjs.map +1 -1
  67. package/dist/filters/traverse.d.ts +14 -12
  68. package/dist/filters/traverse.d.ts.map +1 -1
  69. package/dist/filters/traverse.js +7 -3
  70. package/dist/filters/traverse.js.map +1 -1
  71. package/dist/index.cjs +13 -14
  72. package/dist/index.cjs.map +1 -1
  73. package/dist/index.d.ts +8 -3
  74. package/dist/index.d.ts.map +1 -1
  75. package/dist/index.js +6 -4
  76. package/dist/index.js.map +1 -1
  77. package/dist/package.json.cjs +1 -1
  78. package/dist/package.json.js +1 -1
  79. package/dist/platforma.d.ts +11 -4
  80. package/dist/platforma.d.ts.map +1 -1
  81. package/dist/plugin_model.cjs +171 -0
  82. package/dist/plugin_model.cjs.map +1 -0
  83. package/dist/plugin_model.d.ts +162 -0
  84. package/dist/plugin_model.d.ts.map +1 -0
  85. package/dist/plugin_model.js +169 -0
  86. package/dist/plugin_model.js.map +1 -0
  87. package/dist/render/api.cjs +20 -21
  88. package/dist/render/api.cjs.map +1 -1
  89. package/dist/render/api.d.ts +8 -8
  90. package/dist/render/api.d.ts.map +1 -1
  91. package/dist/render/api.js +20 -21
  92. package/dist/render/api.js.map +1 -1
  93. package/dist/render/internal.cjs.map +1 -1
  94. package/dist/render/internal.d.ts +1 -1
  95. package/dist/render/internal.d.ts.map +1 -1
  96. package/dist/render/internal.js.map +1 -1
  97. package/dist/version.cjs +4 -0
  98. package/dist/version.cjs.map +1 -1
  99. package/dist/version.d.ts +4 -0
  100. package/dist/version.d.ts.map +1 -1
  101. package/dist/version.js +4 -1
  102. package/dist/version.js.map +1 -1
  103. package/package.json +6 -6
  104. package/src/bconfig/normalization.ts +8 -1
  105. package/src/block_api_v3.ts +2 -2
  106. package/src/block_migrations.test.ts +141 -171
  107. package/src/block_migrations.ts +300 -285
  108. package/src/block_model.ts +205 -95
  109. package/src/{builder.ts → block_model_legacy.ts} +1 -1
  110. package/src/block_state_patch.ts +13 -1
  111. package/src/block_storage.test.ts +283 -95
  112. package/src/block_storage.ts +199 -188
  113. package/src/block_storage_callbacks.ts +326 -0
  114. package/src/block_storage_facade.ts +199 -0
  115. package/src/components/PlDataTable/state-migration.ts +4 -4
  116. package/src/components/PlDataTable/table.ts +16 -3
  117. package/src/components/PlDataTable/v5.ts +9 -5
  118. package/src/filters/converters/filterToQuery.ts +8 -7
  119. package/src/filters/distill.ts +19 -11
  120. package/src/filters/traverse.ts +44 -24
  121. package/src/index.ts +7 -3
  122. package/src/platforma.ts +26 -7
  123. package/src/plugin_model.test.ts +168 -0
  124. package/src/plugin_model.ts +242 -0
  125. package/src/render/api.ts +26 -24
  126. package/src/render/internal.ts +1 -1
  127. package/src/typing.test.ts +1 -1
  128. package/src/version.ts +8 -0
  129. package/dist/block_storage_vm.cjs +0 -262
  130. package/dist/block_storage_vm.cjs.map +0 -1
  131. package/dist/block_storage_vm.d.ts +0 -59
  132. package/dist/block_storage_vm.d.ts.map +0 -1
  133. package/dist/block_storage_vm.js +0 -258
  134. package/dist/block_storage_vm.js.map +0 -1
  135. package/dist/branding.d.ts +0 -7
  136. package/dist/branding.d.ts.map +0 -1
  137. package/dist/builder.cjs.map +0 -1
  138. package/dist/builder.d.ts.map +0 -1
  139. package/dist/builder.js.map +0 -1
  140. package/dist/sdk_info.cjs +0 -10
  141. package/dist/sdk_info.cjs.map +0 -1
  142. package/dist/sdk_info.d.ts +0 -5
  143. package/dist/sdk_info.d.ts.map +0 -1
  144. package/dist/sdk_info.js +0 -8
  145. package/dist/sdk_info.js.map +0 -1
  146. package/dist/unionize.d.ts +0 -12
  147. package/dist/unionize.d.ts.map +0 -1
  148. package/src/block_storage_vm.ts +0 -346
  149. package/src/branding.ts +0 -4
  150. package/src/sdk_info.ts +0 -9
  151. package/src/unionize.ts +0 -12
@@ -1 +1 @@
1
- {"version":3,"file":"block_migrations.cjs","sources":["../src/block_migrations.ts"],"sourcesContent":["import { tryRegisterCallback } from \"./internal\";\nimport { createBlockStorage } from \"./block_storage\";\n\nexport type DataVersionKey = string;\nexport type DataVersionMap = Record<string, unknown>;\nexport type DataMigrateFn<From, To> = (prev: Readonly<From>) => To;\nexport type DataCreateFn<T> = () => T;\nexport type DataRecoverFn<T> = (version: DataVersionKey, data: unknown) => T;\n\n/**\n * Helper to define version keys with literal type inference and runtime validation.\n * - Validates that all version values are unique\n * - Validates that no version value is empty\n * - Eliminates need for `as const` assertion\n *\n * @throws Error if duplicate or empty version values are found\n *\n * @example\n * const Version = defineDataVersions({\n * Initial: 'v1',\n * AddedLabels: 'v2',\n * });\n *\n * type VersionedData = {\n * [Version.Initial]: DataV1;\n * [Version.AddedLabels]: DataV2;\n * };\n */\nexport function defineDataVersions<const T extends Record<string, string>>(versions: T): T {\n const values = Object.values(versions) as (string & keyof T)[];\n const keys = Object.keys(versions) as (keyof T)[];\n const emptyKeys = keys.filter((key) => versions[key] === \"\");\n if (emptyKeys.length > 0) {\n throw new Error(`Version values must be non-empty strings (empty: ${emptyKeys.join(\", \")})`);\n }\n const unique = new Set(values);\n if (unique.size !== values.length) {\n const duplicates = values.filter((v, i) => values.indexOf(v) !== i);\n throw new Error(`Duplicate version values: ${[...new Set(duplicates)].join(\", \")}`);\n }\n return versions;\n}\n\n/** Versioned data wrapper for persistence */\nexport type DataVersioned<T> = {\n version: DataVersionKey;\n data: T;\n};\n\n/** Create a DataVersioned wrapper with correct shape */\nexport function makeDataVersioned<T>(version: DataVersionKey, data: T): DataVersioned<T> {\n return { version, data };\n}\n\n/** Result of migration operation, may include warning if migration failed */\nexport type DataMigrationResult<T> = DataVersioned<T> & {\n warning?: string;\n};\n\n/** Thrown by recover() to signal unrecoverable data. */\nexport class DataUnrecoverableError extends Error {\n name = \"DataUnrecoverableError\";\n constructor(dataVersion: DataVersionKey) {\n super(`Unknown version '${dataVersion}'`);\n }\n}\n\nexport function isDataUnrecoverableError(error: unknown): error is DataUnrecoverableError {\n return error instanceof Error && error.name === \"DataUnrecoverableError\";\n}\n\ntype MigrationStep = {\n fromVersion: DataVersionKey;\n toVersion: DataVersionKey;\n migrate: (data: unknown) => unknown;\n};\n\n/**\n * Default recover function for unknown versions.\n * Use as fallback at the end of custom recover functions.\n *\n * @example\n * .recover((version, data) => {\n * if (version === 'legacy') {\n * return transformLegacyData(data);\n * }\n * return defaultRecover(version, data);\n * })\n */\nexport const defaultRecover: DataRecoverFn<never> = (version, _data) => {\n throw new DataUnrecoverableError(version);\n};\n\n/** Symbol for internal builder creation method */\nconst FROM_BUILDER = Symbol(\"fromBuilder\");\n\n/** Internal state passed from builder to DataModel */\ntype BuilderState<S> = {\n versionChain: DataVersionKey[];\n steps: MigrationStep[];\n initialDataFn: () => S;\n recoverFn?: DataRecoverFn<S>;\n};\n\n/**\n * Final builder state after recover() is called.\n * Only allows calling create() to finalize the DataModel.\n *\n * @typeParam VersionedData - Map of version keys to their data types\n * @typeParam CurrentVersion - The current (final) version in the chain\n * @internal\n */\nclass DataModelBuilderWithRecover<\n VersionedData extends DataVersionMap,\n CurrentVersion extends keyof VersionedData & string,\n> {\n private readonly versionChain: DataVersionKey[];\n private readonly migrationSteps: MigrationStep[];\n private readonly recoverFn: DataRecoverFn<VersionedData[CurrentVersion]>;\n\n /** @internal */\n constructor({\n versionChain,\n steps,\n recoverFn,\n }: {\n versionChain: DataVersionKey[];\n steps: MigrationStep[];\n recoverFn: DataRecoverFn<VersionedData[CurrentVersion]>;\n }) {\n this.versionChain = versionChain;\n this.migrationSteps = steps;\n this.recoverFn = recoverFn;\n }\n\n /**\n * Finalize the DataModel with initial data factory.\n *\n * The initial data factory is called when creating new blocks or when\n * migration/recovery fails and data must be reset.\n *\n * @param initialData - Factory function returning initial state (must exactly match CurrentVersion's data type)\n * @returns Finalized DataModel instance\n *\n * @example\n * .init(() => ({ numbers: [], labels: [], description: '' }))\n */\n init<S extends VersionedData[CurrentVersion]>(\n initialData: DataCreateFn<S>,\n // Compile-time check: S must have exactly the same keys as VersionedData[CurrentVersion]\n ..._noExtraKeys: Exclude<keyof S, keyof VersionedData[CurrentVersion]> extends never\n ? []\n : [never]\n ): DataModel<VersionedData[CurrentVersion]> {\n return DataModel[FROM_BUILDER]<VersionedData[CurrentVersion]>({\n versionChain: this.versionChain,\n steps: this.migrationSteps,\n initialDataFn: initialData as DataCreateFn<VersionedData[CurrentVersion]>,\n recoverFn: this.recoverFn,\n });\n }\n}\n\n/**\n * Internal builder for constructing DataModel with type-safe migration chains.\n *\n * Tracks the current version through the generic type system, ensuring:\n * - Migration functions receive correctly typed input\n * - Migration functions must return the correct output type\n * - Version keys must exist in the VersionedData map\n * - All versions must be covered before calling init()\n *\n * @typeParam VersionedData - Map of version keys to their data types\n * @typeParam CurrentVersion - The current version in the migration chain\n * @typeParam RemainingVersions - Versions not yet covered by migrations\n * @internal\n */\nclass DataModelMigrationChain<\n VersionedData extends DataVersionMap,\n CurrentVersion extends keyof VersionedData & string,\n RemainingVersions extends keyof VersionedData & string = Exclude<\n keyof VersionedData & string,\n CurrentVersion\n >,\n> {\n private readonly versionChain: DataVersionKey[];\n private readonly migrationSteps: MigrationStep[];\n\n /** @internal */\n constructor({\n versionChain,\n steps = [],\n }: {\n versionChain: DataVersionKey[];\n steps?: MigrationStep[];\n }) {\n this.versionChain = versionChain;\n this.migrationSteps = steps;\n }\n\n /**\n * Add a migration step to transform data from current version to next version.\n *\n * Migration functions:\n * - Receive data typed as the current version's data type (readonly)\n * - Must return data matching the target version's data type\n * - Should be pure functions (no side effects)\n * - May throw errors (will result in data reset with warning)\n *\n * @typeParam NextVersion - The target version key (must be in RemainingVersions)\n * @param nextVersion - The version key to migrate to\n * @param fn - Migration function transforming current data to next version\n * @returns Builder with updated current version\n *\n * @example\n * .migrate(Version.V2, (data) => ({ ...data, labels: [] }))\n */\n migrate<NextVersion extends RemainingVersions>(\n nextVersion: NextVersion,\n fn: DataMigrateFn<VersionedData[CurrentVersion], VersionedData[NextVersion]>,\n ): DataModelMigrationChain<VersionedData, NextVersion, Exclude<RemainingVersions, NextVersion>> {\n if (this.versionChain.includes(nextVersion)) {\n throw new Error(`Duplicate version '${nextVersion}' in migration chain`);\n }\n const fromVersion = this.versionChain[this.versionChain.length - 1];\n const step: MigrationStep = {\n fromVersion,\n toVersion: nextVersion,\n migrate: fn as (data: unknown) => unknown,\n };\n return new DataModelMigrationChain<\n VersionedData,\n NextVersion,\n Exclude<RemainingVersions, NextVersion>\n >({\n versionChain: [...this.versionChain, nextVersion],\n steps: [...this.migrationSteps, step],\n });\n }\n\n /**\n * Set a recovery handler for unknown or legacy versions.\n *\n * The recover function is called when data has a version not in the migration chain.\n * It should either:\n * - Transform the data to the current version's format and return it\n * - Call `defaultRecover(version, data)` to signal unrecoverable data\n *\n * Can only be called once. After calling, only `init()` is available.\n *\n * @param fn - Recovery function that transforms unknown data or throws\n * @returns Builder with only init() method available\n *\n * @example\n * .recover((version, data) => {\n * if (version === 'legacy' && isLegacyFormat(data)) {\n * return transformLegacy(data);\n * }\n * return defaultRecover(version, data);\n * })\n */\n recover(\n fn: DataRecoverFn<VersionedData[CurrentVersion]>,\n ): DataModelBuilderWithRecover<VersionedData, CurrentVersion> {\n return new DataModelBuilderWithRecover<VersionedData, CurrentVersion>({\n versionChain: [...this.versionChain],\n steps: [...this.migrationSteps],\n recoverFn: fn,\n });\n }\n\n /**\n * Finalize the DataModel with initial data factory.\n *\n * Can only be called when all versions in VersionedData have been covered\n * by the migration chain (RemainingVersions is empty).\n *\n * The initial data factory is called when creating new blocks or when\n * migration/recovery fails and data must be reset.\n *\n * @param initialData - Factory function returning initial state (must exactly match CurrentVersion's data type)\n * @returns Finalized DataModel instance\n *\n * @example\n * .init(() => ({ numbers: [], labels: [], description: '' }))\n */\n init<S extends VersionedData[CurrentVersion]>(\n // Compile-time check: RemainingVersions must be empty (all versions covered)\n this: DataModelMigrationChain<VersionedData, CurrentVersion, never>,\n initialData: DataCreateFn<S>,\n // Compile-time check: S must have exactly the same keys as VersionedData[CurrentVersion]\n ..._noExtraKeys: Exclude<keyof S, keyof VersionedData[CurrentVersion]> extends never\n ? []\n : [never]\n ): DataModel<VersionedData[CurrentVersion]> {\n return DataModel[FROM_BUILDER]<VersionedData[CurrentVersion]>({\n versionChain: this.versionChain,\n steps: this.migrationSteps,\n initialDataFn: initialData as DataCreateFn<VersionedData[CurrentVersion]>,\n });\n }\n}\n\n/**\n * Builder entry point for creating DataModel with type-safe migrations.\n *\n * @typeParam VersionedData - Map of version keys to their data types\n *\n * @example\n * const Version = defineDataVersions({\n * V1: 'v1',\n * V2: 'v2',\n * });\n *\n * type VersionedData = {\n * [Version.V1]: { count: number };\n * [Version.V2]: { count: number; label: string };\n * };\n *\n * const dataModel = new DataModelBuilder<VersionedData>()\n * .from(Version.V1)\n * .migrate(Version.V2, (data) => ({ ...data, label: '' }))\n * .init(() => ({ count: 0, label: '' }));\n */\nexport class DataModelBuilder<VersionedData extends DataVersionMap> {\n /**\n * Start a migration chain from an initial version.\n *\n * @typeParam InitialVersion - The starting version key (inferred from argument)\n * @param initialVersion - The version key to start from\n * @returns Migration chain builder for adding migrations\n *\n * @example\n * new DataModelBuilder<VersionedData>()\n * .from(Version.V1)\n * .migrate(Version.V2, (data) => ({ ...data, newField: '' }))\n */\n from<InitialVersion extends keyof VersionedData & string>(\n initialVersion: InitialVersion,\n ): DataModelMigrationChain<\n VersionedData,\n InitialVersion,\n Exclude<keyof VersionedData & string, InitialVersion>\n > {\n return new DataModelMigrationChain<\n VersionedData,\n InitialVersion,\n Exclude<keyof VersionedData & string, InitialVersion>\n >({ versionChain: [initialVersion] });\n }\n}\n\n/**\n * DataModel defines the block's data structure, initial values, and migrations.\n * Used by BlockModelV3 to manage data state.\n *\n * Use `new DataModelBuilder<VersionedData>()` to create a DataModel:\n *\n * **Simple (no migrations):**\n * @example\n * const Version = defineDataVersions({ V1: DATA_MODEL_DEFAULT_VERSION });\n * type VersionedData = { [Version.V1]: BlockData };\n *\n * const dataModel = new DataModelBuilder<VersionedData>()\n * .from(Version.V1)\n * .init(() => ({ numbers: [], labels: [] }));\n *\n * **With migrations:**\n * @example\n * const Version = defineDataVersions({\n * V1: DATA_MODEL_DEFAULT_VERSION,\n * V2: 'v2',\n * V3: 'v3',\n * });\n *\n * type VersionedData = {\n * [Version.V1]: { numbers: number[] };\n * [Version.V2]: { numbers: number[]; labels: string[] };\n * [Version.V3]: { numbers: number[]; labels: string[]; description: string };\n * };\n *\n * const dataModel = new DataModelBuilder<VersionedData>()\n * .from(Version.V1)\n * .migrate(Version.V2, (data) => ({ ...data, labels: [] }))\n * .migrate(Version.V3, (data) => ({ ...data, description: '' }))\n * .recover((version, data) => {\n * if (version === 'legacy' && typeof data === 'object' && data !== null && 'numbers' in data) {\n * return { numbers: (data as { numbers: number[] }).numbers, labels: [], description: '' };\n * }\n * return defaultRecover(version, data);\n * })\n * .init(() => ({ numbers: [], labels: [], description: '' }));\n */\nexport class DataModel<State> {\n private readonly versionChain: DataVersionKey[];\n private readonly steps: MigrationStep[];\n private readonly initialDataFn: () => State;\n private readonly recoverFn: DataRecoverFn<State>;\n\n private constructor({\n versionChain,\n steps,\n initialDataFn,\n recoverFn = defaultRecover as DataRecoverFn<State>,\n }: {\n versionChain: DataVersionKey[];\n steps: MigrationStep[];\n initialDataFn: () => State;\n recoverFn?: DataRecoverFn<State>;\n }) {\n if (versionChain.length === 0) {\n throw new Error(\"DataModel requires at least one version key\");\n }\n this.versionChain = versionChain;\n this.steps = steps;\n this.initialDataFn = initialDataFn;\n this.recoverFn = recoverFn;\n }\n\n /**\n * Internal method for creating DataModel from builder.\n * Uses Symbol key to prevent external access.\n * @internal\n */\n static [FROM_BUILDER]<S>(state: BuilderState<S>): DataModel<S> {\n return new DataModel<S>(state);\n }\n\n /**\n * The latest (current) version key in the migration chain.\n */\n get version(): DataVersionKey {\n return this.versionChain[this.versionChain.length - 1];\n }\n\n /**\n * Number of migration steps defined.\n */\n get migrationCount(): number {\n return this.steps.length;\n }\n\n /**\n * Get a fresh copy of the initial data.\n */\n initialData(): State {\n return this.initialDataFn();\n }\n\n /**\n * Get initial data wrapped with current version.\n * Used when creating new blocks or resetting to defaults.\n */\n getDefaultData(): DataVersioned<State> {\n return makeDataVersioned(this.version, this.initialDataFn());\n }\n\n private recoverFrom(data: unknown, version: DataVersionKey): DataMigrationResult<State> {\n try {\n return { version: this.version, data: this.recoverFn(version, data) };\n } catch (error) {\n if (isDataUnrecoverableError(error)) {\n return { ...this.getDefaultData(), warning: error.message };\n }\n const errorMessage = error instanceof Error ? error.message : String(error);\n return {\n ...this.getDefaultData(),\n warning: `Recover failed for version '${version}': ${errorMessage}`,\n };\n }\n }\n\n /**\n * Migrate versioned data from any version to the latest.\n *\n * - If data is already at latest version, returns as-is\n * - If version is in chain, applies needed migrations\n * - If version is unknown, calls recover function\n * - If migration/recovery fails, returns default data with warning\n *\n * @param versioned - Data with version tag\n * @returns Migration result with data at latest version\n */\n migrate(versioned: DataVersioned<unknown>): DataMigrationResult<State> {\n const { version: fromVersion, data } = versioned;\n\n if (fromVersion === this.version) {\n return { version: this.version, data: data as State };\n }\n\n const startIndex = this.versionChain.indexOf(fromVersion);\n if (startIndex < 0) {\n return this.recoverFrom(data, fromVersion);\n }\n\n let currentData: unknown = data;\n for (let i = startIndex; i < this.steps.length; i++) {\n const step = this.steps[i];\n try {\n currentData = step.migrate(currentData);\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error);\n return {\n ...this.getDefaultData(),\n warning: `Migration ${step.fromVersion}→${step.toVersion} failed: ${errorMessage}`,\n };\n }\n }\n\n return { version: this.version, data: currentData as State };\n }\n\n /**\n * Register callbacks for use in the VM.\n * Called by BlockModelV3.create() to set up internal callbacks.\n *\n * @internal\n */\n registerCallbacks(): void {\n tryRegisterCallback(\"__pl_data_initial\", () => this.initialDataFn());\n tryRegisterCallback(\"__pl_data_upgrade\", (versioned: DataVersioned<unknown>) =>\n this.migrate(versioned),\n );\n tryRegisterCallback(\"__pl_storage_initial\", () => {\n const { version, data } = this.getDefaultData();\n const storage = createBlockStorage(data, version);\n return JSON.stringify(storage);\n });\n }\n}\n"],"names":["tryRegisterCallback","createBlockStorage"],"mappings":"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"}
1
+ {"version":3,"file":"block_migrations.cjs","sources":["../src/block_migrations.ts"],"sourcesContent":["export type DataVersionKey = string;\nexport type DataMigrateFn<From, To> = (prev: Readonly<From>) => To;\nexport type DataCreateFn<T> = () => T;\nexport type DataRecoverFn<T> = (version: DataVersionKey, data: unknown) => T;\n\n/** Versioned data wrapper for persistence */\nexport type DataVersioned<T> = {\n version: DataVersionKey;\n data: T;\n};\n\n/** Create a DataVersioned wrapper with correct shape */\nexport function makeDataVersioned<T>(version: DataVersionKey, data: T): DataVersioned<T> {\n return { version, data };\n}\n\n/** Result of migration operation, may include warning if migration failed */\nexport type DataMigrationResult<T> = DataVersioned<T> & {\n warning?: string;\n};\n\n/** Thrown by recover() to signal unrecoverable data. */\nexport class DataUnrecoverableError extends Error {\n name = \"DataUnrecoverableError\";\n constructor(dataVersion: DataVersionKey) {\n super(`Unknown version '${dataVersion}'`);\n }\n}\n\nexport function isDataUnrecoverableError(error: unknown): error is DataUnrecoverableError {\n return error instanceof Error && error.name === \"DataUnrecoverableError\";\n}\n\ntype MigrationStep = {\n fromVersion: DataVersionKey;\n toVersion: DataVersionKey;\n migrate: (data: unknown) => unknown;\n};\n\n/**\n * Default recover function for unknown versions.\n * Use as fallback at the end of custom recover functions.\n *\n * @example\n * .recover((version, data) => {\n * if (version === 'legacy') {\n * return transformLegacyData(data);\n * }\n * return defaultRecover(version, data);\n * })\n */\nexport const defaultRecover: DataRecoverFn<never> = (version, _data) => {\n throw new DataUnrecoverableError(version);\n};\n\n/** Symbol for internal builder creation method */\nconst FROM_BUILDER = Symbol(\"fromBuilder\");\n\n/** Legacy V1 model state shape: { args, uiState } */\nexport type LegacyV1State<Args, UiState> = { args: Args; uiState: UiState };\n\n/** Internal state passed from builder to DataModel */\ntype BuilderState<S> = {\n versionChain: DataVersionKey[];\n steps: MigrationStep[];\n initialDataFn: () => S;\n recoverFn?: (version: DataVersionKey, data: unknown) => unknown;\n /** Index of the first step to run after recovery. Equals the number of steps\n * present at the time recover() was called. */\n recoverFromIndex?: number;\n /** Transforms legacy V1 model data ({ args, uiState }) at the initial version. */\n upgradeLegacyFn?: (data: unknown) => unknown;\n};\n\ntype RecoverState = {\n recoverFn?: (version: DataVersionKey, data: unknown) => unknown;\n recoverFromIndex?: number;\n upgradeLegacyFn?: (data: unknown) => unknown;\n};\n\n/**\n * Abstract base for both migration chain types.\n * Holds shared state, buildStep() helper, and init().\n * migrate() cannot be shared due to a TypeScript limitation: when the base class\n * migrate() return type is abstract, subclasses cannot narrow it without losing type safety.\n * Each subclass therefore owns its migrate() with the correct concrete return type.\n *\n * @internal\n */\nabstract class MigrationChainBase<Current> {\n protected readonly versionChain: DataVersionKey[];\n protected readonly migrationSteps: MigrationStep[];\n\n protected constructor(state: { versionChain: DataVersionKey[]; steps: MigrationStep[] }) {\n this.versionChain = state.versionChain;\n this.migrationSteps = state.steps;\n }\n\n /** Appends a migration step and returns the new versionChain and steps arrays. */\n protected buildStep<Next>(\n nextVersion: string,\n fn: DataMigrateFn<Current, Next>,\n ): { versionChain: DataVersionKey[]; steps: MigrationStep[] } {\n if (this.versionChain.includes(nextVersion)) {\n throw new Error(`Duplicate version '${nextVersion}' in migration chain`);\n }\n const fromVersion = this.versionChain[this.versionChain.length - 1];\n const step: MigrationStep = {\n fromVersion,\n toVersion: nextVersion,\n migrate: fn as (data: unknown) => unknown,\n };\n return {\n versionChain: [...this.versionChain, nextVersion],\n steps: [...this.migrationSteps, step],\n };\n }\n\n /** Returns recover-specific fields for DataModel construction. Overridden by WithRecover. */\n protected recoverState(): RecoverState {\n return {};\n }\n\n /**\n * Finalize the DataModel with initial data factory.\n *\n * @param initialData - Factory function returning the initial state\n * @returns Finalized DataModel instance\n */\n init(initialData: DataCreateFn<Current>): DataModel<Current> {\n return DataModel[FROM_BUILDER]<Current>({\n versionChain: this.versionChain,\n steps: this.migrationSteps,\n initialDataFn: initialData,\n ...this.recoverState(),\n });\n }\n}\n\n/**\n * Migration chain after recover() or upgradeLegacy() has been called.\n * Further migrate() calls are allowed; recover() and upgradeLegacy() are not\n * (enforced by type — no such methods on this class).\n *\n * @typeParam Current - Data type at the current point in the chain\n * @internal\n */\nclass DataModelMigrationChainWithRecover<Current> extends MigrationChainBase<Current> {\n private readonly recoverFn?: (version: DataVersionKey, data: unknown) => unknown;\n private readonly recoverFromIndex?: number;\n private readonly upgradeLegacyFn?: (data: unknown) => unknown;\n\n /** @internal */\n constructor(state: {\n versionChain: DataVersionKey[];\n steps: MigrationStep[];\n recoverFn?: (version: DataVersionKey, data: unknown) => unknown;\n recoverFromIndex?: number;\n upgradeLegacyFn?: (data: unknown) => unknown;\n }) {\n super(state);\n this.recoverFn = state.recoverFn;\n this.recoverFromIndex = state.recoverFromIndex;\n this.upgradeLegacyFn = state.upgradeLegacyFn;\n }\n\n protected override recoverState(): RecoverState {\n return {\n recoverFn: this.recoverFn,\n recoverFromIndex: this.recoverFromIndex,\n upgradeLegacyFn: this.upgradeLegacyFn,\n };\n }\n\n /**\n * Add a migration step. Same semantics as on the base chain.\n * recover() and upgradeLegacy() are not available — one has already been called.\n */\n migrate<Next>(\n nextVersion: string,\n fn: DataMigrateFn<Current, Next>,\n ): DataModelMigrationChainWithRecover<Next> {\n const { versionChain, steps } = this.buildStep(nextVersion, fn);\n return new DataModelMigrationChainWithRecover<Next>({\n versionChain,\n steps,\n recoverFn: this.recoverFn,\n recoverFromIndex: this.recoverFromIndex,\n upgradeLegacyFn: this.upgradeLegacyFn,\n });\n }\n}\n\n/**\n * Migration chain builder.\n * Each migrate() call advances the current data type. recover() can be called once\n * at any point — it removes itself from the returned chain so it cannot be called again.\n * Duplicate version keys throw at runtime.\n *\n * @typeParam Current - Data type at the current point in the migration chain\n * @internal\n */\nclass DataModelMigrationChain<Current> extends MigrationChainBase<Current> {\n /** @internal */\n constructor({\n versionChain,\n steps = [],\n }: {\n versionChain: DataVersionKey[];\n steps?: MigrationStep[];\n }) {\n super({ versionChain, steps });\n }\n\n /**\n * Add a migration step transforming data from the current version to the next.\n *\n * @typeParam Next - Data type of the next version\n * @param nextVersion - Version key to migrate to (must be unique in the chain)\n * @param fn - Migration function\n * @returns Builder with the next version as current\n *\n * @example\n * .migrate<BlockDataV2>(\"v2\", (v1) => ({ ...v1, labels: [] }))\n */\n migrate<Next>(\n nextVersion: string,\n fn: DataMigrateFn<Current, Next>,\n ): DataModelMigrationChain<Next> {\n const { versionChain, steps } = this.buildStep(nextVersion, fn);\n return new DataModelMigrationChain<Next>({ versionChain, steps });\n }\n\n /**\n * Set a recovery handler for unknown or legacy versions.\n *\n * The recover function is called when data has a version not in the migration chain.\n * It must return data of the type at this point in the chain (Current). Any migrate()\n * steps added after recover() will then run on the recovered data.\n *\n * Can only be called once — the returned chain has no recover() method.\n * Mutually exclusive with upgradeLegacy().\n *\n * @param fn - Recovery function returning Current (the type at this chain position)\n * @returns Builder with migrate() and init() but without recover() or upgradeLegacy()\n *\n * @example\n * // Recover between migrations — recovered data goes through v3 migration\n * new DataModelBuilder<V1>(\"v1\")\n * .migrate<V2>(\"v2\", (v1) => ({ ...v1, label: \"\" }))\n * .recover((version, data) => {\n * if (version === 'legacy') return transformLegacy(data); // returns V2\n * return defaultRecover(version, data);\n * })\n * .migrate<V3>(\"v3\", (v2) => ({ ...v2, description: \"\" }))\n * .init(() => ({ count: 0, label: \"\", description: \"\" }));\n */\n recover(fn: DataRecoverFn<Current>): DataModelMigrationChainWithRecover<Current> {\n return new DataModelMigrationChainWithRecover<Current>({\n versionChain: this.versionChain,\n steps: this.migrationSteps,\n recoverFn: fn as (version: DataVersionKey, data: unknown) => unknown,\n recoverFromIndex: this.migrationSteps.length,\n });\n }\n\n /**\n * Handle legacy V1 model state ({ args, uiState }) when upgrading a block from\n * BlockModel V1 to BlockModelV3.\n *\n * When a V1 block is upgraded, its stored state `{ args, uiState }` arrives at the\n * initial version (DATA_MODEL_DEFAULT_VERSION) in the migration chain. This method\n * detects the legacy shape and transforms it to the current chain type using the\n * provided typed callback. Non-legacy data passes through unchanged.\n *\n * Should be called right after `.from()` (before any `.migrate()` calls), since legacy\n * data always arrives at the initial version. Any `.migrate()` steps added after\n * `upgradeLegacy()` will run on the transformed result.\n *\n * Can only be called once — the returned chain has no upgradeLegacy() method.\n * Mutually exclusive with recover().\n *\n * @typeParam Args - Type of the legacy block args\n * @typeParam UiState - Type of the legacy block uiState\n * @param fn - Typed transform from { args, uiState } to Current\n * @returns Builder with migrate() and init() but without recover() or upgradeLegacy()\n *\n * @example\n * type OldArgs = { inputFile: string; threshold: number };\n * type OldUiState = { selectedTab: string };\n * type BlockData = { inputFile: string; threshold: number; selectedTab: string };\n *\n * const dataModel = new DataModelBuilder()\n * .from<BlockData>(DATA_MODEL_DEFAULT_VERSION)\n * .upgradeLegacy<OldArgs, OldUiState>(({ args, uiState }) => ({\n * inputFile: args.inputFile,\n * threshold: args.threshold,\n * selectedTab: uiState.selectedTab,\n * }))\n * .init(() => ({ inputFile: '', threshold: 0, selectedTab: 'main' }));\n */\n upgradeLegacy<Args, UiState = unknown>(\n fn: (legacy: LegacyV1State<Args, UiState>) => Current,\n ): DataModelMigrationChainWithRecover<Current> {\n const wrappedFn = (data: unknown): unknown => {\n if (data !== null && typeof data === \"object\" && \"args\" in data) {\n return fn(data as LegacyV1State<Args, UiState>);\n }\n return data;\n };\n return new DataModelMigrationChainWithRecover<Current>({\n versionChain: this.versionChain,\n steps: this.migrationSteps,\n upgradeLegacyFn: wrappedFn,\n });\n }\n}\n\n/**\n * Builder entry point for creating DataModel with type-safe migrations.\n *\n * @example\n * // Simple (no migrations):\n * const dataModel = new DataModelBuilder()\n * .from<BlockData>(DATA_MODEL_DEFAULT_VERSION)\n * .init(() => ({ numbers: [] }));\n *\n * @example\n * // With migrations:\n * const dataModel = new DataModelBuilder()\n * .from<BlockDataV1>(DATA_MODEL_DEFAULT_VERSION)\n * .migrate<BlockDataV2>(\"v2\", (v1) => ({ ...v1, labels: [] }))\n * .migrate<BlockDataV3>(\"v3\", (v2) => ({ ...v2, description: '' }))\n * .init(() => ({ numbers: [], labels: [], description: '' }));\n *\n * @example\n * // With recover() between migrations — recovered data goes through remaining migrations:\n * const dataModelChain = new DataModelBuilder()\n * .from<BlockDataV1>(DATA_MODEL_DEFAULT_VERSION)\n * .migrate<BlockDataV2>(\"v2\", (v1) => ({ ...v1, labels: [] }));\n *\n * // recover() placed before the v3 migration: recovered data goes through v3\n * const dataModel = dataModelChain\n * .recover((version, data) => {\n * if (version === 'legacy' && isLegacyData(data)) return transformLegacy(data); // returns V2\n * return defaultRecover(version, data);\n * })\n * .migrate<BlockDataV3>(\"v3\", (v2) => ({ ...v2, description: '' }))\n * .init(() => ({ numbers: [], labels: [], description: '' }));\n *\n * @example\n * // With upgradeLegacy() — typed upgrade from BlockModel V1 state:\n * type OldArgs = { inputFile: string };\n * type OldUiState = { selectedTab: string };\n * type BlockData = { inputFile: string; selectedTab: string };\n *\n * const dataModel = new DataModelBuilder()\n * .from<BlockData>(DATA_MODEL_DEFAULT_VERSION)\n * .upgradeLegacy<OldArgs, OldUiState>(({ args, uiState }) => ({\n * inputFile: args.inputFile,\n * selectedTab: uiState.selectedTab,\n * }))\n * .init(() => ({ inputFile: '', selectedTab: 'main' }));\n */\nexport class DataModelBuilder {\n /**\n * Start the migration chain with the given initial data type and version key.\n *\n * @typeParam T - Data type for the initial version\n * @param initialVersion - Version key string (e.g. DATA_MODEL_DEFAULT_VERSION or \"v1\")\n * @returns Migration chain builder\n */\n from<T>(initialVersion: string): DataModelMigrationChain<T> {\n return new DataModelMigrationChain<T>({ versionChain: [initialVersion] });\n }\n}\n\n/**\n * DataModel defines the block's data structure, initial values, and migrations.\n * Used by BlockModelV3 to manage data state.\n *\n * Use `new DataModelBuilder()` to create a DataModel.\n *\n * @example\n * // With recover() between migrations:\n * // Recovered data (V2) goes through the v2→v3 migration automatically.\n * const dataModel = new DataModelBuilder()\n * .from<V1>(DATA_MODEL_DEFAULT_VERSION)\n * .migrate<V2>(\"v2\", (v1) => ({ ...v1, label: \"\" }))\n * .recover((version, data) => {\n * if (version === \"legacy\") return transformLegacy(data); // returns V2\n * return defaultRecover(version, data);\n * })\n * .migrate<V3>(\"v3\", (v2) => ({ ...v2, description: \"\" }))\n * .init(() => ({ count: 0, label: \"\", description: \"\" }));\n */\nexport class DataModel<State> {\n /** Latest version key — O(1) access for the common \"already current\" check. */\n private readonly latestVersion: DataVersionKey;\n /** Maps each known version key to the index of the first step to run from it. O(1) lookup. */\n private readonly stepsByFromVersion: ReadonlyMap<DataVersionKey, number>;\n private readonly steps: MigrationStep[];\n private readonly initialDataFn: () => State;\n private readonly recoverFn: (version: DataVersionKey, data: unknown) => unknown;\n private readonly recoverFromIndex: number;\n /** Transforms legacy V1 model data at the initial version before running migrations. */\n private readonly upgradeLegacyFn?: (data: unknown) => unknown;\n\n private constructor({\n versionChain,\n steps,\n initialDataFn,\n recoverFn = defaultRecover,\n recoverFromIndex,\n upgradeLegacyFn,\n }: BuilderState<State>) {\n if (versionChain.length === 0) {\n throw new Error(\"DataModel requires at least one version key\");\n }\n this.latestVersion = versionChain[versionChain.length - 1];\n this.stepsByFromVersion = new Map(versionChain.map((v, i) => [v, i]));\n this.steps = steps;\n this.initialDataFn = initialDataFn;\n this.recoverFn = recoverFn;\n this.recoverFromIndex = recoverFromIndex ?? steps.length;\n this.upgradeLegacyFn = upgradeLegacyFn;\n }\n\n /**\n * Internal method for creating DataModel from builder.\n * Uses Symbol key to prevent external access.\n * @internal\n */\n static [FROM_BUILDER]<S>(state: BuilderState<S>): DataModel<S> {\n return new DataModel<S>(state);\n }\n\n /**\n * The latest (current) version key in the migration chain.\n */\n get version(): DataVersionKey {\n return this.latestVersion;\n }\n\n /**\n * Get a fresh copy of the initial data.\n */\n initialData(): State {\n return this.initialDataFn();\n }\n\n /**\n * Get initial data wrapped with current version.\n * Used when creating new blocks or resetting to defaults.\n */\n getDefaultData(): DataVersioned<State> {\n return makeDataVersioned(this.latestVersion, this.initialDataFn());\n }\n\n private recoverFrom(data: unknown, version: DataVersionKey): DataMigrationResult<State> {\n // Step 1: call the recover function to get data at the recover point\n let currentData: unknown;\n try {\n currentData = this.recoverFn(version, data);\n } catch (error) {\n if (isDataUnrecoverableError(error)) {\n return { ...this.getDefaultData(), warning: error.message };\n }\n const errorMessage = error instanceof Error ? error.message : String(error);\n return {\n ...this.getDefaultData(),\n warning: `Recover failed for version '${version}': ${errorMessage}`,\n };\n }\n\n // Step 2: run any migrations that were added after recover() in the chain\n for (let i = this.recoverFromIndex; i < this.steps.length; i++) {\n const step = this.steps[i];\n try {\n currentData = step.migrate(currentData);\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error);\n return {\n ...this.getDefaultData(),\n warning: `Migration ${step.fromVersion}→${step.toVersion} failed: ${errorMessage}`,\n };\n }\n }\n\n return { version: this.latestVersion, data: currentData as State };\n }\n\n /**\n * Migrate versioned data from any version to the latest.\n *\n * - If version is in chain, applies needed migrations (O(1) lookup)\n * - If version is unknown, calls recover function then runs remaining migrations\n * - If migration/recovery fails, returns default data with warning\n *\n * @param versioned - Data with version tag\n * @returns Migration result with data at latest version\n */\n migrate(versioned: DataVersioned<unknown>): DataMigrationResult<State> {\n const { version: fromVersion, data } = versioned;\n\n if (fromVersion === this.latestVersion) {\n return { version: this.latestVersion, data: data as State };\n }\n\n const startIndex = this.stepsByFromVersion.get(fromVersion);\n if (startIndex === undefined) {\n return this.recoverFrom(data, fromVersion);\n }\n\n let currentData: unknown = data;\n\n // Legacy V1 upgrade: detect and transform { args, uiState } at the initial version\n if (startIndex === 0 && this.upgradeLegacyFn) {\n try {\n currentData = this.upgradeLegacyFn(currentData);\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error);\n return {\n ...this.getDefaultData(),\n warning: `Legacy upgrade failed: ${errorMessage}`,\n };\n }\n }\n\n for (let i = startIndex; i < this.steps.length; i++) {\n const step = this.steps[i];\n try {\n currentData = step.migrate(currentData);\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error);\n return {\n ...this.getDefaultData(),\n warning: `Migration ${step.fromVersion}→${step.toVersion} failed: ${errorMessage}`,\n };\n }\n }\n\n return { version: this.latestVersion, data: currentData as State };\n }\n}\n"],"names":[],"mappings":";;AAWA;AACM,SAAU,iBAAiB,CAAI,OAAuB,EAAE,IAAO,EAAA;AACnE,IAAA,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE;AAC1B;AAOA;AACM,MAAO,sBAAuB,SAAQ,KAAK,CAAA;IAC/C,IAAI,GAAG,wBAAwB;AAC/B,IAAA,WAAA,CAAY,WAA2B,EAAA;AACrC,QAAA,KAAK,CAAC,CAAA,iBAAA,EAAoB,WAAW,CAAA,CAAA,CAAG,CAAC;IAC3C;AACD;AAEK,SAAU,wBAAwB,CAAC,KAAc,EAAA;IACrD,OAAO,KAAK,YAAY,KAAK,IAAI,KAAK,CAAC,IAAI,KAAK,wBAAwB;AAC1E;AAQA;;;;;;;;;;;AAWG;MACU,cAAc,GAAyB,CAAC,OAAO,EAAE,KAAK,KAAI;AACrE,IAAA,MAAM,IAAI,sBAAsB,CAAC,OAAO,CAAC;AAC3C;AAEA;AACA,MAAM,YAAY,GAAG,MAAM,CAAC,aAAa,CAAC;AAwB1C;;;;;;;;AAQG;AACH,MAAe,kBAAkB,CAAA;AACZ,IAAA,YAAY;AACZ,IAAA,cAAc;AAEjC,IAAA,WAAA,CAAsB,KAAiE,EAAA;AACrF,QAAA,IAAI,CAAC,YAAY,GAAG,KAAK,CAAC,YAAY;AACtC,QAAA,IAAI,CAAC,cAAc,GAAG,KAAK,CAAC,KAAK;IACnC;;IAGU,SAAS,CACjB,WAAmB,EACnB,EAAgC,EAAA;QAEhC,IAAI,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC,WAAW,CAAC,EAAE;AAC3C,YAAA,MAAM,IAAI,KAAK,CAAC,sBAAsB,WAAW,CAAA,oBAAA,CAAsB,CAAC;QAC1E;AACA,QAAA,MAAM,WAAW,GAAG,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,YAAY,CAAC,MAAM,GAAG,CAAC,CAAC;AACnE,QAAA,MAAM,IAAI,GAAkB;YAC1B,WAAW;AACX,YAAA,SAAS,EAAE,WAAW;AACtB,YAAA,OAAO,EAAE,EAAgC;SAC1C;QACD,OAAO;YACL,YAAY,EAAE,CAAC,GAAG,IAAI,CAAC,YAAY,EAAE,WAAW,CAAC;YACjD,KAAK,EAAE,CAAC,GAAG,IAAI,CAAC,cAAc,EAAE,IAAI,CAAC;SACtC;IACH;;IAGU,YAAY,GAAA;AACpB,QAAA,OAAO,EAAE;IACX;AAEA;;;;;AAKG;AACH,IAAA,IAAI,CAAC,WAAkC,EAAA;AACrC,QAAA,OAAO,SAAS,CAAC,YAAY,CAAC,CAAU;YACtC,YAAY,EAAE,IAAI,CAAC,YAAY;YAC/B,KAAK,EAAE,IAAI,CAAC,cAAc;AAC1B,YAAA,aAAa,EAAE,WAAW;YAC1B,GAAG,IAAI,CAAC,YAAY,EAAE;AACvB,SAAA,CAAC;IACJ;AACD;AAED;;;;;;;AAOG;AACH,MAAM,kCAA4C,SAAQ,kBAA2B,CAAA;AAClE,IAAA,SAAS;AACT,IAAA,gBAAgB;AAChB,IAAA,eAAe;;AAGhC,IAAA,WAAA,CAAY,KAMX,EAAA;QACC,KAAK,CAAC,KAAK,CAAC;AACZ,QAAA,IAAI,CAAC,SAAS,GAAG,KAAK,CAAC,SAAS;AAChC,QAAA,IAAI,CAAC,gBAAgB,GAAG,KAAK,CAAC,gBAAgB;AAC9C,QAAA,IAAI,CAAC,eAAe,GAAG,KAAK,CAAC,eAAe;IAC9C;IAEmB,YAAY,GAAA;QAC7B,OAAO;YACL,SAAS,EAAE,IAAI,CAAC,SAAS;YACzB,gBAAgB,EAAE,IAAI,CAAC,gBAAgB;YACvC,eAAe,EAAE,IAAI,CAAC,eAAe;SACtC;IACH;AAEA;;;AAGG;IACH,OAAO,CACL,WAAmB,EACnB,EAAgC,EAAA;AAEhC,QAAA,MAAM,EAAE,YAAY,EAAE,KAAK,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,WAAW,EAAE,EAAE,CAAC;QAC/D,OAAO,IAAI,kCAAkC,CAAO;YAClD,YAAY;YACZ,KAAK;YACL,SAAS,EAAE,IAAI,CAAC,SAAS;YACzB,gBAAgB,EAAE,IAAI,CAAC,gBAAgB;YACvC,eAAe,EAAE,IAAI,CAAC,eAAe;AACtC,SAAA,CAAC;IACJ;AACD;AAED;;;;;;;;AAQG;AACH,MAAM,uBAAiC,SAAQ,kBAA2B,CAAA;;AAExE,IAAA,WAAA,CAAY,EACV,YAAY,EACZ,KAAK,GAAG,EAAE,GAIX,EAAA;AACC,QAAA,KAAK,CAAC,EAAE,YAAY,EAAE,KAAK,EAAE,CAAC;IAChC;AAEA;;;;;;;;;;AAUG;IACH,OAAO,CACL,WAAmB,EACnB,EAAgC,EAAA;AAEhC,QAAA,MAAM,EAAE,YAAY,EAAE,KAAK,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,WAAW,EAAE,EAAE,CAAC;QAC/D,OAAO,IAAI,uBAAuB,CAAO,EAAE,YAAY,EAAE,KAAK,EAAE,CAAC;IACnE;AAEA;;;;;;;;;;;;;;;;;;;;;;;AAuBG;AACH,IAAA,OAAO,CAAC,EAA0B,EAAA;QAChC,OAAO,IAAI,kCAAkC,CAAU;YACrD,YAAY,EAAE,IAAI,CAAC,YAAY;YAC/B,KAAK,EAAE,IAAI,CAAC,cAAc;AAC1B,YAAA,SAAS,EAAE,EAAyD;AACpE,YAAA,gBAAgB,EAAE,IAAI,CAAC,cAAc,CAAC,MAAM;AAC7C,SAAA,CAAC;IACJ;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAkCG;AACH,IAAA,aAAa,CACX,EAAqD,EAAA;AAErD,QAAA,MAAM,SAAS,GAAG,CAAC,IAAa,KAAa;AAC3C,YAAA,IAAI,IAAI,KAAK,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,MAAM,IAAI,IAAI,EAAE;AAC/D,gBAAA,OAAO,EAAE,CAAC,IAAoC,CAAC;YACjD;AACA,YAAA,OAAO,IAAI;AACb,QAAA,CAAC;QACD,OAAO,IAAI,kCAAkC,CAAU;YACrD,YAAY,EAAE,IAAI,CAAC,YAAY;YAC/B,KAAK,EAAE,IAAI,CAAC,cAAc;AAC1B,YAAA,eAAe,EAAE,SAAS;AAC3B,SAAA,CAAC;IACJ;AACD;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA6CG;MACU,gBAAgB,CAAA;AAC3B;;;;;;AAMG;AACH,IAAA,IAAI,CAAI,cAAsB,EAAA;QAC5B,OAAO,IAAI,uBAAuB,CAAI,EAAE,YAAY,EAAE,CAAC,cAAc,CAAC,EAAE,CAAC;IAC3E;AACD;AAED;;;;;;;;;;;;;;;;;;AAkBG;MACU,SAAS,CAAA;;AAEH,IAAA,aAAa;;AAEb,IAAA,kBAAkB;AAClB,IAAA,KAAK;AACL,IAAA,aAAa;AACb,IAAA,SAAS;AACT,IAAA,gBAAgB;;AAEhB,IAAA,eAAe;AAEhC,IAAA,WAAA,CAAoB,EAClB,YAAY,EACZ,KAAK,EACL,aAAa,EACb,SAAS,GAAG,cAAc,EAC1B,gBAAgB,EAChB,eAAe,GACK,EAAA;AACpB,QAAA,IAAI,YAAY,CAAC,MAAM,KAAK,CAAC,EAAE;AAC7B,YAAA,MAAM,IAAI,KAAK,CAAC,6CAA6C,CAAC;QAChE;QACA,IAAI,CAAC,aAAa,GAAG,YAAY,CAAC,YAAY,CAAC,MAAM,GAAG,CAAC,CAAC;QAC1D,IAAI,CAAC,kBAAkB,GAAG,IAAI,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;AACrE,QAAA,IAAI,CAAC,KAAK,GAAG,KAAK;AAClB,QAAA,IAAI,CAAC,aAAa,GAAG,aAAa;AAClC,QAAA,IAAI,CAAC,SAAS,GAAG,SAAS;QAC1B,IAAI,CAAC,gBAAgB,GAAG,gBAAgB,IAAI,KAAK,CAAC,MAAM;AACxD,QAAA,IAAI,CAAC,eAAe,GAAG,eAAe;IACxC;AAEA;;;;AAIG;AACH,IAAA,QAAQ,YAAY,CAAC,CAAI,KAAsB,EAAA;AAC7C,QAAA,OAAO,IAAI,SAAS,CAAI,KAAK,CAAC;IAChC;AAEA;;AAEG;AACH,IAAA,IAAI,OAAO,GAAA;QACT,OAAO,IAAI,CAAC,aAAa;IAC3B;AAEA;;AAEG;IACH,WAAW,GAAA;AACT,QAAA,OAAO,IAAI,CAAC,aAAa,EAAE;IAC7B;AAEA;;;AAGG;IACH,cAAc,GAAA;QACZ,OAAO,iBAAiB,CAAC,IAAI,CAAC,aAAa,EAAE,IAAI,CAAC,aAAa,EAAE,CAAC;IACpE;IAEQ,WAAW,CAAC,IAAa,EAAE,OAAuB,EAAA;;AAExD,QAAA,IAAI,WAAoB;AACxB,QAAA,IAAI;YACF,WAAW,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,IAAI,CAAC;QAC7C;QAAE,OAAO,KAAK,EAAE;AACd,YAAA,IAAI,wBAAwB,CAAC,KAAK,CAAC,EAAE;AACnC,gBAAA,OAAO,EAAE,GAAG,IAAI,CAAC,cAAc,EAAE,EAAE,OAAO,EAAE,KAAK,CAAC,OAAO,EAAE;YAC7D;AACA,YAAA,MAAM,YAAY,GAAG,KAAK,YAAY,KAAK,GAAG,KAAK,CAAC,OAAO,GAAG,MAAM,CAAC,KAAK,CAAC;YAC3E,OAAO;gBACL,GAAG,IAAI,CAAC,cAAc,EAAE;AACxB,gBAAA,OAAO,EAAE,CAAA,4BAAA,EAA+B,OAAO,CAAA,GAAA,EAAM,YAAY,CAAA,CAAE;aACpE;QACH;;AAGA,QAAA,KAAK,IAAI,CAAC,GAAG,IAAI,CAAC,gBAAgB,EAAE,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE;YAC9D,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;AAC1B,YAAA,IAAI;AACF,gBAAA,WAAW,GAAG,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC;YACzC;YAAE,OAAO,KAAK,EAAE;AACd,gBAAA,MAAM,YAAY,GAAG,KAAK,YAAY,KAAK,GAAG,KAAK,CAAC,OAAO,GAAG,MAAM,CAAC,KAAK,CAAC;gBAC3E,OAAO;oBACL,GAAG,IAAI,CAAC,cAAc,EAAE;oBACxB,OAAO,EAAE,CAAA,UAAA,EAAa,IAAI,CAAC,WAAW,CAAA,CAAA,EAAI,IAAI,CAAC,SAAS,CAAA,SAAA,EAAY,YAAY,CAAA,CAAE;iBACnF;YACH;QACF;QAEA,OAAO,EAAE,OAAO,EAAE,IAAI,CAAC,aAAa,EAAE,IAAI,EAAE,WAAoB,EAAE;IACpE;AAEA;;;;;;;;;AASG;AACH,IAAA,OAAO,CAAC,SAAiC,EAAA;QACvC,MAAM,EAAE,OAAO,EAAE,WAAW,EAAE,IAAI,EAAE,GAAG,SAAS;AAEhD,QAAA,IAAI,WAAW,KAAK,IAAI,CAAC,aAAa,EAAE;YACtC,OAAO,EAAE,OAAO,EAAE,IAAI,CAAC,aAAa,EAAE,IAAI,EAAE,IAAa,EAAE;QAC7D;QAEA,MAAM,UAAU,GAAG,IAAI,CAAC,kBAAkB,CAAC,GAAG,CAAC,WAAW,CAAC;AAC3D,QAAA,IAAI,UAAU,KAAK,SAAS,EAAE;YAC5B,OAAO,IAAI,CAAC,WAAW,CAAC,IAAI,EAAE,WAAW,CAAC;QAC5C;QAEA,IAAI,WAAW,GAAY,IAAI;;QAG/B,IAAI,UAAU,KAAK,CAAC,IAAI,IAAI,CAAC,eAAe,EAAE;AAC5C,YAAA,IAAI;AACF,gBAAA,WAAW,GAAG,IAAI,CAAC,eAAe,CAAC,WAAW,CAAC;YACjD;YAAE,OAAO,KAAK,EAAE;AACd,gBAAA,MAAM,YAAY,GAAG,KAAK,YAAY,KAAK,GAAG,KAAK,CAAC,OAAO,GAAG,MAAM,CAAC,KAAK,CAAC;gBAC3E,OAAO;oBACL,GAAG,IAAI,CAAC,cAAc,EAAE;oBACxB,OAAO,EAAE,CAAA,uBAAA,EAA0B,YAAY,CAAA,CAAE;iBAClD;YACH;QACF;AAEA,QAAA,KAAK,IAAI,CAAC,GAAG,UAAU,EAAE,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE;YACnD,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;AAC1B,YAAA,IAAI;AACF,gBAAA,WAAW,GAAG,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC;YACzC;YAAE,OAAO,KAAK,EAAE;AACd,gBAAA,MAAM,YAAY,GAAG,KAAK,YAAY,KAAK,GAAG,KAAK,CAAC,OAAO,GAAG,MAAM,CAAC,KAAK,CAAC;gBAC3E,OAAO;oBACL,GAAG,IAAI,CAAC,cAAc,EAAE;oBACxB,OAAO,EAAE,CAAA,UAAA,EAAa,IAAI,CAAC,WAAW,CAAA,CAAA,EAAI,IAAI,CAAC,SAAS,CAAA,SAAA,EAAY,YAAY,CAAA,CAAE;iBACnF;YACH;QACF;QAEA,OAAO,EAAE,OAAO,EAAE,IAAI,CAAC,aAAa,EAAE,IAAI,EAAE,WAAoB,EAAE;IACpE;AACD;;;;;;;;;"}
@@ -1,28 +1,7 @@
1
1
  export type DataVersionKey = string;
2
- export type DataVersionMap = Record<string, unknown>;
3
2
  export type DataMigrateFn<From, To> = (prev: Readonly<From>) => To;
4
3
  export type DataCreateFn<T> = () => T;
5
4
  export type DataRecoverFn<T> = (version: DataVersionKey, data: unknown) => T;
6
- /**
7
- * Helper to define version keys with literal type inference and runtime validation.
8
- * - Validates that all version values are unique
9
- * - Validates that no version value is empty
10
- * - Eliminates need for `as const` assertion
11
- *
12
- * @throws Error if duplicate or empty version values are found
13
- *
14
- * @example
15
- * const Version = defineDataVersions({
16
- * Initial: 'v1',
17
- * AddedLabels: 'v2',
18
- * });
19
- *
20
- * type VersionedData = {
21
- * [Version.Initial]: DataV1;
22
- * [Version.AddedLabels]: DataV2;
23
- * };
24
- */
25
- export declare function defineDataVersions<const T extends Record<string, string>>(versions: T): T;
26
5
  /** Versioned data wrapper for persistence */
27
6
  export type DataVersioned<T> = {
28
7
  version: DataVersionKey;
@@ -60,206 +39,261 @@ type MigrationStep = {
60
39
  export declare const defaultRecover: DataRecoverFn<never>;
61
40
  /** Symbol for internal builder creation method */
62
41
  declare const FROM_BUILDER: unique symbol;
42
+ /** Legacy V1 model state shape: { args, uiState } */
43
+ export type LegacyV1State<Args, UiState> = {
44
+ args: Args;
45
+ uiState: UiState;
46
+ };
63
47
  /** Internal state passed from builder to DataModel */
64
48
  type BuilderState<S> = {
65
49
  versionChain: DataVersionKey[];
66
50
  steps: MigrationStep[];
67
51
  initialDataFn: () => S;
68
- recoverFn?: DataRecoverFn<S>;
52
+ recoverFn?: (version: DataVersionKey, data: unknown) => unknown;
53
+ /** Index of the first step to run after recovery. Equals the number of steps
54
+ * present at the time recover() was called. */
55
+ recoverFromIndex?: number;
56
+ /** Transforms legacy V1 model data ({ args, uiState }) at the initial version. */
57
+ upgradeLegacyFn?: (data: unknown) => unknown;
58
+ };
59
+ type RecoverState = {
60
+ recoverFn?: (version: DataVersionKey, data: unknown) => unknown;
61
+ recoverFromIndex?: number;
62
+ upgradeLegacyFn?: (data: unknown) => unknown;
69
63
  };
70
64
  /**
71
- * Final builder state after recover() is called.
72
- * Only allows calling create() to finalize the DataModel.
65
+ * Abstract base for both migration chain types.
66
+ * Holds shared state, buildStep() helper, and init().
67
+ * migrate() cannot be shared due to a TypeScript limitation: when the base class
68
+ * migrate() return type is abstract, subclasses cannot narrow it without losing type safety.
69
+ * Each subclass therefore owns its migrate() with the correct concrete return type.
73
70
  *
74
- * @typeParam VersionedData - Map of version keys to their data types
75
- * @typeParam CurrentVersion - The current (final) version in the chain
76
71
  * @internal
77
72
  */
78
- declare class DataModelBuilderWithRecover<VersionedData extends DataVersionMap, CurrentVersion extends keyof VersionedData & string> {
79
- private readonly versionChain;
80
- private readonly migrationSteps;
81
- private readonly recoverFn;
82
- /** @internal */
83
- constructor({ versionChain, steps, recoverFn, }: {
73
+ declare abstract class MigrationChainBase<Current> {
74
+ protected readonly versionChain: DataVersionKey[];
75
+ protected readonly migrationSteps: MigrationStep[];
76
+ protected constructor(state: {
84
77
  versionChain: DataVersionKey[];
85
78
  steps: MigrationStep[];
86
- recoverFn: DataRecoverFn<VersionedData[CurrentVersion]>;
87
79
  });
80
+ /** Appends a migration step and returns the new versionChain and steps arrays. */
81
+ protected buildStep<Next>(nextVersion: string, fn: DataMigrateFn<Current, Next>): {
82
+ versionChain: DataVersionKey[];
83
+ steps: MigrationStep[];
84
+ };
85
+ /** Returns recover-specific fields for DataModel construction. Overridden by WithRecover. */
86
+ protected recoverState(): RecoverState;
88
87
  /**
89
88
  * Finalize the DataModel with initial data factory.
90
89
  *
91
- * The initial data factory is called when creating new blocks or when
92
- * migration/recovery fails and data must be reset.
93
- *
94
- * @param initialData - Factory function returning initial state (must exactly match CurrentVersion's data type)
90
+ * @param initialData - Factory function returning the initial state
95
91
  * @returns Finalized DataModel instance
96
- *
97
- * @example
98
- * .init(() => ({ numbers: [], labels: [], description: '' }))
99
92
  */
100
- init<S extends VersionedData[CurrentVersion]>(initialData: DataCreateFn<S>, ..._noExtraKeys: Exclude<keyof S, keyof VersionedData[CurrentVersion]> extends never ? [] : [never]): DataModel<VersionedData[CurrentVersion]>;
93
+ init(initialData: DataCreateFn<Current>): DataModel<Current>;
101
94
  }
102
95
  /**
103
- * Internal builder for constructing DataModel with type-safe migration chains.
96
+ * Migration chain after recover() or upgradeLegacy() has been called.
97
+ * Further migrate() calls are allowed; recover() and upgradeLegacy() are not
98
+ * (enforced by type — no such methods on this class).
104
99
  *
105
- * Tracks the current version through the generic type system, ensuring:
106
- * - Migration functions receive correctly typed input
107
- * - Migration functions must return the correct output type
108
- * - Version keys must exist in the VersionedData map
109
- * - All versions must be covered before calling init()
100
+ * @typeParam Current - Data type at the current point in the chain
101
+ * @internal
102
+ */
103
+ declare class DataModelMigrationChainWithRecover<Current> extends MigrationChainBase<Current> {
104
+ private readonly recoverFn?;
105
+ private readonly recoverFromIndex?;
106
+ private readonly upgradeLegacyFn?;
107
+ /** @internal */
108
+ constructor(state: {
109
+ versionChain: DataVersionKey[];
110
+ steps: MigrationStep[];
111
+ recoverFn?: (version: DataVersionKey, data: unknown) => unknown;
112
+ recoverFromIndex?: number;
113
+ upgradeLegacyFn?: (data: unknown) => unknown;
114
+ });
115
+ protected recoverState(): RecoverState;
116
+ /**
117
+ * Add a migration step. Same semantics as on the base chain.
118
+ * recover() and upgradeLegacy() are not available — one has already been called.
119
+ */
120
+ migrate<Next>(nextVersion: string, fn: DataMigrateFn<Current, Next>): DataModelMigrationChainWithRecover<Next>;
121
+ }
122
+ /**
123
+ * Migration chain builder.
124
+ * Each migrate() call advances the current data type. recover() can be called once
125
+ * at any point — it removes itself from the returned chain so it cannot be called again.
126
+ * Duplicate version keys throw at runtime.
110
127
  *
111
- * @typeParam VersionedData - Map of version keys to their data types
112
- * @typeParam CurrentVersion - The current version in the migration chain
113
- * @typeParam RemainingVersions - Versions not yet covered by migrations
128
+ * @typeParam Current - Data type at the current point in the migration chain
114
129
  * @internal
115
130
  */
116
- declare class DataModelMigrationChain<VersionedData extends DataVersionMap, CurrentVersion extends keyof VersionedData & string, RemainingVersions extends keyof VersionedData & string = Exclude<keyof VersionedData & string, CurrentVersion>> {
117
- private readonly versionChain;
118
- private readonly migrationSteps;
131
+ declare class DataModelMigrationChain<Current> extends MigrationChainBase<Current> {
119
132
  /** @internal */
120
133
  constructor({ versionChain, steps, }: {
121
134
  versionChain: DataVersionKey[];
122
135
  steps?: MigrationStep[];
123
136
  });
124
137
  /**
125
- * Add a migration step to transform data from current version to next version.
126
- *
127
- * Migration functions:
128
- * - Receive data typed as the current version's data type (readonly)
129
- * - Must return data matching the target version's data type
130
- * - Should be pure functions (no side effects)
131
- * - May throw errors (will result in data reset with warning)
138
+ * Add a migration step transforming data from the current version to the next.
132
139
  *
133
- * @typeParam NextVersion - The target version key (must be in RemainingVersions)
134
- * @param nextVersion - The version key to migrate to
135
- * @param fn - Migration function transforming current data to next version
136
- * @returns Builder with updated current version
140
+ * @typeParam Next - Data type of the next version
141
+ * @param nextVersion - Version key to migrate to (must be unique in the chain)
142
+ * @param fn - Migration function
143
+ * @returns Builder with the next version as current
137
144
  *
138
145
  * @example
139
- * .migrate(Version.V2, (data) => ({ ...data, labels: [] }))
146
+ * .migrate<BlockDataV2>("v2", (v1) => ({ ...v1, labels: [] }))
140
147
  */
141
- migrate<NextVersion extends RemainingVersions>(nextVersion: NextVersion, fn: DataMigrateFn<VersionedData[CurrentVersion], VersionedData[NextVersion]>): DataModelMigrationChain<VersionedData, NextVersion, Exclude<RemainingVersions, NextVersion>>;
148
+ migrate<Next>(nextVersion: string, fn: DataMigrateFn<Current, Next>): DataModelMigrationChain<Next>;
142
149
  /**
143
150
  * Set a recovery handler for unknown or legacy versions.
144
151
  *
145
152
  * The recover function is called when data has a version not in the migration chain.
146
- * It should either:
147
- * - Transform the data to the current version's format and return it
148
- * - Call `defaultRecover(version, data)` to signal unrecoverable data
153
+ * It must return data of the type at this point in the chain (Current). Any migrate()
154
+ * steps added after recover() will then run on the recovered data.
149
155
  *
150
- * Can only be called once. After calling, only `init()` is available.
156
+ * Can only be called once the returned chain has no recover() method.
157
+ * Mutually exclusive with upgradeLegacy().
151
158
  *
152
- * @param fn - Recovery function that transforms unknown data or throws
153
- * @returns Builder with only init() method available
159
+ * @param fn - Recovery function returning Current (the type at this chain position)
160
+ * @returns Builder with migrate() and init() but without recover() or upgradeLegacy()
154
161
  *
155
162
  * @example
156
- * .recover((version, data) => {
157
- * if (version === 'legacy' && isLegacyFormat(data)) {
158
- * return transformLegacy(data);
159
- * }
160
- * return defaultRecover(version, data);
161
- * })
163
+ * // Recover between migrations — recovered data goes through v3 migration
164
+ * new DataModelBuilder<V1>("v1")
165
+ * .migrate<V2>("v2", (v1) => ({ ...v1, label: "" }))
166
+ * .recover((version, data) => {
167
+ * if (version === 'legacy') return transformLegacy(data); // returns V2
168
+ * return defaultRecover(version, data);
169
+ * })
170
+ * .migrate<V3>("v3", (v2) => ({ ...v2, description: "" }))
171
+ * .init(() => ({ count: 0, label: "", description: "" }));
162
172
  */
163
- recover(fn: DataRecoverFn<VersionedData[CurrentVersion]>): DataModelBuilderWithRecover<VersionedData, CurrentVersion>;
173
+ recover(fn: DataRecoverFn<Current>): DataModelMigrationChainWithRecover<Current>;
164
174
  /**
165
- * Finalize the DataModel with initial data factory.
175
+ * Handle legacy V1 model state ({ args, uiState }) when upgrading a block from
176
+ * BlockModel V1 to BlockModelV3.
166
177
  *
167
- * Can only be called when all versions in VersionedData have been covered
168
- * by the migration chain (RemainingVersions is empty).
178
+ * When a V1 block is upgraded, its stored state `{ args, uiState }` arrives at the
179
+ * initial version (DATA_MODEL_DEFAULT_VERSION) in the migration chain. This method
180
+ * detects the legacy shape and transforms it to the current chain type using the
181
+ * provided typed callback. Non-legacy data passes through unchanged.
169
182
  *
170
- * The initial data factory is called when creating new blocks or when
171
- * migration/recovery fails and data must be reset.
183
+ * Should be called right after `.from()` (before any `.migrate()` calls), since legacy
184
+ * data always arrives at the initial version. Any `.migrate()` steps added after
185
+ * `upgradeLegacy()` will run on the transformed result.
172
186
  *
173
- * @param initialData - Factory function returning initial state (must exactly match CurrentVersion's data type)
174
- * @returns Finalized DataModel instance
187
+ * Can only be called once the returned chain has no upgradeLegacy() method.
188
+ * Mutually exclusive with recover().
189
+ *
190
+ * @typeParam Args - Type of the legacy block args
191
+ * @typeParam UiState - Type of the legacy block uiState
192
+ * @param fn - Typed transform from { args, uiState } to Current
193
+ * @returns Builder with migrate() and init() but without recover() or upgradeLegacy()
175
194
  *
176
195
  * @example
177
- * .init(() => ({ numbers: [], labels: [], description: '' }))
196
+ * type OldArgs = { inputFile: string; threshold: number };
197
+ * type OldUiState = { selectedTab: string };
198
+ * type BlockData = { inputFile: string; threshold: number; selectedTab: string };
199
+ *
200
+ * const dataModel = new DataModelBuilder()
201
+ * .from<BlockData>(DATA_MODEL_DEFAULT_VERSION)
202
+ * .upgradeLegacy<OldArgs, OldUiState>(({ args, uiState }) => ({
203
+ * inputFile: args.inputFile,
204
+ * threshold: args.threshold,
205
+ * selectedTab: uiState.selectedTab,
206
+ * }))
207
+ * .init(() => ({ inputFile: '', threshold: 0, selectedTab: 'main' }));
178
208
  */
179
- init<S extends VersionedData[CurrentVersion]>(this: DataModelMigrationChain<VersionedData, CurrentVersion, never>, initialData: DataCreateFn<S>, ..._noExtraKeys: Exclude<keyof S, keyof VersionedData[CurrentVersion]> extends never ? [] : [never]): DataModel<VersionedData[CurrentVersion]>;
209
+ upgradeLegacy<Args, UiState = unknown>(fn: (legacy: LegacyV1State<Args, UiState>) => Current): DataModelMigrationChainWithRecover<Current>;
180
210
  }
181
211
  /**
182
212
  * Builder entry point for creating DataModel with type-safe migrations.
183
213
  *
184
- * @typeParam VersionedData - Map of version keys to their data types
214
+ * @example
215
+ * // Simple (no migrations):
216
+ * const dataModel = new DataModelBuilder()
217
+ * .from<BlockData>(DATA_MODEL_DEFAULT_VERSION)
218
+ * .init(() => ({ numbers: [] }));
219
+ *
220
+ * @example
221
+ * // With migrations:
222
+ * const dataModel = new DataModelBuilder()
223
+ * .from<BlockDataV1>(DATA_MODEL_DEFAULT_VERSION)
224
+ * .migrate<BlockDataV2>("v2", (v1) => ({ ...v1, labels: [] }))
225
+ * .migrate<BlockDataV3>("v3", (v2) => ({ ...v2, description: '' }))
226
+ * .init(() => ({ numbers: [], labels: [], description: '' }));
185
227
  *
186
228
  * @example
187
- * const Version = defineDataVersions({
188
- * V1: 'v1',
189
- * V2: 'v2',
190
- * });
229
+ * // With recover() between migrations — recovered data goes through remaining migrations:
230
+ * const dataModelChain = new DataModelBuilder()
231
+ * .from<BlockDataV1>(DATA_MODEL_DEFAULT_VERSION)
232
+ * .migrate<BlockDataV2>("v2", (v1) => ({ ...v1, labels: [] }));
191
233
  *
192
- * type VersionedData = {
193
- * [Version.V1]: { count: number };
194
- * [Version.V2]: { count: number; label: string };
195
- * };
234
+ * // recover() placed before the v3 migration: recovered data goes through v3
235
+ * const dataModel = dataModelChain
236
+ * .recover((version, data) => {
237
+ * if (version === 'legacy' && isLegacyData(data)) return transformLegacy(data); // returns V2
238
+ * return defaultRecover(version, data);
239
+ * })
240
+ * .migrate<BlockDataV3>("v3", (v2) => ({ ...v2, description: '' }))
241
+ * .init(() => ({ numbers: [], labels: [], description: '' }));
196
242
  *
197
- * const dataModel = new DataModelBuilder<VersionedData>()
198
- * .from(Version.V1)
199
- * .migrate(Version.V2, (data) => ({ ...data, label: '' }))
200
- * .init(() => ({ count: 0, label: '' }));
243
+ * @example
244
+ * // With upgradeLegacy() — typed upgrade from BlockModel V1 state:
245
+ * type OldArgs = { inputFile: string };
246
+ * type OldUiState = { selectedTab: string };
247
+ * type BlockData = { inputFile: string; selectedTab: string };
248
+ *
249
+ * const dataModel = new DataModelBuilder()
250
+ * .from<BlockData>(DATA_MODEL_DEFAULT_VERSION)
251
+ * .upgradeLegacy<OldArgs, OldUiState>(({ args, uiState }) => ({
252
+ * inputFile: args.inputFile,
253
+ * selectedTab: uiState.selectedTab,
254
+ * }))
255
+ * .init(() => ({ inputFile: '', selectedTab: 'main' }));
201
256
  */
202
- export declare class DataModelBuilder<VersionedData extends DataVersionMap> {
257
+ export declare class DataModelBuilder {
203
258
  /**
204
- * Start a migration chain from an initial version.
205
- *
206
- * @typeParam InitialVersion - The starting version key (inferred from argument)
207
- * @param initialVersion - The version key to start from
208
- * @returns Migration chain builder for adding migrations
259
+ * Start the migration chain with the given initial data type and version key.
209
260
  *
210
- * @example
211
- * new DataModelBuilder<VersionedData>()
212
- * .from(Version.V1)
213
- * .migrate(Version.V2, (data) => ({ ...data, newField: '' }))
261
+ * @typeParam T - Data type for the initial version
262
+ * @param initialVersion - Version key string (e.g. DATA_MODEL_DEFAULT_VERSION or "v1")
263
+ * @returns Migration chain builder
214
264
  */
215
- from<InitialVersion extends keyof VersionedData & string>(initialVersion: InitialVersion): DataModelMigrationChain<VersionedData, InitialVersion, Exclude<keyof VersionedData & string, InitialVersion>>;
265
+ from<T>(initialVersion: string): DataModelMigrationChain<T>;
216
266
  }
217
267
  /**
218
268
  * DataModel defines the block's data structure, initial values, and migrations.
219
269
  * Used by BlockModelV3 to manage data state.
220
270
  *
221
- * Use `new DataModelBuilder<VersionedData>()` to create a DataModel:
222
- *
223
- * **Simple (no migrations):**
224
- * @example
225
- * const Version = defineDataVersions({ V1: DATA_MODEL_DEFAULT_VERSION });
226
- * type VersionedData = { [Version.V1]: BlockData };
227
- *
228
- * const dataModel = new DataModelBuilder<VersionedData>()
229
- * .from(Version.V1)
230
- * .init(() => ({ numbers: [], labels: [] }));
271
+ * Use `new DataModelBuilder()` to create a DataModel.
231
272
  *
232
- * **With migrations:**
233
273
  * @example
234
- * const Version = defineDataVersions({
235
- * V1: DATA_MODEL_DEFAULT_VERSION,
236
- * V2: 'v2',
237
- * V3: 'v3',
238
- * });
239
- *
240
- * type VersionedData = {
241
- * [Version.V1]: { numbers: number[] };
242
- * [Version.V2]: { numbers: number[]; labels: string[] };
243
- * [Version.V3]: { numbers: number[]; labels: string[]; description: string };
244
- * };
245
- *
246
- * const dataModel = new DataModelBuilder<VersionedData>()
247
- * .from(Version.V1)
248
- * .migrate(Version.V2, (data) => ({ ...data, labels: [] }))
249
- * .migrate(Version.V3, (data) => ({ ...data, description: '' }))
274
+ * // With recover() between migrations:
275
+ * // Recovered data (V2) goes through the v2→v3 migration automatically.
276
+ * const dataModel = new DataModelBuilder()
277
+ * .from<V1>(DATA_MODEL_DEFAULT_VERSION)
278
+ * .migrate<V2>("v2", (v1) => ({ ...v1, label: "" }))
250
279
  * .recover((version, data) => {
251
- * if (version === 'legacy' && typeof data === 'object' && data !== null && 'numbers' in data) {
252
- * return { numbers: (data as { numbers: number[] }).numbers, labels: [], description: '' };
253
- * }
280
+ * if (version === "legacy") return transformLegacy(data); // returns V2
254
281
  * return defaultRecover(version, data);
255
282
  * })
256
- * .init(() => ({ numbers: [], labels: [], description: '' }));
283
+ * .migrate<V3>("v3", (v2) => ({ ...v2, description: "" }))
284
+ * .init(() => ({ count: 0, label: "", description: "" }));
257
285
  */
258
286
  export declare class DataModel<State> {
259
- private readonly versionChain;
287
+ /** Latest version key — O(1) access for the common "already current" check. */
288
+ private readonly latestVersion;
289
+ /** Maps each known version key to the index of the first step to run from it. O(1) lookup. */
290
+ private readonly stepsByFromVersion;
260
291
  private readonly steps;
261
292
  private readonly initialDataFn;
262
293
  private readonly recoverFn;
294
+ private readonly recoverFromIndex;
295
+ /** Transforms legacy V1 model data at the initial version before running migrations. */
296
+ private readonly upgradeLegacyFn?;
263
297
  private constructor();
264
298
  /**
265
299
  * Internal method for creating DataModel from builder.
@@ -271,10 +305,6 @@ export declare class DataModel<State> {
271
305
  * The latest (current) version key in the migration chain.
272
306
  */
273
307
  get version(): DataVersionKey;
274
- /**
275
- * Number of migration steps defined.
276
- */
277
- get migrationCount(): number;
278
308
  /**
279
309
  * Get a fresh copy of the initial data.
280
310
  */
@@ -288,22 +318,14 @@ export declare class DataModel<State> {
288
318
  /**
289
319
  * Migrate versioned data from any version to the latest.
290
320
  *
291
- * - If data is already at latest version, returns as-is
292
- * - If version is in chain, applies needed migrations
293
- * - If version is unknown, calls recover function
321
+ * - If version is in chain, applies needed migrations (O(1) lookup)
322
+ * - If version is unknown, calls recover function then runs remaining migrations
294
323
  * - If migration/recovery fails, returns default data with warning
295
324
  *
296
325
  * @param versioned - Data with version tag
297
326
  * @returns Migration result with data at latest version
298
327
  */
299
328
  migrate(versioned: DataVersioned<unknown>): DataMigrationResult<State>;
300
- /**
301
- * Register callbacks for use in the VM.
302
- * Called by BlockModelV3.create() to set up internal callbacks.
303
- *
304
- * @internal
305
- */
306
- registerCallbacks(): void;
307
329
  }
308
330
  export {};
309
331
  //# sourceMappingURL=block_migrations.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"block_migrations.d.ts","sourceRoot":"","sources":["../src/block_migrations.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"block_migrations.d.ts","sourceRoot":"","sources":["../src/block_migrations.ts"],"names":[],"mappings":"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"}