@milaboratories/pl-middle-layer 1.45.5 → 1.46.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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 +17 -17
- 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
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { SchemaVersionKey, SchemaVersionCurrent, ProjectStructureKey, projectFieldName } from '../model/project_model.js';
|
|
1
|
+
import { SchemaVersionKey, SchemaVersionCurrent, SchemaVersionV2, ProjectStructureKey, projectFieldName } from '../model/project_model.js';
|
|
2
2
|
import { SchemaVersionV1, BlockFrontendStateKeyPrefixV1 } from '../model/project_model_v1.js';
|
|
3
|
-
import { field } from '@milaboratories/pl-client';
|
|
3
|
+
import { field, isNullResourceId } from '@milaboratories/pl-client';
|
|
4
4
|
import { cachedDeserialize } from '@milaboratories/ts-helpers';
|
|
5
5
|
import { allBlocks } from '../model/project_model_util.js';
|
|
6
6
|
|
|
@@ -12,13 +12,19 @@ import { allBlocks } from '../model/project_model_util.js';
|
|
|
12
12
|
*/
|
|
13
13
|
async function applyProjectMigrations(pl, rid) {
|
|
14
14
|
await pl.withWriteTx('ProjectMigration', async (tx) => {
|
|
15
|
-
|
|
15
|
+
let schemaVersion = await tx.getKValueJson(rid, SchemaVersionKey);
|
|
16
16
|
if (schemaVersion === SchemaVersionCurrent)
|
|
17
17
|
return;
|
|
18
|
+
// Apply migrations in sequence
|
|
18
19
|
if (schemaVersion === SchemaVersionV1) {
|
|
19
20
|
await migrateV1ToV2(tx, rid);
|
|
21
|
+
schemaVersion = SchemaVersionV2;
|
|
20
22
|
}
|
|
21
|
-
|
|
23
|
+
if (schemaVersion === SchemaVersionV2) {
|
|
24
|
+
await migrateV2ToV3(tx, rid);
|
|
25
|
+
}
|
|
26
|
+
else if (schemaVersion !== SchemaVersionV1) {
|
|
27
|
+
// If we got here and it's not v1 (which was handled above), it's unknown
|
|
22
28
|
throw new Error(`Unknown project schema version: ${schemaVersion}`);
|
|
23
29
|
}
|
|
24
30
|
tx.setKValue(rid, SchemaVersionKey, JSON.stringify(SchemaVersionCurrent));
|
|
@@ -45,11 +51,66 @@ async function migrateV1ToV2(tx, rid) {
|
|
|
45
51
|
const uiState = kvMap.get(kvKey);
|
|
46
52
|
const valueJson = uiState ? cachedDeserialize(uiState) : {};
|
|
47
53
|
const uiStateR = tx.createJsonGzValue(valueJson);
|
|
48
|
-
const uiStateF = field(rid, projectFieldName(block.id, '
|
|
54
|
+
const uiStateF = field(rid, projectFieldName(block.id, 'blockStorage'));
|
|
49
55
|
tx.createField(uiStateF, 'Dynamic', uiStateR);
|
|
50
56
|
tx.deleteKValue(rid, kvKey);
|
|
51
57
|
}
|
|
52
58
|
}
|
|
59
|
+
/**
|
|
60
|
+
* Migrates the project from schema version 2 to 3.
|
|
61
|
+
*
|
|
62
|
+
* Summary of changes:
|
|
63
|
+
* - Introduces unified 'blockStorage' field containing { args, uiState }
|
|
64
|
+
* - Adds 'currentPrerunArgs' field for staging/prerun rendering
|
|
65
|
+
* - For each block:
|
|
66
|
+
* 1. Read existing 'blockStorage' field (contains uiState in v2)
|
|
67
|
+
* 2. Read existing 'currentArgs' field (contains args)
|
|
68
|
+
* 3. Create unified state = { args: currentArgs, uiState: oldState }
|
|
69
|
+
* 4. Write to new {blockId}-blockStorage field (overwrites)
|
|
70
|
+
* 5. Initialize {blockId}-currentPrerunArgs (same as prodArgs for v1/v2 blocks)
|
|
71
|
+
* - Note: currentArgs and prodArgs fields remain for compatibility layer
|
|
72
|
+
*
|
|
73
|
+
* @param tx - The transaction to use.
|
|
74
|
+
* @param rid - The resource id of the project.
|
|
75
|
+
*/
|
|
76
|
+
async function migrateV2ToV3(tx, rid) {
|
|
77
|
+
const [structure, fullResourceState] = await Promise.all([
|
|
78
|
+
tx.getKValueJson(rid, ProjectStructureKey),
|
|
79
|
+
tx.getResourceData(rid, true),
|
|
80
|
+
]);
|
|
81
|
+
// Build a map of field name -> resource id for quick lookup
|
|
82
|
+
const fieldMap = new Map();
|
|
83
|
+
for (const f of fullResourceState.fields) {
|
|
84
|
+
if (!isNullResourceId(f.value)) {
|
|
85
|
+
fieldMap.set(f.name, f.value);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
for (const block of allBlocks(structure)) {
|
|
89
|
+
// Read existing field values
|
|
90
|
+
const uiStateFieldName = projectFieldName(block.id, 'uiState');
|
|
91
|
+
const currentArgsFieldName = projectFieldName(block.id, 'currentArgs');
|
|
92
|
+
const uiStateRid = fieldMap.get(uiStateFieldName);
|
|
93
|
+
const currentArgsRid = fieldMap.get(currentArgsFieldName);
|
|
94
|
+
// Read field data in parallel where available
|
|
95
|
+
const [uiStateData, currentArgsData] = await Promise.all([
|
|
96
|
+
uiStateRid ? tx.getResourceData(uiStateRid, false) : Promise.resolve(undefined),
|
|
97
|
+
currentArgsRid ? tx.getResourceData(currentArgsRid, false) : Promise.resolve(undefined),
|
|
98
|
+
]);
|
|
99
|
+
// Extract values - in v2, 'blockStorage' contains raw uiState, not wrapped
|
|
100
|
+
const uiState = uiStateData?.data ? cachedDeserialize(uiStateData.data) : {};
|
|
101
|
+
const args = currentArgsData?.data ? cachedDeserialize(currentArgsData.data) : {};
|
|
102
|
+
// Create unified state: { args, uiState }
|
|
103
|
+
const unifiedState = {
|
|
104
|
+
args,
|
|
105
|
+
uiState,
|
|
106
|
+
};
|
|
107
|
+
const blockStorageFieldName = projectFieldName(block.id, 'blockStorage');
|
|
108
|
+
// Write new unified blockStorage field (overwrite existing)
|
|
109
|
+
const stateR = tx.createJsonGzValue(unifiedState);
|
|
110
|
+
const stateF = field(rid, blockStorageFieldName);
|
|
111
|
+
tx.createField(stateF, 'Dynamic', stateR);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
53
114
|
|
|
54
115
|
export { applyProjectMigrations };
|
|
55
116
|
//# sourceMappingURL=migration.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"migration.js","sources":["../../src/mutator/migration.ts"],"sourcesContent":["import type { PlClient, PlTransaction, ResourceId } from '@milaboratories/pl-client';\nimport type { ProjectStructure } from '../model/project_model';\nimport { projectFieldName, ProjectStructureKey, SchemaVersionCurrent, SchemaVersionKey } from '../model/project_model';\nimport { BlockFrontendStateKeyPrefixV1, SchemaVersionV1 } from '../model/project_model_v1';\nimport { field } from '@milaboratories/pl-client';\nimport { cachedDeserialize } from '@milaboratories/ts-helpers';\nimport { allBlocks } from '../model/project_model_util';\n\n/**\n * Migrates the project to the latest schema version.\n *\n * @param pl - The client to use.\n * @param rid - The resource id of the project.\n */\nexport async function applyProjectMigrations(pl: PlClient, rid: ResourceId) {\n await pl.withWriteTx('ProjectMigration', async (tx) => {\n
|
|
1
|
+
{"version":3,"file":"migration.js","sources":["../../src/mutator/migration.ts"],"sourcesContent":["import type { PlClient, PlTransaction, ResourceId } from '@milaboratories/pl-client';\nimport type { ProjectField, ProjectStructure } from '../model/project_model';\nimport { projectFieldName, ProjectStructureKey, SchemaVersionCurrent, SchemaVersionKey, SchemaVersionV2 } from '../model/project_model';\nimport { BlockFrontendStateKeyPrefixV1, SchemaVersionV1 } from '../model/project_model_v1';\nimport { field, isNullResourceId } from '@milaboratories/pl-client';\nimport { cachedDeserialize } from '@milaboratories/ts-helpers';\nimport { allBlocks } from '../model/project_model_util';\n\n/**\n * Migrates the project to the latest schema version.\n *\n * @param pl - The client to use.\n * @param rid - The resource id of the project.\n */\nexport async function applyProjectMigrations(pl: PlClient, rid: ResourceId) {\n await pl.withWriteTx('ProjectMigration', async (tx) => {\n let schemaVersion = await tx.getKValueJson<string>(rid, SchemaVersionKey);\n if (schemaVersion === SchemaVersionCurrent) return;\n\n // Apply migrations in sequence\n if (schemaVersion === SchemaVersionV1) {\n await migrateV1ToV2(tx, rid);\n schemaVersion = SchemaVersionV2;\n }\n\n if (schemaVersion === SchemaVersionV2) {\n await migrateV2ToV3(tx, rid);\n } else if (schemaVersion !== SchemaVersionV1) {\n // If we got here and it's not v1 (which was handled above), it's unknown\n throw new Error(`Unknown project schema version: ${schemaVersion}`);\n }\n\n tx.setKValue(rid, SchemaVersionKey, JSON.stringify(SchemaVersionCurrent));\n await tx.commit();\n });\n}\n\n/**\n * Migrates the project from schema version 1 to 2.\n *\n * Summary of changes:\n * - uiState is now stored in a field instead of a KV\n *\n * @param tx - The transaction to use.\n * @param rid - The resource id of the project.\n */\nasync function migrateV1ToV2(tx: PlTransaction, rid: ResourceId) {\n const [structure, allKV] = await Promise.all([\n tx.getKValueJson<ProjectStructure>(rid, ProjectStructureKey),\n tx.listKeyValues(rid),\n ]);\n const kvMap = new Map<string, Uint8Array>(allKV.map((kv) => [kv.key, kv.value]));\n for (const block of allBlocks(structure)) {\n const kvKey = BlockFrontendStateKeyPrefixV1 + block.id;\n const uiState = kvMap.get(kvKey);\n const valueJson = uiState ? cachedDeserialize(uiState) : {};\n const uiStateR = tx.createJsonGzValue(valueJson);\n const uiStateF = field(rid, projectFieldName(block.id, 'blockStorage'));\n tx.createField(uiStateF, 'Dynamic', uiStateR);\n tx.deleteKValue(rid, kvKey);\n }\n}\n\n/**\n * Migrates the project from schema version 2 to 3.\n *\n * Summary of changes:\n * - Introduces unified 'blockStorage' field containing { args, uiState }\n * - Adds 'currentPrerunArgs' field for staging/prerun rendering\n * - For each block:\n * 1. Read existing 'blockStorage' field (contains uiState in v2)\n * 2. Read existing 'currentArgs' field (contains args)\n * 3. Create unified state = { args: currentArgs, uiState: oldState }\n * 4. Write to new {blockId}-blockStorage field (overwrites)\n * 5. Initialize {blockId}-currentPrerunArgs (same as prodArgs for v1/v2 blocks)\n * - Note: currentArgs and prodArgs fields remain for compatibility layer\n *\n * @param tx - The transaction to use.\n * @param rid - The resource id of the project.\n */\nasync function migrateV2ToV3(tx: PlTransaction, rid: ResourceId) {\n const [structure, fullResourceState] = await Promise.all([\n tx.getKValueJson<ProjectStructure>(rid, ProjectStructureKey),\n tx.getResourceData(rid, true),\n ]);\n\n // Build a map of field name -> resource id for quick lookup\n const fieldMap = new Map<string, ResourceId>();\n for (const f of fullResourceState.fields) {\n if (!isNullResourceId(f.value)) {\n fieldMap.set(f.name, f.value);\n }\n }\n\n for (const block of allBlocks(structure)) {\n // Read existing field values\n const uiStateFieldName = projectFieldName(block.id, 'uiState' as ProjectField['fieldName']);\n const currentArgsFieldName = projectFieldName(block.id, 'currentArgs');\n\n const uiStateRid = fieldMap.get(uiStateFieldName);\n const currentArgsRid = fieldMap.get(currentArgsFieldName);\n\n // Read field data in parallel where available\n const [uiStateData, currentArgsData] = await Promise.all([\n uiStateRid ? tx.getResourceData(uiStateRid, false) : Promise.resolve(undefined),\n currentArgsRid ? tx.getResourceData(currentArgsRid, false) : Promise.resolve(undefined),\n ]);\n\n // Extract values - in v2, 'blockStorage' contains raw uiState, not wrapped\n const uiState = uiStateData?.data ? cachedDeserialize(uiStateData.data) : {};\n const args = currentArgsData?.data ? cachedDeserialize(currentArgsData.data) : {};\n\n // Create unified state: { args, uiState }\n const unifiedState = {\n args,\n uiState,\n };\n\n const blockStorageFieldName = projectFieldName(block.id, 'blockStorage');\n\n // Write new unified blockStorage field (overwrite existing)\n const stateR = tx.createJsonGzValue(unifiedState);\n const stateF = field(rid, blockStorageFieldName);\n tx.createField(stateF, 'Dynamic', stateR);\n }\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"project-v3.test.d.ts","sourceRoot":"","sources":["../../src/mutator/project-v3.test.ts"],"names":[],"mappings":""}
|
package/dist/mutator/project.cjs
CHANGED
|
@@ -57,19 +57,57 @@ class BlockInfo {
|
|
|
57
57
|
throw new Error('inconsistent stage cache fields');
|
|
58
58
|
if (this.fields.blockPack === undefined)
|
|
59
59
|
throw new Error('no block pack field');
|
|
60
|
-
if (this.fields.
|
|
61
|
-
throw new Error('no
|
|
60
|
+
if (this.fields.blockStorage === undefined)
|
|
61
|
+
throw new Error('no block storage field');
|
|
62
62
|
}
|
|
63
|
-
currentArgsC = cached(() => this.fields.currentArgs
|
|
63
|
+
currentArgsC = cached(() => this.fields.currentArgs?.modCount, () => {
|
|
64
|
+
const bin = this.fields.currentArgs?.value;
|
|
65
|
+
if (bin === undefined)
|
|
66
|
+
return undefined;
|
|
67
|
+
return tsHelpers.cachedDeserialize(bin);
|
|
68
|
+
});
|
|
69
|
+
blockStorageC = cached(() => this.fields.blockStorage.modCount, () => {
|
|
70
|
+
const bin = this.fields.blockStorage?.value;
|
|
71
|
+
if (bin === undefined)
|
|
72
|
+
return undefined;
|
|
73
|
+
return tsHelpers.cachedDeserialize(bin);
|
|
74
|
+
});
|
|
75
|
+
blockStorageJ = cached(() => this.fields.blockStorage.modCount, () => {
|
|
76
|
+
const bin = this.fields.blockStorage?.value;
|
|
77
|
+
if (bin === undefined)
|
|
78
|
+
return undefined;
|
|
79
|
+
return tsHelpers.cachedDecode(bin);
|
|
80
|
+
});
|
|
64
81
|
prodArgsC = cached(() => this.fields.prodArgs?.modCount, () => {
|
|
65
82
|
const bin = this.fields.prodArgs?.value;
|
|
66
83
|
if (bin === undefined)
|
|
67
84
|
return undefined;
|
|
68
85
|
return tsHelpers.cachedDeserialize(bin);
|
|
69
86
|
});
|
|
87
|
+
currentPrerunArgsC = cached(() => this.fields.currentPrerunArgs?.modCount, () => {
|
|
88
|
+
const bin = this.fields.currentPrerunArgs?.value;
|
|
89
|
+
if (bin === undefined)
|
|
90
|
+
return undefined;
|
|
91
|
+
return tsHelpers.cachedDeserialize(bin);
|
|
92
|
+
});
|
|
70
93
|
get currentArgs() {
|
|
71
94
|
return this.currentArgsC();
|
|
72
95
|
}
|
|
96
|
+
get blockStorage() {
|
|
97
|
+
try {
|
|
98
|
+
return this.blockStorageC();
|
|
99
|
+
}
|
|
100
|
+
catch (e) {
|
|
101
|
+
console.error('Error getting blockStorage:', e);
|
|
102
|
+
return undefined;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
get blockStorageJson() {
|
|
106
|
+
return this.blockStorageJ();
|
|
107
|
+
}
|
|
108
|
+
get currentPrerunArgs() {
|
|
109
|
+
return this.currentPrerunArgsC();
|
|
110
|
+
}
|
|
73
111
|
get stagingRendered() {
|
|
74
112
|
return this.fields.stagingCtx !== undefined;
|
|
75
113
|
}
|
|
@@ -81,12 +119,16 @@ class BlockInfo {
|
|
|
81
119
|
}
|
|
82
120
|
productionStaleC = cached(() => `${this.fields.currentArgs.modCount}_${this.fields.prodArgs?.modCount}`, () => this.fields.prodArgs === undefined
|
|
83
121
|
|| Buffer.compare(this.fields.currentArgs.value, this.fields.prodArgs.value) !== 0);
|
|
84
|
-
// get productionStale(): boolean {
|
|
85
|
-
// return this.productionRendered && this.productionStaleC() && ;
|
|
86
|
-
// }
|
|
87
122
|
get requireProductionRendering() {
|
|
88
123
|
return !this.productionRendered || this.productionStaleC() || this.productionHasErrors;
|
|
89
124
|
}
|
|
125
|
+
/** Returns true if staging should be re-rendered (stagingCtx is not set) */
|
|
126
|
+
get requireStagingRendering() {
|
|
127
|
+
// No staging needed if currentPrerunArgs is undefined (args derivation failed)
|
|
128
|
+
if (this.fields.currentPrerunArgs === undefined)
|
|
129
|
+
return false;
|
|
130
|
+
return !this.stagingRendered;
|
|
131
|
+
}
|
|
90
132
|
get prodArgs() {
|
|
91
133
|
return this.prodArgsC();
|
|
92
134
|
}
|
|
@@ -161,7 +203,6 @@ class ProjectMutator {
|
|
|
161
203
|
|| this.renderingStateChanged);
|
|
162
204
|
}
|
|
163
205
|
get structure() {
|
|
164
|
-
// clone
|
|
165
206
|
return JSON.parse(JSON.stringify(this.struct));
|
|
166
207
|
}
|
|
167
208
|
//
|
|
@@ -186,9 +227,13 @@ class ProjectMutator {
|
|
|
186
227
|
args = bInfo.prodArgs;
|
|
187
228
|
}
|
|
188
229
|
else {
|
|
189
|
-
argsField =
|
|
230
|
+
argsField = bInfo.fields.currentArgs;
|
|
190
231
|
args = bInfo.currentArgs;
|
|
191
232
|
}
|
|
233
|
+
// Can't compute enrichment targets without args
|
|
234
|
+
if (argsField === undefined) {
|
|
235
|
+
return { args, enrichmentTargets: undefined };
|
|
236
|
+
}
|
|
192
237
|
const blockPackField = tsHelpers.notEmpty(bInfo.fields.blockPack);
|
|
193
238
|
if (plClient.isResourceId(argsField.ref) && plClient.isResourceId(blockPackField.ref))
|
|
194
239
|
return {
|
|
@@ -221,6 +266,8 @@ class ProjectMutator {
|
|
|
221
266
|
return info;
|
|
222
267
|
}
|
|
223
268
|
createJsonFieldValueByContent(content) {
|
|
269
|
+
if (content === undefined)
|
|
270
|
+
throw new Error('content is undefined');
|
|
224
271
|
const value = Buffer.from(content);
|
|
225
272
|
const ref = this.tx.createValue(plClient.Pl.JsonObject, value);
|
|
226
273
|
return { ref, value, status: 'Ready' };
|
|
@@ -321,6 +368,62 @@ class ProjectMutator {
|
|
|
321
368
|
return this.deleteBlockFields(blockId, 'prodOutput', 'prodCtx', 'prodUiCtx', 'prodArgs', 'prodOutputPrevious', 'prodCtxPrevious', 'prodUiCtxPrevious');
|
|
322
369
|
}
|
|
323
370
|
}
|
|
371
|
+
/**
|
|
372
|
+
* Gets current block state and merges with partial updates.
|
|
373
|
+
* Used by legacy v1/v2 methods like setBlockArgs and setUiState.
|
|
374
|
+
*
|
|
375
|
+
* @param blockId The block to get state for
|
|
376
|
+
* @param partialUpdate Partial state to merge (e.g. { args } or { uiState })
|
|
377
|
+
* @returns Merged state in unified format { args, uiState }
|
|
378
|
+
*/
|
|
379
|
+
mergeBlockState(blockId, partialUpdate) {
|
|
380
|
+
const info = this.getBlockInfo(blockId);
|
|
381
|
+
const currentState = info.blockStorage;
|
|
382
|
+
return { ...currentState, ...partialUpdate };
|
|
383
|
+
}
|
|
384
|
+
/**
|
|
385
|
+
* Sets raw block storage content directly (for testing purposes).
|
|
386
|
+
* This bypasses all normalization and VM transformations.
|
|
387
|
+
*
|
|
388
|
+
* @param blockId The block to set storage for
|
|
389
|
+
* @param rawStorageJson Raw storage as JSON string
|
|
390
|
+
*/
|
|
391
|
+
setBlockStorageRaw(blockId, rawStorageJson) {
|
|
392
|
+
this.setBlockFieldObj(blockId, 'blockStorage', this.createJsonFieldValueByContent(rawStorageJson));
|
|
393
|
+
this.blocksWithChangedInputs.add(blockId);
|
|
394
|
+
this.updateLastModified();
|
|
395
|
+
}
|
|
396
|
+
/**
|
|
397
|
+
* Resets a v2+ block to its initial storage state.
|
|
398
|
+
* Gets initial storage from VM and derives args from it.
|
|
399
|
+
*
|
|
400
|
+
* For v1 blocks, use setStates() instead.
|
|
401
|
+
*
|
|
402
|
+
* @param blockId The block to reset
|
|
403
|
+
*/
|
|
404
|
+
resetToInitialStorage(blockId) {
|
|
405
|
+
const info = this.getBlockInfo(blockId);
|
|
406
|
+
const blockConfig = info.config;
|
|
407
|
+
if (blockConfig.modelAPIVersion !== 2) {
|
|
408
|
+
throw new Error('resetToInitialStorage is only supported for model API version 2');
|
|
409
|
+
}
|
|
410
|
+
// Get initial storage from VM
|
|
411
|
+
const initialStorageJson = this.projectHelper.getInitialStorageInVM(blockConfig);
|
|
412
|
+
this.setBlockStorageRaw(blockId, initialStorageJson);
|
|
413
|
+
// Derive args from storage - set or clear currentArgs based on derivation result
|
|
414
|
+
const deriveArgsResult = this.projectHelper.deriveArgsFromStorage(blockConfig, initialStorageJson);
|
|
415
|
+
if (!deriveArgsResult.error) {
|
|
416
|
+
this.setBlockFieldObj(blockId, 'currentArgs', this.createJsonFieldValue(deriveArgsResult.value));
|
|
417
|
+
// Derive prerunArgs from storage
|
|
418
|
+
const prerunArgs = this.projectHelper.derivePrerunArgsFromStorage(blockConfig, initialStorageJson);
|
|
419
|
+
if (prerunArgs !== undefined) {
|
|
420
|
+
this.setBlockFieldObj(blockId, 'currentPrerunArgs', this.createJsonFieldValue(prerunArgs));
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
else {
|
|
424
|
+
this.deleteBlockFields(blockId, 'currentArgs');
|
|
425
|
+
}
|
|
426
|
+
}
|
|
324
427
|
/** Optimally sets inputs for multiple blocks in one go */
|
|
325
428
|
setStates(requests) {
|
|
326
429
|
const changedArgs = [];
|
|
@@ -328,32 +431,76 @@ class ProjectMutator {
|
|
|
328
431
|
for (const req of requests) {
|
|
329
432
|
const info = this.getBlockInfo(req.blockId);
|
|
330
433
|
let blockChanged = false;
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
434
|
+
const blockConfig = info.config;
|
|
435
|
+
// modelAPIVersion === 2 means BlockModelV3 with .args() lambda for deriving args
|
|
436
|
+
if (req.modelAPIVersion !== blockConfig.modelAPIVersion) {
|
|
437
|
+
throw new Error(`Model API version mismatch for block ${req.blockId}: ${req.modelAPIVersion} !== ${blockConfig.modelAPIVersion}`);
|
|
438
|
+
}
|
|
439
|
+
// Derive args from storage using the block's config.args() callback
|
|
440
|
+
let args;
|
|
441
|
+
let prerunArgs;
|
|
442
|
+
if (req.modelAPIVersion === 2) {
|
|
443
|
+
const currentStorageJson = info.blockStorageJson;
|
|
444
|
+
if (currentStorageJson === undefined) {
|
|
445
|
+
throw new Error(`Block ${req.blockId} has no blockStorage - this should not happen`);
|
|
446
|
+
}
|
|
447
|
+
// Apply the state update to storage
|
|
448
|
+
const updatedStorageJson = this.projectHelper.applyStorageUpdateInVM(blockConfig, currentStorageJson, req.payload);
|
|
449
|
+
this.setBlockFieldObj(req.blockId, 'blockStorage', this.createJsonFieldValueByContent(updatedStorageJson));
|
|
450
|
+
// Derive args directly from storage (VM extracts data internally)
|
|
451
|
+
const derivedArgsResult = this.projectHelper.deriveArgsFromStorage(blockConfig, updatedStorageJson);
|
|
452
|
+
if (derivedArgsResult.error) {
|
|
453
|
+
args = undefined;
|
|
454
|
+
prerunArgs = undefined;
|
|
343
455
|
}
|
|
344
456
|
else {
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
457
|
+
args = derivedArgsResult.value;
|
|
458
|
+
// Derive prerunArgs from storage, or fall back to args
|
|
459
|
+
prerunArgs = this.projectHelper.derivePrerunArgsFromStorage(blockConfig, updatedStorageJson);
|
|
348
460
|
}
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
461
|
+
}
|
|
462
|
+
else {
|
|
463
|
+
this.setBlockFieldObj(req.blockId, 'blockStorage', this.createJsonFieldValue(req.state));
|
|
464
|
+
if (req.state !== null && typeof req.state === 'object' && 'args' in req.state) {
|
|
465
|
+
args = req.state.args;
|
|
466
|
+
}
|
|
467
|
+
else {
|
|
468
|
+
args = req.state;
|
|
469
|
+
}
|
|
470
|
+
// For the legacy blocks, prerunArgs = args (same as production args)
|
|
471
|
+
prerunArgs = args;
|
|
472
|
+
}
|
|
473
|
+
// Set or clear currentArgs based on derivation result
|
|
474
|
+
if (args !== undefined) {
|
|
475
|
+
const currentArgsData = tsHelpers.canonicalJsonBytes(args);
|
|
476
|
+
const argsPartRef = this.tx.createValue(plClient.Pl.JsonObject, currentArgsData);
|
|
477
|
+
this.setBlockField(req.blockId, 'currentArgs', argsPartRef, 'Ready', currentArgsData);
|
|
478
|
+
}
|
|
479
|
+
else {
|
|
480
|
+
this.deleteBlockFields(req.blockId, 'currentArgs');
|
|
481
|
+
}
|
|
482
|
+
// Set currentPrerunArgs field and check if it actually changed
|
|
483
|
+
let prerunArgsChanged = false;
|
|
484
|
+
if (prerunArgs !== undefined) {
|
|
485
|
+
const prerunArgsData = tsHelpers.canonicalJsonBytes(prerunArgs);
|
|
486
|
+
const oldPrerunArgsData = info.fields.currentPrerunArgs?.value;
|
|
487
|
+
// Check if prerunArgs actually changed
|
|
488
|
+
if (oldPrerunArgsData === undefined || Buffer.compare(oldPrerunArgsData, prerunArgsData) !== 0) {
|
|
489
|
+
prerunArgsChanged = true;
|
|
490
|
+
}
|
|
491
|
+
const prerunArgsRef = this.tx.createValue(plClient.Pl.JsonObject, prerunArgsData);
|
|
492
|
+
this.setBlockField(req.blockId, 'currentPrerunArgs', prerunArgsRef, 'Ready', prerunArgsData);
|
|
493
|
+
}
|
|
494
|
+
else {
|
|
495
|
+
// prerunArgs is undefined - check if we previously had one
|
|
496
|
+
if (info.fields.currentPrerunArgs !== undefined) {
|
|
497
|
+
prerunArgsChanged = true;
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
blockChanged = true;
|
|
501
|
+
// Only add to changedArgs if prerunArgs changed - this controls staging reset
|
|
502
|
+
if (prerunArgsChanged) {
|
|
503
|
+
changedArgs.push(req.blockId);
|
|
357
504
|
}
|
|
358
505
|
if (blockChanged) {
|
|
359
506
|
// will be assigned our author marker
|
|
@@ -395,15 +542,25 @@ class ProjectMutator {
|
|
|
395
542
|
exportCtx(ctx) {
|
|
396
543
|
return context_export.exportContext(this.tx, plClient.Pl.unwrapHolder(this.tx, this.ctxExportTplHolder), ctx);
|
|
397
544
|
}
|
|
545
|
+
/**
|
|
546
|
+
* Renders staging for a block using currentPrerunArgs.
|
|
547
|
+
* If currentPrerunArgs is not set (prerunArgs returned undefined), skips staging for this block.
|
|
548
|
+
*/
|
|
398
549
|
renderStagingFor(blockId) {
|
|
399
550
|
this.resetStaging(blockId);
|
|
400
551
|
const info = this.getBlockInfo(blockId);
|
|
552
|
+
// If currentPrerunArgs is not set (prerunArgs returned undefined), skip staging for this block
|
|
553
|
+
const prerunArgsRef = info.fields.currentPrerunArgs?.ref;
|
|
554
|
+
if (prerunArgsRef === undefined) {
|
|
555
|
+
return;
|
|
556
|
+
}
|
|
401
557
|
const ctx = this.createStagingCtx(this.getStagingGraph().nodes.get(blockId).upstream);
|
|
402
558
|
if (this.getBlock(blockId).renderingMode !== 'Heavy')
|
|
403
559
|
throw new Error('not supported yet');
|
|
404
560
|
const tpl = info.getTemplate(this.tx);
|
|
561
|
+
// Use currentPrerunArgs for staging rendering
|
|
405
562
|
const results = render_block.createRenderHeavyBlock(this.tx, tpl, {
|
|
406
|
-
args:
|
|
563
|
+
args: prerunArgsRef,
|
|
407
564
|
blockId: this.tx.createValue(plClient.Pl.JsonString, JSON.stringify(blockId)),
|
|
408
565
|
isProduction: this.tx.createValue(plClient.Pl.JsonBool, JSON.stringify(false)),
|
|
409
566
|
context: ctx,
|
|
@@ -420,6 +577,10 @@ class ProjectMutator {
|
|
|
420
577
|
renderProductionFor(blockId) {
|
|
421
578
|
this.resetProduction(blockId);
|
|
422
579
|
const info = this.getBlockInfo(blockId);
|
|
580
|
+
// Can't render production if currentArgs is not set
|
|
581
|
+
if (info.fields.currentArgs === undefined) {
|
|
582
|
+
throw new Error(`Can't render production for block ${blockId}: currentArgs not set`);
|
|
583
|
+
}
|
|
423
584
|
const ctx = this.createProdCtx(this.getPendingProductionGraph().nodes.get(blockId).upstream);
|
|
424
585
|
if (this.getBlock(blockId).renderingMode === 'Light')
|
|
425
586
|
throw new Error('Can\'t render production for light block.');
|
|
@@ -450,10 +611,47 @@ class ProjectMutator {
|
|
|
450
611
|
this.setBlockField(blockId, 'blockPack', plClient.Pl.wrapInHolder(this.tx, bp), 'NotReady');
|
|
451
612
|
// settings
|
|
452
613
|
this.setBlockFieldObj(blockId, 'blockSettings', this.createJsonFieldValue(plModelMiddleLayer.InitialBlockSettings));
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
614
|
+
const blockConfig = info.config;
|
|
615
|
+
let args;
|
|
616
|
+
let prerunArgs;
|
|
617
|
+
let storageToWrite;
|
|
618
|
+
if (spec.storageMode === 'fromModel') {
|
|
619
|
+
// Model API v2+: get initial storage and derive args from it
|
|
620
|
+
storageToWrite = this.projectHelper.getInitialStorageInVM(blockConfig);
|
|
621
|
+
// Derive args directly from storage (VM extracts data internally)
|
|
622
|
+
const deriveArgsResult = this.projectHelper.deriveArgsFromStorage(blockConfig, storageToWrite);
|
|
623
|
+
if (deriveArgsResult.error) {
|
|
624
|
+
args = undefined;
|
|
625
|
+
prerunArgs = undefined;
|
|
626
|
+
}
|
|
627
|
+
else {
|
|
628
|
+
args = deriveArgsResult.value;
|
|
629
|
+
prerunArgs = this.projectHelper.derivePrerunArgsFromStorage(blockConfig, storageToWrite);
|
|
630
|
+
}
|
|
631
|
+
}
|
|
632
|
+
else if (spec.storageMode === 'legacy') {
|
|
633
|
+
// Model API v1: use legacyState from spec
|
|
634
|
+
const parsedState = JSON.parse(spec.legacyState);
|
|
635
|
+
args = parsedState.args;
|
|
636
|
+
if (args === undefined) {
|
|
637
|
+
throw new Error('args is undefined in legacyState');
|
|
638
|
+
}
|
|
639
|
+
prerunArgs = args;
|
|
640
|
+
storageToWrite = spec.legacyState;
|
|
641
|
+
}
|
|
642
|
+
else {
|
|
643
|
+
throw new Error(`Unknown storageMode: ${spec.storageMode}`);
|
|
644
|
+
}
|
|
645
|
+
// currentArgs
|
|
646
|
+
if (args !== undefined) {
|
|
647
|
+
this.setBlockFieldObj(blockId, 'currentArgs', this.createJsonFieldValue(args));
|
|
648
|
+
}
|
|
649
|
+
// currentPrerunArgs
|
|
650
|
+
if (prerunArgs !== undefined) {
|
|
651
|
+
this.setBlockFieldObj(blockId, 'currentPrerunArgs', this.createJsonFieldValue(prerunArgs));
|
|
652
|
+
}
|
|
653
|
+
// blockStorage
|
|
654
|
+
this.setBlockFieldObj(blockId, 'blockStorage', this.createJsonFieldValueByContent(storageToWrite));
|
|
457
655
|
// checking structure
|
|
458
656
|
info.check();
|
|
459
657
|
}
|
|
@@ -629,14 +827,53 @@ class ProjectMutator {
|
|
|
629
827
|
//
|
|
630
828
|
// Block-pack migration
|
|
631
829
|
//
|
|
632
|
-
migrateBlockPack(blockId, spec,
|
|
830
|
+
migrateBlockPack(blockId, spec, newClearState) {
|
|
633
831
|
const info = this.getBlockInfo(blockId);
|
|
832
|
+
const newConfig = model.extractConfig(spec.config);
|
|
634
833
|
this.setBlockField(blockId, 'blockPack', plClient.Pl.wrapInHolder(this.tx, block_pack.createBlockPack(this.tx, spec)), 'NotReady');
|
|
635
|
-
if (
|
|
636
|
-
//
|
|
637
|
-
|
|
834
|
+
if (newClearState !== undefined) {
|
|
835
|
+
// State is being reset - no migration needed
|
|
836
|
+
const supportsStorageFromVM = newConfig.modelAPIVersion === 2;
|
|
837
|
+
if (supportsStorageFromVM) {
|
|
838
|
+
// V2+: Get initial storage directly from VM and derive args from it
|
|
839
|
+
const initialStorageJson = this.projectHelper.getInitialStorageInVM(newConfig);
|
|
840
|
+
this.setBlockStorageRaw(blockId, initialStorageJson);
|
|
841
|
+
// Derive args from storage - only set currentArgs if derivation succeeds
|
|
842
|
+
const deriveArgsResult = this.projectHelper.deriveArgsFromStorage(newConfig, initialStorageJson);
|
|
843
|
+
if (!deriveArgsResult.error) {
|
|
844
|
+
this.setBlockFieldObj(blockId, 'currentArgs', this.createJsonFieldValue(deriveArgsResult.value));
|
|
845
|
+
// Derive prerunArgs from storage
|
|
846
|
+
const prerunArgs = this.projectHelper.derivePrerunArgsFromStorage(newConfig, initialStorageJson);
|
|
847
|
+
if (prerunArgs !== undefined) {
|
|
848
|
+
this.setBlockFieldObj(blockId, 'currentPrerunArgs', this.createJsonFieldValue(prerunArgs));
|
|
849
|
+
}
|
|
850
|
+
}
|
|
851
|
+
this.blocksWithChangedInputs.add(blockId);
|
|
852
|
+
this.updateLastModified();
|
|
853
|
+
}
|
|
854
|
+
else {
|
|
855
|
+
// V1: Use setStates with legacy state format
|
|
856
|
+
this.setStates([{ modelAPIVersion: 1, blockId, state: newClearState.state }]);
|
|
857
|
+
}
|
|
638
858
|
}
|
|
639
859
|
else {
|
|
860
|
+
// State is being preserved - run migrations if needed via VM
|
|
861
|
+
// Only Model API v2 blocks support migrations
|
|
862
|
+
const supportsStateMigrations = newConfig.modelAPIVersion === 2;
|
|
863
|
+
if (supportsStateMigrations) {
|
|
864
|
+
const currentStorageJson = info.blockStorageJson;
|
|
865
|
+
const migrationResult = this.projectHelper.migrateStorageInVM(newConfig, currentStorageJson);
|
|
866
|
+
if (migrationResult.error !== undefined) {
|
|
867
|
+
console.error(`[migrateBlockPack] Block ${blockId} migration error: ${migrationResult.error}`);
|
|
868
|
+
}
|
|
869
|
+
else {
|
|
870
|
+
console.log(`[migrateBlockPack] Block ${blockId}: ${migrationResult.info}`);
|
|
871
|
+
if (migrationResult.warn) {
|
|
872
|
+
console.warn(`[migrateBlockPack] Block ${blockId} migration warning: ${migrationResult.warn}`);
|
|
873
|
+
}
|
|
874
|
+
this.setBlockStorageRaw(blockId, migrationResult.newStorageJson);
|
|
875
|
+
}
|
|
876
|
+
}
|
|
640
877
|
// resetting staging outputs for all downstream blocks
|
|
641
878
|
this.getStagingGraph().traverse('downstream', [blockId], ({ id }) => this.resetStaging(id));
|
|
642
879
|
}
|
|
@@ -737,13 +974,16 @@ class ProjectMutator {
|
|
|
737
974
|
const stagingGraph = this.getStagingGraph();
|
|
738
975
|
stagingGraph.nodes.forEach((node) => {
|
|
739
976
|
const info = this.getBlockInfo(node.id);
|
|
740
|
-
|
|
977
|
+
// Use requireStagingRendering to check both: staging exists AND prerunArgs hasn't changed
|
|
978
|
+
const requiresRendering = info.requireStagingRendering;
|
|
979
|
+
let lag = requiresRendering ? 1 : 0;
|
|
741
980
|
node.upstream.forEach((upstream) => {
|
|
742
981
|
const upstreamLag = lags.get(upstream);
|
|
743
982
|
if (upstreamLag === 0)
|
|
744
983
|
return;
|
|
745
984
|
lag = Math.max(upstreamLag + 1, lag);
|
|
746
985
|
});
|
|
986
|
+
if (!requiresRendering && info.stagingRendered) ;
|
|
747
987
|
cb(node.id, lag);
|
|
748
988
|
lags.set(node.id, lag);
|
|
749
989
|
});
|
|
@@ -760,6 +1000,7 @@ class ProjectMutator {
|
|
|
760
1000
|
// meaning staging already rendered
|
|
761
1001
|
return;
|
|
762
1002
|
if (lagThreshold === undefined || lag <= lagThreshold) {
|
|
1003
|
+
// console.log(`[refreshStagings] RENDER staging for ${blockId} (lag=${lag})`);
|
|
763
1004
|
this.renderStagingFor(blockId);
|
|
764
1005
|
rendered++;
|
|
765
1006
|
}
|