@milaboratories/pl-middle-layer 1.45.5 → 1.46.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (132) hide show
  1. package/dist/index.cjs +58 -0
  2. package/dist/index.cjs.map +1 -1
  3. package/dist/index.js +2 -0
  4. package/dist/index.js.map +1 -1
  5. package/dist/js_render/computable_context.cjs +37 -7
  6. package/dist/js_render/computable_context.cjs.map +1 -1
  7. package/dist/js_render/computable_context.d.ts.map +1 -1
  8. package/dist/js_render/computable_context.js +37 -7
  9. package/dist/js_render/computable_context.js.map +1 -1
  10. package/dist/js_render/context.cjs +12 -4
  11. package/dist/js_render/context.cjs.map +1 -1
  12. package/dist/js_render/context.d.ts +9 -0
  13. package/dist/js_render/context.d.ts.map +1 -1
  14. package/dist/js_render/context.js +12 -4
  15. package/dist/js_render/context.js.map +1 -1
  16. package/dist/js_render/index.cjs +1 -1
  17. package/dist/js_render/index.cjs.map +1 -1
  18. package/dist/js_render/index.js +1 -1
  19. package/dist/js_render/index.js.map +1 -1
  20. package/dist/middle_layer/block.cjs +7 -8
  21. package/dist/middle_layer/block.cjs.map +1 -1
  22. package/dist/middle_layer/block.d.ts +4 -4
  23. package/dist/middle_layer/block.d.ts.map +1 -1
  24. package/dist/middle_layer/block.js +7 -8
  25. package/dist/middle_layer/block.js.map +1 -1
  26. package/dist/middle_layer/block_ctx.cjs +67 -13
  27. package/dist/middle_layer/block_ctx.cjs.map +1 -1
  28. package/dist/middle_layer/block_ctx.d.ts +4 -7
  29. package/dist/middle_layer/block_ctx.d.ts.map +1 -1
  30. package/dist/middle_layer/block_ctx.js +68 -14
  31. package/dist/middle_layer/block_ctx.js.map +1 -1
  32. package/dist/middle_layer/block_ctx_unsafe.cjs +10 -3
  33. package/dist/middle_layer/block_ctx_unsafe.cjs.map +1 -1
  34. package/dist/middle_layer/block_ctx_unsafe.d.ts +1 -1
  35. package/dist/middle_layer/block_ctx_unsafe.d.ts.map +1 -1
  36. package/dist/middle_layer/block_ctx_unsafe.js +10 -3
  37. package/dist/middle_layer/block_ctx_unsafe.js.map +1 -1
  38. package/dist/middle_layer/frontend_path.cjs +1 -0
  39. package/dist/middle_layer/frontend_path.cjs.map +1 -1
  40. package/dist/middle_layer/frontend_path.js +1 -0
  41. package/dist/middle_layer/frontend_path.js.map +1 -1
  42. package/dist/middle_layer/middle_layer.cjs +1 -0
  43. package/dist/middle_layer/middle_layer.cjs.map +1 -1
  44. package/dist/middle_layer/middle_layer.d.ts +1 -1
  45. package/dist/middle_layer/middle_layer.d.ts.map +1 -1
  46. package/dist/middle_layer/middle_layer.js +1 -0
  47. package/dist/middle_layer/middle_layer.js.map +1 -1
  48. package/dist/middle_layer/project.cjs +75 -28
  49. package/dist/middle_layer/project.cjs.map +1 -1
  50. package/dist/middle_layer/project.d.ts +34 -7
  51. package/dist/middle_layer/project.d.ts.map +1 -1
  52. package/dist/middle_layer/project.js +76 -29
  53. package/dist/middle_layer/project.js.map +1 -1
  54. package/dist/middle_layer/project_overview.cjs +32 -11
  55. package/dist/middle_layer/project_overview.cjs.map +1 -1
  56. package/dist/middle_layer/project_overview.d.ts.map +1 -1
  57. package/dist/middle_layer/project_overview.js +32 -11
  58. package/dist/middle_layer/project_overview.js.map +1 -1
  59. package/dist/middle_layer/render.cjs +1 -1
  60. package/dist/middle_layer/render.cjs.map +1 -1
  61. package/dist/middle_layer/render.js +1 -1
  62. package/dist/middle_layer/render.js.map +1 -1
  63. package/dist/middle_layer/render.test.d.ts.map +1 -1
  64. package/dist/model/block_storage_helper.cjs +210 -0
  65. package/dist/model/block_storage_helper.cjs.map +1 -0
  66. package/dist/model/block_storage_helper.d.ts +98 -0
  67. package/dist/model/block_storage_helper.d.ts.map +1 -0
  68. package/dist/model/block_storage_helper.js +153 -0
  69. package/dist/model/block_storage_helper.js.map +1 -0
  70. package/dist/model/index.d.ts +2 -1
  71. package/dist/model/index.d.ts.map +1 -1
  72. package/dist/model/project_helper.cjs +177 -0
  73. package/dist/model/project_helper.cjs.map +1 -1
  74. package/dist/model/project_helper.d.ts +110 -1
  75. package/dist/model/project_helper.d.ts.map +1 -1
  76. package/dist/model/project_helper.js +178 -1
  77. package/dist/model/project_helper.js.map +1 -1
  78. package/dist/model/project_model.cjs +6 -3
  79. package/dist/model/project_model.cjs.map +1 -1
  80. package/dist/model/project_model.d.ts +3 -2
  81. package/dist/model/project_model.d.ts.map +1 -1
  82. package/dist/model/project_model.js +6 -4
  83. package/dist/model/project_model.js.map +1 -1
  84. package/dist/mutator/block-pack/block_pack.cjs +1 -2
  85. package/dist/mutator/block-pack/block_pack.cjs.map +1 -1
  86. package/dist/mutator/block-pack/block_pack.d.ts.map +1 -1
  87. package/dist/mutator/block-pack/block_pack.js +1 -2
  88. package/dist/mutator/block-pack/block_pack.js.map +1 -1
  89. package/dist/mutator/block-pack/frontend.cjs +1 -0
  90. package/dist/mutator/block-pack/frontend.cjs.map +1 -1
  91. package/dist/mutator/block-pack/frontend.js +1 -0
  92. package/dist/mutator/block-pack/frontend.js.map +1 -1
  93. package/dist/mutator/migration.cjs +64 -3
  94. package/dist/mutator/migration.cjs.map +1 -1
  95. package/dist/mutator/migration.d.ts.map +1 -1
  96. package/dist/mutator/migration.js +66 -5
  97. package/dist/mutator/migration.js.map +1 -1
  98. package/dist/mutator/project-v3.test.d.ts +2 -0
  99. package/dist/mutator/project-v3.test.d.ts.map +1 -0
  100. package/dist/mutator/project.cjs +282 -41
  101. package/dist/mutator/project.cjs.map +1 -1
  102. package/dist/mutator/project.d.ts +77 -12
  103. package/dist/mutator/project.d.ts.map +1 -1
  104. package/dist/mutator/project.js +283 -42
  105. package/dist/mutator/project.js.map +1 -1
  106. package/dist/pool/result_pool.cjs +9 -6
  107. package/dist/pool/result_pool.cjs.map +1 -1
  108. package/dist/pool/result_pool.d.ts.map +1 -1
  109. package/dist/pool/result_pool.js +9 -6
  110. package/dist/pool/result_pool.js.map +1 -1
  111. package/package.json +15 -15
  112. package/src/js_render/computable_context.ts +37 -7
  113. package/src/js_render/context.ts +12 -5
  114. package/src/js_render/index.ts +1 -1
  115. package/src/middle_layer/block.ts +13 -14
  116. package/src/middle_layer/block_ctx.ts +70 -23
  117. package/src/middle_layer/block_ctx_unsafe.ts +11 -4
  118. package/src/middle_layer/middle_layer.ts +2 -1
  119. package/src/middle_layer/project.ts +86 -40
  120. package/src/middle_layer/project_overview.ts +44 -20
  121. package/src/middle_layer/render.test.ts +1 -1
  122. package/src/middle_layer/render.ts +1 -1
  123. package/src/model/block_storage_helper.ts +213 -0
  124. package/src/model/index.ts +2 -1
  125. package/src/model/project_helper.ts +249 -1
  126. package/src/model/project_model.ts +9 -5
  127. package/src/mutator/block-pack/block_pack.ts +1 -2
  128. package/src/mutator/migration.ts +79 -6
  129. package/src/mutator/project-v3.test.ts +280 -0
  130. package/src/mutator/project.test.ts +27 -27
  131. package/src/mutator/project.ts +351 -68
  132. package/src/pool/result_pool.ts +11 -4
@@ -4,6 +4,16 @@ var model = require('@platforma-sdk/model');
4
4
  var lruCache = require('lru-cache');
5
5
  var index = require('../js_render/index.cjs');
6
6
 
7
+ // Internal lambda handles for storage operations (registered by SDK's block_storage_vm.ts)
8
+ // All callbacks are prefixed with `__pl_` to indicate internal SDK use
9
+ const STORAGE_NORMALIZE_HANDLE = { __renderLambda: true, handle: '__pl_storage_normalize' };
10
+ const STORAGE_APPLY_UPDATE_HANDLE = { __renderLambda: true, handle: '__pl_storage_applyUpdate' };
11
+ const STORAGE_GET_INFO_HANDLE = { __renderLambda: true, handle: '__pl_storage_getInfo' };
12
+ const STORAGE_MIGRATE_HANDLE = { __renderLambda: true, handle: '__pl_storage_migrate' };
13
+ const ARGS_DERIVE_HANDLE = { __renderLambda: true, handle: '__pl_args_derive' };
14
+ const PRERUN_ARGS_DERIVE_HANDLE = { __renderLambda: true, handle: '__pl_prerunArgs_derive' };
15
+ // Registered by DataModel.registerCallbacks()
16
+ const INITIAL_STORAGE_HANDLE = { __renderLambda: true, handle: '__pl_storage_initial' };
7
17
  class ProjectHelper {
8
18
  quickJs;
9
19
  enrichmentTargetsCache = new lruCache.LRUCache({
@@ -15,6 +25,60 @@ class ProjectHelper {
15
25
  constructor(quickJs) {
16
26
  this.quickJs = quickJs;
17
27
  }
28
+ // =============================================================================
29
+ // Args Derivation from Storage (V3+)
30
+ // =============================================================================
31
+ /**
32
+ * Derives args directly from storage JSON using VM callback.
33
+ * The VM extracts data from storage and calls the block's args() function.
34
+ *
35
+ * This allows the middle layer to work only with storage JSON,
36
+ * without needing to know the underlying data structure.
37
+ *
38
+ * @param blockConfig The block configuration (provides the model code)
39
+ * @param storageJson Storage as JSON string
40
+ * @returns The derived args object, or error if derivation fails
41
+ */
42
+ deriveArgsFromStorage(blockConfig, storageJson) {
43
+ if (blockConfig.modelAPIVersion !== 2) {
44
+ return { error: new Error('deriveArgsFromStorage is only supported for model API version 2') };
45
+ }
46
+ try {
47
+ const result = index.executeSingleLambda(this.quickJs, ARGS_DERIVE_HANDLE, model.extractCodeWithInfo(blockConfig), storageJson);
48
+ if (result.error !== undefined) {
49
+ return { error: new Error(result.error) };
50
+ }
51
+ return { value: result.value };
52
+ }
53
+ catch (e) {
54
+ return { error: new Error('Args derivation from storage failed', { cause: model.ensureError(e) }) };
55
+ }
56
+ }
57
+ /**
58
+ * Derives prerunArgs directly from storage JSON using VM callback.
59
+ * Falls back to args() if prerunArgs is not defined in the block model.
60
+ *
61
+ * @param blockConfig The block configuration (provides the model code)
62
+ * @param storageJson Storage as JSON string
63
+ * @returns The derived prerunArgs, or undefined if derivation fails
64
+ */
65
+ derivePrerunArgsFromStorage(blockConfig, storageJson) {
66
+ if (blockConfig.modelAPIVersion !== 2) {
67
+ throw new Error('derivePrerunArgsFromStorage is only supported for model API version 2');
68
+ }
69
+ try {
70
+ const result = index.executeSingleLambda(this.quickJs, PRERUN_ARGS_DERIVE_HANDLE, model.extractCodeWithInfo(blockConfig), storageJson);
71
+ if (result.error !== undefined) {
72
+ // Return undefined if derivation fails (skip block in staging)
73
+ return undefined;
74
+ }
75
+ return result.value;
76
+ }
77
+ catch {
78
+ // Return undefined if derivation fails (skip block in staging)
79
+ return undefined;
80
+ }
81
+ }
18
82
  calculateEnrichmentTargets(req) {
19
83
  const blockConfig = req.blockConfig();
20
84
  if (blockConfig.enrichmentTargets === undefined)
@@ -30,6 +94,119 @@ class ProjectHelper {
30
94
  const cacheKey = `${key.argsRid}:${key.blockPackRid}`;
31
95
  return this.enrichmentTargetsCache.memo(cacheKey, { context: req }).value;
32
96
  }
97
+ // =============================================================================
98
+ // VM-based Storage Operations
99
+ // =============================================================================
100
+ /**
101
+ * Normalizes raw blockStorage data using VM-based transformation.
102
+ * This calls the model's `__pl_storage_normalize` callback which:
103
+ * - Handles BlockStorage format (with discriminator)
104
+ * - Handles legacy V1/V2 format ({ args, uiState })
105
+ * - Handles raw V3 state
106
+ *
107
+ * @param blockConfig The block configuration (provides the model code)
108
+ * @param rawStorage Raw storage data from resource tree (may be JSON string or object)
109
+ * @returns Object with { storage, state } or undefined if transformation fails
110
+ */
111
+ normalizeStorageInVM(blockConfig, rawStorage) {
112
+ try {
113
+ const result = index.executeSingleLambda(this.quickJs, STORAGE_NORMALIZE_HANDLE, model.extractCodeWithInfo(blockConfig), rawStorage);
114
+ return result;
115
+ }
116
+ catch (e) {
117
+ console.warn('[ProjectHelper.normalizeStorageInVM] Storage normalization failed:', e);
118
+ return undefined;
119
+ }
120
+ }
121
+ /**
122
+ * Creates initial BlockStorage for a new block using VM-based transformation.
123
+ * This calls the '__pl_storage_initial' callback registered by DataModel which:
124
+ * - Gets initial data from DataModel.getDefaultData()
125
+ * - Creates BlockStorage with correct version
126
+ *
127
+ * @param blockConfig The block configuration (provides the model code)
128
+ * @returns Initial storage as JSON string
129
+ * @throws Error if storage creation fails
130
+ */
131
+ getInitialStorageInVM(blockConfig) {
132
+ try {
133
+ const result = index.executeSingleLambda(this.quickJs, INITIAL_STORAGE_HANDLE, model.extractCodeWithInfo(blockConfig));
134
+ return result;
135
+ }
136
+ catch (e) {
137
+ console.error('[ProjectHelper.getInitialStorageInVM] Initial storage creation failed:', e);
138
+ throw new Error(`Block initial storage creation failed: ${e}`);
139
+ }
140
+ }
141
+ /**
142
+ * Applies a state update using VM-based transformation.
143
+ * This calls the model's `__pl_storage_applyUpdate` callback which:
144
+ * - Normalizes current storage
145
+ * - Updates state while preserving other fields (version, plugins)
146
+ * - Returns the updated storage as JSON string
147
+ *
148
+ * @param blockConfig The block configuration (provides the model code)
149
+ * @param currentStorageJson Current storage as JSON string (must be defined)
150
+ * @param newState New state from developer
151
+ * @returns Updated storage as JSON string
152
+ * @throws Error if storage update fails
153
+ */
154
+ applyStorageUpdateInVM(blockConfig, currentStorageJson, payload) {
155
+ try {
156
+ const result = index.executeSingleLambda(this.quickJs, STORAGE_APPLY_UPDATE_HANDLE, model.extractCodeWithInfo(blockConfig), currentStorageJson, payload);
157
+ return result;
158
+ }
159
+ catch (e) {
160
+ console.error('[ProjectHelper.applyStorageUpdateInVM] Storage update failed:', e);
161
+ throw new Error(`Block storage update failed: ${e}`);
162
+ }
163
+ }
164
+ /**
165
+ * Gets storage info from raw storage data by calling the VM's __pl_storage_getInfo callback.
166
+ * Returns structured info about the storage (e.g., dataVersion).
167
+ *
168
+ * @param blockConfig Block configuration
169
+ * @param rawStorageJson Raw storage as JSON string (or undefined)
170
+ * @returns Storage info as JSON string (e.g., '{"dataVersion": 1}')
171
+ */
172
+ getStorageInfoInVM(blockConfig, rawStorageJson) {
173
+ try {
174
+ const result = index.executeSingleLambda(this.quickJs, STORAGE_GET_INFO_HANDLE, model.extractCodeWithInfo(blockConfig), rawStorageJson);
175
+ return result;
176
+ }
177
+ catch (e) {
178
+ console.error('[ProjectHelper.getStorageInfoInVM] Get storage info failed:', e);
179
+ return undefined;
180
+ }
181
+ }
182
+ // =============================================================================
183
+ // Block State Migrations
184
+ // =============================================================================
185
+ /**
186
+ * Runs block state migrations via VM-based transformation.
187
+ * This calls the model's `__pl_storage_migrate` callback which:
188
+ * - Normalizes current storage to get state and version
189
+ * - Calculates target version from number of registered migrations
190
+ * - Runs all necessary migrations sequentially
191
+ * - Returns new storage with updated state and version
192
+ *
193
+ * The middle layer doesn't need to know about dataVersion or storage internals.
194
+ * All migration logic is encapsulated in the model.
195
+ *
196
+ * @param blockConfig The NEW block configuration (provides the model code with migrations)
197
+ * @param currentStorageJson Current storage as JSON string (or undefined)
198
+ * @returns MigrationResult with new storage or skip/error info
199
+ */
200
+ migrateStorageInVM(blockConfig, currentStorageJson) {
201
+ try {
202
+ const result = index.executeSingleLambda(this.quickJs, STORAGE_MIGRATE_HANDLE, model.extractCodeWithInfo(blockConfig), currentStorageJson);
203
+ return result;
204
+ }
205
+ catch (e) {
206
+ console.error('[ProjectHelper.migrateStorageInVM] Migration failed:', e);
207
+ return { error: `VM execution failed: ${e}` };
208
+ }
209
+ }
33
210
  }
34
211
 
35
212
  exports.ProjectHelper = ProjectHelper;
@@ -1 +1 @@
1
- {"version":3,"file":"project_helper.cjs","sources":["../../src/model/project_helper.ts"],"sourcesContent":["import { extractCodeWithInfo, type BlockConfig, type PlRef } from '@platforma-sdk/model';\nimport { LRUCache } from 'lru-cache';\nimport type { QuickJSWASMModule } from 'quickjs-emscripten';\nimport { executeSingleLambda } from '../js_render';\nimport type { ResourceId } from '@milaboratories/pl-client';\n\ntype EnrichmentTargetsRequest = {\n blockConfig: () => BlockConfig;\n args: () => unknown;\n};\n\ntype EnrichmentTargetsValue = {\n value: PlRef[] | undefined;\n};\n\nexport class ProjectHelper {\n private readonly enrichmentTargetsCache = new LRUCache<string, EnrichmentTargetsValue, EnrichmentTargetsRequest>({\n max: 256,\n memoMethod: (_key, _value, { context }) => {\n return { value: this.calculateEnrichmentTargets(context) };\n },\n });\n\n constructor(private readonly quickJs: QuickJSWASMModule) {}\n\n private calculateEnrichmentTargets(req: EnrichmentTargetsRequest): PlRef[] | undefined {\n const blockConfig = req.blockConfig();\n if (blockConfig.enrichmentTargets === undefined) return undefined;\n const args = req.args();\n const result = executeSingleLambda(this.quickJs, blockConfig.enrichmentTargets, extractCodeWithInfo(blockConfig), args) as PlRef[];\n return result;\n }\n\n public getEnrichmentTargets(blockConfig: () => BlockConfig, args: () => unknown, key?: { argsRid: ResourceId; blockPackRid: ResourceId }): PlRef[] | undefined {\n const req = { blockConfig, args };\n if (key === undefined)\n return this.calculateEnrichmentTargets(req);\n const cacheKey = `${key.argsRid}:${key.blockPackRid}`;\n return this.enrichmentTargetsCache.memo(cacheKey, { context: req }).value;\n }\n}\n"],"names":["LRUCache","executeSingleLambda","extractCodeWithInfo"],"mappings":";;;;;;MAea,aAAa,CAAA;AAQK,IAAA,OAAA;IAPZ,sBAAsB,GAAG,IAAIA,iBAAQ,CAA2D;AAC/G,QAAA,GAAG,EAAE,GAAG;QACR,UAAU,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,OAAO,EAAE,KAAI;YACxC,OAAO,EAAE,KAAK,EAAE,IAAI,CAAC,0BAA0B,CAAC,OAAO,CAAC,EAAE;QAC5D,CAAC;AACF,KAAA,CAAC;AAEF,IAAA,WAAA,CAA6B,OAA0B,EAAA;QAA1B,IAAA,CAAA,OAAO,GAAP,OAAO;IAAsB;AAElD,IAAA,0BAA0B,CAAC,GAA6B,EAAA;AAC9D,QAAA,MAAM,WAAW,GAAG,GAAG,CAAC,WAAW,EAAE;AACrC,QAAA,IAAI,WAAW,CAAC,iBAAiB,KAAK,SAAS;AAAE,YAAA,OAAO,SAAS;AACjE,QAAA,MAAM,IAAI,GAAG,GAAG,CAAC,IAAI,EAAE;AACvB,QAAA,MAAM,MAAM,GAAGC,yBAAmB,CAAC,IAAI,CAAC,OAAO,EAAE,WAAW,CAAC,iBAAiB,EAAEC,yBAAmB,CAAC,WAAW,CAAC,EAAE,IAAI,CAAY;AAClI,QAAA,OAAO,MAAM;IACf;AAEO,IAAA,oBAAoB,CAAC,WAA8B,EAAE,IAAmB,EAAE,GAAuD,EAAA;AACtI,QAAA,MAAM,GAAG,GAAG,EAAE,WAAW,EAAE,IAAI,EAAE;QACjC,IAAI,GAAG,KAAK,SAAS;AACnB,YAAA,OAAO,IAAI,CAAC,0BAA0B,CAAC,GAAG,CAAC;QAC7C,MAAM,QAAQ,GAAG,CAAA,EAAG,GAAG,CAAC,OAAO,CAAA,CAAA,EAAI,GAAG,CAAC,YAAY,CAAA,CAAE;AACrD,QAAA,OAAO,IAAI,CAAC,sBAAsB,CAAC,IAAI,CAAC,QAAQ,EAAE,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC,CAAC,KAAK;IAC3E;AACD;;;;"}
1
+ {"version":3,"file":"project_helper.cjs","sources":["../../src/model/project_helper.ts"],"sourcesContent":["import type { ResultOrError, BlockConfig, PlRef, ConfigRenderLambda } from '@platforma-sdk/model';\nimport { extractCodeWithInfo, ensureError } from '@platforma-sdk/model';\nimport { LRUCache } from 'lru-cache';\nimport type { QuickJSWASMModule } from 'quickjs-emscripten';\nimport { executeSingleLambda } from '../js_render';\nimport type { ResourceId } from '@milaboratories/pl-client';\n\ntype EnrichmentTargetsRequest = {\n blockConfig: () => BlockConfig;\n args: () => unknown;\n};\n\ntype EnrichmentTargetsValue = {\n value: PlRef[] | undefined;\n};\n\n/**\n * Result of VM-based storage normalization\n */\ninterface NormalizeStorageResult {\n storage: unknown;\n data: unknown;\n}\n\n/**\n * Result of VM-based storage migration.\n * Returned by migrateStorageInVM().\n *\n * - Error result: { error: string } - serious failure (no context, etc.)\n * - Success result: { newStorageJson: string, info: string, warn?: string } - migration succeeded or reset to initial\n */\nexport type MigrationResult =\n | { error: string }\n | { error?: undefined; newStorageJson: string; info: string; warn?: string };\n\n// Internal lambda handles for storage operations (registered by SDK's block_storage_vm.ts)\n// All callbacks are prefixed with `__pl_` to indicate internal SDK use\nconst STORAGE_NORMALIZE_HANDLE: ConfigRenderLambda = { __renderLambda: true, handle: '__pl_storage_normalize' };\nconst STORAGE_APPLY_UPDATE_HANDLE: ConfigRenderLambda = { __renderLambda: true, handle: '__pl_storage_applyUpdate' };\nconst STORAGE_GET_INFO_HANDLE: ConfigRenderLambda = { __renderLambda: true, handle: '__pl_storage_getInfo' };\nconst STORAGE_MIGRATE_HANDLE: ConfigRenderLambda = { __renderLambda: true, handle: '__pl_storage_migrate' };\nconst ARGS_DERIVE_HANDLE: ConfigRenderLambda = { __renderLambda: true, handle: '__pl_args_derive' };\nconst PRERUN_ARGS_DERIVE_HANDLE: ConfigRenderLambda = { __renderLambda: true, handle: '__pl_prerunArgs_derive' };\n// Registered by DataModel.registerCallbacks()\nconst INITIAL_STORAGE_HANDLE: ConfigRenderLambda = { __renderLambda: true, handle: '__pl_storage_initial' };\n\n/**\n * Result of args derivation from storage.\n * Returned by __pl_args_derive and __pl_prerunArgs_derive VM callbacks.\n */\ntype ArgsDeriveResult =\n | { error: string }\n | { error?: undefined; value: unknown };\n\nexport class ProjectHelper {\n private readonly enrichmentTargetsCache = new LRUCache<string, EnrichmentTargetsValue, EnrichmentTargetsRequest>({\n max: 256,\n memoMethod: (_key, _value, { context }) => {\n return { value: this.calculateEnrichmentTargets(context) };\n },\n });\n\n constructor(private readonly quickJs: QuickJSWASMModule) {}\n\n // =============================================================================\n // Args Derivation from Storage (V3+)\n // =============================================================================\n\n /**\n * Derives args directly from storage JSON using VM callback.\n * The VM extracts data from storage and calls the block's args() function.\n *\n * This allows the middle layer to work only with storage JSON,\n * without needing to know the underlying data structure.\n *\n * @param blockConfig The block configuration (provides the model code)\n * @param storageJson Storage as JSON string\n * @returns The derived args object, or error if derivation fails\n */\n public deriveArgsFromStorage(blockConfig: BlockConfig, storageJson: string): ResultOrError<unknown> {\n if (blockConfig.modelAPIVersion !== 2) {\n return { error: new Error('deriveArgsFromStorage is only supported for model API version 2') };\n }\n\n try {\n const result = executeSingleLambda(\n this.quickJs,\n ARGS_DERIVE_HANDLE,\n extractCodeWithInfo(blockConfig),\n storageJson,\n ) as ArgsDeriveResult;\n\n if (result.error !== undefined) {\n return { error: new Error(result.error) };\n }\n return { value: result.value };\n } catch (e) {\n return { error: new Error('Args derivation from storage failed', { cause: ensureError(e) }) };\n }\n }\n\n /**\n * Derives prerunArgs directly from storage JSON using VM callback.\n * Falls back to args() if prerunArgs is not defined in the block model.\n *\n * @param blockConfig The block configuration (provides the model code)\n * @param storageJson Storage as JSON string\n * @returns The derived prerunArgs, or undefined if derivation fails\n */\n public derivePrerunArgsFromStorage(blockConfig: BlockConfig, storageJson: string): unknown {\n if (blockConfig.modelAPIVersion !== 2) {\n throw new Error('derivePrerunArgsFromStorage is only supported for model API version 2');\n }\n\n try {\n const result = executeSingleLambda(\n this.quickJs,\n PRERUN_ARGS_DERIVE_HANDLE,\n extractCodeWithInfo(blockConfig),\n storageJson,\n ) as ArgsDeriveResult;\n\n if (result.error !== undefined) {\n // Return undefined if derivation fails (skip block in staging)\n return undefined;\n }\n return result.value;\n } catch {\n // Return undefined if derivation fails (skip block in staging)\n return undefined;\n }\n }\n\n private calculateEnrichmentTargets(req: EnrichmentTargetsRequest): PlRef[] | undefined {\n const blockConfig = req.blockConfig();\n if (blockConfig.enrichmentTargets === undefined) return undefined;\n const args = req.args();\n const result = executeSingleLambda(this.quickJs, blockConfig.enrichmentTargets, extractCodeWithInfo(blockConfig), args) as PlRef[];\n return result;\n }\n\n public getEnrichmentTargets(blockConfig: () => BlockConfig, args: () => unknown, key?: { argsRid: ResourceId; blockPackRid: ResourceId }): PlRef[] | undefined {\n const req = { blockConfig, args };\n if (key === undefined)\n return this.calculateEnrichmentTargets(req);\n const cacheKey = `${key.argsRid}:${key.blockPackRid}`;\n return this.enrichmentTargetsCache.memo(cacheKey, { context: req }).value;\n }\n\n // =============================================================================\n // VM-based Storage Operations\n // =============================================================================\n\n /**\n * Normalizes raw blockStorage data using VM-based transformation.\n * This calls the model's `__pl_storage_normalize` callback which:\n * - Handles BlockStorage format (with discriminator)\n * - Handles legacy V1/V2 format ({ args, uiState })\n * - Handles raw V3 state\n *\n * @param blockConfig The block configuration (provides the model code)\n * @param rawStorage Raw storage data from resource tree (may be JSON string or object)\n * @returns Object with { storage, state } or undefined if transformation fails\n */\n public normalizeStorageInVM(blockConfig: BlockConfig, rawStorage: unknown): NormalizeStorageResult | undefined {\n try {\n const result = executeSingleLambda(\n this.quickJs,\n STORAGE_NORMALIZE_HANDLE,\n extractCodeWithInfo(blockConfig),\n rawStorage,\n ) as NormalizeStorageResult;\n return result;\n } catch (e) {\n console.warn('[ProjectHelper.normalizeStorageInVM] Storage normalization failed:', e);\n return undefined;\n }\n }\n\n /**\n * Creates initial BlockStorage for a new block using VM-based transformation.\n * This calls the '__pl_storage_initial' callback registered by DataModel which:\n * - Gets initial data from DataModel.getDefaultData()\n * - Creates BlockStorage with correct version\n *\n * @param blockConfig The block configuration (provides the model code)\n * @returns Initial storage as JSON string\n * @throws Error if storage creation fails\n */\n public getInitialStorageInVM(blockConfig: BlockConfig): string {\n try {\n const result = executeSingleLambda(\n this.quickJs,\n INITIAL_STORAGE_HANDLE,\n extractCodeWithInfo(blockConfig),\n ) as string;\n return result;\n } catch (e) {\n console.error('[ProjectHelper.getInitialStorageInVM] Initial storage creation failed:', e);\n throw new Error(`Block initial storage creation failed: ${e}`);\n }\n }\n\n /**\n * Applies a state update using VM-based transformation.\n * This calls the model's `__pl_storage_applyUpdate` callback which:\n * - Normalizes current storage\n * - Updates state while preserving other fields (version, plugins)\n * - Returns the updated storage as JSON string\n *\n * @param blockConfig The block configuration (provides the model code)\n * @param currentStorageJson Current storage as JSON string (must be defined)\n * @param newState New state from developer\n * @returns Updated storage as JSON string\n * @throws Error if storage update fails\n */\n public applyStorageUpdateInVM(blockConfig: BlockConfig, currentStorageJson: string, payload: { operation: string; value: unknown }): string {\n try {\n const result = executeSingleLambda(\n this.quickJs,\n STORAGE_APPLY_UPDATE_HANDLE,\n extractCodeWithInfo(blockConfig),\n currentStorageJson,\n payload,\n ) as string;\n return result;\n } catch (e) {\n console.error('[ProjectHelper.applyStorageUpdateInVM] Storage update failed:', e);\n throw new Error(`Block storage update failed: ${e}`);\n }\n }\n\n /**\n * Gets storage info from raw storage data by calling the VM's __pl_storage_getInfo callback.\n * Returns structured 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 info as JSON string (e.g., '{\"dataVersion\": 1}')\n */\n public getStorageInfoInVM(blockConfig: BlockConfig, rawStorageJson: string | undefined): string | undefined {\n try {\n const result = executeSingleLambda(\n this.quickJs,\n STORAGE_GET_INFO_HANDLE,\n extractCodeWithInfo(blockConfig),\n rawStorageJson,\n ) as string;\n return result;\n } catch (e) {\n console.error('[ProjectHelper.getStorageInfoInVM] Get storage info failed:', e);\n return undefined;\n }\n }\n\n // =============================================================================\n // Block State Migrations\n // =============================================================================\n\n /**\n * Runs block state migrations via VM-based transformation.\n * This calls the model's `__pl_storage_migrate` callback which:\n * - Normalizes current storage to get state and version\n * - Calculates target version from number of registered migrations\n * - Runs all necessary migrations sequentially\n * - Returns new storage with updated state and version\n *\n * The middle layer doesn't need to know about dataVersion or storage internals.\n * All migration logic is encapsulated in the model.\n *\n * @param blockConfig The NEW block configuration (provides the model code with migrations)\n * @param currentStorageJson Current storage as JSON string (or undefined)\n * @returns MigrationResult with new storage or skip/error info\n */\n public migrateStorageInVM(blockConfig: BlockConfig, currentStorageJson: string | undefined): MigrationResult {\n try {\n const result = executeSingleLambda(\n this.quickJs,\n STORAGE_MIGRATE_HANDLE,\n extractCodeWithInfo(blockConfig),\n currentStorageJson,\n ) as MigrationResult;\n return result;\n } catch (e) {\n console.error('[ProjectHelper.migrateStorageInVM] Migration failed:', e);\n return { error: `VM execution failed: ${e}` };\n }\n }\n}\n"],"names":["LRUCache","executeSingleLambda","extractCodeWithInfo","ensureError"],"mappings":"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"}
@@ -1,14 +1,123 @@
1
- import { type BlockConfig, type PlRef } from '@platforma-sdk/model';
1
+ import type { ResultOrError, BlockConfig, PlRef } from '@platforma-sdk/model';
2
2
  import type { QuickJSWASMModule } from 'quickjs-emscripten';
3
3
  import type { ResourceId } from '@milaboratories/pl-client';
4
+ /**
5
+ * Result of VM-based storage normalization
6
+ */
7
+ interface NormalizeStorageResult {
8
+ storage: unknown;
9
+ data: unknown;
10
+ }
11
+ /**
12
+ * Result of VM-based storage migration.
13
+ * Returned by migrateStorageInVM().
14
+ *
15
+ * - Error result: { error: string } - serious failure (no context, etc.)
16
+ * - Success result: { newStorageJson: string, info: string, warn?: string } - migration succeeded or reset to initial
17
+ */
18
+ export type MigrationResult = {
19
+ error: string;
20
+ } | {
21
+ error?: undefined;
22
+ newStorageJson: string;
23
+ info: string;
24
+ warn?: string;
25
+ };
4
26
  export declare class ProjectHelper {
5
27
  private readonly quickJs;
6
28
  private readonly enrichmentTargetsCache;
7
29
  constructor(quickJs: QuickJSWASMModule);
30
+ /**
31
+ * Derives args directly from storage JSON using VM callback.
32
+ * The VM extracts data from storage and calls the block's args() function.
33
+ *
34
+ * This allows the middle layer to work only with storage JSON,
35
+ * without needing to know the underlying data structure.
36
+ *
37
+ * @param blockConfig The block configuration (provides the model code)
38
+ * @param storageJson Storage as JSON string
39
+ * @returns The derived args object, or error if derivation fails
40
+ */
41
+ deriveArgsFromStorage(blockConfig: BlockConfig, storageJson: string): ResultOrError<unknown>;
42
+ /**
43
+ * Derives prerunArgs directly from storage JSON using VM callback.
44
+ * Falls back to args() if prerunArgs is not defined in the block model.
45
+ *
46
+ * @param blockConfig The block configuration (provides the model code)
47
+ * @param storageJson Storage as JSON string
48
+ * @returns The derived prerunArgs, or undefined if derivation fails
49
+ */
50
+ derivePrerunArgsFromStorage(blockConfig: BlockConfig, storageJson: string): unknown;
8
51
  private calculateEnrichmentTargets;
9
52
  getEnrichmentTargets(blockConfig: () => BlockConfig, args: () => unknown, key?: {
10
53
  argsRid: ResourceId;
11
54
  blockPackRid: ResourceId;
12
55
  }): PlRef[] | undefined;
56
+ /**
57
+ * Normalizes raw blockStorage data using VM-based transformation.
58
+ * This calls the model's `__pl_storage_normalize` callback which:
59
+ * - Handles BlockStorage format (with discriminator)
60
+ * - Handles legacy V1/V2 format ({ args, uiState })
61
+ * - Handles raw V3 state
62
+ *
63
+ * @param blockConfig The block configuration (provides the model code)
64
+ * @param rawStorage Raw storage data from resource tree (may be JSON string or object)
65
+ * @returns Object with { storage, state } or undefined if transformation fails
66
+ */
67
+ normalizeStorageInVM(blockConfig: BlockConfig, rawStorage: unknown): NormalizeStorageResult | undefined;
68
+ /**
69
+ * Creates initial BlockStorage for a new block using VM-based transformation.
70
+ * This calls the '__pl_storage_initial' callback registered by DataModel which:
71
+ * - Gets initial data from DataModel.getDefaultData()
72
+ * - Creates BlockStorage with correct version
73
+ *
74
+ * @param blockConfig The block configuration (provides the model code)
75
+ * @returns Initial storage as JSON string
76
+ * @throws Error if storage creation fails
77
+ */
78
+ getInitialStorageInVM(blockConfig: BlockConfig): string;
79
+ /**
80
+ * Applies a state update using VM-based transformation.
81
+ * This calls the model's `__pl_storage_applyUpdate` callback which:
82
+ * - Normalizes current storage
83
+ * - Updates state while preserving other fields (version, plugins)
84
+ * - Returns the updated storage as JSON string
85
+ *
86
+ * @param blockConfig The block configuration (provides the model code)
87
+ * @param currentStorageJson Current storage as JSON string (must be defined)
88
+ * @param newState New state from developer
89
+ * @returns Updated storage as JSON string
90
+ * @throws Error if storage update fails
91
+ */
92
+ applyStorageUpdateInVM(blockConfig: BlockConfig, currentStorageJson: string, payload: {
93
+ operation: string;
94
+ value: unknown;
95
+ }): string;
96
+ /**
97
+ * Gets storage info from raw storage data by calling the VM's __pl_storage_getInfo callback.
98
+ * Returns structured info about the storage (e.g., dataVersion).
99
+ *
100
+ * @param blockConfig Block configuration
101
+ * @param rawStorageJson Raw storage as JSON string (or undefined)
102
+ * @returns Storage info as JSON string (e.g., '{"dataVersion": 1}')
103
+ */
104
+ getStorageInfoInVM(blockConfig: BlockConfig, rawStorageJson: string | undefined): string | undefined;
105
+ /**
106
+ * Runs block state migrations via VM-based transformation.
107
+ * This calls the model's `__pl_storage_migrate` callback which:
108
+ * - Normalizes current storage to get state and version
109
+ * - Calculates target version from number of registered migrations
110
+ * - Runs all necessary migrations sequentially
111
+ * - Returns new storage with updated state and version
112
+ *
113
+ * The middle layer doesn't need to know about dataVersion or storage internals.
114
+ * All migration logic is encapsulated in the model.
115
+ *
116
+ * @param blockConfig The NEW block configuration (provides the model code with migrations)
117
+ * @param currentStorageJson Current storage as JSON string (or undefined)
118
+ * @returns MigrationResult with new storage or skip/error info
119
+ */
120
+ migrateStorageInVM(blockConfig: BlockConfig, currentStorageJson: string | undefined): MigrationResult;
13
121
  }
122
+ export {};
14
123
  //# sourceMappingURL=project_helper.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"project_helper.d.ts","sourceRoot":"","sources":["../../src/model/project_helper.ts"],"names":[],"mappings":"AAAA,OAAO,EAAuB,KAAK,WAAW,EAAE,KAAK,KAAK,EAAE,MAAM,sBAAsB,CAAC;AAEzF,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAE5D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAC;AAW5D,qBAAa,aAAa;IAQZ,OAAO,CAAC,QAAQ,CAAC,OAAO;IAPpC,OAAO,CAAC,QAAQ,CAAC,sBAAsB,CAKpC;gBAE0B,OAAO,EAAE,iBAAiB;IAEvD,OAAO,CAAC,0BAA0B;IAQ3B,oBAAoB,CAAC,WAAW,EAAE,MAAM,WAAW,EAAE,IAAI,EAAE,MAAM,OAAO,EAAE,GAAG,CAAC,EAAE;QAAE,OAAO,EAAE,UAAU,CAAC;QAAC,YAAY,EAAE,UAAU,CAAA;KAAE,GAAG,KAAK,EAAE,GAAG,SAAS;CAO/J"}
1
+ {"version":3,"file":"project_helper.d.ts","sourceRoot":"","sources":["../../src/model/project_helper.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,WAAW,EAAE,KAAK,EAAsB,MAAM,sBAAsB,CAAC;AAGlG,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAE5D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAC;AAW5D;;GAEG;AACH,UAAU,sBAAsB;IAC9B,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,EAAE,OAAO,CAAC;CACf;AAED;;;;;;GAMG;AACH,MAAM,MAAM,eAAe,GACvB;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,GACjB;IAAE,KAAK,CAAC,EAAE,SAAS,CAAC;IAAC,cAAc,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAqB/E,qBAAa,aAAa;IAQZ,OAAO,CAAC,QAAQ,CAAC,OAAO;IAPpC,OAAO,CAAC,QAAQ,CAAC,sBAAsB,CAKpC;gBAE0B,OAAO,EAAE,iBAAiB;IAMvD;;;;;;;;;;OAUG;IACI,qBAAqB,CAAC,WAAW,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,GAAG,aAAa,CAAC,OAAO,CAAC;IAsBnG;;;;;;;OAOG;IACI,2BAA2B,CAAC,WAAW,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO;IAwB1F,OAAO,CAAC,0BAA0B;IAQ3B,oBAAoB,CAAC,WAAW,EAAE,MAAM,WAAW,EAAE,IAAI,EAAE,MAAM,OAAO,EAAE,GAAG,CAAC,EAAE;QAAE,OAAO,EAAE,UAAU,CAAC;QAAC,YAAY,EAAE,UAAU,CAAA;KAAE,GAAG,KAAK,EAAE,GAAG,SAAS;IAY9J;;;;;;;;;;OAUG;IACI,oBAAoB,CAAC,WAAW,EAAE,WAAW,EAAE,UAAU,EAAE,OAAO,GAAG,sBAAsB,GAAG,SAAS;IAe9G;;;;;;;;;OASG;IACI,qBAAqB,CAAC,WAAW,EAAE,WAAW,GAAG,MAAM;IAc9D;;;;;;;;;;;;OAYG;IACI,sBAAsB,CAAC,WAAW,EAAE,WAAW,EAAE,kBAAkB,EAAE,MAAM,EAAE,OAAO,EAAE;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,OAAO,CAAA;KAAE,GAAG,MAAM;IAgB3I;;;;;;;OAOG;IACI,kBAAkB,CAAC,WAAW,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS;IAmB3G;;;;;;;;;;;;;;OAcG;IACI,kBAAkB,CAAC,WAAW,EAAE,WAAW,EAAE,kBAAkB,EAAE,MAAM,GAAG,SAAS,GAAG,eAAe;CAc7G"}
@@ -1,7 +1,17 @@
1
- import { extractCodeWithInfo } from '@platforma-sdk/model';
1
+ import { extractCodeWithInfo, ensureError } from '@platforma-sdk/model';
2
2
  import { LRUCache } from 'lru-cache';
3
3
  import { executeSingleLambda } from '../js_render/index.js';
4
4
 
5
+ // Internal lambda handles for storage operations (registered by SDK's block_storage_vm.ts)
6
+ // All callbacks are prefixed with `__pl_` to indicate internal SDK use
7
+ const STORAGE_NORMALIZE_HANDLE = { __renderLambda: true, handle: '__pl_storage_normalize' };
8
+ const STORAGE_APPLY_UPDATE_HANDLE = { __renderLambda: true, handle: '__pl_storage_applyUpdate' };
9
+ const STORAGE_GET_INFO_HANDLE = { __renderLambda: true, handle: '__pl_storage_getInfo' };
10
+ const STORAGE_MIGRATE_HANDLE = { __renderLambda: true, handle: '__pl_storage_migrate' };
11
+ const ARGS_DERIVE_HANDLE = { __renderLambda: true, handle: '__pl_args_derive' };
12
+ const PRERUN_ARGS_DERIVE_HANDLE = { __renderLambda: true, handle: '__pl_prerunArgs_derive' };
13
+ // Registered by DataModel.registerCallbacks()
14
+ const INITIAL_STORAGE_HANDLE = { __renderLambda: true, handle: '__pl_storage_initial' };
5
15
  class ProjectHelper {
6
16
  quickJs;
7
17
  enrichmentTargetsCache = new LRUCache({
@@ -13,6 +23,60 @@ class ProjectHelper {
13
23
  constructor(quickJs) {
14
24
  this.quickJs = quickJs;
15
25
  }
26
+ // =============================================================================
27
+ // Args Derivation from Storage (V3+)
28
+ // =============================================================================
29
+ /**
30
+ * Derives args directly from storage JSON using VM callback.
31
+ * The VM extracts data from storage and calls the block's args() function.
32
+ *
33
+ * This allows the middle layer to work only with storage JSON,
34
+ * without needing to know the underlying data structure.
35
+ *
36
+ * @param blockConfig The block configuration (provides the model code)
37
+ * @param storageJson Storage as JSON string
38
+ * @returns The derived args object, or error if derivation fails
39
+ */
40
+ deriveArgsFromStorage(blockConfig, storageJson) {
41
+ if (blockConfig.modelAPIVersion !== 2) {
42
+ return { error: new Error('deriveArgsFromStorage is only supported for model API version 2') };
43
+ }
44
+ try {
45
+ const result = executeSingleLambda(this.quickJs, ARGS_DERIVE_HANDLE, extractCodeWithInfo(blockConfig), storageJson);
46
+ if (result.error !== undefined) {
47
+ return { error: new Error(result.error) };
48
+ }
49
+ return { value: result.value };
50
+ }
51
+ catch (e) {
52
+ return { error: new Error('Args derivation from storage failed', { cause: ensureError(e) }) };
53
+ }
54
+ }
55
+ /**
56
+ * Derives prerunArgs directly from storage JSON using VM callback.
57
+ * Falls back to args() if prerunArgs is not defined in the block model.
58
+ *
59
+ * @param blockConfig The block configuration (provides the model code)
60
+ * @param storageJson Storage as JSON string
61
+ * @returns The derived prerunArgs, or undefined if derivation fails
62
+ */
63
+ derivePrerunArgsFromStorage(blockConfig, storageJson) {
64
+ if (blockConfig.modelAPIVersion !== 2) {
65
+ throw new Error('derivePrerunArgsFromStorage is only supported for model API version 2');
66
+ }
67
+ try {
68
+ const result = executeSingleLambda(this.quickJs, PRERUN_ARGS_DERIVE_HANDLE, extractCodeWithInfo(blockConfig), storageJson);
69
+ if (result.error !== undefined) {
70
+ // Return undefined if derivation fails (skip block in staging)
71
+ return undefined;
72
+ }
73
+ return result.value;
74
+ }
75
+ catch {
76
+ // Return undefined if derivation fails (skip block in staging)
77
+ return undefined;
78
+ }
79
+ }
16
80
  calculateEnrichmentTargets(req) {
17
81
  const blockConfig = req.blockConfig();
18
82
  if (blockConfig.enrichmentTargets === undefined)
@@ -28,6 +92,119 @@ class ProjectHelper {
28
92
  const cacheKey = `${key.argsRid}:${key.blockPackRid}`;
29
93
  return this.enrichmentTargetsCache.memo(cacheKey, { context: req }).value;
30
94
  }
95
+ // =============================================================================
96
+ // VM-based Storage Operations
97
+ // =============================================================================
98
+ /**
99
+ * Normalizes raw blockStorage data using VM-based transformation.
100
+ * This calls the model's `__pl_storage_normalize` callback which:
101
+ * - Handles BlockStorage format (with discriminator)
102
+ * - Handles legacy V1/V2 format ({ args, uiState })
103
+ * - Handles raw V3 state
104
+ *
105
+ * @param blockConfig The block configuration (provides the model code)
106
+ * @param rawStorage Raw storage data from resource tree (may be JSON string or object)
107
+ * @returns Object with { storage, state } or undefined if transformation fails
108
+ */
109
+ normalizeStorageInVM(blockConfig, rawStorage) {
110
+ try {
111
+ const result = executeSingleLambda(this.quickJs, STORAGE_NORMALIZE_HANDLE, extractCodeWithInfo(blockConfig), rawStorage);
112
+ return result;
113
+ }
114
+ catch (e) {
115
+ console.warn('[ProjectHelper.normalizeStorageInVM] Storage normalization failed:', e);
116
+ return undefined;
117
+ }
118
+ }
119
+ /**
120
+ * Creates initial BlockStorage for a new block using VM-based transformation.
121
+ * This calls the '__pl_storage_initial' callback registered by DataModel which:
122
+ * - Gets initial data from DataModel.getDefaultData()
123
+ * - Creates BlockStorage with correct version
124
+ *
125
+ * @param blockConfig The block configuration (provides the model code)
126
+ * @returns Initial storage as JSON string
127
+ * @throws Error if storage creation fails
128
+ */
129
+ getInitialStorageInVM(blockConfig) {
130
+ try {
131
+ const result = executeSingleLambda(this.quickJs, INITIAL_STORAGE_HANDLE, extractCodeWithInfo(blockConfig));
132
+ return result;
133
+ }
134
+ catch (e) {
135
+ console.error('[ProjectHelper.getInitialStorageInVM] Initial storage creation failed:', e);
136
+ throw new Error(`Block initial storage creation failed: ${e}`);
137
+ }
138
+ }
139
+ /**
140
+ * Applies a state update using VM-based transformation.
141
+ * This calls the model's `__pl_storage_applyUpdate` callback which:
142
+ * - Normalizes current storage
143
+ * - Updates state while preserving other fields (version, plugins)
144
+ * - Returns the updated storage as JSON string
145
+ *
146
+ * @param blockConfig The block configuration (provides the model code)
147
+ * @param currentStorageJson Current storage as JSON string (must be defined)
148
+ * @param newState New state from developer
149
+ * @returns Updated storage as JSON string
150
+ * @throws Error if storage update fails
151
+ */
152
+ applyStorageUpdateInVM(blockConfig, currentStorageJson, payload) {
153
+ try {
154
+ const result = executeSingleLambda(this.quickJs, STORAGE_APPLY_UPDATE_HANDLE, extractCodeWithInfo(blockConfig), currentStorageJson, payload);
155
+ return result;
156
+ }
157
+ catch (e) {
158
+ console.error('[ProjectHelper.applyStorageUpdateInVM] Storage update failed:', e);
159
+ throw new Error(`Block storage update failed: ${e}`);
160
+ }
161
+ }
162
+ /**
163
+ * Gets storage info from raw storage data by calling the VM's __pl_storage_getInfo callback.
164
+ * Returns structured info about the storage (e.g., dataVersion).
165
+ *
166
+ * @param blockConfig Block configuration
167
+ * @param rawStorageJson Raw storage as JSON string (or undefined)
168
+ * @returns Storage info as JSON string (e.g., '{"dataVersion": 1}')
169
+ */
170
+ getStorageInfoInVM(blockConfig, rawStorageJson) {
171
+ try {
172
+ const result = executeSingleLambda(this.quickJs, STORAGE_GET_INFO_HANDLE, extractCodeWithInfo(blockConfig), rawStorageJson);
173
+ return result;
174
+ }
175
+ catch (e) {
176
+ console.error('[ProjectHelper.getStorageInfoInVM] Get storage info failed:', e);
177
+ return undefined;
178
+ }
179
+ }
180
+ // =============================================================================
181
+ // Block State Migrations
182
+ // =============================================================================
183
+ /**
184
+ * Runs block state migrations via VM-based transformation.
185
+ * This calls the model's `__pl_storage_migrate` callback which:
186
+ * - Normalizes current storage to get state and version
187
+ * - Calculates target version from number of registered migrations
188
+ * - Runs all necessary migrations sequentially
189
+ * - Returns new storage with updated state and version
190
+ *
191
+ * The middle layer doesn't need to know about dataVersion or storage internals.
192
+ * All migration logic is encapsulated in the model.
193
+ *
194
+ * @param blockConfig The NEW block configuration (provides the model code with migrations)
195
+ * @param currentStorageJson Current storage as JSON string (or undefined)
196
+ * @returns MigrationResult with new storage or skip/error info
197
+ */
198
+ migrateStorageInVM(blockConfig, currentStorageJson) {
199
+ try {
200
+ const result = executeSingleLambda(this.quickJs, STORAGE_MIGRATE_HANDLE, extractCodeWithInfo(blockConfig), currentStorageJson);
201
+ return result;
202
+ }
203
+ catch (e) {
204
+ console.error('[ProjectHelper.migrateStorageInVM] Migration failed:', e);
205
+ return { error: `VM execution failed: ${e}` };
206
+ }
207
+ }
31
208
  }
32
209
 
33
210
  export { ProjectHelper };
@@ -1 +1 @@
1
- {"version":3,"file":"project_helper.js","sources":["../../src/model/project_helper.ts"],"sourcesContent":["import { extractCodeWithInfo, type BlockConfig, type PlRef } from '@platforma-sdk/model';\nimport { LRUCache } from 'lru-cache';\nimport type { QuickJSWASMModule } from 'quickjs-emscripten';\nimport { executeSingleLambda } from '../js_render';\nimport type { ResourceId } from '@milaboratories/pl-client';\n\ntype EnrichmentTargetsRequest = {\n blockConfig: () => BlockConfig;\n args: () => unknown;\n};\n\ntype EnrichmentTargetsValue = {\n value: PlRef[] | undefined;\n};\n\nexport class ProjectHelper {\n private readonly enrichmentTargetsCache = new LRUCache<string, EnrichmentTargetsValue, EnrichmentTargetsRequest>({\n max: 256,\n memoMethod: (_key, _value, { context }) => {\n return { value: this.calculateEnrichmentTargets(context) };\n },\n });\n\n constructor(private readonly quickJs: QuickJSWASMModule) {}\n\n private calculateEnrichmentTargets(req: EnrichmentTargetsRequest): PlRef[] | undefined {\n const blockConfig = req.blockConfig();\n if (blockConfig.enrichmentTargets === undefined) return undefined;\n const args = req.args();\n const result = executeSingleLambda(this.quickJs, blockConfig.enrichmentTargets, extractCodeWithInfo(blockConfig), args) as PlRef[];\n return result;\n }\n\n public getEnrichmentTargets(blockConfig: () => BlockConfig, args: () => unknown, key?: { argsRid: ResourceId; blockPackRid: ResourceId }): PlRef[] | undefined {\n const req = { blockConfig, args };\n if (key === undefined)\n return this.calculateEnrichmentTargets(req);\n const cacheKey = `${key.argsRid}:${key.blockPackRid}`;\n return this.enrichmentTargetsCache.memo(cacheKey, { context: req }).value;\n }\n}\n"],"names":[],"mappings":";;;;MAea,aAAa,CAAA;AAQK,IAAA,OAAA;IAPZ,sBAAsB,GAAG,IAAI,QAAQ,CAA2D;AAC/G,QAAA,GAAG,EAAE,GAAG;QACR,UAAU,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,OAAO,EAAE,KAAI;YACxC,OAAO,EAAE,KAAK,EAAE,IAAI,CAAC,0BAA0B,CAAC,OAAO,CAAC,EAAE;QAC5D,CAAC;AACF,KAAA,CAAC;AAEF,IAAA,WAAA,CAA6B,OAA0B,EAAA;QAA1B,IAAA,CAAA,OAAO,GAAP,OAAO;IAAsB;AAElD,IAAA,0BAA0B,CAAC,GAA6B,EAAA;AAC9D,QAAA,MAAM,WAAW,GAAG,GAAG,CAAC,WAAW,EAAE;AACrC,QAAA,IAAI,WAAW,CAAC,iBAAiB,KAAK,SAAS;AAAE,YAAA,OAAO,SAAS;AACjE,QAAA,MAAM,IAAI,GAAG,GAAG,CAAC,IAAI,EAAE;AACvB,QAAA,MAAM,MAAM,GAAG,mBAAmB,CAAC,IAAI,CAAC,OAAO,EAAE,WAAW,CAAC,iBAAiB,EAAE,mBAAmB,CAAC,WAAW,CAAC,EAAE,IAAI,CAAY;AAClI,QAAA,OAAO,MAAM;IACf;AAEO,IAAA,oBAAoB,CAAC,WAA8B,EAAE,IAAmB,EAAE,GAAuD,EAAA;AACtI,QAAA,MAAM,GAAG,GAAG,EAAE,WAAW,EAAE,IAAI,EAAE;QACjC,IAAI,GAAG,KAAK,SAAS;AACnB,YAAA,OAAO,IAAI,CAAC,0BAA0B,CAAC,GAAG,CAAC;QAC7C,MAAM,QAAQ,GAAG,CAAA,EAAG,GAAG,CAAC,OAAO,CAAA,CAAA,EAAI,GAAG,CAAC,YAAY,CAAA,CAAE;AACrD,QAAA,OAAO,IAAI,CAAC,sBAAsB,CAAC,IAAI,CAAC,QAAQ,EAAE,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC,CAAC,KAAK;IAC3E;AACD;;;;"}
1
+ {"version":3,"file":"project_helper.js","sources":["../../src/model/project_helper.ts"],"sourcesContent":["import type { ResultOrError, BlockConfig, PlRef, ConfigRenderLambda } from '@platforma-sdk/model';\nimport { extractCodeWithInfo, ensureError } from '@platforma-sdk/model';\nimport { LRUCache } from 'lru-cache';\nimport type { QuickJSWASMModule } from 'quickjs-emscripten';\nimport { executeSingleLambda } from '../js_render';\nimport type { ResourceId } from '@milaboratories/pl-client';\n\ntype EnrichmentTargetsRequest = {\n blockConfig: () => BlockConfig;\n args: () => unknown;\n};\n\ntype EnrichmentTargetsValue = {\n value: PlRef[] | undefined;\n};\n\n/**\n * Result of VM-based storage normalization\n */\ninterface NormalizeStorageResult {\n storage: unknown;\n data: unknown;\n}\n\n/**\n * Result of VM-based storage migration.\n * Returned by migrateStorageInVM().\n *\n * - Error result: { error: string } - serious failure (no context, etc.)\n * - Success result: { newStorageJson: string, info: string, warn?: string } - migration succeeded or reset to initial\n */\nexport type MigrationResult =\n | { error: string }\n | { error?: undefined; newStorageJson: string; info: string; warn?: string };\n\n// Internal lambda handles for storage operations (registered by SDK's block_storage_vm.ts)\n// All callbacks are prefixed with `__pl_` to indicate internal SDK use\nconst STORAGE_NORMALIZE_HANDLE: ConfigRenderLambda = { __renderLambda: true, handle: '__pl_storage_normalize' };\nconst STORAGE_APPLY_UPDATE_HANDLE: ConfigRenderLambda = { __renderLambda: true, handle: '__pl_storage_applyUpdate' };\nconst STORAGE_GET_INFO_HANDLE: ConfigRenderLambda = { __renderLambda: true, handle: '__pl_storage_getInfo' };\nconst STORAGE_MIGRATE_HANDLE: ConfigRenderLambda = { __renderLambda: true, handle: '__pl_storage_migrate' };\nconst ARGS_DERIVE_HANDLE: ConfigRenderLambda = { __renderLambda: true, handle: '__pl_args_derive' };\nconst PRERUN_ARGS_DERIVE_HANDLE: ConfigRenderLambda = { __renderLambda: true, handle: '__pl_prerunArgs_derive' };\n// Registered by DataModel.registerCallbacks()\nconst INITIAL_STORAGE_HANDLE: ConfigRenderLambda = { __renderLambda: true, handle: '__pl_storage_initial' };\n\n/**\n * Result of args derivation from storage.\n * Returned by __pl_args_derive and __pl_prerunArgs_derive VM callbacks.\n */\ntype ArgsDeriveResult =\n | { error: string }\n | { error?: undefined; value: unknown };\n\nexport class ProjectHelper {\n private readonly enrichmentTargetsCache = new LRUCache<string, EnrichmentTargetsValue, EnrichmentTargetsRequest>({\n max: 256,\n memoMethod: (_key, _value, { context }) => {\n return { value: this.calculateEnrichmentTargets(context) };\n },\n });\n\n constructor(private readonly quickJs: QuickJSWASMModule) {}\n\n // =============================================================================\n // Args Derivation from Storage (V3+)\n // =============================================================================\n\n /**\n * Derives args directly from storage JSON using VM callback.\n * The VM extracts data from storage and calls the block's args() function.\n *\n * This allows the middle layer to work only with storage JSON,\n * without needing to know the underlying data structure.\n *\n * @param blockConfig The block configuration (provides the model code)\n * @param storageJson Storage as JSON string\n * @returns The derived args object, or error if derivation fails\n */\n public deriveArgsFromStorage(blockConfig: BlockConfig, storageJson: string): ResultOrError<unknown> {\n if (blockConfig.modelAPIVersion !== 2) {\n return { error: new Error('deriveArgsFromStorage is only supported for model API version 2') };\n }\n\n try {\n const result = executeSingleLambda(\n this.quickJs,\n ARGS_DERIVE_HANDLE,\n extractCodeWithInfo(blockConfig),\n storageJson,\n ) as ArgsDeriveResult;\n\n if (result.error !== undefined) {\n return { error: new Error(result.error) };\n }\n return { value: result.value };\n } catch (e) {\n return { error: new Error('Args derivation from storage failed', { cause: ensureError(e) }) };\n }\n }\n\n /**\n * Derives prerunArgs directly from storage JSON using VM callback.\n * Falls back to args() if prerunArgs is not defined in the block model.\n *\n * @param blockConfig The block configuration (provides the model code)\n * @param storageJson Storage as JSON string\n * @returns The derived prerunArgs, or undefined if derivation fails\n */\n public derivePrerunArgsFromStorage(blockConfig: BlockConfig, storageJson: string): unknown {\n if (blockConfig.modelAPIVersion !== 2) {\n throw new Error('derivePrerunArgsFromStorage is only supported for model API version 2');\n }\n\n try {\n const result = executeSingleLambda(\n this.quickJs,\n PRERUN_ARGS_DERIVE_HANDLE,\n extractCodeWithInfo(blockConfig),\n storageJson,\n ) as ArgsDeriveResult;\n\n if (result.error !== undefined) {\n // Return undefined if derivation fails (skip block in staging)\n return undefined;\n }\n return result.value;\n } catch {\n // Return undefined if derivation fails (skip block in staging)\n return undefined;\n }\n }\n\n private calculateEnrichmentTargets(req: EnrichmentTargetsRequest): PlRef[] | undefined {\n const blockConfig = req.blockConfig();\n if (blockConfig.enrichmentTargets === undefined) return undefined;\n const args = req.args();\n const result = executeSingleLambda(this.quickJs, blockConfig.enrichmentTargets, extractCodeWithInfo(blockConfig), args) as PlRef[];\n return result;\n }\n\n public getEnrichmentTargets(blockConfig: () => BlockConfig, args: () => unknown, key?: { argsRid: ResourceId; blockPackRid: ResourceId }): PlRef[] | undefined {\n const req = { blockConfig, args };\n if (key === undefined)\n return this.calculateEnrichmentTargets(req);\n const cacheKey = `${key.argsRid}:${key.blockPackRid}`;\n return this.enrichmentTargetsCache.memo(cacheKey, { context: req }).value;\n }\n\n // =============================================================================\n // VM-based Storage Operations\n // =============================================================================\n\n /**\n * Normalizes raw blockStorage data using VM-based transformation.\n * This calls the model's `__pl_storage_normalize` callback which:\n * - Handles BlockStorage format (with discriminator)\n * - Handles legacy V1/V2 format ({ args, uiState })\n * - Handles raw V3 state\n *\n * @param blockConfig The block configuration (provides the model code)\n * @param rawStorage Raw storage data from resource tree (may be JSON string or object)\n * @returns Object with { storage, state } or undefined if transformation fails\n */\n public normalizeStorageInVM(blockConfig: BlockConfig, rawStorage: unknown): NormalizeStorageResult | undefined {\n try {\n const result = executeSingleLambda(\n this.quickJs,\n STORAGE_NORMALIZE_HANDLE,\n extractCodeWithInfo(blockConfig),\n rawStorage,\n ) as NormalizeStorageResult;\n return result;\n } catch (e) {\n console.warn('[ProjectHelper.normalizeStorageInVM] Storage normalization failed:', e);\n return undefined;\n }\n }\n\n /**\n * Creates initial BlockStorage for a new block using VM-based transformation.\n * This calls the '__pl_storage_initial' callback registered by DataModel which:\n * - Gets initial data from DataModel.getDefaultData()\n * - Creates BlockStorage with correct version\n *\n * @param blockConfig The block configuration (provides the model code)\n * @returns Initial storage as JSON string\n * @throws Error if storage creation fails\n */\n public getInitialStorageInVM(blockConfig: BlockConfig): string {\n try {\n const result = executeSingleLambda(\n this.quickJs,\n INITIAL_STORAGE_HANDLE,\n extractCodeWithInfo(blockConfig),\n ) as string;\n return result;\n } catch (e) {\n console.error('[ProjectHelper.getInitialStorageInVM] Initial storage creation failed:', e);\n throw new Error(`Block initial storage creation failed: ${e}`);\n }\n }\n\n /**\n * Applies a state update using VM-based transformation.\n * This calls the model's `__pl_storage_applyUpdate` callback which:\n * - Normalizes current storage\n * - Updates state while preserving other fields (version, plugins)\n * - Returns the updated storage as JSON string\n *\n * @param blockConfig The block configuration (provides the model code)\n * @param currentStorageJson Current storage as JSON string (must be defined)\n * @param newState New state from developer\n * @returns Updated storage as JSON string\n * @throws Error if storage update fails\n */\n public applyStorageUpdateInVM(blockConfig: BlockConfig, currentStorageJson: string, payload: { operation: string; value: unknown }): string {\n try {\n const result = executeSingleLambda(\n this.quickJs,\n STORAGE_APPLY_UPDATE_HANDLE,\n extractCodeWithInfo(blockConfig),\n currentStorageJson,\n payload,\n ) as string;\n return result;\n } catch (e) {\n console.error('[ProjectHelper.applyStorageUpdateInVM] Storage update failed:', e);\n throw new Error(`Block storage update failed: ${e}`);\n }\n }\n\n /**\n * Gets storage info from raw storage data by calling the VM's __pl_storage_getInfo callback.\n * Returns structured 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 info as JSON string (e.g., '{\"dataVersion\": 1}')\n */\n public getStorageInfoInVM(blockConfig: BlockConfig, rawStorageJson: string | undefined): string | undefined {\n try {\n const result = executeSingleLambda(\n this.quickJs,\n STORAGE_GET_INFO_HANDLE,\n extractCodeWithInfo(blockConfig),\n rawStorageJson,\n ) as string;\n return result;\n } catch (e) {\n console.error('[ProjectHelper.getStorageInfoInVM] Get storage info failed:', e);\n return undefined;\n }\n }\n\n // =============================================================================\n // Block State Migrations\n // =============================================================================\n\n /**\n * Runs block state migrations via VM-based transformation.\n * This calls the model's `__pl_storage_migrate` callback which:\n * - Normalizes current storage to get state and version\n * - Calculates target version from number of registered migrations\n * - Runs all necessary migrations sequentially\n * - Returns new storage with updated state and version\n *\n * The middle layer doesn't need to know about dataVersion or storage internals.\n * All migration logic is encapsulated in the model.\n *\n * @param blockConfig The NEW block configuration (provides the model code with migrations)\n * @param currentStorageJson Current storage as JSON string (or undefined)\n * @returns MigrationResult with new storage or skip/error info\n */\n public migrateStorageInVM(blockConfig: BlockConfig, currentStorageJson: string | undefined): MigrationResult {\n try {\n const result = executeSingleLambda(\n this.quickJs,\n STORAGE_MIGRATE_HANDLE,\n extractCodeWithInfo(blockConfig),\n currentStorageJson,\n ) as MigrationResult;\n return result;\n } catch (e) {\n console.error('[ProjectHelper.migrateStorageInVM] Migration failed:', e);\n return { error: `VM execution failed: ${e}` };\n }\n }\n}\n"],"names":[],"mappings":";;;;AAmCA;AACA;AACA,MAAM,wBAAwB,GAAuB,EAAE,cAAc,EAAE,IAAI,EAAE,MAAM,EAAE,wBAAwB,EAAE;AAC/G,MAAM,2BAA2B,GAAuB,EAAE,cAAc,EAAE,IAAI,EAAE,MAAM,EAAE,0BAA0B,EAAE;AACpH,MAAM,uBAAuB,GAAuB,EAAE,cAAc,EAAE,IAAI,EAAE,MAAM,EAAE,sBAAsB,EAAE;AAC5G,MAAM,sBAAsB,GAAuB,EAAE,cAAc,EAAE,IAAI,EAAE,MAAM,EAAE,sBAAsB,EAAE;AAC3G,MAAM,kBAAkB,GAAuB,EAAE,cAAc,EAAE,IAAI,EAAE,MAAM,EAAE,kBAAkB,EAAE;AACnG,MAAM,yBAAyB,GAAuB,EAAE,cAAc,EAAE,IAAI,EAAE,MAAM,EAAE,wBAAwB,EAAE;AAChH;AACA,MAAM,sBAAsB,GAAuB,EAAE,cAAc,EAAE,IAAI,EAAE,MAAM,EAAE,sBAAsB,EAAE;MAU9F,aAAa,CAAA;AAQK,IAAA,OAAA;IAPZ,sBAAsB,GAAG,IAAI,QAAQ,CAA2D;AAC/G,QAAA,GAAG,EAAE,GAAG;QACR,UAAU,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,OAAO,EAAE,KAAI;YACxC,OAAO,EAAE,KAAK,EAAE,IAAI,CAAC,0BAA0B,CAAC,OAAO,CAAC,EAAE;QAC5D,CAAC;AACF,KAAA,CAAC;AAEF,IAAA,WAAA,CAA6B,OAA0B,EAAA;QAA1B,IAAA,CAAA,OAAO,GAAP,OAAO;IAAsB;;;;AAM1D;;;;;;;;;;AAUG;IACI,qBAAqB,CAAC,WAAwB,EAAE,WAAmB,EAAA;AACxE,QAAA,IAAI,WAAW,CAAC,eAAe,KAAK,CAAC,EAAE;YACrC,OAAO,EAAE,KAAK,EAAE,IAAI,KAAK,CAAC,iEAAiE,CAAC,EAAE;QAChG;AAEA,QAAA,IAAI;AACF,YAAA,MAAM,MAAM,GAAG,mBAAmB,CAChC,IAAI,CAAC,OAAO,EACZ,kBAAkB,EAClB,mBAAmB,CAAC,WAAW,CAAC,EAChC,WAAW,CACQ;AAErB,YAAA,IAAI,MAAM,CAAC,KAAK,KAAK,SAAS,EAAE;gBAC9B,OAAO,EAAE,KAAK,EAAE,IAAI,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE;YAC3C;AACA,YAAA,OAAO,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE;QAChC;QAAE,OAAO,CAAC,EAAE;AACV,YAAA,OAAO,EAAE,KAAK,EAAE,IAAI,KAAK,CAAC,qCAAqC,EAAE,EAAE,KAAK,EAAE,WAAW,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE;QAC/F;IACF;AAEA;;;;;;;AAOG;IACI,2BAA2B,CAAC,WAAwB,EAAE,WAAmB,EAAA;AAC9E,QAAA,IAAI,WAAW,CAAC,eAAe,KAAK,CAAC,EAAE;AACrC,YAAA,MAAM,IAAI,KAAK,CAAC,uEAAuE,CAAC;QAC1F;AAEA,QAAA,IAAI;AACF,YAAA,MAAM,MAAM,GAAG,mBAAmB,CAChC,IAAI,CAAC,OAAO,EACZ,yBAAyB,EACzB,mBAAmB,CAAC,WAAW,CAAC,EAChC,WAAW,CACQ;AAErB,YAAA,IAAI,MAAM,CAAC,KAAK,KAAK,SAAS,EAAE;;AAE9B,gBAAA,OAAO,SAAS;YAClB;YACA,OAAO,MAAM,CAAC,KAAK;QACrB;AAAE,QAAA,MAAM;;AAEN,YAAA,OAAO,SAAS;QAClB;IACF;AAEQ,IAAA,0BAA0B,CAAC,GAA6B,EAAA;AAC9D,QAAA,MAAM,WAAW,GAAG,GAAG,CAAC,WAAW,EAAE;AACrC,QAAA,IAAI,WAAW,CAAC,iBAAiB,KAAK,SAAS;AAAE,YAAA,OAAO,SAAS;AACjE,QAAA,MAAM,IAAI,GAAG,GAAG,CAAC,IAAI,EAAE;AACvB,QAAA,MAAM,MAAM,GAAG,mBAAmB,CAAC,IAAI,CAAC,OAAO,EAAE,WAAW,CAAC,iBAAiB,EAAE,mBAAmB,CAAC,WAAW,CAAC,EAAE,IAAI,CAAY;AAClI,QAAA,OAAO,MAAM;IACf;AAEO,IAAA,oBAAoB,CAAC,WAA8B,EAAE,IAAmB,EAAE,GAAuD,EAAA;AACtI,QAAA,MAAM,GAAG,GAAG,EAAE,WAAW,EAAE,IAAI,EAAE;QACjC,IAAI,GAAG,KAAK,SAAS;AACnB,YAAA,OAAO,IAAI,CAAC,0BAA0B,CAAC,GAAG,CAAC;QAC7C,MAAM,QAAQ,GAAG,CAAA,EAAG,GAAG,CAAC,OAAO,CAAA,CAAA,EAAI,GAAG,CAAC,YAAY,CAAA,CAAE;AACrD,QAAA,OAAO,IAAI,CAAC,sBAAsB,CAAC,IAAI,CAAC,QAAQ,EAAE,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC,CAAC,KAAK;IAC3E;;;;AAMA;;;;;;;;;;AAUG;IACI,oBAAoB,CAAC,WAAwB,EAAE,UAAmB,EAAA;AACvE,QAAA,IAAI;AACF,YAAA,MAAM,MAAM,GAAG,mBAAmB,CAChC,IAAI,CAAC,OAAO,EACZ,wBAAwB,EACxB,mBAAmB,CAAC,WAAW,CAAC,EAChC,UAAU,CACe;AAC3B,YAAA,OAAO,MAAM;QACf;QAAE,OAAO,CAAC,EAAE;AACV,YAAA,OAAO,CAAC,IAAI,CAAC,oEAAoE,EAAE,CAAC,CAAC;AACrF,YAAA,OAAO,SAAS;QAClB;IACF;AAEA;;;;;;;;;AASG;AACI,IAAA,qBAAqB,CAAC,WAAwB,EAAA;AACnD,QAAA,IAAI;AACF,YAAA,MAAM,MAAM,GAAG,mBAAmB,CAChC,IAAI,CAAC,OAAO,EACZ,sBAAsB,EACtB,mBAAmB,CAAC,WAAW,CAAC,CACvB;AACX,YAAA,OAAO,MAAM;QACf;QAAE,OAAO,CAAC,EAAE;AACV,YAAA,OAAO,CAAC,KAAK,CAAC,wEAAwE,EAAE,CAAC,CAAC;AAC1F,YAAA,MAAM,IAAI,KAAK,CAAC,0CAA0C,CAAC,CAAA,CAAE,CAAC;QAChE;IACF;AAEA;;;;;;;;;;;;AAYG;AACI,IAAA,sBAAsB,CAAC,WAAwB,EAAE,kBAA0B,EAAE,OAA8C,EAAA;AAChI,QAAA,IAAI;AACF,YAAA,MAAM,MAAM,GAAG,mBAAmB,CAChC,IAAI,CAAC,OAAO,EACZ,2BAA2B,EAC3B,mBAAmB,CAAC,WAAW,CAAC,EAChC,kBAAkB,EAClB,OAAO,CACE;AACX,YAAA,OAAO,MAAM;QACf;QAAE,OAAO,CAAC,EAAE;AACV,YAAA,OAAO,CAAC,KAAK,CAAC,+DAA+D,EAAE,CAAC,CAAC;AACjF,YAAA,MAAM,IAAI,KAAK,CAAC,gCAAgC,CAAC,CAAA,CAAE,CAAC;QACtD;IACF;AAEA;;;;;;;AAOG;IACI,kBAAkB,CAAC,WAAwB,EAAE,cAAkC,EAAA;AACpF,QAAA,IAAI;AACF,YAAA,MAAM,MAAM,GAAG,mBAAmB,CAChC,IAAI,CAAC,OAAO,EACZ,uBAAuB,EACvB,mBAAmB,CAAC,WAAW,CAAC,EAChC,cAAc,CACL;AACX,YAAA,OAAO,MAAM;QACf;QAAE,OAAO,CAAC,EAAE;AACV,YAAA,OAAO,CAAC,KAAK,CAAC,6DAA6D,EAAE,CAAC,CAAC;AAC/E,YAAA,OAAO,SAAS;QAClB;IACF;;;;AAMA;;;;;;;;;;;;;;AAcG;IACI,kBAAkB,CAAC,WAAwB,EAAE,kBAAsC,EAAA;AACxF,QAAA,IAAI;AACF,YAAA,MAAM,MAAM,GAAG,mBAAmB,CAChC,IAAI,CAAC,OAAO,EACZ,sBAAsB,EACtB,mBAAmB,CAAC,WAAW,CAAC,EAChC,kBAAkB,CACA;AACpB,YAAA,OAAO,MAAM;QACf;QAAE,OAAO,CAAC,EAAE;AACV,YAAA,OAAO,CAAC,KAAK,CAAC,sDAAsD,EAAE,CAAC,CAAC;AACxE,YAAA,OAAO,EAAE,KAAK,EAAE,wBAAwB,CAAC,CAAA,CAAE,EAAE;QAC/C;IACF;AACD;;;;"}