@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.
- package/dist/index.cjs +58 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/js_render/computable_context.cjs +37 -7
- package/dist/js_render/computable_context.cjs.map +1 -1
- package/dist/js_render/computable_context.d.ts.map +1 -1
- package/dist/js_render/computable_context.js +37 -7
- package/dist/js_render/computable_context.js.map +1 -1
- package/dist/js_render/context.cjs +12 -4
- package/dist/js_render/context.cjs.map +1 -1
- package/dist/js_render/context.d.ts +9 -0
- package/dist/js_render/context.d.ts.map +1 -1
- package/dist/js_render/context.js +12 -4
- package/dist/js_render/context.js.map +1 -1
- package/dist/js_render/index.cjs +1 -1
- package/dist/js_render/index.cjs.map +1 -1
- package/dist/js_render/index.js +1 -1
- package/dist/js_render/index.js.map +1 -1
- package/dist/middle_layer/block.cjs +7 -8
- package/dist/middle_layer/block.cjs.map +1 -1
- package/dist/middle_layer/block.d.ts +4 -4
- package/dist/middle_layer/block.d.ts.map +1 -1
- package/dist/middle_layer/block.js +7 -8
- package/dist/middle_layer/block.js.map +1 -1
- package/dist/middle_layer/block_ctx.cjs +67 -13
- package/dist/middle_layer/block_ctx.cjs.map +1 -1
- package/dist/middle_layer/block_ctx.d.ts +4 -7
- package/dist/middle_layer/block_ctx.d.ts.map +1 -1
- package/dist/middle_layer/block_ctx.js +68 -14
- package/dist/middle_layer/block_ctx.js.map +1 -1
- package/dist/middle_layer/block_ctx_unsafe.cjs +10 -3
- package/dist/middle_layer/block_ctx_unsafe.cjs.map +1 -1
- package/dist/middle_layer/block_ctx_unsafe.d.ts +1 -1
- package/dist/middle_layer/block_ctx_unsafe.d.ts.map +1 -1
- package/dist/middle_layer/block_ctx_unsafe.js +10 -3
- package/dist/middle_layer/block_ctx_unsafe.js.map +1 -1
- package/dist/middle_layer/frontend_path.cjs +1 -0
- package/dist/middle_layer/frontend_path.cjs.map +1 -1
- package/dist/middle_layer/frontend_path.js +1 -0
- package/dist/middle_layer/frontend_path.js.map +1 -1
- package/dist/middle_layer/middle_layer.cjs +1 -0
- package/dist/middle_layer/middle_layer.cjs.map +1 -1
- package/dist/middle_layer/middle_layer.d.ts +1 -1
- package/dist/middle_layer/middle_layer.d.ts.map +1 -1
- package/dist/middle_layer/middle_layer.js +1 -0
- package/dist/middle_layer/middle_layer.js.map +1 -1
- package/dist/middle_layer/project.cjs +75 -28
- package/dist/middle_layer/project.cjs.map +1 -1
- package/dist/middle_layer/project.d.ts +34 -7
- package/dist/middle_layer/project.d.ts.map +1 -1
- package/dist/middle_layer/project.js +76 -29
- package/dist/middle_layer/project.js.map +1 -1
- package/dist/middle_layer/project_overview.cjs +32 -11
- package/dist/middle_layer/project_overview.cjs.map +1 -1
- package/dist/middle_layer/project_overview.d.ts.map +1 -1
- package/dist/middle_layer/project_overview.js +32 -11
- package/dist/middle_layer/project_overview.js.map +1 -1
- package/dist/middle_layer/render.cjs +1 -1
- package/dist/middle_layer/render.cjs.map +1 -1
- package/dist/middle_layer/render.js +1 -1
- package/dist/middle_layer/render.js.map +1 -1
- package/dist/middle_layer/render.test.d.ts.map +1 -1
- package/dist/model/block_storage_helper.cjs +210 -0
- package/dist/model/block_storage_helper.cjs.map +1 -0
- package/dist/model/block_storage_helper.d.ts +98 -0
- package/dist/model/block_storage_helper.d.ts.map +1 -0
- package/dist/model/block_storage_helper.js +153 -0
- package/dist/model/block_storage_helper.js.map +1 -0
- package/dist/model/index.d.ts +2 -1
- package/dist/model/index.d.ts.map +1 -1
- package/dist/model/project_helper.cjs +177 -0
- package/dist/model/project_helper.cjs.map +1 -1
- package/dist/model/project_helper.d.ts +110 -1
- package/dist/model/project_helper.d.ts.map +1 -1
- package/dist/model/project_helper.js +178 -1
- package/dist/model/project_helper.js.map +1 -1
- package/dist/model/project_model.cjs +6 -3
- package/dist/model/project_model.cjs.map +1 -1
- package/dist/model/project_model.d.ts +3 -2
- package/dist/model/project_model.d.ts.map +1 -1
- package/dist/model/project_model.js +6 -4
- package/dist/model/project_model.js.map +1 -1
- package/dist/mutator/block-pack/block_pack.cjs +1 -2
- package/dist/mutator/block-pack/block_pack.cjs.map +1 -1
- package/dist/mutator/block-pack/block_pack.d.ts.map +1 -1
- package/dist/mutator/block-pack/block_pack.js +1 -2
- package/dist/mutator/block-pack/block_pack.js.map +1 -1
- package/dist/mutator/block-pack/frontend.cjs +1 -0
- package/dist/mutator/block-pack/frontend.cjs.map +1 -1
- package/dist/mutator/block-pack/frontend.js +1 -0
- package/dist/mutator/block-pack/frontend.js.map +1 -1
- package/dist/mutator/migration.cjs +64 -3
- package/dist/mutator/migration.cjs.map +1 -1
- package/dist/mutator/migration.d.ts.map +1 -1
- package/dist/mutator/migration.js +66 -5
- package/dist/mutator/migration.js.map +1 -1
- package/dist/mutator/project-v3.test.d.ts +2 -0
- package/dist/mutator/project-v3.test.d.ts.map +1 -0
- package/dist/mutator/project.cjs +282 -41
- package/dist/mutator/project.cjs.map +1 -1
- package/dist/mutator/project.d.ts +77 -12
- package/dist/mutator/project.d.ts.map +1 -1
- package/dist/mutator/project.js +283 -42
- package/dist/mutator/project.js.map +1 -1
- package/dist/pool/result_pool.cjs +9 -6
- package/dist/pool/result_pool.cjs.map +1 -1
- package/dist/pool/result_pool.d.ts.map +1 -1
- package/dist/pool/result_pool.js +9 -6
- package/dist/pool/result_pool.js.map +1 -1
- package/package.json +15 -15
- package/src/js_render/computable_context.ts +37 -7
- package/src/js_render/context.ts +12 -5
- package/src/js_render/index.ts +1 -1
- package/src/middle_layer/block.ts +13 -14
- package/src/middle_layer/block_ctx.ts +70 -23
- package/src/middle_layer/block_ctx_unsafe.ts +11 -4
- package/src/middle_layer/middle_layer.ts +2 -1
- package/src/middle_layer/project.ts +86 -40
- package/src/middle_layer/project_overview.ts +44 -20
- package/src/middle_layer/render.test.ts +1 -1
- package/src/middle_layer/render.ts +1 -1
- package/src/model/block_storage_helper.ts +213 -0
- package/src/model/index.ts +2 -1
- package/src/model/project_helper.ts +249 -1
- package/src/model/project_model.ts +9 -5
- package/src/mutator/block-pack/block_pack.ts +1 -2
- package/src/mutator/migration.ts +79 -6
- package/src/mutator/project-v3.test.ts +280 -0
- package/src/mutator/project.test.ts +27 -27
- package/src/mutator/project.ts +351 -68
- package/src/pool/result_pool.ts +11 -4
package/dist/mutator/project.js
CHANGED
|
@@ -7,7 +7,7 @@ import { InitialBlockSettings } from '@milaboratories/pl-model-middle-layer';
|
|
|
7
7
|
import Denque from 'denque';
|
|
8
8
|
import { getPreparedExportTemplateEnvelope, exportContext } from './context_export.js';
|
|
9
9
|
import { loadTemplate } from './template/template_loading.js';
|
|
10
|
-
import { notEmpty, canonicalJsonBytes,
|
|
10
|
+
import { notEmpty, canonicalJsonBytes, cachedDeserialize, cachedDecode } from '@milaboratories/ts-helpers';
|
|
11
11
|
import { extractConfig, UiError } from '@platforma-sdk/model';
|
|
12
12
|
import { getDebugFlags } from '../debug/index.js';
|
|
13
13
|
|
|
@@ -55,19 +55,57 @@ class BlockInfo {
|
|
|
55
55
|
throw new Error('inconsistent stage cache fields');
|
|
56
56
|
if (this.fields.blockPack === undefined)
|
|
57
57
|
throw new Error('no block pack field');
|
|
58
|
-
if (this.fields.
|
|
59
|
-
throw new Error('no
|
|
58
|
+
if (this.fields.blockStorage === undefined)
|
|
59
|
+
throw new Error('no block storage field');
|
|
60
60
|
}
|
|
61
|
-
currentArgsC = cached(() => this.fields.currentArgs
|
|
61
|
+
currentArgsC = cached(() => this.fields.currentArgs?.modCount, () => {
|
|
62
|
+
const bin = this.fields.currentArgs?.value;
|
|
63
|
+
if (bin === undefined)
|
|
64
|
+
return undefined;
|
|
65
|
+
return cachedDeserialize(bin);
|
|
66
|
+
});
|
|
67
|
+
blockStorageC = cached(() => this.fields.blockStorage.modCount, () => {
|
|
68
|
+
const bin = this.fields.blockStorage?.value;
|
|
69
|
+
if (bin === undefined)
|
|
70
|
+
return undefined;
|
|
71
|
+
return cachedDeserialize(bin);
|
|
72
|
+
});
|
|
73
|
+
blockStorageJ = cached(() => this.fields.blockStorage.modCount, () => {
|
|
74
|
+
const bin = this.fields.blockStorage?.value;
|
|
75
|
+
if (bin === undefined)
|
|
76
|
+
return undefined;
|
|
77
|
+
return cachedDecode(bin);
|
|
78
|
+
});
|
|
62
79
|
prodArgsC = cached(() => this.fields.prodArgs?.modCount, () => {
|
|
63
80
|
const bin = this.fields.prodArgs?.value;
|
|
64
81
|
if (bin === undefined)
|
|
65
82
|
return undefined;
|
|
66
83
|
return cachedDeserialize(bin);
|
|
67
84
|
});
|
|
85
|
+
currentPrerunArgsC = cached(() => this.fields.currentPrerunArgs?.modCount, () => {
|
|
86
|
+
const bin = this.fields.currentPrerunArgs?.value;
|
|
87
|
+
if (bin === undefined)
|
|
88
|
+
return undefined;
|
|
89
|
+
return cachedDeserialize(bin);
|
|
90
|
+
});
|
|
68
91
|
get currentArgs() {
|
|
69
92
|
return this.currentArgsC();
|
|
70
93
|
}
|
|
94
|
+
get blockStorage() {
|
|
95
|
+
try {
|
|
96
|
+
return this.blockStorageC();
|
|
97
|
+
}
|
|
98
|
+
catch (e) {
|
|
99
|
+
console.error('Error getting blockStorage:', e);
|
|
100
|
+
return undefined;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
get blockStorageJson() {
|
|
104
|
+
return this.blockStorageJ();
|
|
105
|
+
}
|
|
106
|
+
get currentPrerunArgs() {
|
|
107
|
+
return this.currentPrerunArgsC();
|
|
108
|
+
}
|
|
71
109
|
get stagingRendered() {
|
|
72
110
|
return this.fields.stagingCtx !== undefined;
|
|
73
111
|
}
|
|
@@ -79,12 +117,16 @@ class BlockInfo {
|
|
|
79
117
|
}
|
|
80
118
|
productionStaleC = cached(() => `${this.fields.currentArgs.modCount}_${this.fields.prodArgs?.modCount}`, () => this.fields.prodArgs === undefined
|
|
81
119
|
|| Buffer.compare(this.fields.currentArgs.value, this.fields.prodArgs.value) !== 0);
|
|
82
|
-
// get productionStale(): boolean {
|
|
83
|
-
// return this.productionRendered && this.productionStaleC() && ;
|
|
84
|
-
// }
|
|
85
120
|
get requireProductionRendering() {
|
|
86
121
|
return !this.productionRendered || this.productionStaleC() || this.productionHasErrors;
|
|
87
122
|
}
|
|
123
|
+
/** Returns true if staging should be re-rendered (stagingCtx is not set) */
|
|
124
|
+
get requireStagingRendering() {
|
|
125
|
+
// No staging needed if currentPrerunArgs is undefined (args derivation failed)
|
|
126
|
+
if (this.fields.currentPrerunArgs === undefined)
|
|
127
|
+
return false;
|
|
128
|
+
return !this.stagingRendered;
|
|
129
|
+
}
|
|
88
130
|
get prodArgs() {
|
|
89
131
|
return this.prodArgsC();
|
|
90
132
|
}
|
|
@@ -159,7 +201,6 @@ class ProjectMutator {
|
|
|
159
201
|
|| this.renderingStateChanged);
|
|
160
202
|
}
|
|
161
203
|
get structure() {
|
|
162
|
-
// clone
|
|
163
204
|
return JSON.parse(JSON.stringify(this.struct));
|
|
164
205
|
}
|
|
165
206
|
//
|
|
@@ -184,9 +225,13 @@ class ProjectMutator {
|
|
|
184
225
|
args = bInfo.prodArgs;
|
|
185
226
|
}
|
|
186
227
|
else {
|
|
187
|
-
argsField =
|
|
228
|
+
argsField = bInfo.fields.currentArgs;
|
|
188
229
|
args = bInfo.currentArgs;
|
|
189
230
|
}
|
|
231
|
+
// Can't compute enrichment targets without args
|
|
232
|
+
if (argsField === undefined) {
|
|
233
|
+
return { args, enrichmentTargets: undefined };
|
|
234
|
+
}
|
|
190
235
|
const blockPackField = notEmpty(bInfo.fields.blockPack);
|
|
191
236
|
if (isResourceId(argsField.ref) && isResourceId(blockPackField.ref))
|
|
192
237
|
return {
|
|
@@ -219,6 +264,8 @@ class ProjectMutator {
|
|
|
219
264
|
return info;
|
|
220
265
|
}
|
|
221
266
|
createJsonFieldValueByContent(content) {
|
|
267
|
+
if (content === undefined)
|
|
268
|
+
throw new Error('content is undefined');
|
|
222
269
|
const value = Buffer.from(content);
|
|
223
270
|
const ref = this.tx.createValue(Pl.JsonObject, value);
|
|
224
271
|
return { ref, value, status: 'Ready' };
|
|
@@ -319,6 +366,62 @@ class ProjectMutator {
|
|
|
319
366
|
return this.deleteBlockFields(blockId, 'prodOutput', 'prodCtx', 'prodUiCtx', 'prodArgs', 'prodOutputPrevious', 'prodCtxPrevious', 'prodUiCtxPrevious');
|
|
320
367
|
}
|
|
321
368
|
}
|
|
369
|
+
/**
|
|
370
|
+
* Gets current block state and merges with partial updates.
|
|
371
|
+
* Used by legacy v1/v2 methods like setBlockArgs and setUiState.
|
|
372
|
+
*
|
|
373
|
+
* @param blockId The block to get state for
|
|
374
|
+
* @param partialUpdate Partial state to merge (e.g. { args } or { uiState })
|
|
375
|
+
* @returns Merged state in unified format { args, uiState }
|
|
376
|
+
*/
|
|
377
|
+
mergeBlockState(blockId, partialUpdate) {
|
|
378
|
+
const info = this.getBlockInfo(blockId);
|
|
379
|
+
const currentState = info.blockStorage;
|
|
380
|
+
return { ...currentState, ...partialUpdate };
|
|
381
|
+
}
|
|
382
|
+
/**
|
|
383
|
+
* Sets raw block storage content directly (for testing purposes).
|
|
384
|
+
* This bypasses all normalization and VM transformations.
|
|
385
|
+
*
|
|
386
|
+
* @param blockId The block to set storage for
|
|
387
|
+
* @param rawStorageJson Raw storage as JSON string
|
|
388
|
+
*/
|
|
389
|
+
setBlockStorageRaw(blockId, rawStorageJson) {
|
|
390
|
+
this.setBlockFieldObj(blockId, 'blockStorage', this.createJsonFieldValueByContent(rawStorageJson));
|
|
391
|
+
this.blocksWithChangedInputs.add(blockId);
|
|
392
|
+
this.updateLastModified();
|
|
393
|
+
}
|
|
394
|
+
/**
|
|
395
|
+
* Resets a v2+ block to its initial storage state.
|
|
396
|
+
* Gets initial storage from VM and derives args from it.
|
|
397
|
+
*
|
|
398
|
+
* For v1 blocks, use setStates() instead.
|
|
399
|
+
*
|
|
400
|
+
* @param blockId The block to reset
|
|
401
|
+
*/
|
|
402
|
+
resetToInitialStorage(blockId) {
|
|
403
|
+
const info = this.getBlockInfo(blockId);
|
|
404
|
+
const blockConfig = info.config;
|
|
405
|
+
if (blockConfig.modelAPIVersion !== 2) {
|
|
406
|
+
throw new Error('resetToInitialStorage is only supported for model API version 2');
|
|
407
|
+
}
|
|
408
|
+
// Get initial storage from VM
|
|
409
|
+
const initialStorageJson = this.projectHelper.getInitialStorageInVM(blockConfig);
|
|
410
|
+
this.setBlockStorageRaw(blockId, initialStorageJson);
|
|
411
|
+
// Derive args from storage - set or clear currentArgs based on derivation result
|
|
412
|
+
const deriveArgsResult = this.projectHelper.deriveArgsFromStorage(blockConfig, initialStorageJson);
|
|
413
|
+
if (!deriveArgsResult.error) {
|
|
414
|
+
this.setBlockFieldObj(blockId, 'currentArgs', this.createJsonFieldValue(deriveArgsResult.value));
|
|
415
|
+
// Derive prerunArgs from storage
|
|
416
|
+
const prerunArgs = this.projectHelper.derivePrerunArgsFromStorage(blockConfig, initialStorageJson);
|
|
417
|
+
if (prerunArgs !== undefined) {
|
|
418
|
+
this.setBlockFieldObj(blockId, 'currentPrerunArgs', this.createJsonFieldValue(prerunArgs));
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
else {
|
|
422
|
+
this.deleteBlockFields(blockId, 'currentArgs');
|
|
423
|
+
}
|
|
424
|
+
}
|
|
322
425
|
/** Optimally sets inputs for multiple blocks in one go */
|
|
323
426
|
setStates(requests) {
|
|
324
427
|
const changedArgs = [];
|
|
@@ -326,32 +429,76 @@ class ProjectMutator {
|
|
|
326
429
|
for (const req of requests) {
|
|
327
430
|
const info = this.getBlockInfo(req.blockId);
|
|
328
431
|
let blockChanged = false;
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
432
|
+
const blockConfig = info.config;
|
|
433
|
+
// modelAPIVersion === 2 means BlockModelV3 with .args() lambda for deriving args
|
|
434
|
+
if (req.modelAPIVersion !== blockConfig.modelAPIVersion) {
|
|
435
|
+
throw new Error(`Model API version mismatch for block ${req.blockId}: ${req.modelAPIVersion} !== ${blockConfig.modelAPIVersion}`);
|
|
436
|
+
}
|
|
437
|
+
// Derive args from storage using the block's config.args() callback
|
|
438
|
+
let args;
|
|
439
|
+
let prerunArgs;
|
|
440
|
+
if (req.modelAPIVersion === 2) {
|
|
441
|
+
const currentStorageJson = info.blockStorageJson;
|
|
442
|
+
if (currentStorageJson === undefined) {
|
|
443
|
+
throw new Error(`Block ${req.blockId} has no blockStorage - this should not happen`);
|
|
444
|
+
}
|
|
445
|
+
// Apply the state update to storage
|
|
446
|
+
const updatedStorageJson = this.projectHelper.applyStorageUpdateInVM(blockConfig, currentStorageJson, req.payload);
|
|
447
|
+
this.setBlockFieldObj(req.blockId, 'blockStorage', this.createJsonFieldValueByContent(updatedStorageJson));
|
|
448
|
+
// Derive args directly from storage (VM extracts data internally)
|
|
449
|
+
const derivedArgsResult = this.projectHelper.deriveArgsFromStorage(blockConfig, updatedStorageJson);
|
|
450
|
+
if (derivedArgsResult.error) {
|
|
451
|
+
args = undefined;
|
|
452
|
+
prerunArgs = undefined;
|
|
341
453
|
}
|
|
342
454
|
else {
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
455
|
+
args = derivedArgsResult.value;
|
|
456
|
+
// Derive prerunArgs from storage, or fall back to args
|
|
457
|
+
prerunArgs = this.projectHelper.derivePrerunArgsFromStorage(blockConfig, updatedStorageJson);
|
|
346
458
|
}
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
459
|
+
}
|
|
460
|
+
else {
|
|
461
|
+
this.setBlockFieldObj(req.blockId, 'blockStorage', this.createJsonFieldValue(req.state));
|
|
462
|
+
if (req.state !== null && typeof req.state === 'object' && 'args' in req.state) {
|
|
463
|
+
args = req.state.args;
|
|
464
|
+
}
|
|
465
|
+
else {
|
|
466
|
+
args = req.state;
|
|
467
|
+
}
|
|
468
|
+
// For the legacy blocks, prerunArgs = args (same as production args)
|
|
469
|
+
prerunArgs = args;
|
|
470
|
+
}
|
|
471
|
+
// Set or clear currentArgs based on derivation result
|
|
472
|
+
if (args !== undefined) {
|
|
473
|
+
const currentArgsData = canonicalJsonBytes(args);
|
|
474
|
+
const argsPartRef = this.tx.createValue(Pl.JsonObject, currentArgsData);
|
|
475
|
+
this.setBlockField(req.blockId, 'currentArgs', argsPartRef, 'Ready', currentArgsData);
|
|
476
|
+
}
|
|
477
|
+
else {
|
|
478
|
+
this.deleteBlockFields(req.blockId, 'currentArgs');
|
|
479
|
+
}
|
|
480
|
+
// Set currentPrerunArgs field and check if it actually changed
|
|
481
|
+
let prerunArgsChanged = false;
|
|
482
|
+
if (prerunArgs !== undefined) {
|
|
483
|
+
const prerunArgsData = canonicalJsonBytes(prerunArgs);
|
|
484
|
+
const oldPrerunArgsData = info.fields.currentPrerunArgs?.value;
|
|
485
|
+
// Check if prerunArgs actually changed
|
|
486
|
+
if (oldPrerunArgsData === undefined || Buffer.compare(oldPrerunArgsData, prerunArgsData) !== 0) {
|
|
487
|
+
prerunArgsChanged = true;
|
|
488
|
+
}
|
|
489
|
+
const prerunArgsRef = this.tx.createValue(Pl.JsonObject, prerunArgsData);
|
|
490
|
+
this.setBlockField(req.blockId, 'currentPrerunArgs', prerunArgsRef, 'Ready', prerunArgsData);
|
|
491
|
+
}
|
|
492
|
+
else {
|
|
493
|
+
// prerunArgs is undefined - check if we previously had one
|
|
494
|
+
if (info.fields.currentPrerunArgs !== undefined) {
|
|
495
|
+
prerunArgsChanged = true;
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
blockChanged = true;
|
|
499
|
+
// Only add to changedArgs if prerunArgs changed - this controls staging reset
|
|
500
|
+
if (prerunArgsChanged) {
|
|
501
|
+
changedArgs.push(req.blockId);
|
|
355
502
|
}
|
|
356
503
|
if (blockChanged) {
|
|
357
504
|
// will be assigned our author marker
|
|
@@ -393,15 +540,25 @@ class ProjectMutator {
|
|
|
393
540
|
exportCtx(ctx) {
|
|
394
541
|
return exportContext(this.tx, Pl.unwrapHolder(this.tx, this.ctxExportTplHolder), ctx);
|
|
395
542
|
}
|
|
543
|
+
/**
|
|
544
|
+
* Renders staging for a block using currentPrerunArgs.
|
|
545
|
+
* If currentPrerunArgs is not set (prerunArgs returned undefined), skips staging for this block.
|
|
546
|
+
*/
|
|
396
547
|
renderStagingFor(blockId) {
|
|
397
548
|
this.resetStaging(blockId);
|
|
398
549
|
const info = this.getBlockInfo(blockId);
|
|
550
|
+
// If currentPrerunArgs is not set (prerunArgs returned undefined), skip staging for this block
|
|
551
|
+
const prerunArgsRef = info.fields.currentPrerunArgs?.ref;
|
|
552
|
+
if (prerunArgsRef === undefined) {
|
|
553
|
+
return;
|
|
554
|
+
}
|
|
399
555
|
const ctx = this.createStagingCtx(this.getStagingGraph().nodes.get(blockId).upstream);
|
|
400
556
|
if (this.getBlock(blockId).renderingMode !== 'Heavy')
|
|
401
557
|
throw new Error('not supported yet');
|
|
402
558
|
const tpl = info.getTemplate(this.tx);
|
|
559
|
+
// Use currentPrerunArgs for staging rendering
|
|
403
560
|
const results = createRenderHeavyBlock(this.tx, tpl, {
|
|
404
|
-
args:
|
|
561
|
+
args: prerunArgsRef,
|
|
405
562
|
blockId: this.tx.createValue(Pl.JsonString, JSON.stringify(blockId)),
|
|
406
563
|
isProduction: this.tx.createValue(Pl.JsonBool, JSON.stringify(false)),
|
|
407
564
|
context: ctx,
|
|
@@ -418,6 +575,10 @@ class ProjectMutator {
|
|
|
418
575
|
renderProductionFor(blockId) {
|
|
419
576
|
this.resetProduction(blockId);
|
|
420
577
|
const info = this.getBlockInfo(blockId);
|
|
578
|
+
// Can't render production if currentArgs is not set
|
|
579
|
+
if (info.fields.currentArgs === undefined) {
|
|
580
|
+
throw new Error(`Can't render production for block ${blockId}: currentArgs not set`);
|
|
581
|
+
}
|
|
421
582
|
const ctx = this.createProdCtx(this.getPendingProductionGraph().nodes.get(blockId).upstream);
|
|
422
583
|
if (this.getBlock(blockId).renderingMode === 'Light')
|
|
423
584
|
throw new Error('Can\'t render production for light block.');
|
|
@@ -448,10 +609,47 @@ class ProjectMutator {
|
|
|
448
609
|
this.setBlockField(blockId, 'blockPack', Pl.wrapInHolder(this.tx, bp), 'NotReady');
|
|
449
610
|
// settings
|
|
450
611
|
this.setBlockFieldObj(blockId, 'blockSettings', this.createJsonFieldValue(InitialBlockSettings));
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
612
|
+
const blockConfig = info.config;
|
|
613
|
+
let args;
|
|
614
|
+
let prerunArgs;
|
|
615
|
+
let storageToWrite;
|
|
616
|
+
if (spec.storageMode === 'fromModel') {
|
|
617
|
+
// Model API v2+: get initial storage and derive args from it
|
|
618
|
+
storageToWrite = this.projectHelper.getInitialStorageInVM(blockConfig);
|
|
619
|
+
// Derive args directly from storage (VM extracts data internally)
|
|
620
|
+
const deriveArgsResult = this.projectHelper.deriveArgsFromStorage(blockConfig, storageToWrite);
|
|
621
|
+
if (deriveArgsResult.error) {
|
|
622
|
+
args = undefined;
|
|
623
|
+
prerunArgs = undefined;
|
|
624
|
+
}
|
|
625
|
+
else {
|
|
626
|
+
args = deriveArgsResult.value;
|
|
627
|
+
prerunArgs = this.projectHelper.derivePrerunArgsFromStorage(blockConfig, storageToWrite);
|
|
628
|
+
}
|
|
629
|
+
}
|
|
630
|
+
else if (spec.storageMode === 'legacy') {
|
|
631
|
+
// Model API v1: use legacyState from spec
|
|
632
|
+
const parsedState = JSON.parse(spec.legacyState);
|
|
633
|
+
args = parsedState.args;
|
|
634
|
+
if (args === undefined) {
|
|
635
|
+
throw new Error('args is undefined in legacyState');
|
|
636
|
+
}
|
|
637
|
+
prerunArgs = args;
|
|
638
|
+
storageToWrite = spec.legacyState;
|
|
639
|
+
}
|
|
640
|
+
else {
|
|
641
|
+
throw new Error(`Unknown storageMode: ${spec.storageMode}`);
|
|
642
|
+
}
|
|
643
|
+
// currentArgs
|
|
644
|
+
if (args !== undefined) {
|
|
645
|
+
this.setBlockFieldObj(blockId, 'currentArgs', this.createJsonFieldValue(args));
|
|
646
|
+
}
|
|
647
|
+
// currentPrerunArgs
|
|
648
|
+
if (prerunArgs !== undefined) {
|
|
649
|
+
this.setBlockFieldObj(blockId, 'currentPrerunArgs', this.createJsonFieldValue(prerunArgs));
|
|
650
|
+
}
|
|
651
|
+
// blockStorage
|
|
652
|
+
this.setBlockFieldObj(blockId, 'blockStorage', this.createJsonFieldValueByContent(storageToWrite));
|
|
455
653
|
// checking structure
|
|
456
654
|
info.check();
|
|
457
655
|
}
|
|
@@ -627,14 +825,53 @@ class ProjectMutator {
|
|
|
627
825
|
//
|
|
628
826
|
// Block-pack migration
|
|
629
827
|
//
|
|
630
|
-
migrateBlockPack(blockId, spec,
|
|
828
|
+
migrateBlockPack(blockId, spec, newClearState) {
|
|
631
829
|
const info = this.getBlockInfo(blockId);
|
|
830
|
+
const newConfig = extractConfig(spec.config);
|
|
632
831
|
this.setBlockField(blockId, 'blockPack', Pl.wrapInHolder(this.tx, createBlockPack(this.tx, spec)), 'NotReady');
|
|
633
|
-
if (
|
|
634
|
-
//
|
|
635
|
-
|
|
832
|
+
if (newClearState !== undefined) {
|
|
833
|
+
// State is being reset - no migration needed
|
|
834
|
+
const supportsStorageFromVM = newConfig.modelAPIVersion === 2;
|
|
835
|
+
if (supportsStorageFromVM) {
|
|
836
|
+
// V2+: Get initial storage directly from VM and derive args from it
|
|
837
|
+
const initialStorageJson = this.projectHelper.getInitialStorageInVM(newConfig);
|
|
838
|
+
this.setBlockStorageRaw(blockId, initialStorageJson);
|
|
839
|
+
// Derive args from storage - only set currentArgs if derivation succeeds
|
|
840
|
+
const deriveArgsResult = this.projectHelper.deriveArgsFromStorage(newConfig, initialStorageJson);
|
|
841
|
+
if (!deriveArgsResult.error) {
|
|
842
|
+
this.setBlockFieldObj(blockId, 'currentArgs', this.createJsonFieldValue(deriveArgsResult.value));
|
|
843
|
+
// Derive prerunArgs from storage
|
|
844
|
+
const prerunArgs = this.projectHelper.derivePrerunArgsFromStorage(newConfig, initialStorageJson);
|
|
845
|
+
if (prerunArgs !== undefined) {
|
|
846
|
+
this.setBlockFieldObj(blockId, 'currentPrerunArgs', this.createJsonFieldValue(prerunArgs));
|
|
847
|
+
}
|
|
848
|
+
}
|
|
849
|
+
this.blocksWithChangedInputs.add(blockId);
|
|
850
|
+
this.updateLastModified();
|
|
851
|
+
}
|
|
852
|
+
else {
|
|
853
|
+
// V1: Use setStates with legacy state format
|
|
854
|
+
this.setStates([{ modelAPIVersion: 1, blockId, state: newClearState.state }]);
|
|
855
|
+
}
|
|
636
856
|
}
|
|
637
857
|
else {
|
|
858
|
+
// State is being preserved - run migrations if needed via VM
|
|
859
|
+
// Only Model API v2 blocks support migrations
|
|
860
|
+
const supportsStateMigrations = newConfig.modelAPIVersion === 2;
|
|
861
|
+
if (supportsStateMigrations) {
|
|
862
|
+
const currentStorageJson = info.blockStorageJson;
|
|
863
|
+
const migrationResult = this.projectHelper.migrateStorageInVM(newConfig, currentStorageJson);
|
|
864
|
+
if (migrationResult.error !== undefined) {
|
|
865
|
+
console.error(`[migrateBlockPack] Block ${blockId} migration error: ${migrationResult.error}`);
|
|
866
|
+
}
|
|
867
|
+
else {
|
|
868
|
+
console.log(`[migrateBlockPack] Block ${blockId}: ${migrationResult.info}`);
|
|
869
|
+
if (migrationResult.warn) {
|
|
870
|
+
console.warn(`[migrateBlockPack] Block ${blockId} migration warning: ${migrationResult.warn}`);
|
|
871
|
+
}
|
|
872
|
+
this.setBlockStorageRaw(blockId, migrationResult.newStorageJson);
|
|
873
|
+
}
|
|
874
|
+
}
|
|
638
875
|
// resetting staging outputs for all downstream blocks
|
|
639
876
|
this.getStagingGraph().traverse('downstream', [blockId], ({ id }) => this.resetStaging(id));
|
|
640
877
|
}
|
|
@@ -735,13 +972,16 @@ class ProjectMutator {
|
|
|
735
972
|
const stagingGraph = this.getStagingGraph();
|
|
736
973
|
stagingGraph.nodes.forEach((node) => {
|
|
737
974
|
const info = this.getBlockInfo(node.id);
|
|
738
|
-
|
|
975
|
+
// Use requireStagingRendering to check both: staging exists AND prerunArgs hasn't changed
|
|
976
|
+
const requiresRendering = info.requireStagingRendering;
|
|
977
|
+
let lag = requiresRendering ? 1 : 0;
|
|
739
978
|
node.upstream.forEach((upstream) => {
|
|
740
979
|
const upstreamLag = lags.get(upstream);
|
|
741
980
|
if (upstreamLag === 0)
|
|
742
981
|
return;
|
|
743
982
|
lag = Math.max(upstreamLag + 1, lag);
|
|
744
983
|
});
|
|
984
|
+
if (!requiresRendering && info.stagingRendered) ;
|
|
745
985
|
cb(node.id, lag);
|
|
746
986
|
lags.set(node.id, lag);
|
|
747
987
|
});
|
|
@@ -758,6 +998,7 @@ class ProjectMutator {
|
|
|
758
998
|
// meaning staging already rendered
|
|
759
999
|
return;
|
|
760
1000
|
if (lagThreshold === undefined || lag <= lagThreshold) {
|
|
1001
|
+
// console.log(`[refreshStagings] RENDER staging for ${blockId} (lag=${lag})`);
|
|
761
1002
|
this.renderStagingFor(blockId);
|
|
762
1003
|
rendered++;
|
|
763
1004
|
}
|