@milaboratories/pl-middle-layer 1.58.4 → 1.59.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 (85) hide show
  1. package/dist/index.d.ts +2 -2
  2. package/dist/middle_layer/middle_layer.cjs +71 -47
  3. package/dist/middle_layer/middle_layer.cjs.map +1 -1
  4. package/dist/middle_layer/middle_layer.d.ts +18 -18
  5. package/dist/middle_layer/middle_layer.d.ts.map +1 -1
  6. package/dist/middle_layer/middle_layer.js +72 -48
  7. package/dist/middle_layer/middle_layer.js.map +1 -1
  8. package/dist/middle_layer/project.cjs +8 -9
  9. package/dist/middle_layer/project.cjs.map +1 -1
  10. package/dist/middle_layer/project.d.ts +6 -5
  11. package/dist/middle_layer/project.d.ts.map +1 -1
  12. package/dist/middle_layer/project.js +9 -10
  13. package/dist/middle_layer/project.js.map +1 -1
  14. package/dist/middle_layer/project_list.cjs +3 -3
  15. package/dist/middle_layer/project_list.cjs.map +1 -1
  16. package/dist/middle_layer/project_list.d.ts +1 -1
  17. package/dist/middle_layer/project_list.js +4 -4
  18. package/dist/middle_layer/project_list.js.map +1 -1
  19. package/dist/middle_layer/project_overview.cjs.map +1 -1
  20. package/dist/middle_layer/project_overview.js.map +1 -1
  21. package/dist/middle_layer/util.cjs.map +1 -1
  22. package/dist/middle_layer/util.js.map +1 -1
  23. package/dist/model/index.d.ts +2 -2
  24. package/dist/model/project_helper.cjs.map +1 -1
  25. package/dist/model/project_helper.d.ts +3 -3
  26. package/dist/model/project_helper.d.ts.map +1 -1
  27. package/dist/model/project_helper.js.map +1 -1
  28. package/dist/model/project_model.cjs.map +1 -1
  29. package/dist/model/project_model.d.ts +6 -5
  30. package/dist/model/project_model.d.ts.map +1 -1
  31. package/dist/model/project_model.js.map +1 -1
  32. package/dist/model/template_spec.d.ts +2 -2
  33. package/dist/model/template_spec.d.ts.map +1 -1
  34. package/dist/mutator/migration.cjs +1 -1
  35. package/dist/mutator/migration.cjs.map +1 -1
  36. package/dist/mutator/migration.js +2 -2
  37. package/dist/mutator/migration.js.map +1 -1
  38. package/dist/mutator/project.cjs +6 -6
  39. package/dist/mutator/project.cjs.map +1 -1
  40. package/dist/mutator/project.d.ts +3 -3
  41. package/dist/mutator/project.d.ts.map +1 -1
  42. package/dist/mutator/project.js +7 -7
  43. package/dist/mutator/project.js.map +1 -1
  44. package/dist/mutator/template/template_cache.cjs +7 -7
  45. package/dist/mutator/template/template_cache.cjs.map +1 -1
  46. package/dist/mutator/template/template_cache.d.ts +8 -8
  47. package/dist/mutator/template/template_cache.d.ts.map +1 -1
  48. package/dist/mutator/template/template_cache.js +8 -8
  49. package/dist/mutator/template/template_cache.js.map +1 -1
  50. package/dist/network_check/template.cjs +5 -5
  51. package/dist/network_check/template.cjs.map +1 -1
  52. package/dist/network_check/template.js +6 -6
  53. package/dist/network_check/template.js.map +1 -1
  54. package/dist/pool/data.cjs +2 -1
  55. package/dist/pool/data.cjs.map +1 -1
  56. package/dist/pool/data.d.ts +1 -1
  57. package/dist/pool/data.d.ts.map +1 -1
  58. package/dist/pool/data.js +3 -2
  59. package/dist/pool/data.js.map +1 -1
  60. package/dist/pool/driver.cjs +3 -1
  61. package/dist/pool/driver.cjs.map +1 -1
  62. package/dist/pool/driver.d.ts.map +1 -1
  63. package/dist/pool/driver.js +3 -1
  64. package/dist/pool/driver.js.map +1 -1
  65. package/package.json +16 -16
  66. package/src/index.ts +1 -1
  67. package/src/middle_layer/middle_layer.ts +99 -61
  68. package/src/middle_layer/project.ts +14 -13
  69. package/src/middle_layer/project_list.ts +10 -8
  70. package/src/middle_layer/project_overview.ts +2 -2
  71. package/src/middle_layer/render.test.ts +9 -9
  72. package/src/middle_layer/util.ts +2 -2
  73. package/src/model/index.ts +1 -1
  74. package/src/model/project_helper.ts +2 -2
  75. package/src/model/project_model.ts +7 -4
  76. package/src/model/template_spec.ts +2 -2
  77. package/src/mutator/block-pack/block_pack.test.ts +7 -2
  78. package/src/mutator/migration.ts +7 -7
  79. package/src/mutator/project.ts +20 -19
  80. package/src/mutator/template/template_cache.test.ts +6 -6
  81. package/src/mutator/template/template_cache.ts +24 -21
  82. package/src/mutator/template/template_render.test.ts +7 -7
  83. package/src/network_check/template.ts +8 -8
  84. package/src/pool/data.ts +6 -4
  85. package/src/pool/driver.ts +3 -1
@@ -1 +1 @@
1
- {"version":3,"file":"project_helper.cjs","names":["LRUCache","ConsoleLoggerAdapter","BLOCK_STORAGE_FACADE_VERSION","executeSingleLambda","BlockStorageFacadeCallbacks"],"sources":["../../src/model/project_helper.ts"],"sourcesContent":["import type { ResultOrError, BlockConfig, BlockStorage, PlRef } from \"@platforma-sdk/model\";\nimport type { StringifiedJson } from \"@milaboratories/pl-model-common\";\nimport {\n extractCodeWithInfo,\n ensureError,\n BlockStorageFacadeCallbacks,\n BLOCK_STORAGE_FACADE_VERSION,\n} from \"@platforma-sdk/model\";\nimport { LRUCache } from \"lru-cache\";\nimport type { QuickJSWASMModule } from \"quickjs-emscripten\";\nimport { executeSingleLambda } from \"../js_render\";\nimport type { ResourceId } from \"@milaboratories/pl-client\";\nimport { ConsoleLoggerAdapter, type MiLogger } from \"@milaboratories/ts-helpers\";\nimport type { StorageDebugView } from \"@milaboratories/pl-model-middle-layer\";\n\ntype EnrichmentTargetsRequest = {\n blockConfig: () => BlockConfig;\n args: () => unknown;\n};\n\ntype EnrichmentTargetsValue = {\n value: PlRef[] | undefined;\n};\n\n/**\n * Result of VM-based storage migration.\n * Returned by migrateStorageInVM().\n *\n * - Error result: { error: string } - serious failure (no context, etc.)\n * - Success result: { newStorageJson: StringifiedJson<BlockStorage>, info: string } - migration succeeded\n */\nexport type MigrationResult =\n | { error: string }\n | { error?: undefined; newStorageJson: StringifiedJson<BlockStorage>; info: string };\n\n/**\n * Result of args derivation from storage.\n * Returned by __pl_args_derive and __pl_prerunArgs_derive VM callbacks.\n */\ntype ArgsDeriveResult = { error: string } | { error?: undefined; value: unknown };\n\nexport class ProjectHelper {\n private readonly enrichmentTargetsCache = new LRUCache<\n string,\n EnrichmentTargetsValue,\n EnrichmentTargetsRequest\n >({\n max: 256,\n memoMethod: (_key, _value, { context }) => {\n return { value: this.calculateEnrichmentTargets(context) };\n },\n });\n\n constructor(\n private readonly quickJs: QuickJSWASMModule,\n public readonly logger: MiLogger = new ConsoleLoggerAdapter(),\n ) {}\n\n // =============================================================================\n // Args Derivation from Storage (V3+)\n // =============================================================================\n\n /**\n * Derives args directly from storage JSON using VM callback.\n * The VM extracts data from storage and calls the block's args() function.\n *\n * This allows the middle layer to work only with storage JSON,\n * without needing to know the underlying data structure.\n *\n * @param blockConfig The block configuration (provides the model code)\n * @param storageJson Storage as JSON string\n * @returns The derived args object, or error if derivation fails\n */\n public deriveArgsFromStorage(\n blockConfig: BlockConfig,\n storageJson: string,\n ): ResultOrError<unknown> {\n if (blockConfig.modelAPIVersion !== BLOCK_STORAGE_FACADE_VERSION) {\n return {\n error: new Error(\"deriveArgsFromStorage is only supported for model API version 2\"),\n };\n }\n\n try {\n const result = executeSingleLambda(\n this.quickJs,\n blockConfig.blockLifecycleCallbacks[BlockStorageFacadeCallbacks.ArgsDerive],\n extractCodeWithInfo(blockConfig),\n storageJson,\n ) as ArgsDeriveResult;\n\n if (result.error !== undefined) {\n return { error: new Error(result.error) };\n }\n return { value: result.value };\n } catch (e) {\n return { error: new Error(\"Args derivation from storage failed\", { cause: ensureError(e) }) };\n }\n }\n\n /**\n * Derives prerunArgs directly from storage JSON using VM callback.\n * Falls back to args() if prerunArgs is not defined in the block model.\n *\n * @param blockConfig The block configuration (provides the model code)\n * @param storageJson Storage as JSON string\n * @returns The derived prerunArgs, or undefined if derivation fails\n */\n public derivePrerunArgsFromStorage(blockConfig: BlockConfig, storageJson: string): unknown {\n if (blockConfig.modelAPIVersion !== BLOCK_STORAGE_FACADE_VERSION) {\n throw new Error(\"derivePrerunArgsFromStorage is only supported for model API version 2\");\n }\n\n try {\n const result = executeSingleLambda(\n this.quickJs,\n blockConfig.blockLifecycleCallbacks[BlockStorageFacadeCallbacks.PrerunArgsDerive],\n extractCodeWithInfo(blockConfig),\n storageJson,\n ) as ArgsDeriveResult;\n\n if (result.error !== undefined) {\n // Return undefined if derivation fails (skip block in staging)\n return undefined;\n }\n return result.value;\n } catch {\n // Return undefined if derivation fails (skip block in staging)\n return undefined;\n }\n }\n\n private calculateEnrichmentTargets(req: EnrichmentTargetsRequest): PlRef[] | undefined {\n const blockConfig = req.blockConfig();\n if (blockConfig.enrichmentTargets === undefined) return undefined;\n const args = req.args();\n const result = executeSingleLambda(\n this.quickJs,\n blockConfig.enrichmentTargets,\n extractCodeWithInfo(blockConfig),\n args,\n ) as PlRef[];\n return result;\n }\n\n public getEnrichmentTargets(\n blockConfig: () => BlockConfig,\n args: () => unknown,\n key?: { argsRid: ResourceId; blockPackRid: ResourceId },\n ): PlRef[] | undefined {\n const req = { blockConfig, args };\n if (key === undefined) return this.calculateEnrichmentTargets(req);\n const cacheKey = `${key.argsRid}:${key.blockPackRid}`;\n return this.enrichmentTargetsCache.memo(cacheKey, { context: req }).value;\n }\n\n // =============================================================================\n // VM-based Storage Operations\n // =============================================================================\n\n /**\n * Creates initial BlockStorage for a new block using VM-based transformation.\n * This calls the '__pl_storage_initial' callback registered by DataModel which:\n * - Gets initial data from DataModel.getDefaultData()\n * - Creates BlockStorage with correct version\n *\n * @param blockConfig The block configuration (provides the model code)\n * @returns Initial storage as JSON string\n * @throws Error if storage creation fails\n */\n public getInitialStorageInVM(blockConfig: BlockConfig): string {\n if (blockConfig.modelAPIVersion !== BLOCK_STORAGE_FACADE_VERSION) {\n throw new Error(\"getInitialStorageInVM is only supported for model API version 2\");\n }\n\n try {\n const result = executeSingleLambda(\n this.quickJs,\n blockConfig.blockLifecycleCallbacks[BlockStorageFacadeCallbacks.StorageInitial],\n extractCodeWithInfo(blockConfig),\n ) as string;\n return result;\n } catch (e) {\n this.logger.error(\n new Error(\"[ProjectHelper.getInitialStorageInVM] Initial storage creation failed\", {\n cause: e,\n }),\n );\n throw new Error(`Block initial storage creation failed: ${e}`);\n }\n }\n\n /**\n * Applies a state update using VM-based transformation.\n * This calls the model's `__pl_storage_applyUpdate` callback which:\n * - Normalizes current storage\n * - Updates state while preserving other fields (version, plugins)\n * - Returns the updated storage as JSON string\n *\n * @param blockConfig The block configuration (provides the model code)\n * @param currentStorageJson Current storage as JSON string (must be defined)\n * @param newState New state from developer\n * @returns Updated storage as JSON string\n * @throws Error if storage update fails\n */\n public applyStorageUpdateInVM(\n blockConfig: BlockConfig,\n currentStorageJson: string,\n payload: { operation: string; value: unknown },\n ): string {\n if (blockConfig.modelAPIVersion !== BLOCK_STORAGE_FACADE_VERSION) {\n throw new Error(\"applyStorageUpdateInVM is only supported for model API version 2\");\n }\n\n try {\n const result = executeSingleLambda(\n this.quickJs,\n blockConfig.blockLifecycleCallbacks[BlockStorageFacadeCallbacks.StorageApplyUpdate],\n extractCodeWithInfo(blockConfig),\n currentStorageJson,\n payload,\n ) as string;\n return result;\n } catch (e) {\n this.logger.error(\n new Error(\"[ProjectHelper.applyStorageUpdateInVM] Storage update failed\", { cause: e }),\n );\n throw new Error(`Block storage update failed: ${e}`);\n }\n }\n\n /**\n * Gets storage debug view from raw storage data by calling the VM's __pl_storage_debugView callback.\n * Returns structured debug info about the storage (e.g., dataVersion).\n *\n * @param blockConfig Block configuration\n * @param rawStorageJson Raw storage as JSON string (or undefined)\n * @returns Storage debug view as JSON string (e.g., '{\"dataVersion\": \"v1\"}')\n */\n public getStorageDebugViewInVM(\n blockConfig: BlockConfig,\n rawStorageJson: string | undefined,\n ): StringifiedJson<StorageDebugView> | undefined {\n if (blockConfig.modelAPIVersion !== BLOCK_STORAGE_FACADE_VERSION) {\n throw new Error(\"getStorageDebugViewInVM is only supported for model API version 2\");\n }\n\n try {\n const result = executeSingleLambda(\n this.quickJs,\n blockConfig.blockLifecycleCallbacks[BlockStorageFacadeCallbacks.StorageDebugView],\n extractCodeWithInfo(blockConfig),\n rawStorageJson,\n ) as StringifiedJson<StorageDebugView>;\n return result;\n } catch (e) {\n this.logger.error(\n new Error(\"[ProjectHelper.getStorageDebugViewInVM] Get storage debug view failed\", {\n cause: e,\n }),\n );\n return undefined;\n }\n }\n\n // =============================================================================\n // Block State Migrations\n // =============================================================================\n\n /**\n * Runs block state migrations via VM-based transformation.\n * This calls the model's `__pl_storage_migrate` callback which:\n * - Normalizes current storage to get state and version\n * - Applies DataModel upgrade to reach target version key\n * - Runs all necessary migrations sequentially\n * - Returns new storage with updated state and version\n *\n * The middle layer doesn't need to know about dataVersion or storage internals.\n * All migration logic is encapsulated in the model.\n *\n * @param blockConfig The NEW block configuration (provides the model code with migrations)\n * @param currentStorageJson Current storage as JSON string (or undefined)\n * @returns MigrationResult with new storage or skip/error info\n */\n public migrateStorageInVM(\n blockConfig: BlockConfig,\n currentStorageJson: string | undefined,\n ): MigrationResult {\n if (blockConfig.modelAPIVersion !== BLOCK_STORAGE_FACADE_VERSION) {\n return { error: \"migrateStorageInVM is only supported for model API version 2\" };\n }\n\n try {\n const result = executeSingleLambda(\n this.quickJs,\n blockConfig.blockLifecycleCallbacks[BlockStorageFacadeCallbacks.StorageMigrate],\n extractCodeWithInfo(blockConfig),\n currentStorageJson,\n ) as MigrationResult;\n return result;\n } catch (e) {\n this.logger.error(\n new Error(\"[ProjectHelper.migrateStorageInVM] Migration failed\", { cause: e }),\n );\n return { error: `VM execution failed: ${e}` };\n }\n }\n}\n"],"mappings":";;;;;;AAyCA,IAAa,gBAAb,MAA2B;CACzB,yBAA0C,IAAIA,UAAAA,SAI5C;EACA,KAAK;EACL,aAAa,MAAM,QAAQ,EAAE,cAAc;AACzC,UAAO,EAAE,OAAO,KAAK,2BAA2B,QAAQ,EAAE;;EAE7D,CAAC;CAEF,YACE,SACA,SAAmC,IAAIC,2BAAAA,sBAAsB,EAC7D;AAFiB,OAAA,UAAA;AACD,OAAA,SAAA;;;;;;;;;;;;;CAkBlB,sBACE,aACA,aACwB;AACxB,MAAI,YAAY,oBAAoBC,qBAAAA,6BAClC,QAAO,EACL,uBAAO,IAAI,MAAM,kEAAkE,EACpF;AAGH,MAAI;GACF,MAAM,SAASC,cAAAA,oBACb,KAAK,SACL,YAAY,wBAAwBC,qBAAAA,4BAA4B,cAAA,GAAA,qBAAA,qBAC5C,YAAY,EAChC,YACD;AAED,OAAI,OAAO,UAAU,KAAA,EACnB,QAAO,EAAE,OAAO,IAAI,MAAM,OAAO,MAAM,EAAE;AAE3C,UAAO,EAAE,OAAO,OAAO,OAAO;WACvB,GAAG;AACV,UAAO,EAAE,OAAO,IAAI,MAAM,uCAAuC,EAAE,QAAA,GAAA,qBAAA,aAAmB,EAAE,EAAE,CAAC,EAAE;;;;;;;;;;;CAYjG,4BAAmC,aAA0B,aAA8B;AACzF,MAAI,YAAY,oBAAoBF,qBAAAA,6BAClC,OAAM,IAAI,MAAM,wEAAwE;AAG1F,MAAI;GACF,MAAM,SAASC,cAAAA,oBACb,KAAK,SACL,YAAY,wBAAwBC,qBAAAA,4BAA4B,oBAAA,GAAA,qBAAA,qBAC5C,YAAY,EAChC,YACD;AAED,OAAI,OAAO,UAAU,KAAA,EAEnB;AAEF,UAAO,OAAO;UACR;AAEN;;;CAIJ,2BAAmC,KAAoD;EACrF,MAAM,cAAc,IAAI,aAAa;AACrC,MAAI,YAAY,sBAAsB,KAAA,EAAW,QAAO,KAAA;EACxD,MAAM,OAAO,IAAI,MAAM;AAOvB,SANeD,cAAAA,oBACb,KAAK,SACL,YAAY,oBAAA,GAAA,qBAAA,qBACQ,YAAY,EAChC,KACD;;CAIH,qBACE,aACA,MACA,KACqB;EACrB,MAAM,MAAM;GAAE;GAAa;GAAM;AACjC,MAAI,QAAQ,KAAA,EAAW,QAAO,KAAK,2BAA2B,IAAI;EAClE,MAAM,WAAW,GAAG,IAAI,QAAQ,GAAG,IAAI;AACvC,SAAO,KAAK,uBAAuB,KAAK,UAAU,EAAE,SAAS,KAAK,CAAC,CAAC;;;;;;;;;;;;CAiBtE,sBAA6B,aAAkC;AAC7D,MAAI,YAAY,oBAAoBD,qBAAAA,6BAClC,OAAM,IAAI,MAAM,kEAAkE;AAGpF,MAAI;AAMF,UALeC,cAAAA,oBACb,KAAK,SACL,YAAY,wBAAwBC,qBAAAA,4BAA4B,kBAAA,GAAA,qBAAA,qBAC5C,YAAY,CACjC;WAEM,GAAG;AACV,QAAK,OAAO,MACV,IAAI,MAAM,yEAAyE,EACjF,OAAO,GACR,CAAC,CACH;AACD,SAAM,IAAI,MAAM,0CAA0C,IAAI;;;;;;;;;;;;;;;;CAiBlE,uBACE,aACA,oBACA,SACQ;AACR,MAAI,YAAY,oBAAoBF,qBAAAA,6BAClC,OAAM,IAAI,MAAM,mEAAmE;AAGrF,MAAI;AAQF,UAPeC,cAAAA,oBACb,KAAK,SACL,YAAY,wBAAwBC,qBAAAA,4BAA4B,sBAAA,GAAA,qBAAA,qBAC5C,YAAY,EAChC,oBACA,QACD;WAEM,GAAG;AACV,QAAK,OAAO,MACV,IAAI,MAAM,gEAAgE,EAAE,OAAO,GAAG,CAAC,CACxF;AACD,SAAM,IAAI,MAAM,gCAAgC,IAAI;;;;;;;;;;;CAYxD,wBACE,aACA,gBAC+C;AAC/C,MAAI,YAAY,oBAAoBF,qBAAAA,6BAClC,OAAM,IAAI,MAAM,oEAAoE;AAGtF,MAAI;AAOF,UANeC,cAAAA,oBACb,KAAK,SACL,YAAY,wBAAwBC,qBAAAA,4BAA4B,oBAAA,GAAA,qBAAA,qBAC5C,YAAY,EAChC,eACD;WAEM,GAAG;AACV,QAAK,OAAO,MACV,IAAI,MAAM,yEAAyE,EACjF,OAAO,GACR,CAAC,CACH;AACD;;;;;;;;;;;;;;;;;;CAuBJ,mBACE,aACA,oBACiB;AACjB,MAAI,YAAY,oBAAoBF,qBAAAA,6BAClC,QAAO,EAAE,OAAO,gEAAgE;AAGlF,MAAI;AAOF,UANeC,cAAAA,oBACb,KAAK,SACL,YAAY,wBAAwBC,qBAAAA,4BAA4B,kBAAA,GAAA,qBAAA,qBAC5C,YAAY,EAChC,mBACD;WAEM,GAAG;AACV,QAAK,OAAO,MACV,IAAI,MAAM,uDAAuD,EAAE,OAAO,GAAG,CAAC,CAC/E;AACD,UAAO,EAAE,OAAO,wBAAwB,KAAK"}
1
+ {"version":3,"file":"project_helper.cjs","names":["LRUCache","ConsoleLoggerAdapter","BLOCK_STORAGE_FACADE_VERSION","executeSingleLambda","BlockStorageFacadeCallbacks"],"sources":["../../src/model/project_helper.ts"],"sourcesContent":["import type { ResultOrError, BlockConfig, BlockStorage, PlRef } from \"@platforma-sdk/model\";\nimport type { StringifiedJson } from \"@milaboratories/pl-model-common\";\nimport {\n extractCodeWithInfo,\n ensureError,\n BlockStorageFacadeCallbacks,\n BLOCK_STORAGE_FACADE_VERSION,\n} from \"@platforma-sdk/model\";\nimport { LRUCache } from \"lru-cache\";\nimport type { QuickJSWASMModule } from \"quickjs-emscripten\";\nimport { executeSingleLambda } from \"../js_render\";\nimport type { SignedResourceId } from \"@milaboratories/pl-client\";\nimport { ConsoleLoggerAdapter, type MiLogger } from \"@milaboratories/ts-helpers\";\nimport type { StorageDebugView } from \"@milaboratories/pl-model-middle-layer\";\n\ntype EnrichmentTargetsRequest = {\n blockConfig: () => BlockConfig;\n args: () => unknown;\n};\n\ntype EnrichmentTargetsValue = {\n value: PlRef[] | undefined;\n};\n\n/**\n * Result of VM-based storage migration.\n * Returned by migrateStorageInVM().\n *\n * - Error result: { error: string } - serious failure (no context, etc.)\n * - Success result: { newStorageJson: StringifiedJson<BlockStorage>, info: string } - migration succeeded\n */\nexport type MigrationResult =\n | { error: string }\n | { error?: undefined; newStorageJson: StringifiedJson<BlockStorage>; info: string };\n\n/**\n * Result of args derivation from storage.\n * Returned by __pl_args_derive and __pl_prerunArgs_derive VM callbacks.\n */\ntype ArgsDeriveResult = { error: string } | { error?: undefined; value: unknown };\n\nexport class ProjectHelper {\n private readonly enrichmentTargetsCache = new LRUCache<\n string,\n EnrichmentTargetsValue,\n EnrichmentTargetsRequest\n >({\n max: 256,\n memoMethod: (_key, _value, { context }) => {\n return { value: this.calculateEnrichmentTargets(context) };\n },\n });\n\n constructor(\n private readonly quickJs: QuickJSWASMModule,\n public readonly logger: MiLogger = new ConsoleLoggerAdapter(),\n ) {}\n\n // =============================================================================\n // Args Derivation from Storage (V3+)\n // =============================================================================\n\n /**\n * Derives args directly from storage JSON using VM callback.\n * The VM extracts data from storage and calls the block's args() function.\n *\n * This allows the middle layer to work only with storage JSON,\n * without needing to know the underlying data structure.\n *\n * @param blockConfig The block configuration (provides the model code)\n * @param storageJson Storage as JSON string\n * @returns The derived args object, or error if derivation fails\n */\n public deriveArgsFromStorage(\n blockConfig: BlockConfig,\n storageJson: string,\n ): ResultOrError<unknown> {\n if (blockConfig.modelAPIVersion !== BLOCK_STORAGE_FACADE_VERSION) {\n return {\n error: new Error(\"deriveArgsFromStorage is only supported for model API version 2\"),\n };\n }\n\n try {\n const result = executeSingleLambda(\n this.quickJs,\n blockConfig.blockLifecycleCallbacks[BlockStorageFacadeCallbacks.ArgsDerive],\n extractCodeWithInfo(blockConfig),\n storageJson,\n ) as ArgsDeriveResult;\n\n if (result.error !== undefined) {\n return { error: new Error(result.error) };\n }\n return { value: result.value };\n } catch (e) {\n return { error: new Error(\"Args derivation from storage failed\", { cause: ensureError(e) }) };\n }\n }\n\n /**\n * Derives prerunArgs directly from storage JSON using VM callback.\n * Falls back to args() if prerunArgs is not defined in the block model.\n *\n * @param blockConfig The block configuration (provides the model code)\n * @param storageJson Storage as JSON string\n * @returns The derived prerunArgs, or undefined if derivation fails\n */\n public derivePrerunArgsFromStorage(blockConfig: BlockConfig, storageJson: string): unknown {\n if (blockConfig.modelAPIVersion !== BLOCK_STORAGE_FACADE_VERSION) {\n throw new Error(\"derivePrerunArgsFromStorage is only supported for model API version 2\");\n }\n\n try {\n const result = executeSingleLambda(\n this.quickJs,\n blockConfig.blockLifecycleCallbacks[BlockStorageFacadeCallbacks.PrerunArgsDerive],\n extractCodeWithInfo(blockConfig),\n storageJson,\n ) as ArgsDeriveResult;\n\n if (result.error !== undefined) {\n // Return undefined if derivation fails (skip block in staging)\n return undefined;\n }\n return result.value;\n } catch {\n // Return undefined if derivation fails (skip block in staging)\n return undefined;\n }\n }\n\n private calculateEnrichmentTargets(req: EnrichmentTargetsRequest): PlRef[] | undefined {\n const blockConfig = req.blockConfig();\n if (blockConfig.enrichmentTargets === undefined) return undefined;\n const args = req.args();\n const result = executeSingleLambda(\n this.quickJs,\n blockConfig.enrichmentTargets,\n extractCodeWithInfo(blockConfig),\n args,\n ) as PlRef[];\n return result;\n }\n\n public getEnrichmentTargets(\n blockConfig: () => BlockConfig,\n args: () => unknown,\n key?: { argsRid: SignedResourceId; blockPackRid: SignedResourceId },\n ): PlRef[] | undefined {\n const req = { blockConfig, args };\n if (key === undefined) return this.calculateEnrichmentTargets(req);\n const cacheKey = `${key.argsRid}:${key.blockPackRid}`;\n return this.enrichmentTargetsCache.memo(cacheKey, { context: req }).value;\n }\n\n // =============================================================================\n // VM-based Storage Operations\n // =============================================================================\n\n /**\n * Creates initial BlockStorage for a new block using VM-based transformation.\n * This calls the '__pl_storage_initial' callback registered by DataModel which:\n * - Gets initial data from DataModel.getDefaultData()\n * - Creates BlockStorage with correct version\n *\n * @param blockConfig The block configuration (provides the model code)\n * @returns Initial storage as JSON string\n * @throws Error if storage creation fails\n */\n public getInitialStorageInVM(blockConfig: BlockConfig): string {\n if (blockConfig.modelAPIVersion !== BLOCK_STORAGE_FACADE_VERSION) {\n throw new Error(\"getInitialStorageInVM is only supported for model API version 2\");\n }\n\n try {\n const result = executeSingleLambda(\n this.quickJs,\n blockConfig.blockLifecycleCallbacks[BlockStorageFacadeCallbacks.StorageInitial],\n extractCodeWithInfo(blockConfig),\n ) as string;\n return result;\n } catch (e) {\n this.logger.error(\n new Error(\"[ProjectHelper.getInitialStorageInVM] Initial storage creation failed\", {\n cause: e,\n }),\n );\n throw new Error(`Block initial storage creation failed: ${e}`);\n }\n }\n\n /**\n * Applies a state update using VM-based transformation.\n * This calls the model's `__pl_storage_applyUpdate` callback which:\n * - Normalizes current storage\n * - Updates state while preserving other fields (version, plugins)\n * - Returns the updated storage as JSON string\n *\n * @param blockConfig The block configuration (provides the model code)\n * @param currentStorageJson Current storage as JSON string (must be defined)\n * @param newState New state from developer\n * @returns Updated storage as JSON string\n * @throws Error if storage update fails\n */\n public applyStorageUpdateInVM(\n blockConfig: BlockConfig,\n currentStorageJson: string,\n payload: { operation: string; value: unknown },\n ): string {\n if (blockConfig.modelAPIVersion !== BLOCK_STORAGE_FACADE_VERSION) {\n throw new Error(\"applyStorageUpdateInVM is only supported for model API version 2\");\n }\n\n try {\n const result = executeSingleLambda(\n this.quickJs,\n blockConfig.blockLifecycleCallbacks[BlockStorageFacadeCallbacks.StorageApplyUpdate],\n extractCodeWithInfo(blockConfig),\n currentStorageJson,\n payload,\n ) as string;\n return result;\n } catch (e) {\n this.logger.error(\n new Error(\"[ProjectHelper.applyStorageUpdateInVM] Storage update failed\", { cause: e }),\n );\n throw new Error(`Block storage update failed: ${e}`);\n }\n }\n\n /**\n * Gets storage debug view from raw storage data by calling the VM's __pl_storage_debugView callback.\n * Returns structured debug info about the storage (e.g., dataVersion).\n *\n * @param blockConfig Block configuration\n * @param rawStorageJson Raw storage as JSON string (or undefined)\n * @returns Storage debug view as JSON string (e.g., '{\"dataVersion\": \"v1\"}')\n */\n public getStorageDebugViewInVM(\n blockConfig: BlockConfig,\n rawStorageJson: string | undefined,\n ): StringifiedJson<StorageDebugView> | undefined {\n if (blockConfig.modelAPIVersion !== BLOCK_STORAGE_FACADE_VERSION) {\n throw new Error(\"getStorageDebugViewInVM is only supported for model API version 2\");\n }\n\n try {\n const result = executeSingleLambda(\n this.quickJs,\n blockConfig.blockLifecycleCallbacks[BlockStorageFacadeCallbacks.StorageDebugView],\n extractCodeWithInfo(blockConfig),\n rawStorageJson,\n ) as StringifiedJson<StorageDebugView>;\n return result;\n } catch (e) {\n this.logger.error(\n new Error(\"[ProjectHelper.getStorageDebugViewInVM] Get storage debug view failed\", {\n cause: e,\n }),\n );\n return undefined;\n }\n }\n\n // =============================================================================\n // Block State Migrations\n // =============================================================================\n\n /**\n * Runs block state migrations via VM-based transformation.\n * This calls the model's `__pl_storage_migrate` callback which:\n * - Normalizes current storage to get state and version\n * - Applies DataModel upgrade to reach target version key\n * - Runs all necessary migrations sequentially\n * - Returns new storage with updated state and version\n *\n * The middle layer doesn't need to know about dataVersion or storage internals.\n * All migration logic is encapsulated in the model.\n *\n * @param blockConfig The NEW block configuration (provides the model code with migrations)\n * @param currentStorageJson Current storage as JSON string (or undefined)\n * @returns MigrationResult with new storage or skip/error info\n */\n public migrateStorageInVM(\n blockConfig: BlockConfig,\n currentStorageJson: string | undefined,\n ): MigrationResult {\n if (blockConfig.modelAPIVersion !== BLOCK_STORAGE_FACADE_VERSION) {\n return { error: \"migrateStorageInVM is only supported for model API version 2\" };\n }\n\n try {\n const result = executeSingleLambda(\n this.quickJs,\n blockConfig.blockLifecycleCallbacks[BlockStorageFacadeCallbacks.StorageMigrate],\n extractCodeWithInfo(blockConfig),\n currentStorageJson,\n ) as MigrationResult;\n return result;\n } catch (e) {\n this.logger.error(\n new Error(\"[ProjectHelper.migrateStorageInVM] Migration failed\", { cause: e }),\n );\n return { error: `VM execution failed: ${e}` };\n }\n }\n}\n"],"mappings":"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"}
@@ -1,7 +1,7 @@
1
1
  import { BlockConfig, BlockStorage, PlRef, ResultOrError } from "@platforma-sdk/model";
2
2
  import { StorageDebugView } from "@milaboratories/pl-model-middle-layer";
3
3
  import { MiLogger } from "@milaboratories/ts-helpers";
4
- import { ResourceId } from "@milaboratories/pl-client";
4
+ import { SignedResourceId } from "@milaboratories/pl-client";
5
5
  import { QuickJSWASMModule } from "quickjs-emscripten";
6
6
  import { StringifiedJson } from "@milaboratories/pl-model-common";
7
7
 
@@ -48,8 +48,8 @@ declare class ProjectHelper {
48
48
  derivePrerunArgsFromStorage(blockConfig: BlockConfig, storageJson: string): unknown;
49
49
  private calculateEnrichmentTargets;
50
50
  getEnrichmentTargets(blockConfig: () => BlockConfig, args: () => unknown, key?: {
51
- argsRid: ResourceId;
52
- blockPackRid: ResourceId;
51
+ argsRid: SignedResourceId;
52
+ blockPackRid: SignedResourceId;
53
53
  }): PlRef[] | undefined;
54
54
  /**
55
55
  * Creates initial BlockStorage for a new block using VM-based transformation.
@@ -1 +1 @@
1
- {"version":3,"file":"project_helper.d.ts","names":[],"sources":["../../src/model/project_helper.ts"],"mappings":";;;;;;;;;;AA+BA;;;;;KAAY,eAAA;EACN,KAAA;AAAA;EACA,KAAA;EAAmB,cAAA,EAAgB,eAAA,CAAgB,YAAA;EAAe,IAAA;AAAA;AAAA,cAQ3D,aAAA;EAAA,iBAaQ,OAAA;EAAA,SACD,MAAA,EAAQ,QAAA;EAAA,iBAbT,sBAAA;cAYE,OAAA,EAAS,iBAAA,EACV,MAAA,GAAQ,QAAA;EAAA;;;;;;;;;;;EAkBnB,qBAAA,CACL,WAAA,EAAa,WAAA,EACb,WAAA,WACC,aAAA;EAsKA;;;;;;;;EAtII,2BAAA,CAA4B,WAAA,EAAa,WAAA,EAAa,WAAA;EAAA,QAwBrD,0BAAA;EAaD,oBAAA,CACL,WAAA,QAAmB,WAAA,EACnB,IAAA,iBACA,GAAA;IAAQ,OAAA,EAAS,UAAA;IAAY,YAAA,EAAc,UAAA;EAAA,IAC1C,KAAA;EA5EI;;;;;;;;;;EAiGA,qBAAA,CAAsB,WAAA,EAAa,WAAA;EAxBrB;;;;;;;;;;;;;EA2Dd,sBAAA,CACL,WAAA,EAAa,WAAA,EACb,kBAAA,UACA,OAAA;IAAW,SAAA;IAAmB,KAAA;EAAA;EAAA;;;;;;;;EA+BzB,uBAAA,CACL,WAAA,EAAa,WAAA,EACb,cAAA,uBACC,eAAA,CAAgB,gBAAA;EA2CJ;;;;;;;;;;;;;;;EADR,kBAAA,CACL,WAAA,EAAa,WAAA,EACb,kBAAA,uBACC,eAAA;AAAA"}
1
+ {"version":3,"file":"project_helper.d.ts","names":[],"sources":["../../src/model/project_helper.ts"],"mappings":";;;;;;;;;;AA+BA;;;;;KAAY,eAAA;EACN,KAAA;AAAA;EACA,KAAA;EAAmB,cAAA,EAAgB,eAAA,CAAgB,YAAA;EAAe,IAAA;AAAA;AAAA,cAQ3D,aAAA;EAAA,iBAaQ,OAAA;EAAA,SACD,MAAA,EAAQ,QAAA;EAAA,iBAbT,sBAAA;cAYE,OAAA,EAAS,iBAAA,EACV,MAAA,GAAQ,QAAA;EAAA;;;;;;;;;;;EAkBnB,qBAAA,CACL,WAAA,EAAa,WAAA,EACb,WAAA,WACC,aAAA;EAsKA;;;;;;;;EAtII,2BAAA,CAA4B,WAAA,EAAa,WAAA,EAAa,WAAA;EAAA,QAwBrD,0BAAA;EAaD,oBAAA,CACL,WAAA,QAAmB,WAAA,EACnB,IAAA,iBACA,GAAA;IAAQ,OAAA,EAAS,gBAAA;IAAkB,YAAA,EAAc,gBAAA;EAAA,IAChD,KAAA;EA5EI;;;;;;;;;;EAiGA,qBAAA,CAAsB,WAAA,EAAa,WAAA;EAxBrB;;;;;;;;;;;;;EA2Dd,sBAAA,CACL,WAAA,EAAa,WAAA,EACb,kBAAA,UACA,OAAA;IAAW,SAAA;IAAmB,KAAA;EAAA;EAAA;;;;;;;;EA+BzB,uBAAA,CACL,WAAA,EAAa,WAAA,EACb,cAAA,uBACC,eAAA,CAAgB,gBAAA;EA2CJ;;;;;;;;;;;;;;;EADR,kBAAA,CACL,WAAA,EAAa,WAAA,EACb,kBAAA,uBACC,eAAA;AAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"project_helper.js","names":[],"sources":["../../src/model/project_helper.ts"],"sourcesContent":["import type { ResultOrError, BlockConfig, BlockStorage, PlRef } from \"@platforma-sdk/model\";\nimport type { StringifiedJson } from \"@milaboratories/pl-model-common\";\nimport {\n extractCodeWithInfo,\n ensureError,\n BlockStorageFacadeCallbacks,\n BLOCK_STORAGE_FACADE_VERSION,\n} from \"@platforma-sdk/model\";\nimport { LRUCache } from \"lru-cache\";\nimport type { QuickJSWASMModule } from \"quickjs-emscripten\";\nimport { executeSingleLambda } from \"../js_render\";\nimport type { ResourceId } from \"@milaboratories/pl-client\";\nimport { ConsoleLoggerAdapter, type MiLogger } from \"@milaboratories/ts-helpers\";\nimport type { StorageDebugView } from \"@milaboratories/pl-model-middle-layer\";\n\ntype EnrichmentTargetsRequest = {\n blockConfig: () => BlockConfig;\n args: () => unknown;\n};\n\ntype EnrichmentTargetsValue = {\n value: PlRef[] | undefined;\n};\n\n/**\n * Result of VM-based storage migration.\n * Returned by migrateStorageInVM().\n *\n * - Error result: { error: string } - serious failure (no context, etc.)\n * - Success result: { newStorageJson: StringifiedJson<BlockStorage>, info: string } - migration succeeded\n */\nexport type MigrationResult =\n | { error: string }\n | { error?: undefined; newStorageJson: StringifiedJson<BlockStorage>; info: string };\n\n/**\n * Result of args derivation from storage.\n * Returned by __pl_args_derive and __pl_prerunArgs_derive VM callbacks.\n */\ntype ArgsDeriveResult = { error: string } | { error?: undefined; value: unknown };\n\nexport class ProjectHelper {\n private readonly enrichmentTargetsCache = new LRUCache<\n string,\n EnrichmentTargetsValue,\n EnrichmentTargetsRequest\n >({\n max: 256,\n memoMethod: (_key, _value, { context }) => {\n return { value: this.calculateEnrichmentTargets(context) };\n },\n });\n\n constructor(\n private readonly quickJs: QuickJSWASMModule,\n public readonly logger: MiLogger = new ConsoleLoggerAdapter(),\n ) {}\n\n // =============================================================================\n // Args Derivation from Storage (V3+)\n // =============================================================================\n\n /**\n * Derives args directly from storage JSON using VM callback.\n * The VM extracts data from storage and calls the block's args() function.\n *\n * This allows the middle layer to work only with storage JSON,\n * without needing to know the underlying data structure.\n *\n * @param blockConfig The block configuration (provides the model code)\n * @param storageJson Storage as JSON string\n * @returns The derived args object, or error if derivation fails\n */\n public deriveArgsFromStorage(\n blockConfig: BlockConfig,\n storageJson: string,\n ): ResultOrError<unknown> {\n if (blockConfig.modelAPIVersion !== BLOCK_STORAGE_FACADE_VERSION) {\n return {\n error: new Error(\"deriveArgsFromStorage is only supported for model API version 2\"),\n };\n }\n\n try {\n const result = executeSingleLambda(\n this.quickJs,\n blockConfig.blockLifecycleCallbacks[BlockStorageFacadeCallbacks.ArgsDerive],\n extractCodeWithInfo(blockConfig),\n storageJson,\n ) as ArgsDeriveResult;\n\n if (result.error !== undefined) {\n return { error: new Error(result.error) };\n }\n return { value: result.value };\n } catch (e) {\n return { error: new Error(\"Args derivation from storage failed\", { cause: ensureError(e) }) };\n }\n }\n\n /**\n * Derives prerunArgs directly from storage JSON using VM callback.\n * Falls back to args() if prerunArgs is not defined in the block model.\n *\n * @param blockConfig The block configuration (provides the model code)\n * @param storageJson Storage as JSON string\n * @returns The derived prerunArgs, or undefined if derivation fails\n */\n public derivePrerunArgsFromStorage(blockConfig: BlockConfig, storageJson: string): unknown {\n if (blockConfig.modelAPIVersion !== BLOCK_STORAGE_FACADE_VERSION) {\n throw new Error(\"derivePrerunArgsFromStorage is only supported for model API version 2\");\n }\n\n try {\n const result = executeSingleLambda(\n this.quickJs,\n blockConfig.blockLifecycleCallbacks[BlockStorageFacadeCallbacks.PrerunArgsDerive],\n extractCodeWithInfo(blockConfig),\n storageJson,\n ) as ArgsDeriveResult;\n\n if (result.error !== undefined) {\n // Return undefined if derivation fails (skip block in staging)\n return undefined;\n }\n return result.value;\n } catch {\n // Return undefined if derivation fails (skip block in staging)\n return undefined;\n }\n }\n\n private calculateEnrichmentTargets(req: EnrichmentTargetsRequest): PlRef[] | undefined {\n const blockConfig = req.blockConfig();\n if (blockConfig.enrichmentTargets === undefined) return undefined;\n const args = req.args();\n const result = executeSingleLambda(\n this.quickJs,\n blockConfig.enrichmentTargets,\n extractCodeWithInfo(blockConfig),\n args,\n ) as PlRef[];\n return result;\n }\n\n public getEnrichmentTargets(\n blockConfig: () => BlockConfig,\n args: () => unknown,\n key?: { argsRid: ResourceId; blockPackRid: ResourceId },\n ): PlRef[] | undefined {\n const req = { blockConfig, args };\n if (key === undefined) return this.calculateEnrichmentTargets(req);\n const cacheKey = `${key.argsRid}:${key.blockPackRid}`;\n return this.enrichmentTargetsCache.memo(cacheKey, { context: req }).value;\n }\n\n // =============================================================================\n // VM-based Storage Operations\n // =============================================================================\n\n /**\n * Creates initial BlockStorage for a new block using VM-based transformation.\n * This calls the '__pl_storage_initial' callback registered by DataModel which:\n * - Gets initial data from DataModel.getDefaultData()\n * - Creates BlockStorage with correct version\n *\n * @param blockConfig The block configuration (provides the model code)\n * @returns Initial storage as JSON string\n * @throws Error if storage creation fails\n */\n public getInitialStorageInVM(blockConfig: BlockConfig): string {\n if (blockConfig.modelAPIVersion !== BLOCK_STORAGE_FACADE_VERSION) {\n throw new Error(\"getInitialStorageInVM is only supported for model API version 2\");\n }\n\n try {\n const result = executeSingleLambda(\n this.quickJs,\n blockConfig.blockLifecycleCallbacks[BlockStorageFacadeCallbacks.StorageInitial],\n extractCodeWithInfo(blockConfig),\n ) as string;\n return result;\n } catch (e) {\n this.logger.error(\n new Error(\"[ProjectHelper.getInitialStorageInVM] Initial storage creation failed\", {\n cause: e,\n }),\n );\n throw new Error(`Block initial storage creation failed: ${e}`);\n }\n }\n\n /**\n * Applies a state update using VM-based transformation.\n * This calls the model's `__pl_storage_applyUpdate` callback which:\n * - Normalizes current storage\n * - Updates state while preserving other fields (version, plugins)\n * - Returns the updated storage as JSON string\n *\n * @param blockConfig The block configuration (provides the model code)\n * @param currentStorageJson Current storage as JSON string (must be defined)\n * @param newState New state from developer\n * @returns Updated storage as JSON string\n * @throws Error if storage update fails\n */\n public applyStorageUpdateInVM(\n blockConfig: BlockConfig,\n currentStorageJson: string,\n payload: { operation: string; value: unknown },\n ): string {\n if (blockConfig.modelAPIVersion !== BLOCK_STORAGE_FACADE_VERSION) {\n throw new Error(\"applyStorageUpdateInVM is only supported for model API version 2\");\n }\n\n try {\n const result = executeSingleLambda(\n this.quickJs,\n blockConfig.blockLifecycleCallbacks[BlockStorageFacadeCallbacks.StorageApplyUpdate],\n extractCodeWithInfo(blockConfig),\n currentStorageJson,\n payload,\n ) as string;\n return result;\n } catch (e) {\n this.logger.error(\n new Error(\"[ProjectHelper.applyStorageUpdateInVM] Storage update failed\", { cause: e }),\n );\n throw new Error(`Block storage update failed: ${e}`);\n }\n }\n\n /**\n * Gets storage debug view from raw storage data by calling the VM's __pl_storage_debugView callback.\n * Returns structured debug info about the storage (e.g., dataVersion).\n *\n * @param blockConfig Block configuration\n * @param rawStorageJson Raw storage as JSON string (or undefined)\n * @returns Storage debug view as JSON string (e.g., '{\"dataVersion\": \"v1\"}')\n */\n public getStorageDebugViewInVM(\n blockConfig: BlockConfig,\n rawStorageJson: string | undefined,\n ): StringifiedJson<StorageDebugView> | undefined {\n if (blockConfig.modelAPIVersion !== BLOCK_STORAGE_FACADE_VERSION) {\n throw new Error(\"getStorageDebugViewInVM is only supported for model API version 2\");\n }\n\n try {\n const result = executeSingleLambda(\n this.quickJs,\n blockConfig.blockLifecycleCallbacks[BlockStorageFacadeCallbacks.StorageDebugView],\n extractCodeWithInfo(blockConfig),\n rawStorageJson,\n ) as StringifiedJson<StorageDebugView>;\n return result;\n } catch (e) {\n this.logger.error(\n new Error(\"[ProjectHelper.getStorageDebugViewInVM] Get storage debug view failed\", {\n cause: e,\n }),\n );\n return undefined;\n }\n }\n\n // =============================================================================\n // Block State Migrations\n // =============================================================================\n\n /**\n * Runs block state migrations via VM-based transformation.\n * This calls the model's `__pl_storage_migrate` callback which:\n * - Normalizes current storage to get state and version\n * - Applies DataModel upgrade to reach target version key\n * - Runs all necessary migrations sequentially\n * - Returns new storage with updated state and version\n *\n * The middle layer doesn't need to know about dataVersion or storage internals.\n * All migration logic is encapsulated in the model.\n *\n * @param blockConfig The NEW block configuration (provides the model code with migrations)\n * @param currentStorageJson Current storage as JSON string (or undefined)\n * @returns MigrationResult with new storage or skip/error info\n */\n public migrateStorageInVM(\n blockConfig: BlockConfig,\n currentStorageJson: string | undefined,\n ): MigrationResult {\n if (blockConfig.modelAPIVersion !== BLOCK_STORAGE_FACADE_VERSION) {\n return { error: \"migrateStorageInVM is only supported for model API version 2\" };\n }\n\n try {\n const result = executeSingleLambda(\n this.quickJs,\n blockConfig.blockLifecycleCallbacks[BlockStorageFacadeCallbacks.StorageMigrate],\n extractCodeWithInfo(blockConfig),\n currentStorageJson,\n ) as MigrationResult;\n return result;\n } catch (e) {\n this.logger.error(\n new Error(\"[ProjectHelper.migrateStorageInVM] Migration failed\", { cause: e }),\n );\n return { error: `VM execution failed: ${e}` };\n }\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"project_helper.js","names":[],"sources":["../../src/model/project_helper.ts"],"sourcesContent":["import type { ResultOrError, BlockConfig, BlockStorage, PlRef } from \"@platforma-sdk/model\";\nimport type { StringifiedJson } from \"@milaboratories/pl-model-common\";\nimport {\n extractCodeWithInfo,\n ensureError,\n BlockStorageFacadeCallbacks,\n BLOCK_STORAGE_FACADE_VERSION,\n} from \"@platforma-sdk/model\";\nimport { LRUCache } from \"lru-cache\";\nimport type { QuickJSWASMModule } from \"quickjs-emscripten\";\nimport { executeSingleLambda } from \"../js_render\";\nimport type { SignedResourceId } from \"@milaboratories/pl-client\";\nimport { ConsoleLoggerAdapter, type MiLogger } from \"@milaboratories/ts-helpers\";\nimport type { StorageDebugView } from \"@milaboratories/pl-model-middle-layer\";\n\ntype EnrichmentTargetsRequest = {\n blockConfig: () => BlockConfig;\n args: () => unknown;\n};\n\ntype EnrichmentTargetsValue = {\n value: PlRef[] | undefined;\n};\n\n/**\n * Result of VM-based storage migration.\n * Returned by migrateStorageInVM().\n *\n * - Error result: { error: string } - serious failure (no context, etc.)\n * - Success result: { newStorageJson: StringifiedJson<BlockStorage>, info: string } - migration succeeded\n */\nexport type MigrationResult =\n | { error: string }\n | { error?: undefined; newStorageJson: StringifiedJson<BlockStorage>; info: string };\n\n/**\n * Result of args derivation from storage.\n * Returned by __pl_args_derive and __pl_prerunArgs_derive VM callbacks.\n */\ntype ArgsDeriveResult = { error: string } | { error?: undefined; value: unknown };\n\nexport class ProjectHelper {\n private readonly enrichmentTargetsCache = new LRUCache<\n string,\n EnrichmentTargetsValue,\n EnrichmentTargetsRequest\n >({\n max: 256,\n memoMethod: (_key, _value, { context }) => {\n return { value: this.calculateEnrichmentTargets(context) };\n },\n });\n\n constructor(\n private readonly quickJs: QuickJSWASMModule,\n public readonly logger: MiLogger = new ConsoleLoggerAdapter(),\n ) {}\n\n // =============================================================================\n // Args Derivation from Storage (V3+)\n // =============================================================================\n\n /**\n * Derives args directly from storage JSON using VM callback.\n * The VM extracts data from storage and calls the block's args() function.\n *\n * This allows the middle layer to work only with storage JSON,\n * without needing to know the underlying data structure.\n *\n * @param blockConfig The block configuration (provides the model code)\n * @param storageJson Storage as JSON string\n * @returns The derived args object, or error if derivation fails\n */\n public deriveArgsFromStorage(\n blockConfig: BlockConfig,\n storageJson: string,\n ): ResultOrError<unknown> {\n if (blockConfig.modelAPIVersion !== BLOCK_STORAGE_FACADE_VERSION) {\n return {\n error: new Error(\"deriveArgsFromStorage is only supported for model API version 2\"),\n };\n }\n\n try {\n const result = executeSingleLambda(\n this.quickJs,\n blockConfig.blockLifecycleCallbacks[BlockStorageFacadeCallbacks.ArgsDerive],\n extractCodeWithInfo(blockConfig),\n storageJson,\n ) as ArgsDeriveResult;\n\n if (result.error !== undefined) {\n return { error: new Error(result.error) };\n }\n return { value: result.value };\n } catch (e) {\n return { error: new Error(\"Args derivation from storage failed\", { cause: ensureError(e) }) };\n }\n }\n\n /**\n * Derives prerunArgs directly from storage JSON using VM callback.\n * Falls back to args() if prerunArgs is not defined in the block model.\n *\n * @param blockConfig The block configuration (provides the model code)\n * @param storageJson Storage as JSON string\n * @returns The derived prerunArgs, or undefined if derivation fails\n */\n public derivePrerunArgsFromStorage(blockConfig: BlockConfig, storageJson: string): unknown {\n if (blockConfig.modelAPIVersion !== BLOCK_STORAGE_FACADE_VERSION) {\n throw new Error(\"derivePrerunArgsFromStorage is only supported for model API version 2\");\n }\n\n try {\n const result = executeSingleLambda(\n this.quickJs,\n blockConfig.blockLifecycleCallbacks[BlockStorageFacadeCallbacks.PrerunArgsDerive],\n extractCodeWithInfo(blockConfig),\n storageJson,\n ) as ArgsDeriveResult;\n\n if (result.error !== undefined) {\n // Return undefined if derivation fails (skip block in staging)\n return undefined;\n }\n return result.value;\n } catch {\n // Return undefined if derivation fails (skip block in staging)\n return undefined;\n }\n }\n\n private calculateEnrichmentTargets(req: EnrichmentTargetsRequest): PlRef[] | undefined {\n const blockConfig = req.blockConfig();\n if (blockConfig.enrichmentTargets === undefined) return undefined;\n const args = req.args();\n const result = executeSingleLambda(\n this.quickJs,\n blockConfig.enrichmentTargets,\n extractCodeWithInfo(blockConfig),\n args,\n ) as PlRef[];\n return result;\n }\n\n public getEnrichmentTargets(\n blockConfig: () => BlockConfig,\n args: () => unknown,\n key?: { argsRid: SignedResourceId; blockPackRid: SignedResourceId },\n ): PlRef[] | undefined {\n const req = { blockConfig, args };\n if (key === undefined) return this.calculateEnrichmentTargets(req);\n const cacheKey = `${key.argsRid}:${key.blockPackRid}`;\n return this.enrichmentTargetsCache.memo(cacheKey, { context: req }).value;\n }\n\n // =============================================================================\n // VM-based Storage Operations\n // =============================================================================\n\n /**\n * Creates initial BlockStorage for a new block using VM-based transformation.\n * This calls the '__pl_storage_initial' callback registered by DataModel which:\n * - Gets initial data from DataModel.getDefaultData()\n * - Creates BlockStorage with correct version\n *\n * @param blockConfig The block configuration (provides the model code)\n * @returns Initial storage as JSON string\n * @throws Error if storage creation fails\n */\n public getInitialStorageInVM(blockConfig: BlockConfig): string {\n if (blockConfig.modelAPIVersion !== BLOCK_STORAGE_FACADE_VERSION) {\n throw new Error(\"getInitialStorageInVM is only supported for model API version 2\");\n }\n\n try {\n const result = executeSingleLambda(\n this.quickJs,\n blockConfig.blockLifecycleCallbacks[BlockStorageFacadeCallbacks.StorageInitial],\n extractCodeWithInfo(blockConfig),\n ) as string;\n return result;\n } catch (e) {\n this.logger.error(\n new Error(\"[ProjectHelper.getInitialStorageInVM] Initial storage creation failed\", {\n cause: e,\n }),\n );\n throw new Error(`Block initial storage creation failed: ${e}`);\n }\n }\n\n /**\n * Applies a state update using VM-based transformation.\n * This calls the model's `__pl_storage_applyUpdate` callback which:\n * - Normalizes current storage\n * - Updates state while preserving other fields (version, plugins)\n * - Returns the updated storage as JSON string\n *\n * @param blockConfig The block configuration (provides the model code)\n * @param currentStorageJson Current storage as JSON string (must be defined)\n * @param newState New state from developer\n * @returns Updated storage as JSON string\n * @throws Error if storage update fails\n */\n public applyStorageUpdateInVM(\n blockConfig: BlockConfig,\n currentStorageJson: string,\n payload: { operation: string; value: unknown },\n ): string {\n if (blockConfig.modelAPIVersion !== BLOCK_STORAGE_FACADE_VERSION) {\n throw new Error(\"applyStorageUpdateInVM is only supported for model API version 2\");\n }\n\n try {\n const result = executeSingleLambda(\n this.quickJs,\n blockConfig.blockLifecycleCallbacks[BlockStorageFacadeCallbacks.StorageApplyUpdate],\n extractCodeWithInfo(blockConfig),\n currentStorageJson,\n payload,\n ) as string;\n return result;\n } catch (e) {\n this.logger.error(\n new Error(\"[ProjectHelper.applyStorageUpdateInVM] Storage update failed\", { cause: e }),\n );\n throw new Error(`Block storage update failed: ${e}`);\n }\n }\n\n /**\n * Gets storage debug view from raw storage data by calling the VM's __pl_storage_debugView callback.\n * Returns structured debug info about the storage (e.g., dataVersion).\n *\n * @param blockConfig Block configuration\n * @param rawStorageJson Raw storage as JSON string (or undefined)\n * @returns Storage debug view as JSON string (e.g., '{\"dataVersion\": \"v1\"}')\n */\n public getStorageDebugViewInVM(\n blockConfig: BlockConfig,\n rawStorageJson: string | undefined,\n ): StringifiedJson<StorageDebugView> | undefined {\n if (blockConfig.modelAPIVersion !== BLOCK_STORAGE_FACADE_VERSION) {\n throw new Error(\"getStorageDebugViewInVM is only supported for model API version 2\");\n }\n\n try {\n const result = executeSingleLambda(\n this.quickJs,\n blockConfig.blockLifecycleCallbacks[BlockStorageFacadeCallbacks.StorageDebugView],\n extractCodeWithInfo(blockConfig),\n rawStorageJson,\n ) as StringifiedJson<StorageDebugView>;\n return result;\n } catch (e) {\n this.logger.error(\n new Error(\"[ProjectHelper.getStorageDebugViewInVM] Get storage debug view failed\", {\n cause: e,\n }),\n );\n return undefined;\n }\n }\n\n // =============================================================================\n // Block State Migrations\n // =============================================================================\n\n /**\n * Runs block state migrations via VM-based transformation.\n * This calls the model's `__pl_storage_migrate` callback which:\n * - Normalizes current storage to get state and version\n * - Applies DataModel upgrade to reach target version key\n * - Runs all necessary migrations sequentially\n * - Returns new storage with updated state and version\n *\n * The middle layer doesn't need to know about dataVersion or storage internals.\n * All migration logic is encapsulated in the model.\n *\n * @param blockConfig The NEW block configuration (provides the model code with migrations)\n * @param currentStorageJson Current storage as JSON string (or undefined)\n * @returns MigrationResult with new storage or skip/error info\n */\n public migrateStorageInVM(\n blockConfig: BlockConfig,\n currentStorageJson: string | undefined,\n ): MigrationResult {\n if (blockConfig.modelAPIVersion !== BLOCK_STORAGE_FACADE_VERSION) {\n return { error: \"migrateStorageInVM is only supported for model API version 2\" };\n }\n\n try {\n const result = executeSingleLambda(\n this.quickJs,\n blockConfig.blockLifecycleCallbacks[BlockStorageFacadeCallbacks.StorageMigrate],\n extractCodeWithInfo(blockConfig),\n currentStorageJson,\n ) as MigrationResult;\n return result;\n } catch (e) {\n this.logger.error(\n new Error(\"[ProjectHelper.migrateStorageInVM] Migration failed\", { cause: e }),\n );\n return { error: `VM execution failed: ${e}` };\n }\n }\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"project_model.cjs","names":[],"sources":["../../src/model/project_model.ts"],"sourcesContent":["import type { ResourceId, ResourceType } from \"@milaboratories/pl-client\";\nimport type {\n ProjectListEntry as ProjectListEntryFromModel,\n ProjectMeta,\n} from \"@milaboratories/pl-model-middle-layer\";\nimport type { BlockRenderingMode } from \"@platforma-sdk/model\";\n\nexport interface ProjectListEntry extends ProjectListEntryFromModel {\n /** Project resource ID. */\n rid: ResourceId;\n}\n\n/** Entry representing a single block in block structure */\nexport interface Block {\n /** Unique block id */\n readonly id: string;\n\n /**\n * Label shown to the user\n * @deprecated\n * */\n label: string;\n\n /** How to approach block rendering */\n renderingMode: BlockRenderingMode;\n}\n\n/** Block group in block structure */\nexport interface BlockGroup {\n /** Unique group id */\n readonly id: string;\n\n /** Label shown to the user */\n label: string;\n\n /** Blocks */\n blocks: Block[];\n}\n\n/** Root of block structure value */\nexport interface ProjectStructure {\n /** The structure */\n readonly groups: BlockGroup[];\n}\n\nexport const InitialBlockStructure: ProjectStructure = {\n groups: [{ id: \"default\", label: \"Default\", blocks: [] }],\n};\n\n/** Root of project rendering state */\nexport interface ProjectRenderingState {\n /** Timestamp of last staging rendering event */\n stagingRefreshTimestamp: number;\n\n /** Blocks with detached production state, i.e. some of the dependencies of\n * such blocks were re-rendered, but their state was left \"as is\". */\n blocksInLimbo: string[];\n}\n\nexport const InitialProjectRenderingState: ProjectRenderingState = {\n stagingRefreshTimestamp: 0,\n blocksInLimbo: [],\n};\n\nexport const InitialBlockMeta: ProjectMeta = {\n label: \"New Project\",\n};\n\n//\n// Pl Model\n//\n\nexport const ProjectResourceType: ResourceType = { name: \"UserProject\", version: \"2\" };\n\nexport const SchemaVersionKey = \"SchemaVersion\";\nexport const SchemaVersionV2 = \"2\";\nexport const SchemaVersionV3 = \"3\";\nexport const SchemaVersionCurrent = \"4\";\n\nexport const ProjectCreatedTimestamp = \"ProjectCreated\";\nexport const ProjectLastModifiedTimestamp = \"ProjectLastModified\";\nexport const ProjectMetaKey = \"ProjectMeta\";\nexport const ProjectStructureKey = \"ProjectStructure\";\nexport const BlockRenderingStateKey = \"BlockRenderingState\";\n\nexport const BlockArgsAuthorKeyPrefix = \"BlockArgsAuthor/\";\nexport const BlockArgsAuthorKeyPattern = /^BlockArgsAuthor\\/(?<blockid>.*)$/;\n\nexport function blockArgsAuthorKey(blockId: string): string {\n return `${BlockArgsAuthorKeyPrefix}${blockId}`;\n}\n\nexport const ProjectStructureAuthorKey = \"ProjectStructureAuthor\";\n\nexport const ServiceTemplateCacheFieldPrefix = \"__serviceTemplate_\";\n\nexport function getServiceTemplateField(hash: string): string {\n return `${ServiceTemplateCacheFieldPrefix}${hash}`;\n}\n\nexport interface ProjectField {\n blockId: string;\n fieldName:\n | \"blockPack\"\n | \"blockSettings\"\n | \"blockStorage\" // Persistent storage for v3 blocks (state, plugins data, etc.)\n | \"prodArgs\"\n | \"currentArgs\"\n | \"currentPrerunArgs\" // Derived args for staging/prerun rendering (from prerunArgs() or args())\n | \"prodChainCtx\" // Pre-built production context chain node (accumulated prodCtx from all blocks above)\n | \"prodCtx\"\n | \"prodUiCtx\"\n | \"prodOutput\"\n | \"prodCtxPrevious\"\n | \"prodUiCtxPrevious\"\n | \"prodOutputPrevious\"\n | \"stagingCtx\"\n | \"stagingUiCtx\"\n | \"stagingOutput\"\n | \"stagingCtxPrevious\"\n | \"stagingUiCtxPrevious\"\n | \"stagingOutputPrevious\";\n}\n\nexport const FieldsToDuplicate: Set<ProjectField[\"fieldName\"]> = new Set([\n \"blockPack\",\n \"blockSettings\",\n \"blockStorage\",\n \"prodArgs\",\n \"currentArgs\",\n \"currentPrerunArgs\",\n \"prodCtx\",\n \"prodUiCtx\",\n \"prodOutput\",\n]);\n\nexport function projectFieldName(blockId: string, fieldName: ProjectField[\"fieldName\"]): string {\n return `${blockId}-${fieldName}`;\n}\n\nconst projectFieldPattern =\n /^(?<blockId>.*)-(?<fieldName>blockPack|blockSettings|blockStorage|inputsValid|prodArgs|currentArgs|currentPrerunArgs|prodChainCtx|prodCtx|prodUiCtx|prodOutput|prodCtxPrevious|prodUiCtxPrevious|prodOutputPrevious|stagingCtx|stagingUiCtx|stagingOutput|stagingCtxPrevious|stagingUiCtxPrevious|stagingOutputPrevious)$/;\n\nexport function parseProjectField(name: string): ProjectField | undefined {\n const match = name.match(projectFieldPattern);\n if (match === null) return undefined;\n const { blockId, fieldName } = match.groups!;\n return { blockId, fieldName } as ProjectField;\n}\n"],"mappings":";AA6CA,MAAa,wBAA0C,EACrD,QAAQ,CAAC;CAAE,IAAI;CAAW,OAAO;CAAW,QAAQ,EAAE;CAAE,CAAC,EAC1D;AAYD,MAAa,+BAAsD;CACjE,yBAAyB;CACzB,eAAe,EAAE;CAClB;AAED,MAAa,mBAAgC,EAC3C,OAAO,eACR;AAMD,MAAa,sBAAoC;CAAE,MAAM;CAAe,SAAS;CAAK;AAEtF,MAAa,mBAAmB;AAGhC,MAAa,uBAAuB;AAEpC,MAAa,0BAA0B;AACvC,MAAa,+BAA+B;AAC5C,MAAa,iBAAiB;AAC9B,MAAa,sBAAsB;AACnC,MAAa,yBAAyB;AAEtC,MAAa,2BAA2B;AAGxC,SAAgB,mBAAmB,SAAyB;AAC1D,QAAO,GAAG,2BAA2B;;AAGvC,MAAa,4BAA4B;AAEzC,MAAa,kCAAkC;AAE/C,SAAgB,wBAAwB,MAAsB;AAC5D,QAAO,GAAG,kCAAkC;;AA2B9C,MAAa,oBAAoD,IAAI,IAAI;CACvE;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACD,CAAC;AAEF,SAAgB,iBAAiB,SAAiB,WAA8C;AAC9F,QAAO,GAAG,QAAQ,GAAG;;AAGvB,MAAM,sBACJ;AAEF,SAAgB,kBAAkB,MAAwC;CACxE,MAAM,QAAQ,KAAK,MAAM,oBAAoB;AAC7C,KAAI,UAAU,KAAM,QAAO,KAAA;CAC3B,MAAM,EAAE,SAAS,cAAc,MAAM;AACrC,QAAO;EAAE;EAAS;EAAW"}
1
+ {"version":3,"file":"project_model.cjs","names":[],"sources":["../../src/model/project_model.ts"],"sourcesContent":["import type { ResourceType } from \"@milaboratories/pl-client\";\nimport type { ProjectId } from \"@milaboratories/pl-model-common\";\nimport type {\n ProjectListEntry as ProjectListEntryFromModel,\n ProjectMeta,\n} from \"@milaboratories/pl-model-middle-layer\";\nimport type { BlockRenderingMode } from \"@platforma-sdk/model\";\n\nexport type { ProjectId };\n\nexport interface ProjectListEntry extends Omit<ProjectListEntryFromModel, \"id\"> {\n /** Unique project identifier in middle layer. Use to operate with given project. */\n id: ProjectId;\n}\n\n/** Entry representing a single block in block structure */\nexport interface Block {\n /** Unique block id */\n readonly id: string;\n\n /**\n * Label shown to the user\n * @deprecated\n * */\n label: string;\n\n /** How to approach block rendering */\n renderingMode: BlockRenderingMode;\n}\n\n/** Block group in block structure */\nexport interface BlockGroup {\n /** Unique group id */\n readonly id: string;\n\n /** Label shown to the user */\n label: string;\n\n /** Blocks */\n blocks: Block[];\n}\n\n/** Root of block structure value */\nexport interface ProjectStructure {\n /** The structure */\n readonly groups: BlockGroup[];\n}\n\nexport const InitialBlockStructure: ProjectStructure = {\n groups: [{ id: \"default\", label: \"Default\", blocks: [] }],\n};\n\n/** Root of project rendering state */\nexport interface ProjectRenderingState {\n /** Timestamp of last staging rendering event */\n stagingRefreshTimestamp: number;\n\n /** Blocks with detached production state, i.e. some of the dependencies of\n * such blocks were re-rendered, but their state was left \"as is\". */\n blocksInLimbo: string[];\n}\n\nexport const InitialProjectRenderingState: ProjectRenderingState = {\n stagingRefreshTimestamp: 0,\n blocksInLimbo: [],\n};\n\nexport const InitialBlockMeta: ProjectMeta = {\n label: \"New Project\",\n};\n\n//\n// Pl Model\n//\n\nexport const ProjectResourceType: ResourceType = { name: \"UserProject\", version: \"2\" };\n\nexport const SchemaVersionKey = \"SchemaVersion\";\nexport const SchemaVersionV2 = \"2\";\nexport const SchemaVersionV3 = \"3\";\nexport const SchemaVersionCurrent = \"4\";\n\nexport const ProjectCreatedTimestamp = \"ProjectCreated\";\nexport const ProjectLastModifiedTimestamp = \"ProjectLastModified\";\nexport const ProjectMetaKey = \"ProjectMeta\";\nexport const ProjectStructureKey = \"ProjectStructure\";\nexport const BlockRenderingStateKey = \"BlockRenderingState\";\n\nexport const BlockArgsAuthorKeyPrefix = \"BlockArgsAuthor/\";\nexport const BlockArgsAuthorKeyPattern = /^BlockArgsAuthor\\/(?<blockid>.*)$/;\n\nexport function blockArgsAuthorKey(blockId: string): string {\n return `${BlockArgsAuthorKeyPrefix}${blockId}`;\n}\n\nexport const ProjectStructureAuthorKey = \"ProjectStructureAuthor\";\n\nexport const ServiceTemplateCacheFieldPrefix = \"__serviceTemplate_\";\n\nexport function getServiceTemplateField(hash: string): string {\n return `${ServiceTemplateCacheFieldPrefix}${hash}`;\n}\n\nexport interface ProjectField {\n blockId: string;\n fieldName:\n | \"blockPack\"\n | \"blockSettings\"\n | \"blockStorage\" // Persistent storage for v3 blocks (state, plugins data, etc.)\n | \"prodArgs\"\n | \"currentArgs\"\n | \"currentPrerunArgs\" // Derived args for staging/prerun rendering (from prerunArgs() or args())\n | \"prodChainCtx\" // Pre-built production context chain node (accumulated prodCtx from all blocks above)\n | \"prodCtx\"\n | \"prodUiCtx\"\n | \"prodOutput\"\n | \"prodCtxPrevious\"\n | \"prodUiCtxPrevious\"\n | \"prodOutputPrevious\"\n | \"stagingCtx\"\n | \"stagingUiCtx\"\n | \"stagingOutput\"\n | \"stagingCtxPrevious\"\n | \"stagingUiCtxPrevious\"\n | \"stagingOutputPrevious\";\n}\n\nexport const FieldsToDuplicate: Set<ProjectField[\"fieldName\"]> = new Set([\n \"blockPack\",\n \"blockSettings\",\n \"blockStorage\",\n \"prodArgs\",\n \"currentArgs\",\n \"currentPrerunArgs\",\n \"prodCtx\",\n \"prodUiCtx\",\n \"prodOutput\",\n]);\n\nexport function projectFieldName(blockId: string, fieldName: ProjectField[\"fieldName\"]): string {\n return `${blockId}-${fieldName}`;\n}\n\nconst projectFieldPattern =\n /^(?<blockId>.*)-(?<fieldName>blockPack|blockSettings|blockStorage|inputsValid|prodArgs|currentArgs|currentPrerunArgs|prodChainCtx|prodCtx|prodUiCtx|prodOutput|prodCtxPrevious|prodUiCtxPrevious|prodOutputPrevious|stagingCtx|stagingUiCtx|stagingOutput|stagingCtxPrevious|stagingUiCtxPrevious|stagingOutputPrevious)$/;\n\nexport function parseProjectField(name: string): ProjectField | undefined {\n const match = name.match(projectFieldPattern);\n if (match === null) return undefined;\n const { blockId, fieldName } = match.groups!;\n return { blockId, fieldName } as ProjectField;\n}\n"],"mappings":";AAgDA,MAAa,wBAA0C,EACrD,QAAQ,CAAC;CAAE,IAAI;CAAW,OAAO;CAAW,QAAQ,EAAE;CAAE,CAAC,EAC1D;AAYD,MAAa,+BAAsD;CACjE,yBAAyB;CACzB,eAAe,EAAE;CAClB;AAED,MAAa,mBAAgC,EAC3C,OAAO,eACR;AAMD,MAAa,sBAAoC;CAAE,MAAM;CAAe,SAAS;CAAK;AAEtF,MAAa,mBAAmB;AAGhC,MAAa,uBAAuB;AAEpC,MAAa,0BAA0B;AACvC,MAAa,+BAA+B;AAC5C,MAAa,iBAAiB;AAC9B,MAAa,sBAAsB;AACnC,MAAa,yBAAyB;AAEtC,MAAa,2BAA2B;AAGxC,SAAgB,mBAAmB,SAAyB;AAC1D,QAAO,GAAG,2BAA2B;;AAGvC,MAAa,4BAA4B;AAEzC,MAAa,kCAAkC;AAE/C,SAAgB,wBAAwB,MAAsB;AAC5D,QAAO,GAAG,kCAAkC;;AA2B9C,MAAa,oBAAoD,IAAI,IAAI;CACvE;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACD,CAAC;AAEF,SAAgB,iBAAiB,SAAiB,WAA8C;AAC9F,QAAO,GAAG,QAAQ,GAAG;;AAGvB,MAAM,sBACJ;AAEF,SAAgB,kBAAkB,MAAwC;CACxE,MAAM,QAAQ,KAAK,MAAM,oBAAoB;AAC7C,KAAI,UAAU,KAAM,QAAO,KAAA;CAC3B,MAAM,EAAE,SAAS,cAAc,MAAM;AACrC,QAAO;EAAE;EAAS;EAAW"}
@@ -1,10 +1,11 @@
1
1
  import { ProjectListEntry, ProjectMeta } from "@milaboratories/pl-model-middle-layer";
2
- import { ResourceId, ResourceType } from "@milaboratories/pl-client";
2
+ import { ResourceType } from "@milaboratories/pl-client";
3
+ import { ProjectId } from "@milaboratories/pl-model-common";
3
4
 
4
5
  //#region src/model/project_model.d.ts
5
- interface ProjectListEntry$1 extends ProjectListEntry {
6
- /** Project resource ID. */
7
- rid: ResourceId;
6
+ interface ProjectListEntry$1 extends Omit<ProjectListEntry, "id"> {
7
+ /** Unique project identifier in middle layer. Use to operate with given project. */
8
+ id: ProjectId;
8
9
  }
9
10
  declare const ProjectResourceType: ResourceType;
10
11
  declare const SchemaVersionKey = "SchemaVersion";
@@ -20,5 +21,5 @@ interface ProjectField {
20
21
  fieldName: "blockPack" | "blockSettings" | "blockStorage" | "prodArgs" | "currentArgs" | "currentPrerunArgs" | "prodChainCtx" | "prodCtx" | "prodUiCtx" | "prodOutput" | "prodCtxPrevious" | "prodUiCtxPrevious" | "prodOutputPrevious" | "stagingCtx" | "stagingUiCtx" | "stagingOutput" | "stagingCtxPrevious" | "stagingUiCtxPrevious" | "stagingOutputPrevious";
21
22
  }
22
23
  //#endregion
23
- export { BlockArgsAuthorKeyPrefix, ProjectCreatedTimestamp, ProjectField, ProjectLastModifiedTimestamp, ProjectListEntry$1 as ProjectListEntry, ProjectMetaKey, ProjectResourceType, ProjectStructureAuthorKey, ProjectStructureKey, SchemaVersionCurrent, SchemaVersionKey };
24
+ export { BlockArgsAuthorKeyPrefix, ProjectCreatedTimestamp, ProjectField, type ProjectId, ProjectLastModifiedTimestamp, ProjectListEntry$1 as ProjectListEntry, ProjectMetaKey, ProjectResourceType, ProjectStructureAuthorKey, ProjectStructureKey, SchemaVersionCurrent, SchemaVersionKey };
24
25
  //# sourceMappingURL=project_model.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"project_model.d.ts","names":[],"sources":["../../src/model/project_model.ts"],"mappings":";;;;UAOiB,kBAAA,SAAyB,gBAAA;;EAExC,GAAA,EAAK,UAAA;AAAA;AAAA,cA+DM,mBAAA,EAAqB,YAAA;AAAA,cAErB,gBAAA;AAAA,cAGA,oBAAA;AAAA,cAEA,uBAAA;AAAA,cACA,4BAAA;AAAA,cACA,cAAA;AAAA,cACA,mBAAA;AAAA,cAGA,wBAAA;AAAA,cAOA,yBAAA;AAAA,UAQI,YAAA;EACf,OAAA;EACA,SAAA;AAAA"}
1
+ {"version":3,"file":"project_model.d.ts","names":[],"sources":["../../src/model/project_model.ts"],"mappings":";;;;;UAUiB,kBAAA,SAAyB,IAAA,CAAK,gBAAA;EAA9B;EAEf,EAAA,EAAI,SAAA;AAAA;AAAA,cA+DO,mBAAA,EAAqB,YAAA;AAAA,cAErB,gBAAA;AAAA,cAGA,oBAAA;AAAA,cAEA,uBAAA;AAAA,cACA,4BAAA;AAAA,cACA,cAAA;AAAA,cACA,mBAAA;AAAA,cAGA,wBAAA;AAAA,cAOA,yBAAA;AAAA,UAQI,YAAA;EACf,OAAA;EACA,SAAA;AAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"project_model.js","names":[],"sources":["../../src/model/project_model.ts"],"sourcesContent":["import type { ResourceId, ResourceType } from \"@milaboratories/pl-client\";\nimport type {\n ProjectListEntry as ProjectListEntryFromModel,\n ProjectMeta,\n} from \"@milaboratories/pl-model-middle-layer\";\nimport type { BlockRenderingMode } from \"@platforma-sdk/model\";\n\nexport interface ProjectListEntry extends ProjectListEntryFromModel {\n /** Project resource ID. */\n rid: ResourceId;\n}\n\n/** Entry representing a single block in block structure */\nexport interface Block {\n /** Unique block id */\n readonly id: string;\n\n /**\n * Label shown to the user\n * @deprecated\n * */\n label: string;\n\n /** How to approach block rendering */\n renderingMode: BlockRenderingMode;\n}\n\n/** Block group in block structure */\nexport interface BlockGroup {\n /** Unique group id */\n readonly id: string;\n\n /** Label shown to the user */\n label: string;\n\n /** Blocks */\n blocks: Block[];\n}\n\n/** Root of block structure value */\nexport interface ProjectStructure {\n /** The structure */\n readonly groups: BlockGroup[];\n}\n\nexport const InitialBlockStructure: ProjectStructure = {\n groups: [{ id: \"default\", label: \"Default\", blocks: [] }],\n};\n\n/** Root of project rendering state */\nexport interface ProjectRenderingState {\n /** Timestamp of last staging rendering event */\n stagingRefreshTimestamp: number;\n\n /** Blocks with detached production state, i.e. some of the dependencies of\n * such blocks were re-rendered, but their state was left \"as is\". */\n blocksInLimbo: string[];\n}\n\nexport const InitialProjectRenderingState: ProjectRenderingState = {\n stagingRefreshTimestamp: 0,\n blocksInLimbo: [],\n};\n\nexport const InitialBlockMeta: ProjectMeta = {\n label: \"New Project\",\n};\n\n//\n// Pl Model\n//\n\nexport const ProjectResourceType: ResourceType = { name: \"UserProject\", version: \"2\" };\n\nexport const SchemaVersionKey = \"SchemaVersion\";\nexport const SchemaVersionV2 = \"2\";\nexport const SchemaVersionV3 = \"3\";\nexport const SchemaVersionCurrent = \"4\";\n\nexport const ProjectCreatedTimestamp = \"ProjectCreated\";\nexport const ProjectLastModifiedTimestamp = \"ProjectLastModified\";\nexport const ProjectMetaKey = \"ProjectMeta\";\nexport const ProjectStructureKey = \"ProjectStructure\";\nexport const BlockRenderingStateKey = \"BlockRenderingState\";\n\nexport const BlockArgsAuthorKeyPrefix = \"BlockArgsAuthor/\";\nexport const BlockArgsAuthorKeyPattern = /^BlockArgsAuthor\\/(?<blockid>.*)$/;\n\nexport function blockArgsAuthorKey(blockId: string): string {\n return `${BlockArgsAuthorKeyPrefix}${blockId}`;\n}\n\nexport const ProjectStructureAuthorKey = \"ProjectStructureAuthor\";\n\nexport const ServiceTemplateCacheFieldPrefix = \"__serviceTemplate_\";\n\nexport function getServiceTemplateField(hash: string): string {\n return `${ServiceTemplateCacheFieldPrefix}${hash}`;\n}\n\nexport interface ProjectField {\n blockId: string;\n fieldName:\n | \"blockPack\"\n | \"blockSettings\"\n | \"blockStorage\" // Persistent storage for v3 blocks (state, plugins data, etc.)\n | \"prodArgs\"\n | \"currentArgs\"\n | \"currentPrerunArgs\" // Derived args for staging/prerun rendering (from prerunArgs() or args())\n | \"prodChainCtx\" // Pre-built production context chain node (accumulated prodCtx from all blocks above)\n | \"prodCtx\"\n | \"prodUiCtx\"\n | \"prodOutput\"\n | \"prodCtxPrevious\"\n | \"prodUiCtxPrevious\"\n | \"prodOutputPrevious\"\n | \"stagingCtx\"\n | \"stagingUiCtx\"\n | \"stagingOutput\"\n | \"stagingCtxPrevious\"\n | \"stagingUiCtxPrevious\"\n | \"stagingOutputPrevious\";\n}\n\nexport const FieldsToDuplicate: Set<ProjectField[\"fieldName\"]> = new Set([\n \"blockPack\",\n \"blockSettings\",\n \"blockStorage\",\n \"prodArgs\",\n \"currentArgs\",\n \"currentPrerunArgs\",\n \"prodCtx\",\n \"prodUiCtx\",\n \"prodOutput\",\n]);\n\nexport function projectFieldName(blockId: string, fieldName: ProjectField[\"fieldName\"]): string {\n return `${blockId}-${fieldName}`;\n}\n\nconst projectFieldPattern =\n /^(?<blockId>.*)-(?<fieldName>blockPack|blockSettings|blockStorage|inputsValid|prodArgs|currentArgs|currentPrerunArgs|prodChainCtx|prodCtx|prodUiCtx|prodOutput|prodCtxPrevious|prodUiCtxPrevious|prodOutputPrevious|stagingCtx|stagingUiCtx|stagingOutput|stagingCtxPrevious|stagingUiCtxPrevious|stagingOutputPrevious)$/;\n\nexport function parseProjectField(name: string): ProjectField | undefined {\n const match = name.match(projectFieldPattern);\n if (match === null) return undefined;\n const { blockId, fieldName } = match.groups!;\n return { blockId, fieldName } as ProjectField;\n}\n"],"mappings":";AA6CA,MAAa,wBAA0C,EACrD,QAAQ,CAAC;CAAE,IAAI;CAAW,OAAO;CAAW,QAAQ,EAAE;CAAE,CAAC,EAC1D;AAYD,MAAa,+BAAsD;CACjE,yBAAyB;CACzB,eAAe,EAAE;CAClB;AAED,MAAa,mBAAgC,EAC3C,OAAO,eACR;AAMD,MAAa,sBAAoC;CAAE,MAAM;CAAe,SAAS;CAAK;AAEtF,MAAa,mBAAmB;AAGhC,MAAa,uBAAuB;AAEpC,MAAa,0BAA0B;AACvC,MAAa,+BAA+B;AAC5C,MAAa,iBAAiB;AAC9B,MAAa,sBAAsB;AACnC,MAAa,yBAAyB;AAEtC,MAAa,2BAA2B;AAGxC,SAAgB,mBAAmB,SAAyB;AAC1D,QAAO,GAAG,2BAA2B;;AAGvC,MAAa,4BAA4B;AAEzC,MAAa,kCAAkC;AAE/C,SAAgB,wBAAwB,MAAsB;AAC5D,QAAO,GAAG,kCAAkC;;AA2B9C,MAAa,oBAAoD,IAAI,IAAI;CACvE;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACD,CAAC;AAEF,SAAgB,iBAAiB,SAAiB,WAA8C;AAC9F,QAAO,GAAG,QAAQ,GAAG;;AAGvB,MAAM,sBACJ;AAEF,SAAgB,kBAAkB,MAAwC;CACxE,MAAM,QAAQ,KAAK,MAAM,oBAAoB;AAC7C,KAAI,UAAU,KAAM,QAAO,KAAA;CAC3B,MAAM,EAAE,SAAS,cAAc,MAAM;AACrC,QAAO;EAAE;EAAS;EAAW"}
1
+ {"version":3,"file":"project_model.js","names":[],"sources":["../../src/model/project_model.ts"],"sourcesContent":["import type { ResourceType } from \"@milaboratories/pl-client\";\nimport type { ProjectId } from \"@milaboratories/pl-model-common\";\nimport type {\n ProjectListEntry as ProjectListEntryFromModel,\n ProjectMeta,\n} from \"@milaboratories/pl-model-middle-layer\";\nimport type { BlockRenderingMode } from \"@platforma-sdk/model\";\n\nexport type { ProjectId };\n\nexport interface ProjectListEntry extends Omit<ProjectListEntryFromModel, \"id\"> {\n /** Unique project identifier in middle layer. Use to operate with given project. */\n id: ProjectId;\n}\n\n/** Entry representing a single block in block structure */\nexport interface Block {\n /** Unique block id */\n readonly id: string;\n\n /**\n * Label shown to the user\n * @deprecated\n * */\n label: string;\n\n /** How to approach block rendering */\n renderingMode: BlockRenderingMode;\n}\n\n/** Block group in block structure */\nexport interface BlockGroup {\n /** Unique group id */\n readonly id: string;\n\n /** Label shown to the user */\n label: string;\n\n /** Blocks */\n blocks: Block[];\n}\n\n/** Root of block structure value */\nexport interface ProjectStructure {\n /** The structure */\n readonly groups: BlockGroup[];\n}\n\nexport const InitialBlockStructure: ProjectStructure = {\n groups: [{ id: \"default\", label: \"Default\", blocks: [] }],\n};\n\n/** Root of project rendering state */\nexport interface ProjectRenderingState {\n /** Timestamp of last staging rendering event */\n stagingRefreshTimestamp: number;\n\n /** Blocks with detached production state, i.e. some of the dependencies of\n * such blocks were re-rendered, but their state was left \"as is\". */\n blocksInLimbo: string[];\n}\n\nexport const InitialProjectRenderingState: ProjectRenderingState = {\n stagingRefreshTimestamp: 0,\n blocksInLimbo: [],\n};\n\nexport const InitialBlockMeta: ProjectMeta = {\n label: \"New Project\",\n};\n\n//\n// Pl Model\n//\n\nexport const ProjectResourceType: ResourceType = { name: \"UserProject\", version: \"2\" };\n\nexport const SchemaVersionKey = \"SchemaVersion\";\nexport const SchemaVersionV2 = \"2\";\nexport const SchemaVersionV3 = \"3\";\nexport const SchemaVersionCurrent = \"4\";\n\nexport const ProjectCreatedTimestamp = \"ProjectCreated\";\nexport const ProjectLastModifiedTimestamp = \"ProjectLastModified\";\nexport const ProjectMetaKey = \"ProjectMeta\";\nexport const ProjectStructureKey = \"ProjectStructure\";\nexport const BlockRenderingStateKey = \"BlockRenderingState\";\n\nexport const BlockArgsAuthorKeyPrefix = \"BlockArgsAuthor/\";\nexport const BlockArgsAuthorKeyPattern = /^BlockArgsAuthor\\/(?<blockid>.*)$/;\n\nexport function blockArgsAuthorKey(blockId: string): string {\n return `${BlockArgsAuthorKeyPrefix}${blockId}`;\n}\n\nexport const ProjectStructureAuthorKey = \"ProjectStructureAuthor\";\n\nexport const ServiceTemplateCacheFieldPrefix = \"__serviceTemplate_\";\n\nexport function getServiceTemplateField(hash: string): string {\n return `${ServiceTemplateCacheFieldPrefix}${hash}`;\n}\n\nexport interface ProjectField {\n blockId: string;\n fieldName:\n | \"blockPack\"\n | \"blockSettings\"\n | \"blockStorage\" // Persistent storage for v3 blocks (state, plugins data, etc.)\n | \"prodArgs\"\n | \"currentArgs\"\n | \"currentPrerunArgs\" // Derived args for staging/prerun rendering (from prerunArgs() or args())\n | \"prodChainCtx\" // Pre-built production context chain node (accumulated prodCtx from all blocks above)\n | \"prodCtx\"\n | \"prodUiCtx\"\n | \"prodOutput\"\n | \"prodCtxPrevious\"\n | \"prodUiCtxPrevious\"\n | \"prodOutputPrevious\"\n | \"stagingCtx\"\n | \"stagingUiCtx\"\n | \"stagingOutput\"\n | \"stagingCtxPrevious\"\n | \"stagingUiCtxPrevious\"\n | \"stagingOutputPrevious\";\n}\n\nexport const FieldsToDuplicate: Set<ProjectField[\"fieldName\"]> = new Set([\n \"blockPack\",\n \"blockSettings\",\n \"blockStorage\",\n \"prodArgs\",\n \"currentArgs\",\n \"currentPrerunArgs\",\n \"prodCtx\",\n \"prodUiCtx\",\n \"prodOutput\",\n]);\n\nexport function projectFieldName(blockId: string, fieldName: ProjectField[\"fieldName\"]): string {\n return `${blockId}-${fieldName}`;\n}\n\nconst projectFieldPattern =\n /^(?<blockId>.*)-(?<fieldName>blockPack|blockSettings|blockStorage|inputsValid|prodArgs|currentArgs|currentPrerunArgs|prodChainCtx|prodCtx|prodUiCtx|prodOutput|prodCtxPrevious|prodUiCtxPrevious|prodOutputPrevious|stagingCtx|stagingUiCtx|stagingOutput|stagingCtxPrevious|stagingUiCtxPrevious|stagingOutputPrevious)$/;\n\nexport function parseProjectField(name: string): ProjectField | undefined {\n const match = name.match(projectFieldPattern);\n if (match === null) return undefined;\n const { blockId, fieldName } = match.groups!;\n return { blockId, fieldName } as ProjectField;\n}\n"],"mappings":";AAgDA,MAAa,wBAA0C,EACrD,QAAQ,CAAC;CAAE,IAAI;CAAW,OAAO;CAAW,QAAQ,EAAE;CAAE,CAAC,EAC1D;AAYD,MAAa,+BAAsD;CACjE,yBAAyB;CACzB,eAAe,EAAE;CAClB;AAED,MAAa,mBAAgC,EAC3C,OAAO,eACR;AAMD,MAAa,sBAAoC;CAAE,MAAM;CAAe,SAAS;CAAK;AAEtF,MAAa,mBAAmB;AAGhC,MAAa,uBAAuB;AAEpC,MAAa,0BAA0B;AACvC,MAAa,+BAA+B;AAC5C,MAAa,iBAAiB;AAC9B,MAAa,sBAAsB;AACnC,MAAa,yBAAyB;AAEtC,MAAa,2BAA2B;AAGxC,SAAgB,mBAAmB,SAAyB;AAC1D,QAAO,GAAG,2BAA2B;;AAGvC,MAAa,4BAA4B;AAEzC,MAAa,kCAAkC;AAE/C,SAAgB,wBAAwB,MAAsB;AAC5D,QAAO,GAAG,kCAAkC;;AA2B9C,MAAa,oBAAoD,IAAI,IAAI;CACvE;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACD,CAAC;AAEF,SAAgB,iBAAiB,SAAiB,WAA8C;AAC9F,QAAO,GAAG,QAAQ,GAAG;;AAGvB,MAAM,sBACJ;AAEF,SAAgB,kBAAkB,MAAwC;CACxE,MAAM,QAAQ,KAAK,MAAM,oBAAoB;AAC7C,KAAI,UAAU,KAAM,QAAO,KAAA;CAC3B,MAAM,EAAE,SAAS,cAAc,MAAM;AACrC,QAAO;EAAE;EAAS;EAAW"}
@@ -1,4 +1,4 @@
1
- import { ResourceId } from "@milaboratories/pl-client";
1
+ import { SignedResourceId } from "@milaboratories/pl-client";
2
2
  import { CompiledTemplateV3, TemplateData } from "@milaboratories/pl-model-backend";
3
3
 
4
4
  //#region src/model/template_spec.d.ts
@@ -17,7 +17,7 @@ interface PreparedTemplate {
17
17
  }
18
18
  interface CachedTemplate {
19
19
  readonly type: "cached";
20
- readonly resourceId: ResourceId;
20
+ readonly resourceId: SignedResourceId;
21
21
  }
22
22
  interface TemplateFromFile {
23
23
  readonly type: "from-file";
@@ -1 +1 @@
1
- {"version":3,"file":"template_spec.d.ts","names":[],"sources":["../../src/model/template_spec.ts"],"mappings":";;;;UAGiB,oBAAA;EAAA,SACN,IAAA;EACT,QAAA;EACA,IAAA;AAAA;AAAA,UAGe,gBAAA;EAAA,SACN,IAAA;EACT,OAAA,EAAS,UAAA;AAAA;AAAA,UAGM,gBAAA;EAAA,SACN,IAAA;EACT,IAAA,EAAM,YAAA,GAAe,kBAAA;AAAA;AAAA,UAGN,cAAA;EAAA,SACN,IAAA;EAAA,SACA,UAAA,EAAY,UAAA;AAAA;AAAA,UAGN,gBAAA;EAAA,SACN,IAAA;EACT,IAAA;AAAA;AAAA,KAGU,oBAAA,GACR,oBAAA,GACA,gBAAA,GACA,gBAAA,GACA,cAAA;AAAA,KACQ,eAAA,GAAkB,oBAAA,GAAuB,gBAAA"}
1
+ {"version":3,"file":"template_spec.d.ts","names":[],"sources":["../../src/model/template_spec.ts"],"mappings":";;;;UAGiB,oBAAA;EAAA,SACN,IAAA;EACT,QAAA;EACA,IAAA;AAAA;AAAA,UAGe,gBAAA;EAAA,SACN,IAAA;EACT,OAAA,EAAS,UAAA;AAAA;AAAA,UAGM,gBAAA;EAAA,SACN,IAAA;EACT,IAAA,EAAM,YAAA,GAAe,kBAAA;AAAA;AAAA,UAGN,cAAA;EAAA,SACN,IAAA;EAAA,SACA,UAAA,EAAY,gBAAA;AAAA;AAAA,UAGN,gBAAA;EAAA,SACN,IAAA;EACT,IAAA;AAAA;AAAA,KAGU,oBAAA,GACR,oBAAA,GACA,gBAAA,GACA,gBAAA,GACA,cAAA;AAAA,KACQ,eAAA,GAAkB,oBAAA,GAAuB,gBAAA"}
@@ -72,7 +72,7 @@ async function migrateV1ToV2(tx, rid) {
72
72
  async function migrateV2ToV3(tx, rid) {
73
73
  const [structure, fullResourceState] = await Promise.all([tx.getKValueJson(rid, require_project_model.ProjectStructureKey), tx.getResourceData(rid, true)]);
74
74
  const fieldMap = /* @__PURE__ */ new Map();
75
- for (const f of fullResourceState.fields) if (!(0, _milaboratories_pl_client.isNullResourceId)(f.value)) fieldMap.set(f.name, f.value);
75
+ for (const f of fullResourceState.fields) if (!(0, _milaboratories_pl_client.isNullSignedResourceId)(f.value)) fieldMap.set(f.name, f.value);
76
76
  for (const block of require_project_model_util.allBlocks(structure)) {
77
77
  const uiStateFieldName = require_project_model.projectFieldName(block.id, "uiState");
78
78
  const currentArgsFieldName = require_project_model.projectFieldName(block.id, "currentArgs");
@@ -1 +1 @@
1
- {"version":3,"file":"migration.cjs","names":["SchemaVersionKey","UiError","ProjectStructureKey","allBlocks","BlockFrontendStateKeyPrefixV1","projectFieldName"],"sources":["../../src/mutator/migration.ts"],"sourcesContent":["import { UiError } from \"@milaboratories/pl-model-common\";\nimport type { PlClient, PlTransaction, ResourceId } from \"@milaboratories/pl-client\";\nimport type { ProjectField, ProjectStructure } from \"../model/project_model\";\nimport {\n projectFieldName,\n ProjectStructureKey,\n SchemaVersionCurrent,\n SchemaVersionKey,\n SchemaVersionV2,\n SchemaVersionV3,\n} from \"../model/project_model\";\nimport { BlockFrontendStateKeyPrefixV1, SchemaVersionV1 } from \"../model/project_model_v1\";\nimport { field, isNullResourceId } from \"@milaboratories/pl-client\";\nimport { cachedDeserialize } from \"@milaboratories/ts-helpers\";\nimport { allBlocks } from \"../model/project_model_util\";\n\n/**\n * Migrates the project to the latest schema version.\n *\n * @param pl - The client to use.\n * @param rid - The resource id of the project.\n */\nexport async function applyProjectMigrations(pl: PlClient, rid: ResourceId) {\n await pl.withWriteTx(\"ProjectMigration\", async (tx) => {\n let schemaVersion = await tx.getKValueJson<string>(rid, SchemaVersionKey);\n if (schemaVersion === SchemaVersionCurrent) return;\n\n // Apply migrations in sequence\n if (schemaVersion === SchemaVersionV1) {\n await migrateV1ToV2(tx, rid);\n schemaVersion = SchemaVersionV2;\n }\n\n if (schemaVersion === SchemaVersionV2) {\n await migrateV2ToV3(tx, rid);\n schemaVersion = SchemaVersionV3;\n }\n\n if (schemaVersion === SchemaVersionV3) {\n // V3 → V4: production context chain + staging re-render.\n // The actual chain building and staging reset happens in fixProblemsAndMigrate()\n // (called from ProjectMutator.load). This migration step just bumps the schema\n // to prevent older clients from operating on the new project structure.\n schemaVersion = SchemaVersionCurrent;\n }\n\n if (schemaVersion !== SchemaVersionCurrent) {\n throw new UiError(\n `This project was created with a newer version of Platforma. Please update to the latest version to open it.`,\n );\n }\n\n tx.setKValue(rid, SchemaVersionKey, JSON.stringify(SchemaVersionCurrent));\n await tx.commit();\n });\n}\n\n/**\n * Migrates the project from schema version 1 to 2.\n *\n * Summary of changes:\n * - uiState is now stored in a field instead of a KV\n *\n * @param tx - The transaction to use.\n * @param rid - The resource id of the project.\n */\nasync function migrateV1ToV2(tx: PlTransaction, rid: ResourceId) {\n const [structure, allKV] = await Promise.all([\n tx.getKValueJson<ProjectStructure>(rid, ProjectStructureKey),\n tx.listKeyValues(rid),\n ]);\n const kvMap = new Map<string, Uint8Array>(allKV.map((kv) => [kv.key, kv.value]));\n for (const block of allBlocks(structure)) {\n const kvKey = BlockFrontendStateKeyPrefixV1 + block.id;\n const uiState = kvMap.get(kvKey);\n const valueJson = uiState ? cachedDeserialize(uiState) : {};\n const uiStateR = tx.createJsonGzValue(valueJson);\n const uiStateF = field(rid, projectFieldName(block.id, \"blockStorage\"));\n tx.createField(uiStateF, \"Dynamic\", uiStateR);\n tx.deleteKValue(rid, kvKey);\n }\n}\n\n/**\n * Migrates the project from schema version 2 to 3.\n *\n * Summary of changes:\n * - Introduces unified 'blockStorage' field containing { args, uiState }\n * - Adds 'currentPrerunArgs' field for staging/prerun rendering\n * - For each block:\n * 1. Read existing 'blockStorage' field (contains uiState in v2)\n * 2. Read existing 'currentArgs' field (contains args)\n * 3. Create unified state = { args: currentArgs, uiState: oldState }\n * 4. Write to new {blockId}-blockStorage field (overwrites)\n * 5. Initialize {blockId}-currentPrerunArgs (same as prodArgs for v1/v2 blocks)\n * - Note: currentArgs and prodArgs fields remain for compatibility layer\n *\n * @param tx - The transaction to use.\n * @param rid - The resource id of the project.\n */\nasync function migrateV2ToV3(tx: PlTransaction, rid: ResourceId) {\n const [structure, fullResourceState] = await Promise.all([\n tx.getKValueJson<ProjectStructure>(rid, ProjectStructureKey),\n tx.getResourceData(rid, true),\n ]);\n\n // Build a map of field name -> resource id for quick lookup\n const fieldMap = new Map<string, ResourceId>();\n for (const f of fullResourceState.fields) {\n if (!isNullResourceId(f.value)) {\n fieldMap.set(f.name, f.value);\n }\n }\n\n for (const block of allBlocks(structure)) {\n // Read existing field values\n const uiStateFieldName = projectFieldName(block.id, \"uiState\" as ProjectField[\"fieldName\"]);\n const currentArgsFieldName = projectFieldName(block.id, \"currentArgs\");\n\n const uiStateRid = fieldMap.get(uiStateFieldName);\n const currentArgsRid = fieldMap.get(currentArgsFieldName);\n\n // Read field data in parallel where available\n const [uiStateData, currentArgsData] = await Promise.all([\n uiStateRid ? tx.getResourceData(uiStateRid, false) : Promise.resolve(undefined),\n currentArgsRid ? tx.getResourceData(currentArgsRid, false) : Promise.resolve(undefined),\n ]);\n\n // Extract values - in v2, 'blockStorage' contains raw uiState, not wrapped\n const uiState = uiStateData?.data ? cachedDeserialize(uiStateData.data) : {};\n const args = currentArgsData?.data ? cachedDeserialize(currentArgsData.data) : {};\n\n // Create unified state: { args, uiState }\n const unifiedState = {\n args,\n uiState,\n };\n\n const blockStorageFieldName = projectFieldName(block.id, \"blockStorage\");\n\n // Write new unified blockStorage field (overwrite existing)\n const stateR = tx.createJsonGzValue(unifiedState);\n const stateF = field(rid, blockStorageFieldName);\n tx.createField(stateF, \"Dynamic\", stateR);\n\n // Initialize currentPrerunArgs from currentArgs (for legacy blocks, prerunArgs = args)\n if (currentArgsRid) {\n const prerunArgsR = tx.createJsonGzValue(args);\n const prerunArgsF = field(rid, projectFieldName(block.id, \"currentPrerunArgs\"));\n tx.createField(prerunArgsF, \"Dynamic\", prerunArgsR);\n }\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"migration.cjs","names":["SchemaVersionKey","UiError","ProjectStructureKey","allBlocks","BlockFrontendStateKeyPrefixV1","projectFieldName"],"sources":["../../src/mutator/migration.ts"],"sourcesContent":["import { UiError } from \"@milaboratories/pl-model-common\";\nimport type { PlClient, PlTransaction, SignedResourceId } from \"@milaboratories/pl-client\";\nimport type { ProjectField, ProjectStructure } from \"../model/project_model\";\nimport {\n projectFieldName,\n ProjectStructureKey,\n SchemaVersionCurrent,\n SchemaVersionKey,\n SchemaVersionV2,\n SchemaVersionV3,\n} from \"../model/project_model\";\nimport { BlockFrontendStateKeyPrefixV1, SchemaVersionV1 } from \"../model/project_model_v1\";\nimport { field, isNullSignedResourceId } from \"@milaboratories/pl-client\";\nimport { cachedDeserialize } from \"@milaboratories/ts-helpers\";\nimport { allBlocks } from \"../model/project_model_util\";\n\n/**\n * Migrates the project to the latest schema version.\n *\n * @param pl - The client to use.\n * @param rid - The resource id of the project.\n */\nexport async function applyProjectMigrations(pl: PlClient, rid: SignedResourceId) {\n await pl.withWriteTx(\"ProjectMigration\", async (tx) => {\n let schemaVersion = await tx.getKValueJson<string>(rid, SchemaVersionKey);\n if (schemaVersion === SchemaVersionCurrent) return;\n\n // Apply migrations in sequence\n if (schemaVersion === SchemaVersionV1) {\n await migrateV1ToV2(tx, rid);\n schemaVersion = SchemaVersionV2;\n }\n\n if (schemaVersion === SchemaVersionV2) {\n await migrateV2ToV3(tx, rid);\n schemaVersion = SchemaVersionV3;\n }\n\n if (schemaVersion === SchemaVersionV3) {\n // V3 → V4: production context chain + staging re-render.\n // The actual chain building and staging reset happens in fixProblemsAndMigrate()\n // (called from ProjectMutator.load). This migration step just bumps the schema\n // to prevent older clients from operating on the new project structure.\n schemaVersion = SchemaVersionCurrent;\n }\n\n if (schemaVersion !== SchemaVersionCurrent) {\n throw new UiError(\n `This project was created with a newer version of Platforma. Please update to the latest version to open it.`,\n );\n }\n\n tx.setKValue(rid, SchemaVersionKey, JSON.stringify(SchemaVersionCurrent));\n await tx.commit();\n });\n}\n\n/**\n * Migrates the project from schema version 1 to 2.\n *\n * Summary of changes:\n * - uiState is now stored in a field instead of a KV\n *\n * @param tx - The transaction to use.\n * @param rid - The resource id of the project.\n */\nasync function migrateV1ToV2(tx: PlTransaction, rid: SignedResourceId) {\n const [structure, allKV] = await Promise.all([\n tx.getKValueJson<ProjectStructure>(rid, ProjectStructureKey),\n tx.listKeyValues(rid),\n ]);\n const kvMap = new Map<string, Uint8Array>(allKV.map((kv) => [kv.key, kv.value]));\n for (const block of allBlocks(structure)) {\n const kvKey = BlockFrontendStateKeyPrefixV1 + block.id;\n const uiState = kvMap.get(kvKey);\n const valueJson = uiState ? cachedDeserialize(uiState) : {};\n const uiStateR = tx.createJsonGzValue(valueJson);\n const uiStateF = field(rid, projectFieldName(block.id, \"blockStorage\"));\n tx.createField(uiStateF, \"Dynamic\", uiStateR);\n tx.deleteKValue(rid, kvKey);\n }\n}\n\n/**\n * Migrates the project from schema version 2 to 3.\n *\n * Summary of changes:\n * - Introduces unified 'blockStorage' field containing { args, uiState }\n * - Adds 'currentPrerunArgs' field for staging/prerun rendering\n * - For each block:\n * 1. Read existing 'blockStorage' field (contains uiState in v2)\n * 2. Read existing 'currentArgs' field (contains args)\n * 3. Create unified state = { args: currentArgs, uiState: oldState }\n * 4. Write to new {blockId}-blockStorage field (overwrites)\n * 5. Initialize {blockId}-currentPrerunArgs (same as prodArgs for v1/v2 blocks)\n * - Note: currentArgs and prodArgs fields remain for compatibility layer\n *\n * @param tx - The transaction to use.\n * @param rid - The resource id of the project.\n */\nasync function migrateV2ToV3(tx: PlTransaction, rid: SignedResourceId) {\n const [structure, fullResourceState] = await Promise.all([\n tx.getKValueJson<ProjectStructure>(rid, ProjectStructureKey),\n tx.getResourceData(rid, true),\n ]);\n\n // Build a map of field name -> resource id for quick lookup\n const fieldMap = new Map<string, SignedResourceId>();\n for (const f of fullResourceState.fields) {\n if (!isNullSignedResourceId(f.value)) {\n fieldMap.set(f.name, f.value);\n }\n }\n\n for (const block of allBlocks(structure)) {\n // Read existing field values\n const uiStateFieldName = projectFieldName(block.id, \"uiState\" as ProjectField[\"fieldName\"]);\n const currentArgsFieldName = projectFieldName(block.id, \"currentArgs\");\n\n const uiStateRid = fieldMap.get(uiStateFieldName);\n const currentArgsRid = fieldMap.get(currentArgsFieldName);\n\n // Read field data in parallel where available\n const [uiStateData, currentArgsData] = await Promise.all([\n uiStateRid ? tx.getResourceData(uiStateRid, false) : Promise.resolve(undefined),\n currentArgsRid ? tx.getResourceData(currentArgsRid, false) : Promise.resolve(undefined),\n ]);\n\n // Extract values - in v2, 'blockStorage' contains raw uiState, not wrapped\n const uiState = uiStateData?.data ? cachedDeserialize(uiStateData.data) : {};\n const args = currentArgsData?.data ? cachedDeserialize(currentArgsData.data) : {};\n\n // Create unified state: { args, uiState }\n const unifiedState = {\n args,\n uiState,\n };\n\n const blockStorageFieldName = projectFieldName(block.id, \"blockStorage\");\n\n // Write new unified blockStorage field (overwrite existing)\n const stateR = tx.createJsonGzValue(unifiedState);\n const stateF = field(rid, blockStorageFieldName);\n tx.createField(stateF, \"Dynamic\", stateR);\n\n // Initialize currentPrerunArgs from currentArgs (for legacy blocks, prerunArgs = args)\n if (currentArgsRid) {\n const prerunArgsR = tx.createJsonGzValue(args);\n const prerunArgsF = field(rid, projectFieldName(block.id, \"currentPrerunArgs\"));\n tx.createField(prerunArgsF, \"Dynamic\", prerunArgsR);\n }\n }\n}\n"],"mappings":"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"}
@@ -2,7 +2,7 @@ import { ProjectStructureKey, SchemaVersionKey, projectFieldName } from "../mode
2
2
  import { allBlocks } from "../model/project_model_util.js";
3
3
  import { BlockFrontendStateKeyPrefixV1 } from "../model/project_model_v1.js";
4
4
  import { cachedDeserialize } from "@milaboratories/ts-helpers";
5
- import { field, isNullResourceId } from "@milaboratories/pl-client";
5
+ import { field, isNullSignedResourceId } from "@milaboratories/pl-client";
6
6
  import { UiError } from "@milaboratories/pl-model-common";
7
7
  //#region src/mutator/migration.ts
8
8
  /**
@@ -71,7 +71,7 @@ async function migrateV1ToV2(tx, rid) {
71
71
  async function migrateV2ToV3(tx, rid) {
72
72
  const [structure, fullResourceState] = await Promise.all([tx.getKValueJson(rid, ProjectStructureKey), tx.getResourceData(rid, true)]);
73
73
  const fieldMap = /* @__PURE__ */ new Map();
74
- for (const f of fullResourceState.fields) if (!isNullResourceId(f.value)) fieldMap.set(f.name, f.value);
74
+ for (const f of fullResourceState.fields) if (!isNullSignedResourceId(f.value)) fieldMap.set(f.name, f.value);
75
75
  for (const block of allBlocks(structure)) {
76
76
  const uiStateFieldName = projectFieldName(block.id, "uiState");
77
77
  const currentArgsFieldName = projectFieldName(block.id, "currentArgs");
@@ -1 +1 @@
1
- {"version":3,"file":"migration.js","names":[],"sources":["../../src/mutator/migration.ts"],"sourcesContent":["import { UiError } from \"@milaboratories/pl-model-common\";\nimport type { PlClient, PlTransaction, ResourceId } from \"@milaboratories/pl-client\";\nimport type { ProjectField, ProjectStructure } from \"../model/project_model\";\nimport {\n projectFieldName,\n ProjectStructureKey,\n SchemaVersionCurrent,\n SchemaVersionKey,\n SchemaVersionV2,\n SchemaVersionV3,\n} from \"../model/project_model\";\nimport { BlockFrontendStateKeyPrefixV1, SchemaVersionV1 } from \"../model/project_model_v1\";\nimport { field, isNullResourceId } from \"@milaboratories/pl-client\";\nimport { cachedDeserialize } from \"@milaboratories/ts-helpers\";\nimport { allBlocks } from \"../model/project_model_util\";\n\n/**\n * Migrates the project to the latest schema version.\n *\n * @param pl - The client to use.\n * @param rid - The resource id of the project.\n */\nexport async function applyProjectMigrations(pl: PlClient, rid: ResourceId) {\n await pl.withWriteTx(\"ProjectMigration\", async (tx) => {\n let schemaVersion = await tx.getKValueJson<string>(rid, SchemaVersionKey);\n if (schemaVersion === SchemaVersionCurrent) return;\n\n // Apply migrations in sequence\n if (schemaVersion === SchemaVersionV1) {\n await migrateV1ToV2(tx, rid);\n schemaVersion = SchemaVersionV2;\n }\n\n if (schemaVersion === SchemaVersionV2) {\n await migrateV2ToV3(tx, rid);\n schemaVersion = SchemaVersionV3;\n }\n\n if (schemaVersion === SchemaVersionV3) {\n // V3 → V4: production context chain + staging re-render.\n // The actual chain building and staging reset happens in fixProblemsAndMigrate()\n // (called from ProjectMutator.load). This migration step just bumps the schema\n // to prevent older clients from operating on the new project structure.\n schemaVersion = SchemaVersionCurrent;\n }\n\n if (schemaVersion !== SchemaVersionCurrent) {\n throw new UiError(\n `This project was created with a newer version of Platforma. Please update to the latest version to open it.`,\n );\n }\n\n tx.setKValue(rid, SchemaVersionKey, JSON.stringify(SchemaVersionCurrent));\n await tx.commit();\n });\n}\n\n/**\n * Migrates the project from schema version 1 to 2.\n *\n * Summary of changes:\n * - uiState is now stored in a field instead of a KV\n *\n * @param tx - The transaction to use.\n * @param rid - The resource id of the project.\n */\nasync function migrateV1ToV2(tx: PlTransaction, rid: ResourceId) {\n const [structure, allKV] = await Promise.all([\n tx.getKValueJson<ProjectStructure>(rid, ProjectStructureKey),\n tx.listKeyValues(rid),\n ]);\n const kvMap = new Map<string, Uint8Array>(allKV.map((kv) => [kv.key, kv.value]));\n for (const block of allBlocks(structure)) {\n const kvKey = BlockFrontendStateKeyPrefixV1 + block.id;\n const uiState = kvMap.get(kvKey);\n const valueJson = uiState ? cachedDeserialize(uiState) : {};\n const uiStateR = tx.createJsonGzValue(valueJson);\n const uiStateF = field(rid, projectFieldName(block.id, \"blockStorage\"));\n tx.createField(uiStateF, \"Dynamic\", uiStateR);\n tx.deleteKValue(rid, kvKey);\n }\n}\n\n/**\n * Migrates the project from schema version 2 to 3.\n *\n * Summary of changes:\n * - Introduces unified 'blockStorage' field containing { args, uiState }\n * - Adds 'currentPrerunArgs' field for staging/prerun rendering\n * - For each block:\n * 1. Read existing 'blockStorage' field (contains uiState in v2)\n * 2. Read existing 'currentArgs' field (contains args)\n * 3. Create unified state = { args: currentArgs, uiState: oldState }\n * 4. Write to new {blockId}-blockStorage field (overwrites)\n * 5. Initialize {blockId}-currentPrerunArgs (same as prodArgs for v1/v2 blocks)\n * - Note: currentArgs and prodArgs fields remain for compatibility layer\n *\n * @param tx - The transaction to use.\n * @param rid - The resource id of the project.\n */\nasync function migrateV2ToV3(tx: PlTransaction, rid: ResourceId) {\n const [structure, fullResourceState] = await Promise.all([\n tx.getKValueJson<ProjectStructure>(rid, ProjectStructureKey),\n tx.getResourceData(rid, true),\n ]);\n\n // Build a map of field name -> resource id for quick lookup\n const fieldMap = new Map<string, ResourceId>();\n for (const f of fullResourceState.fields) {\n if (!isNullResourceId(f.value)) {\n fieldMap.set(f.name, f.value);\n }\n }\n\n for (const block of allBlocks(structure)) {\n // Read existing field values\n const uiStateFieldName = projectFieldName(block.id, \"uiState\" as ProjectField[\"fieldName\"]);\n const currentArgsFieldName = projectFieldName(block.id, \"currentArgs\");\n\n const uiStateRid = fieldMap.get(uiStateFieldName);\n const currentArgsRid = fieldMap.get(currentArgsFieldName);\n\n // Read field data in parallel where available\n const [uiStateData, currentArgsData] = await Promise.all([\n uiStateRid ? tx.getResourceData(uiStateRid, false) : Promise.resolve(undefined),\n currentArgsRid ? tx.getResourceData(currentArgsRid, false) : Promise.resolve(undefined),\n ]);\n\n // Extract values - in v2, 'blockStorage' contains raw uiState, not wrapped\n const uiState = uiStateData?.data ? cachedDeserialize(uiStateData.data) : {};\n const args = currentArgsData?.data ? cachedDeserialize(currentArgsData.data) : {};\n\n // Create unified state: { args, uiState }\n const unifiedState = {\n args,\n uiState,\n };\n\n const blockStorageFieldName = projectFieldName(block.id, \"blockStorage\");\n\n // Write new unified blockStorage field (overwrite existing)\n const stateR = tx.createJsonGzValue(unifiedState);\n const stateF = field(rid, blockStorageFieldName);\n tx.createField(stateF, \"Dynamic\", stateR);\n\n // Initialize currentPrerunArgs from currentArgs (for legacy blocks, prerunArgs = args)\n if (currentArgsRid) {\n const prerunArgsR = tx.createJsonGzValue(args);\n const prerunArgsF = field(rid, projectFieldName(block.id, \"currentPrerunArgs\"));\n tx.createField(prerunArgsF, \"Dynamic\", prerunArgsR);\n }\n }\n}\n"],"mappings":";;;;;;;;;;;;;AAsBA,eAAsB,uBAAuB,IAAc,KAAiB;AAC1E,OAAM,GAAG,YAAY,oBAAoB,OAAO,OAAO;EACrD,IAAI,gBAAgB,MAAM,GAAG,cAAsB,KAAK,iBAAiB;AACzE,MAAI,kBAAA,IAAwC;AAG5C,MAAI,kBAAA,KAAmC;AACrC,SAAM,cAAc,IAAI,IAAI;AAC5B,mBAAA;;AAGF,MAAI,kBAAA,KAAmC;AACrC,SAAM,cAAc,IAAI,IAAI;AAC5B,mBAAA;;AAGF,MAAI,kBAAA,IAKF,iBAAA;AAGF,MAAI,kBAAA,IACF,OAAM,IAAI,QACR,8GACD;AAGH,KAAG,UAAU,KAAK,kBAAkB,KAAK,UAAA,IAA+B,CAAC;AACzE,QAAM,GAAG,QAAQ;GACjB;;;;;;;;;;;AAYJ,eAAe,cAAc,IAAmB,KAAiB;CAC/D,MAAM,CAAC,WAAW,SAAS,MAAM,QAAQ,IAAI,CAC3C,GAAG,cAAgC,KAAK,oBAAoB,EAC5D,GAAG,cAAc,IAAI,CACtB,CAAC;CACF,MAAM,QAAQ,IAAI,IAAwB,MAAM,KAAK,OAAO,CAAC,GAAG,KAAK,GAAG,MAAM,CAAC,CAAC;AAChF,MAAK,MAAM,SAAS,UAAU,UAAU,EAAE;EACxC,MAAM,QAAQ,gCAAgC,MAAM;EACpD,MAAM,UAAU,MAAM,IAAI,MAAM;EAChC,MAAM,YAAY,UAAU,kBAAkB,QAAQ,GAAG,EAAE;EAC3D,MAAM,WAAW,GAAG,kBAAkB,UAAU;EAChD,MAAM,WAAW,MAAM,KAAK,iBAAiB,MAAM,IAAI,eAAe,CAAC;AACvE,KAAG,YAAY,UAAU,WAAW,SAAS;AAC7C,KAAG,aAAa,KAAK,MAAM;;;;;;;;;;;;;;;;;;;;AAqB/B,eAAe,cAAc,IAAmB,KAAiB;CAC/D,MAAM,CAAC,WAAW,qBAAqB,MAAM,QAAQ,IAAI,CACvD,GAAG,cAAgC,KAAK,oBAAoB,EAC5D,GAAG,gBAAgB,KAAK,KAAK,CAC9B,CAAC;CAGF,MAAM,2BAAW,IAAI,KAAyB;AAC9C,MAAK,MAAM,KAAK,kBAAkB,OAChC,KAAI,CAAC,iBAAiB,EAAE,MAAM,CAC5B,UAAS,IAAI,EAAE,MAAM,EAAE,MAAM;AAIjC,MAAK,MAAM,SAAS,UAAU,UAAU,EAAE;EAExC,MAAM,mBAAmB,iBAAiB,MAAM,IAAI,UAAuC;EAC3F,MAAM,uBAAuB,iBAAiB,MAAM,IAAI,cAAc;EAEtE,MAAM,aAAa,SAAS,IAAI,iBAAiB;EACjD,MAAM,iBAAiB,SAAS,IAAI,qBAAqB;EAGzD,MAAM,CAAC,aAAa,mBAAmB,MAAM,QAAQ,IAAI,CACvD,aAAa,GAAG,gBAAgB,YAAY,MAAM,GAAG,QAAQ,QAAQ,KAAA,EAAU,EAC/E,iBAAiB,GAAG,gBAAgB,gBAAgB,MAAM,GAAG,QAAQ,QAAQ,KAAA,EAAU,CACxF,CAAC;EAGF,MAAM,UAAU,aAAa,OAAO,kBAAkB,YAAY,KAAK,GAAG,EAAE;EAC5E,MAAM,OAAO,iBAAiB,OAAO,kBAAkB,gBAAgB,KAAK,GAAG,EAAE;EAGjF,MAAM,eAAe;GACnB;GACA;GACD;EAED,MAAM,wBAAwB,iBAAiB,MAAM,IAAI,eAAe;EAGxE,MAAM,SAAS,GAAG,kBAAkB,aAAa;EACjD,MAAM,SAAS,MAAM,KAAK,sBAAsB;AAChD,KAAG,YAAY,QAAQ,WAAW,OAAO;AAGzC,MAAI,gBAAgB;GAClB,MAAM,cAAc,GAAG,kBAAkB,KAAK;GAC9C,MAAM,cAAc,MAAM,KAAK,iBAAiB,MAAM,IAAI,oBAAoB,CAAC;AAC/E,MAAG,YAAY,aAAa,WAAW,YAAY"}
1
+ {"version":3,"file":"migration.js","names":[],"sources":["../../src/mutator/migration.ts"],"sourcesContent":["import { UiError } from \"@milaboratories/pl-model-common\";\nimport type { PlClient, PlTransaction, SignedResourceId } from \"@milaboratories/pl-client\";\nimport type { ProjectField, ProjectStructure } from \"../model/project_model\";\nimport {\n projectFieldName,\n ProjectStructureKey,\n SchemaVersionCurrent,\n SchemaVersionKey,\n SchemaVersionV2,\n SchemaVersionV3,\n} from \"../model/project_model\";\nimport { BlockFrontendStateKeyPrefixV1, SchemaVersionV1 } from \"../model/project_model_v1\";\nimport { field, isNullSignedResourceId } from \"@milaboratories/pl-client\";\nimport { cachedDeserialize } from \"@milaboratories/ts-helpers\";\nimport { allBlocks } from \"../model/project_model_util\";\n\n/**\n * Migrates the project to the latest schema version.\n *\n * @param pl - The client to use.\n * @param rid - The resource id of the project.\n */\nexport async function applyProjectMigrations(pl: PlClient, rid: SignedResourceId) {\n await pl.withWriteTx(\"ProjectMigration\", async (tx) => {\n let schemaVersion = await tx.getKValueJson<string>(rid, SchemaVersionKey);\n if (schemaVersion === SchemaVersionCurrent) return;\n\n // Apply migrations in sequence\n if (schemaVersion === SchemaVersionV1) {\n await migrateV1ToV2(tx, rid);\n schemaVersion = SchemaVersionV2;\n }\n\n if (schemaVersion === SchemaVersionV2) {\n await migrateV2ToV3(tx, rid);\n schemaVersion = SchemaVersionV3;\n }\n\n if (schemaVersion === SchemaVersionV3) {\n // V3 → V4: production context chain + staging re-render.\n // The actual chain building and staging reset happens in fixProblemsAndMigrate()\n // (called from ProjectMutator.load). This migration step just bumps the schema\n // to prevent older clients from operating on the new project structure.\n schemaVersion = SchemaVersionCurrent;\n }\n\n if (schemaVersion !== SchemaVersionCurrent) {\n throw new UiError(\n `This project was created with a newer version of Platforma. Please update to the latest version to open it.`,\n );\n }\n\n tx.setKValue(rid, SchemaVersionKey, JSON.stringify(SchemaVersionCurrent));\n await tx.commit();\n });\n}\n\n/**\n * Migrates the project from schema version 1 to 2.\n *\n * Summary of changes:\n * - uiState is now stored in a field instead of a KV\n *\n * @param tx - The transaction to use.\n * @param rid - The resource id of the project.\n */\nasync function migrateV1ToV2(tx: PlTransaction, rid: SignedResourceId) {\n const [structure, allKV] = await Promise.all([\n tx.getKValueJson<ProjectStructure>(rid, ProjectStructureKey),\n tx.listKeyValues(rid),\n ]);\n const kvMap = new Map<string, Uint8Array>(allKV.map((kv) => [kv.key, kv.value]));\n for (const block of allBlocks(structure)) {\n const kvKey = BlockFrontendStateKeyPrefixV1 + block.id;\n const uiState = kvMap.get(kvKey);\n const valueJson = uiState ? cachedDeserialize(uiState) : {};\n const uiStateR = tx.createJsonGzValue(valueJson);\n const uiStateF = field(rid, projectFieldName(block.id, \"blockStorage\"));\n tx.createField(uiStateF, \"Dynamic\", uiStateR);\n tx.deleteKValue(rid, kvKey);\n }\n}\n\n/**\n * Migrates the project from schema version 2 to 3.\n *\n * Summary of changes:\n * - Introduces unified 'blockStorage' field containing { args, uiState }\n * - Adds 'currentPrerunArgs' field for staging/prerun rendering\n * - For each block:\n * 1. Read existing 'blockStorage' field (contains uiState in v2)\n * 2. Read existing 'currentArgs' field (contains args)\n * 3. Create unified state = { args: currentArgs, uiState: oldState }\n * 4. Write to new {blockId}-blockStorage field (overwrites)\n * 5. Initialize {blockId}-currentPrerunArgs (same as prodArgs for v1/v2 blocks)\n * - Note: currentArgs and prodArgs fields remain for compatibility layer\n *\n * @param tx - The transaction to use.\n * @param rid - The resource id of the project.\n */\nasync function migrateV2ToV3(tx: PlTransaction, rid: SignedResourceId) {\n const [structure, fullResourceState] = await Promise.all([\n tx.getKValueJson<ProjectStructure>(rid, ProjectStructureKey),\n tx.getResourceData(rid, true),\n ]);\n\n // Build a map of field name -> resource id for quick lookup\n const fieldMap = new Map<string, SignedResourceId>();\n for (const f of fullResourceState.fields) {\n if (!isNullSignedResourceId(f.value)) {\n fieldMap.set(f.name, f.value);\n }\n }\n\n for (const block of allBlocks(structure)) {\n // Read existing field values\n const uiStateFieldName = projectFieldName(block.id, \"uiState\" as ProjectField[\"fieldName\"]);\n const currentArgsFieldName = projectFieldName(block.id, \"currentArgs\");\n\n const uiStateRid = fieldMap.get(uiStateFieldName);\n const currentArgsRid = fieldMap.get(currentArgsFieldName);\n\n // Read field data in parallel where available\n const [uiStateData, currentArgsData] = await Promise.all([\n uiStateRid ? tx.getResourceData(uiStateRid, false) : Promise.resolve(undefined),\n currentArgsRid ? tx.getResourceData(currentArgsRid, false) : Promise.resolve(undefined),\n ]);\n\n // Extract values - in v2, 'blockStorage' contains raw uiState, not wrapped\n const uiState = uiStateData?.data ? cachedDeserialize(uiStateData.data) : {};\n const args = currentArgsData?.data ? cachedDeserialize(currentArgsData.data) : {};\n\n // Create unified state: { args, uiState }\n const unifiedState = {\n args,\n uiState,\n };\n\n const blockStorageFieldName = projectFieldName(block.id, \"blockStorage\");\n\n // Write new unified blockStorage field (overwrite existing)\n const stateR = tx.createJsonGzValue(unifiedState);\n const stateF = field(rid, blockStorageFieldName);\n tx.createField(stateF, \"Dynamic\", stateR);\n\n // Initialize currentPrerunArgs from currentArgs (for legacy blocks, prerunArgs = args)\n if (currentArgsRid) {\n const prerunArgsR = tx.createJsonGzValue(args);\n const prerunArgsF = field(rid, projectFieldName(block.id, \"currentPrerunArgs\"));\n tx.createField(prerunArgsF, \"Dynamic\", prerunArgsR);\n }\n }\n}\n"],"mappings":";;;;;;;;;;;;;AAsBA,eAAsB,uBAAuB,IAAc,KAAuB;AAChF,OAAM,GAAG,YAAY,oBAAoB,OAAO,OAAO;EACrD,IAAI,gBAAgB,MAAM,GAAG,cAAsB,KAAK,iBAAiB;AACzE,MAAI,kBAAA,IAAwC;AAG5C,MAAI,kBAAA,KAAmC;AACrC,SAAM,cAAc,IAAI,IAAI;AAC5B,mBAAA;;AAGF,MAAI,kBAAA,KAAmC;AACrC,SAAM,cAAc,IAAI,IAAI;AAC5B,mBAAA;;AAGF,MAAI,kBAAA,IAKF,iBAAA;AAGF,MAAI,kBAAA,IACF,OAAM,IAAI,QACR,8GACD;AAGH,KAAG,UAAU,KAAK,kBAAkB,KAAK,UAAA,IAA+B,CAAC;AACzE,QAAM,GAAG,QAAQ;GACjB;;;;;;;;;;;AAYJ,eAAe,cAAc,IAAmB,KAAuB;CACrE,MAAM,CAAC,WAAW,SAAS,MAAM,QAAQ,IAAI,CAC3C,GAAG,cAAgC,KAAK,oBAAoB,EAC5D,GAAG,cAAc,IAAI,CACtB,CAAC;CACF,MAAM,QAAQ,IAAI,IAAwB,MAAM,KAAK,OAAO,CAAC,GAAG,KAAK,GAAG,MAAM,CAAC,CAAC;AAChF,MAAK,MAAM,SAAS,UAAU,UAAU,EAAE;EACxC,MAAM,QAAQ,gCAAgC,MAAM;EACpD,MAAM,UAAU,MAAM,IAAI,MAAM;EAChC,MAAM,YAAY,UAAU,kBAAkB,QAAQ,GAAG,EAAE;EAC3D,MAAM,WAAW,GAAG,kBAAkB,UAAU;EAChD,MAAM,WAAW,MAAM,KAAK,iBAAiB,MAAM,IAAI,eAAe,CAAC;AACvE,KAAG,YAAY,UAAU,WAAW,SAAS;AAC7C,KAAG,aAAa,KAAK,MAAM;;;;;;;;;;;;;;;;;;;;AAqB/B,eAAe,cAAc,IAAmB,KAAuB;CACrE,MAAM,CAAC,WAAW,qBAAqB,MAAM,QAAQ,IAAI,CACvD,GAAG,cAAgC,KAAK,oBAAoB,EAC5D,GAAG,gBAAgB,KAAK,KAAK,CAC9B,CAAC;CAGF,MAAM,2BAAW,IAAI,KAA+B;AACpD,MAAK,MAAM,KAAK,kBAAkB,OAChC,KAAI,CAAC,uBAAuB,EAAE,MAAM,CAClC,UAAS,IAAI,EAAE,MAAM,EAAE,MAAM;AAIjC,MAAK,MAAM,SAAS,UAAU,UAAU,EAAE;EAExC,MAAM,mBAAmB,iBAAiB,MAAM,IAAI,UAAuC;EAC3F,MAAM,uBAAuB,iBAAiB,MAAM,IAAI,cAAc;EAEtE,MAAM,aAAa,SAAS,IAAI,iBAAiB;EACjD,MAAM,iBAAiB,SAAS,IAAI,qBAAqB;EAGzD,MAAM,CAAC,aAAa,mBAAmB,MAAM,QAAQ,IAAI,CACvD,aAAa,GAAG,gBAAgB,YAAY,MAAM,GAAG,QAAQ,QAAQ,KAAA,EAAU,EAC/E,iBAAiB,GAAG,gBAAgB,gBAAgB,MAAM,GAAG,QAAQ,QAAQ,KAAA,EAAU,CACxF,CAAC;EAGF,MAAM,UAAU,aAAa,OAAO,kBAAkB,YAAY,KAAK,GAAG,EAAE;EAC5E,MAAM,OAAO,iBAAiB,OAAO,kBAAkB,gBAAgB,KAAK,GAAG,EAAE;EAGjF,MAAM,eAAe;GACnB;GACA;GACD;EAED,MAAM,wBAAwB,iBAAiB,MAAM,IAAI,eAAe;EAGxE,MAAM,SAAS,GAAG,kBAAkB,aAAa;EACjD,MAAM,SAAS,MAAM,KAAK,sBAAsB;AAChD,KAAG,YAAY,QAAQ,WAAW,OAAO;AAGzC,MAAI,gBAAgB;GAClB,MAAM,cAAc,GAAG,kBAAkB,KAAK;GAC9C,MAAM,cAAc,MAAM,KAAK,iBAAiB,MAAM,IAAI,oBAAoB,CAAC;AAC/E,MAAG,YAAY,aAAa,WAAW,YAAY"}
@@ -893,7 +893,7 @@ var ProjectMutator = class ProjectMutator {
893
893
  };
894
894
  blockInfoStates.set(projectField.blockId, info);
895
895
  }
896
- info.fields[projectField.fieldName] = (0, _milaboratories_pl_client.isNullResourceId)(f.value) ? { modCount: 0 } : {
896
+ info.fields[projectField.fieldName] = (0, _milaboratories_pl_client.isNullSignedResourceId)(f.value) ? { modCount: 0 } : {
897
897
  modCount: 0,
898
898
  ref: f.value
899
899
  };
@@ -926,13 +926,13 @@ var ProjectMutator = class ProjectMutator {
926
926
  for (const [info, fieldName, state, response] of blockFieldRequests) {
927
927
  const result = await response;
928
928
  state.value = result.data;
929
- if ((0, _milaboratories_pl_client.isNotNullResourceId)(result.error)) state.status = "Error";
930
- else if (result.resourceReady || (0, _milaboratories_pl_client.isNotNullResourceId)(result.originalResourceId)) state.status = "Ready";
929
+ if ((0, _milaboratories_pl_client.isNotNullSignedResourceId)(result.error)) state.status = "Error";
930
+ else if (result.resourceReady || (0, _milaboratories_pl_client.isNotNullSignedResourceId)(result.originalResourceId)) state.status = "Ready";
931
931
  else state.status = "NotReady";
932
932
  if (fieldName === "blockPack") {
933
933
  const refField = result.fields.find((f) => f.name === _milaboratories_pl_client.Pl.HolderRefField);
934
934
  if (refField === void 0) throw new Error("Block pack ref field is missing");
935
- blockPackRequests.push([info, tx.getResourceData((0, _milaboratories_pl_client.ensureResourceIdNotNull)(refField.value), false)]);
935
+ blockPackRequests.push([info, tx.getResourceData((0, _milaboratories_pl_client.ensureSignedResourceIdNotNull)(refField.value), false)]);
936
936
  }
937
937
  }
938
938
  for (const [info, response] of blockPackRequests) {
@@ -944,7 +944,7 @@ var ProjectMutator = class ProjectMutator {
944
944
  const ctxExportTplCacheFieldName = require_project_model.getServiceTemplateField(ctxExportTplEnvelope.hash);
945
945
  const ctxExportTplField = fullResourceState.fields.find((f) => f.name === ctxExportTplCacheFieldName);
946
946
  let ctxExportTplHolder;
947
- if (ctxExportTplField !== void 0) ctxExportTplHolder = (0, _milaboratories_pl_client.ensureResourceIdNotNull)(ctxExportTplField.value);
947
+ if (ctxExportTplField !== void 0) ctxExportTplHolder = (0, _milaboratories_pl_client.ensureSignedResourceIdNotNull)(ctxExportTplField.value);
948
948
  else {
949
949
  ctxExportTplHolder = _milaboratories_pl_client.Pl.wrapInHolder(tx, require_template_loading.loadTemplate(tx, ctxExportTplEnvelope.spec));
950
950
  tx.createField((0, _milaboratories_pl_client.field)(rid, require_project_model.getServiceTemplateField(ctxExportTplEnvelope.hash)), "Dynamic", ctxExportTplHolder);
@@ -1023,7 +1023,7 @@ async function duplicateProject(tx, sourceRid, options) {
1023
1023
  tx.setKValue(newPrj, require_project_model.ProjectCreatedTimestamp, ts);
1024
1024
  tx.setKValue(newPrj, require_project_model.ProjectLastModifiedTimestamp, ts);
1025
1025
  for (const f of sourceData.fields) {
1026
- if ((0, _milaboratories_pl_client.isNullResourceId)(f.value)) continue;
1026
+ if ((0, _milaboratories_pl_client.isNullSignedResourceId)(f.value)) continue;
1027
1027
  const parsed = require_project_model.parseProjectField(f.name);
1028
1028
  if (parsed !== void 0 && !require_project_model.FieldsToDuplicate.has(parsed.fieldName)) continue;
1029
1029
  tx.createField((0, _milaboratories_pl_client.field)(newPrj, f.name), "Dynamic", f.value);