@milaboratories/pl-middle-layer 1.48.23 → 1.48.24
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/mutator/project.cjs +40 -9
- package/dist/mutator/project.cjs.map +1 -1
- package/dist/mutator/project.js +40 -9
- package/dist/mutator/project.js.map +1 -1
- package/package.json +11 -11
- package/src/mutator/project.ts +37 -9
package/dist/mutator/project.cjs
CHANGED
|
@@ -12,6 +12,7 @@ let _milaboratories_ts_helpers = require("@milaboratories/ts-helpers");
|
|
|
12
12
|
let _milaboratories_pl_client = require("@milaboratories/pl-client");
|
|
13
13
|
let denque = require("denque");
|
|
14
14
|
denque = require_runtime.__toESM(denque);
|
|
15
|
+
let node_zlib = require("node:zlib");
|
|
15
16
|
|
|
16
17
|
//#region src/mutator/project.ts
|
|
17
18
|
function cached(modIdCb, valueCb) {
|
|
@@ -217,17 +218,47 @@ var ProjectMutator = class ProjectMutator {
|
|
|
217
218
|
if (info === void 0) throw new Error(`No such block: ${blockId}`);
|
|
218
219
|
return info;
|
|
219
220
|
}
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
const value = Buffer.from(
|
|
221
|
+
/** Create a plain JSON resource value from a JS object (no compression). */
|
|
222
|
+
createJsonFieldValue(obj) {
|
|
223
|
+
const value = Buffer.from(JSON.stringify(obj));
|
|
223
224
|
return {
|
|
224
225
|
ref: this.tx.createValue(_milaboratories_pl_client.Pl.JsonObject, value),
|
|
225
226
|
value,
|
|
226
227
|
status: "Ready"
|
|
227
228
|
};
|
|
228
229
|
}
|
|
229
|
-
|
|
230
|
-
|
|
230
|
+
/** Create a plain JSON resource value from a pre-serialized JSON string (no compression). */
|
|
231
|
+
createJsonFieldValueFromContent(json) {
|
|
232
|
+
const value = Buffer.from(json);
|
|
233
|
+
return {
|
|
234
|
+
ref: this.tx.createValue(_milaboratories_pl_client.Pl.JsonObject, value),
|
|
235
|
+
value,
|
|
236
|
+
status: "Ready"
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
/** Create a gzip-compressed JSON resource value from a JS object (compressed if >= 16KB). */
|
|
240
|
+
createGzJsonFieldValue(obj) {
|
|
241
|
+
const jsonBytes = (0, _milaboratories_ts_helpers.canonicalJsonBytes)(obj);
|
|
242
|
+
return this.createGzJsonFieldValueFromBytes(jsonBytes);
|
|
243
|
+
}
|
|
244
|
+
/** Create a gzip-compressed JSON resource value from a pre-serialized JSON string (compressed if >= 16KB). */
|
|
245
|
+
createGzJsonFieldValueFromContent(json) {
|
|
246
|
+
return this.createGzJsonFieldValueFromBytes(Buffer.from(json));
|
|
247
|
+
}
|
|
248
|
+
createGzJsonFieldValueFromBytes(jsonBytes) {
|
|
249
|
+
if (jsonBytes.length >= 16384) {
|
|
250
|
+
const data = (0, node_zlib.gzipSync)(jsonBytes);
|
|
251
|
+
return {
|
|
252
|
+
ref: this.tx.createValue(_milaboratories_pl_client.Pl.JsonGzObject, data),
|
|
253
|
+
value: data,
|
|
254
|
+
status: "Ready"
|
|
255
|
+
};
|
|
256
|
+
}
|
|
257
|
+
return {
|
|
258
|
+
ref: this.tx.createValue(_milaboratories_pl_client.Pl.JsonObject, jsonBytes),
|
|
259
|
+
value: jsonBytes,
|
|
260
|
+
status: "Ready"
|
|
261
|
+
};
|
|
231
262
|
}
|
|
232
263
|
getBlock(blockId) {
|
|
233
264
|
for (const block of require_project_model_util.allBlocks(this.struct)) if (block.id === blockId) return block;
|
|
@@ -327,7 +358,7 @@ var ProjectMutator = class ProjectMutator {
|
|
|
327
358
|
* @param rawStorageJson Raw storage as JSON string
|
|
328
359
|
*/
|
|
329
360
|
setBlockStorageRaw(blockId, rawStorageJson) {
|
|
330
|
-
this.setBlockFieldObj(blockId, "blockStorage", this.
|
|
361
|
+
this.setBlockFieldObj(blockId, "blockStorage", this.createGzJsonFieldValueFromContent(rawStorageJson));
|
|
331
362
|
this.blocksWithChangedInputs.add(blockId);
|
|
332
363
|
this.updateLastModified();
|
|
333
364
|
}
|
|
@@ -372,7 +403,7 @@ var ProjectMutator = class ProjectMutator {
|
|
|
372
403
|
const currentStorageJson = info.blockStorageJson;
|
|
373
404
|
if (currentStorageJson === void 0) throw new Error(`Block ${req.blockId} has no blockStorage - this should not happen`);
|
|
374
405
|
const updatedStorageJson = this.projectHelper.applyStorageUpdateInVM(blockConfig, currentStorageJson, req.payload);
|
|
375
|
-
this.setBlockFieldObj(req.blockId, "blockStorage", this.
|
|
406
|
+
this.setBlockFieldObj(req.blockId, "blockStorage", this.createGzJsonFieldValueFromContent(updatedStorageJson));
|
|
376
407
|
const derivedArgsResult = this.projectHelper.deriveArgsFromStorage(blockConfig, updatedStorageJson);
|
|
377
408
|
if (derivedArgsResult.error) {
|
|
378
409
|
args = void 0;
|
|
@@ -382,7 +413,7 @@ var ProjectMutator = class ProjectMutator {
|
|
|
382
413
|
prerunArgs = this.projectHelper.derivePrerunArgsFromStorage(blockConfig, updatedStorageJson);
|
|
383
414
|
}
|
|
384
415
|
} else {
|
|
385
|
-
this.setBlockFieldObj(req.blockId, "blockStorage", this.
|
|
416
|
+
this.setBlockFieldObj(req.blockId, "blockStorage", this.createGzJsonFieldValue(req.state));
|
|
386
417
|
if (req.state !== null && typeof req.state === "object" && "args" in req.state) args = req.state.args;
|
|
387
418
|
else args = req.state;
|
|
388
419
|
prerunArgs = args;
|
|
@@ -505,7 +536,7 @@ var ProjectMutator = class ProjectMutator {
|
|
|
505
536
|
} else throw new Error(`Unknown storageMode: ${spec.storageMode}`);
|
|
506
537
|
if (args !== void 0) this.setBlockFieldObj(blockId, "currentArgs", this.createJsonFieldValue(args));
|
|
507
538
|
if (prerunArgs !== void 0) this.setBlockFieldObj(blockId, "currentPrerunArgs", this.createJsonFieldValue(prerunArgs));
|
|
508
|
-
this.setBlockFieldObj(blockId, "blockStorage", this.
|
|
539
|
+
this.setBlockFieldObj(blockId, "blockStorage", this.createGzJsonFieldValueFromContent(storageToWrite));
|
|
509
540
|
info.check();
|
|
510
541
|
}
|
|
511
542
|
getFieldNamesToDuplicate(blockId) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"project.cjs","names":["ConsoleLoggerAdapter","Pl","BlockPackTemplateField","InitialBlockSettings","stagingGraph","productionGraph","allBlocks","projectFieldName","BLOCK_STORAGE_FACADE_VERSION","createBContextFromUpstreams","exportContext","createRenderHeavyBlock","createBlockPack","FieldsToDuplicate","graphDiff","Denque","blockArgsAuthorKey","ProjectStructureAuthorKey","ProjectLastModifiedTimestamp","ProjectStructureKey","BlockRenderingStateKey","ProjectMetaKey","SchemaVersionKey","parseProjectField","SchemaVersionCurrent","UiError","getPreparedExportTemplateEnvelope","getServiceTemplateField","loadTemplate","InitialBlockMeta","ProjectResourceType","ProjectCreatedTimestamp","InitialBlockStructure","InitialProjectRenderingState","PlClient","getDebugFlags"],"sources":["../../src/mutator/project.ts"],"sourcesContent":["import type {\n AnyRef,\n AnyResourceRef,\n BasicResourceData,\n PlTransaction,\n ResourceData,\n ResourceId,\n TxOps,\n} from \"@milaboratories/pl-client\";\nimport {\n ensureResourceIdNotNull,\n field,\n isNotNullResourceId,\n isNullResourceId,\n isResource,\n isResourceId,\n isResourceRef,\n Pl,\n PlClient,\n} from \"@milaboratories/pl-client\";\nimport { createRenderHeavyBlock, createBContextFromUpstreams } from \"./template/render_block\";\nimport type {\n Block,\n ProjectStructure,\n ProjectField,\n ProjectRenderingState,\n} from \"../model/project_model\";\nimport {\n BlockRenderingStateKey,\n ProjectStructureKey,\n parseProjectField,\n projectFieldName,\n SchemaVersionCurrent,\n SchemaVersionKey,\n ProjectResourceType,\n InitialBlockStructure,\n InitialProjectRenderingState,\n ProjectMetaKey,\n InitialBlockMeta,\n blockArgsAuthorKey,\n ProjectLastModifiedTimestamp,\n ProjectCreatedTimestamp,\n ProjectStructureAuthorKey,\n getServiceTemplateField,\n FieldsToDuplicate,\n} from \"../model/project_model\";\nimport { BlockPackTemplateField, createBlockPack } from \"./block-pack/block_pack\";\nimport type { BlockGraph, ProductionGraphBlockInfo } from \"../model/project_model_util\";\nimport { allBlocks, graphDiff, productionGraph, stagingGraph } from \"../model/project_model_util\";\nimport type { BlockPackSpecPrepared } from \"../model\";\nimport type {\n AuthorMarker,\n BlockPackSpec,\n BlockSettings,\n ProjectMeta,\n} from \"@milaboratories/pl-model-middle-layer\";\nimport { InitialBlockSettings } from \"@milaboratories/pl-model-middle-layer\";\nimport Denque from \"denque\";\nimport { exportContext, getPreparedExportTemplateEnvelope } from \"./context_export\";\nimport { loadTemplate } from \"./template/template_loading\";\nimport {\n cachedDeserialize,\n notEmpty,\n canonicalJsonBytes,\n cachedDecode,\n type MiLogger,\n ConsoleLoggerAdapter,\n} from \"@milaboratories/ts-helpers\";\nimport type { ProjectHelper } from \"../model/project_helper\";\nimport {\n extractConfig,\n UiError,\n BLOCK_STORAGE_FACADE_VERSION,\n type BlockConfig,\n} from \"@platforma-sdk/model\";\nimport { getDebugFlags } from \"../debug\";\nimport type { BlockPackInfo } from \"../model/block_pack\";\n\ntype FieldStatus = \"NotReady\" | \"Ready\" | \"Error\";\n\ninterface BlockFieldState {\n modCount: number;\n ref?: AnyRef;\n status?: FieldStatus;\n value?: Uint8Array;\n}\n\ntype BlockFieldStates = Partial<Record<ProjectField[\"fieldName\"], BlockFieldState>>;\ntype BlockFieldStateValue = Omit<BlockFieldState, \"modCount\">;\n\ninterface BlockInfoState {\n readonly id: string;\n readonly fields: BlockFieldStates;\n blockConfig?: BlockConfig;\n blockPack?: BlockPackSpec;\n}\n\nfunction cached<ModId, T>(modIdCb: () => ModId, valueCb: () => T): () => T {\n let initialized = false;\n let lastModId: ModId | undefined = undefined;\n let value: T | undefined = undefined;\n return () => {\n if (!initialized) {\n initialized = true;\n lastModId = modIdCb();\n value = valueCb();\n return value;\n }\n const currentModId = modIdCb();\n if (lastModId !== currentModId) {\n lastModId = currentModId;\n value = valueCb();\n }\n return valueCb();\n };\n}\n\nclass BlockInfo {\n constructor(\n public readonly id: string,\n public readonly fields: BlockFieldStates,\n public readonly config: BlockConfig,\n public readonly source: BlockPackSpec,\n private readonly logger: MiLogger = new ConsoleLoggerAdapter(),\n ) {}\n\n public check() {\n // state assertions\n\n if ((this.fields.prodOutput === undefined) !== (this.fields.prodCtx === undefined))\n throw new Error(\"inconsistent prod fields\");\n\n if ((this.fields.stagingOutput === undefined) !== (this.fields.stagingCtx === undefined))\n throw new Error(\"inconsistent stage fields\");\n\n if (\n (this.fields.prodOutputPrevious === undefined) !==\n (this.fields.prodCtxPrevious === undefined)\n )\n throw new Error(\"inconsistent prod cache fields\");\n\n if (\n (this.fields.stagingOutputPrevious === undefined) !==\n (this.fields.stagingCtxPrevious === undefined)\n )\n throw new Error(\"inconsistent stage cache fields\");\n\n if (this.fields.blockPack === undefined) throw new Error(\"no block pack field\");\n\n if (this.fields.blockStorage === undefined) throw new Error(\"no block storage field\");\n }\n\n private readonly currentArgsC = cached(\n () => this.fields.currentArgs?.modCount,\n () => {\n const bin = this.fields.currentArgs?.value;\n if (bin === undefined) return undefined;\n return cachedDeserialize(bin);\n },\n );\n\n private readonly blockStorageC = cached(\n () => this.fields.blockStorage!.modCount,\n () => {\n const bin = this.fields.blockStorage?.value;\n if (bin === undefined) return undefined;\n return cachedDeserialize<Record<string, unknown>>(bin);\n },\n );\n\n private readonly blockStorageJ = cached(\n () => this.fields.blockStorage!.modCount,\n () => {\n const bin = this.fields.blockStorage?.value;\n if (bin === undefined) return undefined;\n return cachedDecode(bin);\n },\n );\n\n private readonly prodArgsC = cached(\n () => this.fields.prodArgs?.modCount,\n () => {\n const bin = this.fields.prodArgs?.value;\n if (bin === undefined) return undefined;\n return cachedDeserialize(bin);\n },\n );\n\n private readonly currentPrerunArgsC = cached(\n () => this.fields.currentPrerunArgs?.modCount,\n () => {\n const bin = this.fields.currentPrerunArgs?.value;\n if (bin === undefined) return undefined;\n return cachedDeserialize(bin);\n },\n );\n\n get currentArgs(): unknown {\n return this.currentArgsC();\n }\n\n get blockStorage(): unknown {\n try {\n return this.blockStorageC();\n } catch (e) {\n this.logger.error(new Error(`Error getting blockStorage for ${this.id}`, { cause: e }));\n return undefined;\n }\n }\n\n get blockStorageJson() {\n return this.blockStorageJ();\n }\n\n get currentPrerunArgs(): unknown {\n return this.currentPrerunArgsC();\n }\n\n get stagingRendered(): boolean {\n return this.fields.stagingCtx !== undefined;\n }\n\n get productionRendered(): boolean {\n return this.fields.prodCtx !== undefined;\n }\n\n get productionHasErrors(): boolean {\n return this.fields.prodUiCtx?.status === \"Error\";\n }\n\n private readonly productionStaleC: () => boolean = cached(\n () => `${this.fields.currentArgs!.modCount}_${this.fields.prodArgs?.modCount}`,\n () =>\n this.fields.prodArgs === undefined ||\n Buffer.compare(this.fields.currentArgs!.value!, this.fields.prodArgs.value!) !== 0,\n );\n\n get requireProductionRendering(): boolean {\n return !this.productionRendered || this.productionStaleC() || this.productionHasErrors;\n }\n\n /** Returns true if staging should be re-rendered (stagingCtx is not set) */\n get requireStagingRendering(): boolean {\n // No staging needed if currentPrerunArgs is undefined (args derivation failed)\n if (this.fields.currentPrerunArgs === undefined) return false;\n return !this.stagingRendered;\n }\n\n get prodArgs(): unknown {\n return this.prodArgsC();\n }\n\n public getTemplate(tx: PlTransaction): AnyRef {\n return tx.getFutureFieldValue(\n Pl.unwrapHolder(tx, this.fields.blockPack!.ref!),\n BlockPackTemplateField,\n \"Input\",\n );\n }\n}\n\n/**\n * Specification for creating a new block.\n * Discriminated union based on `storageMode`.\n */\n/** Specification for creating a new block. Discriminated union based on `storageMode`. */\nexport type NewBlockSpec =\n | { storageMode: \"fromModel\"; blockPack: BlockPackSpecPrepared }\n | { storageMode: \"legacy\"; blockPack: BlockPackSpecPrepared; legacyState: string };\n\nconst NoNewBlocks = (blockId: string) => {\n throw new Error(`No new block info for ${blockId}`);\n};\n\n/**\n * Request to set block state using unified state format.\n * For v3 blocks: state is the block's state\n * For v1/v2 blocks: state should be { args, uiState } format\n */\nexport type SetStatesRequest =\n | {\n blockId: string;\n /** The unified state to set */\n state: unknown;\n modelAPIVersion: 1;\n }\n | {\n blockId: string;\n /** Storage operation payload - middle layer is agnostic to specific operations */\n payload: { operation: string; value: unknown };\n modelAPIVersion: 2;\n };\n\nexport type ClearState = {\n state: unknown;\n};\n\nexport class ProjectMutator {\n private globalModCount = 0;\n private fieldsChanged: boolean = false;\n\n //\n // Change trackers\n //\n\n private lastModifiedChanged = false;\n private structureChanged = false;\n private metaChanged = false;\n private renderingStateChanged = false;\n\n /** Set blocks will be assigned current mutator author marker on save */\n private readonly blocksWithChangedInputs = new Set<string>();\n\n constructor(\n public readonly rid: ResourceId,\n private readonly tx: PlTransaction,\n private readonly author: AuthorMarker | undefined,\n private readonly schema: string,\n private lastModified: number,\n private meta: ProjectMeta,\n private struct: ProjectStructure,\n private readonly renderingState: Omit<ProjectRenderingState, \"blocksInLimbo\">,\n private readonly blocksInLimbo: Set<string>,\n private readonly blockInfos: Map<string, BlockInfo>,\n private readonly ctxExportTplHolder: AnyResourceRef,\n private readonly projectHelper: ProjectHelper,\n ) {}\n\n private fixProblemsAndMigrate() {\n // Fix inconsistent production fields\n this.blockInfos.forEach((blockInfo) => {\n if (\n blockInfo.fields.prodArgs === undefined ||\n blockInfo.fields.prodOutput === undefined ||\n blockInfo.fields.prodCtx === undefined\n )\n this.deleteBlockFields(blockInfo.id, \"prodArgs\", \"prodOutput\", \"prodCtx\", \"prodUiCtx\");\n });\n\n // Fix inconsistent staging fields\n this.blockInfos.forEach((blockInfo) => {\n if (blockInfo.fields.stagingOutput === undefined || blockInfo.fields.stagingCtx === undefined)\n this.deleteBlockFields(blockInfo.id, \"stagingOutput\", \"stagingCtx\", \"stagingUiCtx\");\n });\n\n // Fix inconsistent cache fields\n this.blockInfos.forEach((blockInfo) => {\n if (\n blockInfo.fields.prodOutputPrevious === undefined ||\n blockInfo.fields.prodCtxPrevious === undefined\n )\n this.deleteBlockFields(\n blockInfo.id,\n \"prodOutputPrevious\",\n \"prodCtxPrevious\",\n \"prodUiCtxPrevious\",\n );\n if (\n blockInfo.fields.stagingOutputPrevious === undefined ||\n blockInfo.fields.stagingCtxPrevious === undefined\n )\n this.deleteBlockFields(\n blockInfo.id,\n \"stagingOutputPrevious\",\n \"stagingCtxPrevious\",\n \"stagingUiCtxPrevious\",\n );\n });\n\n // Migration for addition of block settings field\n let initialBlockSettings: Omit<BlockFieldState, \"modCount\"> | undefined;\n this.blockInfos.forEach((blockInfo) => {\n if (blockInfo.fields.blockSettings === undefined) {\n if (initialBlockSettings === undefined)\n initialBlockSettings = this.createJsonFieldValue(InitialBlockSettings);\n this.setBlockFieldObj(blockInfo.id, \"blockSettings\", initialBlockSettings);\n }\n });\n\n // Validate after fixes\n this.blockInfos.forEach((info) => info.check());\n }\n\n get wasModified(): boolean {\n return (\n this.lastModifiedChanged ||\n this.structureChanged ||\n this.fieldsChanged ||\n this.metaChanged ||\n this.renderingStateChanged\n );\n }\n\n get structure(): ProjectStructure {\n return JSON.parse(JSON.stringify(this.struct)) as ProjectStructure;\n }\n\n //\n // Graph calculation\n //\n\n private stagingGraph: BlockGraph | undefined = undefined;\n private pendingProductionGraph: BlockGraph | undefined = undefined;\n private actualProductionGraph: BlockGraph | undefined = undefined;\n\n private getStagingGraph(): BlockGraph {\n if (this.stagingGraph === undefined) this.stagingGraph = stagingGraph(this.struct);\n return this.stagingGraph;\n }\n\n private getProductionGraphBlockInfo(\n blockId: string,\n prod: boolean,\n ): ProductionGraphBlockInfo | undefined {\n const bInfo = this.getBlockInfo(blockId);\n\n let argsField: BlockFieldState | undefined;\n let args: unknown;\n\n if (prod) {\n if (bInfo.fields.prodArgs === undefined) return undefined;\n argsField = bInfo.fields.prodArgs;\n args = bInfo.prodArgs;\n } else {\n argsField = bInfo.fields.currentArgs;\n args = bInfo.currentArgs;\n }\n\n // Can't compute enrichment targets without args\n if (argsField === undefined) {\n return { args, enrichmentTargets: undefined };\n }\n\n const blockPackField = notEmpty(bInfo.fields.blockPack);\n\n if (isResourceId(argsField.ref!) && isResourceId(blockPackField.ref!))\n return {\n args,\n enrichmentTargets: this.projectHelper.getEnrichmentTargets(\n () => bInfo.config,\n () => args,\n { argsRid: argsField.ref, blockPackRid: blockPackField.ref },\n ),\n };\n else\n return {\n args,\n enrichmentTargets: this.projectHelper.getEnrichmentTargets(\n () => bInfo.config,\n () => args,\n ),\n };\n }\n\n private getPendingProductionGraph(): BlockGraph {\n if (this.pendingProductionGraph === undefined)\n this.pendingProductionGraph = productionGraph(this.struct, (blockId) =>\n this.getProductionGraphBlockInfo(blockId, false),\n );\n return this.pendingProductionGraph;\n }\n\n private getActualProductionGraph(): BlockGraph {\n if (this.actualProductionGraph === undefined)\n this.actualProductionGraph = productionGraph(this.struct, (blockId) =>\n this.getProductionGraphBlockInfo(blockId, true),\n );\n return this.actualProductionGraph;\n }\n\n //\n // Generic helpers to interact with project state\n //\n\n private getBlockInfo(blockId: string): BlockInfo {\n const info = this.blockInfos.get(blockId);\n if (info === undefined) throw new Error(`No such block: ${blockId}`);\n return info;\n }\n\n private createJsonFieldValueByContent(content: string): BlockFieldStateValue {\n if (content === undefined) throw new Error(\"content is undefined\");\n const value = Buffer.from(content);\n const ref = this.tx.createValue(Pl.JsonObject, value);\n return { ref, value, status: \"Ready\" };\n }\n\n private createJsonFieldValue(obj: unknown): BlockFieldStateValue {\n return this.createJsonFieldValueByContent(JSON.stringify(obj));\n }\n\n private getBlock(blockId: string): Block {\n for (const block of allBlocks(this.struct)) if (block.id === blockId) return block;\n throw new Error(\"block not found\");\n }\n\n private setBlockFieldObj(\n blockId: string,\n fieldName: keyof BlockFieldStates,\n state: BlockFieldStateValue,\n ) {\n const fid = field(this.rid, projectFieldName(blockId, fieldName));\n\n if (state.ref === undefined) throw new Error(\"Can't set value with empty ref\");\n\n if (this.getBlockInfo(blockId).fields[fieldName] === undefined)\n this.tx.createField(fid, \"Dynamic\", state.ref);\n else this.tx.setField(fid, state.ref);\n\n this.getBlockInfo(blockId).fields[fieldName] = {\n modCount: this.globalModCount++,\n ...state,\n };\n\n this.fieldsChanged = true;\n }\n\n private setBlockField(\n blockId: string,\n fieldName: keyof BlockFieldStates,\n ref: AnyRef,\n status: FieldStatus,\n value?: Uint8Array,\n ) {\n this.setBlockFieldObj(blockId, fieldName, { ref, status, value });\n }\n\n private deleteBlockFields(blockId: string, ...fieldNames: (keyof BlockFieldStates)[]): boolean {\n let deleted = false;\n const info = this.getBlockInfo(blockId);\n for (const fieldName of fieldNames) {\n const fields = info.fields;\n if (!(fieldName in fields)) continue;\n this.tx.removeField(field(this.rid, projectFieldName(blockId, fieldName)));\n delete fields[fieldName];\n this.fieldsChanged = true;\n deleted = true;\n }\n return deleted;\n }\n\n private updateLastModified() {\n this.lastModified = Date.now();\n this.lastModifiedChanged = true;\n }\n\n //\n // Main project actions\n //\n\n private resetStagingRefreshTimestamp() {\n this.renderingState.stagingRefreshTimestamp = Date.now();\n this.renderingStateChanged = true;\n }\n\n private resetStaging(blockId: string): void {\n const fields = this.getBlockInfo(blockId).fields;\n if (\n fields.stagingOutput?.status === \"Ready\" &&\n fields.stagingCtx?.status === \"Ready\" &&\n fields.stagingUiCtx?.status === \"Ready\"\n ) {\n this.setBlockFieldObj(blockId, \"stagingOutputPrevious\", fields.stagingOutput);\n this.setBlockFieldObj(blockId, \"stagingCtxPrevious\", fields.stagingCtx);\n this.setBlockFieldObj(blockId, \"stagingUiCtxPrevious\", fields.stagingUiCtx);\n }\n if (this.deleteBlockFields(blockId, \"stagingOutput\", \"stagingCtx\", \"stagingUiCtx\"))\n this.resetStagingRefreshTimestamp();\n }\n\n private resetProduction(blockId: string): void {\n const fields = this.getBlockInfo(blockId).fields;\n if (\n fields.prodOutput?.status === \"Ready\" &&\n fields.prodCtx?.status === \"Ready\" &&\n fields.prodUiCtx?.status === \"Ready\"\n ) {\n this.setBlockFieldObj(blockId, \"prodOutputPrevious\", fields.prodOutput);\n this.setBlockFieldObj(blockId, \"prodCtxPrevious\", fields.prodCtx);\n this.setBlockFieldObj(blockId, \"prodUiCtxPrevious\", fields.prodUiCtx);\n }\n this.deleteBlockFields(blockId, \"prodOutput\", \"prodCtx\", \"prodUiCtx\", \"prodArgs\");\n }\n\n /** Running blocks are reset, already computed moved to limbo. Returns if\n * either of the actions were actually performed.\n * This method ensures the block is left in a consistent state that passes check() constraints. */\n private resetOrLimboProduction(blockId: string): boolean {\n const fields = this.getBlockInfo(blockId).fields;\n\n // Check if we can safely move to limbo (both core production fields are ready)\n if (fields.prodOutput?.status === \"Ready\" && fields.prodCtx?.status === \"Ready\") {\n if (this.blocksInLimbo.has(blockId))\n // we are already in limbo\n return false;\n\n // limbo - keep the ready production results but clean up cache\n this.blocksInLimbo.add(blockId);\n this.renderingStateChanged = true;\n\n // doing some gc - clean up previous cache fields\n this.deleteBlockFields(blockId, \"prodOutputPrevious\", \"prodCtxPrevious\", \"prodUiCtxPrevious\");\n\n return true;\n } else {\n // reset - clean up any partial/inconsistent production stat\n return this.deleteBlockFields(\n blockId,\n \"prodOutput\",\n \"prodCtx\",\n \"prodUiCtx\",\n \"prodArgs\",\n \"prodOutputPrevious\",\n \"prodCtxPrevious\",\n \"prodUiCtxPrevious\",\n );\n }\n }\n\n /**\n * Gets current block state and merges with partial updates.\n * Used by legacy v1/v2 methods like setBlockArgs and setUiState.\n *\n * @param blockId The block to get state for\n * @param partialUpdate Partial state to merge (e.g. { args } or { uiState })\n * @returns Merged state in unified format { args, uiState }\n */\n public mergeBlockState(\n blockId: string,\n partialUpdate: { args?: unknown; uiState?: unknown },\n ): { args?: unknown; uiState?: unknown } {\n const info = this.getBlockInfo(blockId);\n const currentState = info.blockStorage as { args?: unknown; uiState?: unknown } | undefined;\n if (currentState === undefined) {\n throw new Error(`Cannot merge block state for ${blockId}: blockStorage is unavailable`);\n }\n return { ...currentState, ...partialUpdate };\n }\n\n /**\n * Sets raw block storage content directly (for testing purposes).\n * This bypasses all normalization and VM transformations.\n *\n * @param blockId The block to set storage for\n * @param rawStorageJson Raw storage as JSON string\n */\n public setBlockStorageRaw(blockId: string, rawStorageJson: string): void {\n this.setBlockFieldObj(\n blockId,\n \"blockStorage\",\n this.createJsonFieldValueByContent(rawStorageJson),\n );\n this.blocksWithChangedInputs.add(blockId);\n this.updateLastModified();\n }\n\n /**\n * Resets a v2+ block to its initial storage state.\n * Gets initial storage from VM and derives args from it.\n *\n * For v1 blocks, use setStates() instead.\n *\n * @param blockId The block to reset\n */\n public resetToInitialStorage(blockId: string): void {\n const info = this.getBlockInfo(blockId);\n const blockConfig = info.config;\n\n if (blockConfig.modelAPIVersion !== BLOCK_STORAGE_FACADE_VERSION) {\n throw new Error(\"resetToInitialStorage is only supported for model API version 2\");\n }\n\n // Get initial storage from VM\n const initialStorageJson = this.projectHelper.getInitialStorageInVM(blockConfig);\n this.setBlockStorageRaw(blockId, initialStorageJson);\n\n // Derive args from storage - set or clear currentArgs based on derivation result\n const deriveArgsResult = this.projectHelper.deriveArgsFromStorage(\n blockConfig,\n initialStorageJson,\n );\n if (!deriveArgsResult.error) {\n this.setBlockFieldObj(\n blockId,\n \"currentArgs\",\n this.createJsonFieldValue(deriveArgsResult.value),\n );\n // Derive prerunArgs from storage\n const prerunArgs = this.projectHelper.derivePrerunArgsFromStorage(\n blockConfig,\n initialStorageJson,\n );\n if (prerunArgs !== undefined) {\n this.setBlockFieldObj(blockId, \"currentPrerunArgs\", this.createJsonFieldValue(prerunArgs));\n } else {\n this.deleteBlockFields(blockId, \"currentPrerunArgs\");\n }\n } else {\n if (info.fields.currentPrerunArgs !== undefined) {\n this.projectHelper.logger.warn(\n `[staging] ${blockId}: currentPrerunArgs cleared (args derivation failed)`,\n );\n }\n this.deleteBlockFields(blockId, \"currentArgs\");\n this.deleteBlockFields(blockId, \"currentPrerunArgs\");\n }\n }\n\n /** Optimally sets inputs for multiple blocks in one go */\n public setStates(requests: SetStatesRequest[]) {\n const changedArgs: string[] = [];\n let somethingChanged = false;\n for (const req of requests) {\n const info = this.getBlockInfo(req.blockId);\n let blockChanged = false;\n\n const blockConfig = info.config;\n // modelAPIVersion === 2 means BlockModelV3 with .args() lambda for deriving args\n\n if (req.modelAPIVersion !== blockConfig.modelAPIVersion) {\n throw new Error(\n `Model API version mismatch for block ${req.blockId}: ${req.modelAPIVersion} !== ${blockConfig.modelAPIVersion}`,\n );\n }\n\n // Derive args from storage using the block's config.args() callback\n let args: unknown;\n let prerunArgs: unknown;\n\n if (req.modelAPIVersion === BLOCK_STORAGE_FACADE_VERSION) {\n const currentStorageJson = info.blockStorageJson;\n if (currentStorageJson === undefined) {\n throw new Error(`Block ${req.blockId} has no blockStorage - this should not happen`);\n }\n\n // Apply the state update to storage\n const updatedStorageJson = this.projectHelper.applyStorageUpdateInVM(\n blockConfig,\n currentStorageJson,\n req.payload,\n );\n\n this.setBlockFieldObj(\n req.blockId,\n \"blockStorage\",\n this.createJsonFieldValueByContent(updatedStorageJson),\n );\n\n // Derive args directly from storage (VM extracts data internally)\n const derivedArgsResult = this.projectHelper.deriveArgsFromStorage(\n blockConfig,\n updatedStorageJson,\n );\n if (derivedArgsResult.error) {\n args = undefined;\n prerunArgs = undefined;\n } else {\n args = derivedArgsResult.value;\n // Derive prerunArgs from storage, or fall back to args\n prerunArgs = this.projectHelper.derivePrerunArgsFromStorage(\n blockConfig,\n updatedStorageJson,\n );\n }\n } else {\n this.setBlockFieldObj(req.blockId, \"blockStorage\", this.createJsonFieldValue(req.state));\n if (req.state !== null && typeof req.state === \"object\" && \"args\" in req.state) {\n args = (req.state as { args: unknown }).args;\n } else {\n args = req.state;\n }\n // For the legacy blocks, prerunArgs = args (same as production args)\n prerunArgs = args;\n }\n\n // Set or clear currentArgs based on derivation result\n if (args !== undefined) {\n const currentArgsData = canonicalJsonBytes(args);\n const argsPartRef = this.tx.createValue(Pl.JsonObject, currentArgsData);\n this.setBlockField(req.blockId, \"currentArgs\", argsPartRef, \"Ready\", currentArgsData);\n } else {\n this.deleteBlockFields(req.blockId, \"currentArgs\");\n }\n\n // Set currentPrerunArgs field and check if it actually changed\n let prerunArgsChanged = false;\n if (prerunArgs !== undefined) {\n const prerunArgsData = canonicalJsonBytes(prerunArgs);\n const oldPrerunArgsData = info.fields.currentPrerunArgs?.value;\n // Check if prerunArgs actually changed\n if (\n oldPrerunArgsData === undefined ||\n Buffer.compare(oldPrerunArgsData, prerunArgsData) !== 0\n ) {\n prerunArgsChanged = true;\n }\n const prerunArgsRef = this.tx.createValue(Pl.JsonObject, prerunArgsData);\n this.setBlockField(\n req.blockId,\n \"currentPrerunArgs\",\n prerunArgsRef,\n \"Ready\",\n prerunArgsData,\n );\n } else {\n this.deleteBlockFields(req.blockId, \"currentPrerunArgs\");\n }\n\n blockChanged = true;\n // Only add to changedArgs if prerunArgs changed - this controls staging reset\n if (prerunArgsChanged) {\n changedArgs.push(req.blockId);\n }\n\n if (blockChanged) {\n // will be assigned our author marker\n this.blocksWithChangedInputs.add(req.blockId);\n somethingChanged = true;\n }\n }\n\n // resetting staging outputs for all downstream blocks\n this.getStagingGraph().traverse(\"downstream\", changedArgs, ({ id }) => this.resetStaging(id));\n\n if (somethingChanged) this.updateLastModified();\n }\n\n public setBlockSettings(blockId: string, newValue: BlockSettings): void {\n this.setBlockFieldObj(blockId, \"blockSettings\", this.createJsonFieldValue(newValue));\n this.updateLastModified();\n }\n\n private createProdCtx(upstream: Set<string>): AnyRef {\n const upstreamContexts: AnyRef[] = [];\n upstream.forEach((id) => {\n const info = this.getBlockInfo(id);\n if (info.fields[\"prodCtx\"]?.ref === undefined)\n throw new Error(\"One of the upstreams staging is not rendered.\");\n upstreamContexts.push(Pl.unwrapHolder(this.tx, info.fields[\"prodCtx\"].ref));\n });\n return createBContextFromUpstreams(this.tx, upstreamContexts);\n }\n\n private createStagingCtx(upstream: Set<string>): AnyRef {\n const upstreamContexts: AnyRef[] = [];\n upstream.forEach((id) => {\n const info = this.getBlockInfo(id);\n if (info.fields[\"stagingCtx\"]?.ref !== undefined) {\n upstreamContexts.push(Pl.unwrapHolder(this.tx, info.fields[\"stagingCtx\"].ref));\n } else if (info.fields.currentPrerunArgs !== undefined) {\n // Upstream has currentPrerunArgs but no staging — this is an inconsistency\n throw new Error(`Upstream ${id} staging is not rendered but has currentPrerunArgs set.`);\n }\n // Blocks without currentPrerunArgs (e.g. block model doesn't define prerunArgs, or args\n // derivation failed) never get stagingCtx. Use prodCtx if available.\n if (info.fields[\"prodCtx\"]?.ref !== undefined)\n upstreamContexts.push(Pl.unwrapHolder(this.tx, info.fields[\"prodCtx\"].ref));\n });\n return createBContextFromUpstreams(this.tx, upstreamContexts);\n }\n\n private exportCtx(ctx: AnyRef): AnyRef {\n return exportContext(this.tx, Pl.unwrapHolder(this.tx, this.ctxExportTplHolder), ctx);\n }\n\n /**\n * Renders staging for a block using currentPrerunArgs.\n * If currentPrerunArgs is not set (prerunArgs returned undefined), skips staging for this block.\n */\n private renderStagingFor(blockId: string) {\n const info = this.getBlockInfo(blockId);\n\n // Check BEFORE resetStaging: if currentPrerunArgs is not set (e.g. prerunArgs() returned undefined\n // because inputs aren't ready, or args derivation failed), skip without clearing existing staging.\n // Otherwise resetStaging would delete stagingCtx, and downstream blocks that reference this block\n // as an upstream would fail in createStagingCtx.\n const prerunArgsRef = info.fields.currentPrerunArgs?.ref;\n if (prerunArgsRef === undefined) {\n return;\n }\n\n this.resetStaging(blockId);\n\n const ctx = this.createStagingCtx(this.getStagingGraph().nodes.get(blockId)!.upstream);\n\n if (this.getBlock(blockId).renderingMode !== \"Heavy\") throw new Error(\"not supported yet\");\n\n const tpl = info.getTemplate(this.tx);\n\n // Use currentPrerunArgs for staging rendering\n const results = createRenderHeavyBlock(this.tx, tpl, {\n args: prerunArgsRef,\n blockId: this.tx.createValue(Pl.JsonString, JSON.stringify(blockId)),\n isProduction: this.tx.createValue(Pl.JsonBool, JSON.stringify(false)),\n context: ctx,\n });\n\n // Here we set the staging ctx to the input context of the staging workflow, not the output because exports\n // of one staging context should stay within the same block, and not travel downstream.\n // We may change this decision in the future if wanted to support traveling staging exports downstream.\n this.setBlockField(blockId, \"stagingCtx\", Pl.wrapInEphHolder(this.tx, ctx), \"NotReady\");\n\n // Yet the staging UI Ctx is the output context of the staging workflow, because it is used to form the result pool\n // thus creating a certain discrepancy between staging workflow context behavior and desktop's result pool.\n this.setBlockField(blockId, \"stagingUiCtx\", this.exportCtx(results.context), \"NotReady\");\n this.setBlockField(blockId, \"stagingOutput\", results.result, \"NotReady\");\n }\n\n private renderProductionFor(blockId: string) {\n this.resetProduction(blockId);\n\n const info = this.getBlockInfo(blockId);\n\n // Can't render production if currentArgs is not set\n if (info.fields.currentArgs === undefined) {\n throw new Error(`Can't render production for block ${blockId}: currentArgs not set`);\n }\n\n const ctx = this.createProdCtx(this.getPendingProductionGraph().nodes.get(blockId)!.upstream);\n\n if (this.getBlock(blockId).renderingMode === \"Light\")\n throw new Error(\"Can't render production for light block.\");\n\n const tpl = info.getTemplate(this.tx);\n\n const results = createRenderHeavyBlock(this.tx, tpl, {\n args: info.fields.currentArgs.ref!,\n blockId: this.tx.createValue(Pl.JsonString, JSON.stringify(blockId)),\n isProduction: this.tx.createValue(Pl.JsonBool, JSON.stringify(true)),\n context: ctx,\n });\n this.setBlockField(\n blockId,\n \"prodCtx\",\n Pl.wrapInEphHolder(this.tx, results.context),\n \"NotReady\",\n );\n this.setBlockField(blockId, \"prodUiCtx\", this.exportCtx(results.context), \"NotReady\");\n this.setBlockField(blockId, \"prodOutput\", results.result, \"NotReady\");\n\n // saving inputs for which we rendered the production\n this.setBlockFieldObj(blockId, \"prodArgs\", info.fields.currentArgs);\n\n // removing block from limbo as we juts rendered fresh production for it\n if (this.blocksInLimbo.delete(blockId)) this.renderingStateChanged = true;\n }\n\n //\n // Structure changes\n //\n\n private initializeNewBlock(blockId: string, spec: NewBlockSpec): void {\n const info = new BlockInfo(\n blockId,\n {},\n extractConfig(spec.blockPack.config),\n spec.blockPack.source,\n this.projectHelper.logger,\n );\n this.blockInfos.set(blockId, info);\n\n // block pack\n const bp = createBlockPack(this.tx, spec.blockPack);\n this.setBlockField(blockId, \"blockPack\", Pl.wrapInHolder(this.tx, bp), \"NotReady\");\n\n // settings\n this.setBlockFieldObj(\n blockId,\n \"blockSettings\",\n this.createJsonFieldValue(InitialBlockSettings),\n );\n\n const blockConfig = info.config;\n\n let args: unknown;\n let prerunArgs: unknown;\n let storageToWrite: string;\n\n if (spec.storageMode === \"fromModel\") {\n // Model API v2+: get initial storage and derive args from it\n storageToWrite = this.projectHelper.getInitialStorageInVM(blockConfig);\n\n // Derive args directly from storage (VM extracts data internally)\n const deriveArgsResult = this.projectHelper.deriveArgsFromStorage(\n blockConfig,\n storageToWrite,\n );\n if (deriveArgsResult.error) {\n args = undefined;\n prerunArgs = undefined;\n } else {\n args = deriveArgsResult.value;\n prerunArgs = this.projectHelper.derivePrerunArgsFromStorage(blockConfig, storageToWrite);\n }\n } else if (spec.storageMode === \"legacy\") {\n // Model API v1: use legacyState from spec\n const parsedState = JSON.parse(spec.legacyState);\n args = parsedState.args;\n if (args === undefined) {\n throw new Error(\"args is undefined in legacyState\");\n }\n prerunArgs = args;\n storageToWrite = spec.legacyState;\n } else {\n throw new Error(`Unknown storageMode: ${(spec as NewBlockSpec).storageMode}`);\n }\n\n // currentArgs\n if (args !== undefined) {\n this.setBlockFieldObj(blockId, \"currentArgs\", this.createJsonFieldValue(args));\n }\n\n // currentPrerunArgs\n if (prerunArgs !== undefined) {\n this.setBlockFieldObj(blockId, \"currentPrerunArgs\", this.createJsonFieldValue(prerunArgs));\n }\n\n // blockStorage\n this.setBlockFieldObj(\n blockId,\n \"blockStorage\",\n this.createJsonFieldValueByContent(storageToWrite),\n );\n\n // checking structure\n info.check();\n }\n\n private getFieldNamesToDuplicate(blockId: string): Set<ProjectField[\"fieldName\"]> {\n const fields = this.getBlockInfo(blockId).fields;\n\n const diff = <T>(setA: Set<T>, setB: Set<T>): Set<T> =>\n new Set([...setA].filter((x) => !setB.has(x)));\n\n // Check if we can safely move to limbo (both core production fields are ready)\n if (fields.prodOutput?.status === \"Ready\" && fields.prodCtx?.status === \"Ready\") {\n if (this.blocksInLimbo.has(blockId))\n // we are already in limbo\n return FieldsToDuplicate;\n\n return diff(\n FieldsToDuplicate,\n new Set([\"prodOutputPrevious\", \"prodCtxPrevious\", \"prodUiCtxPrevious\"]),\n );\n } else {\n return diff(\n FieldsToDuplicate,\n new Set([\n \"prodOutput\",\n \"prodCtx\",\n \"prodUiCtx\",\n \"prodArgs\",\n \"prodOutputPrevious\",\n \"prodCtxPrevious\",\n \"prodUiCtxPrevious\",\n ]),\n );\n }\n }\n\n private initializeBlockDuplicate(blockId: string, originalBlockInfo: BlockInfo) {\n const info = new BlockInfo(\n blockId,\n {},\n originalBlockInfo.config,\n originalBlockInfo.source,\n this.projectHelper.logger,\n );\n\n this.blockInfos.set(blockId, info);\n\n const fieldNamesToDuplicate = this.getFieldNamesToDuplicate(blockId);\n\n // Copy all fields from original block to new block by sharing references\n for (const [fieldName, fieldState] of Object.entries(originalBlockInfo.fields)) {\n if (\n fieldNamesToDuplicate.has(fieldName as ProjectField[\"fieldName\"]) &&\n fieldState &&\n fieldState.ref\n ) {\n this.setBlockFieldObj(blockId, fieldName as keyof BlockFieldStates, {\n ref: fieldState.ref,\n status: fieldState.status,\n value: fieldState.value,\n });\n }\n }\n\n this.resetOrLimboProduction(blockId);\n\n info.check();\n }\n\n /** Very generic method, better check for more specialized case-specific methods first. */\n public updateStructure(\n newStructure: ProjectStructure,\n newBlockInitializer: (blockId: string) => void = NoNewBlocks,\n ): void {\n const currentStagingGraph = this.getStagingGraph();\n const currentActualProductionGraph = this.getActualProductionGraph();\n\n const newStagingGraph = stagingGraph(newStructure);\n\n const stagingDiff = graphDiff(currentStagingGraph, newStagingGraph);\n\n // removing blocks\n for (const blockId of stagingDiff.onlyInA) {\n const { fields } = this.getBlockInfo(blockId);\n this.deleteBlockFields(blockId, ...(Object.keys(fields) as ProjectField[\"fieldName\"][]));\n this.blockInfos.delete(blockId);\n if (this.blocksInLimbo.delete(blockId)) this.renderingStateChanged = true;\n }\n\n // creating new blocks\n for (const blockId of stagingDiff.onlyInB) {\n newBlockInitializer(blockId);\n }\n\n // resetting stagings affected by topology change\n for (const blockId of stagingDiff.different) this.resetStaging(blockId);\n\n // new actual production graph without new blocks\n const newActualProductionGraph = productionGraph(newStructure, (blockId) =>\n this.getProductionGraphBlockInfo(blockId, true),\n );\n\n const prodDiff = graphDiff(currentActualProductionGraph, newActualProductionGraph);\n\n // applying changes due to topology change in production to affected nodes and\n // all their downstreams\n currentActualProductionGraph.traverse(\"downstream\", [...prodDiff.different], (node) => {\n this.resetOrLimboProduction(node.id);\n });\n\n if (\n stagingDiff.onlyInB.size > 0 ||\n stagingDiff.onlyInA.size > 0 ||\n stagingDiff.different.size > 0\n )\n this.resetStagingRefreshTimestamp();\n\n this.struct = newStructure;\n this.structureChanged = true;\n this.stagingGraph = undefined;\n this.pendingProductionGraph = undefined;\n this.actualProductionGraph = undefined;\n\n this.updateLastModified();\n }\n\n //\n // Structure change helpers\n //\n\n public addBlock(block: Block, spec: NewBlockSpec, before?: string): void {\n const newStruct = this.structure; // copy current structure\n if (before === undefined) {\n // adding as a very last block\n newStruct.groups[newStruct.groups.length - 1].blocks.push(block);\n } else {\n let done = false;\n for (const group of newStruct.groups) {\n const idx = group.blocks.findIndex((b) => b.id === before);\n if (idx < 0) continue;\n group.blocks.splice(idx, 0, block);\n done = true;\n break;\n }\n if (!done) throw new Error(`Can't find element with id: ${before}`);\n }\n this.updateStructure(newStruct, (blockId) => {\n if (blockId !== block.id) throw new Error(\"Unexpected\");\n this.initializeNewBlock(blockId, spec);\n });\n }\n\n /**\n * Duplicates an existing block by copying all its fields and structure.\n * This method creates a deep copy of the block at the mutator level.\n *\n * @param originalBlockId id of the block to duplicate\n * @param newBlockId id for the new duplicated block\n * @param after id of the block to insert new block after\n */\n public duplicateBlock(originalBlockId: string, newBlockId: string, after?: string): void {\n // Get the original block from structure\n const originalBlock = this.getBlock(originalBlockId);\n const originalBlockInfo = this.getBlockInfo(originalBlockId);\n\n // Create new block in structure\n const newBlock: Block = {\n id: newBlockId,\n label: originalBlock.label,\n renderingMode: originalBlock.renderingMode,\n };\n\n // Add the new block to structure\n const newStruct = this.structure; // copy current structure\n if (after === undefined) {\n // adding as a very last block\n newStruct.groups[newStruct.groups.length - 1].blocks.push(newBlock);\n } else {\n let done = false;\n for (const group of newStruct.groups) {\n const idx = group.blocks.findIndex((b) => b.id === after);\n if (idx < 0) continue;\n group.blocks.splice(idx + 1, 0, newBlock);\n done = true;\n break;\n }\n if (!done) throw new Error(`Can't find element with id: ${after}`);\n }\n\n this.updateStructure(newStruct, (blockId) => {\n if (blockId !== newBlockId) throw new Error(\"Unexpected\");\n this.initializeBlockDuplicate(blockId, originalBlockInfo);\n });\n }\n\n public deleteBlock(blockId: string): void {\n const newStruct = this.structure; // copy current structure\n let done = false;\n for (const group of newStruct.groups) {\n const idx = group.blocks.findIndex((b) => b.id === blockId);\n if (idx < 0) continue;\n group.blocks.splice(idx, 1);\n done = true;\n break;\n }\n if (!done) throw new Error(`Can't find element with id: ${blockId}`);\n this.updateStructure(newStruct);\n }\n\n //\n // Block-pack migration\n //\n\n public migrateBlockPack(\n blockId: string,\n spec: BlockPackSpecPrepared,\n newClearState?: ClearState,\n ): void {\n const info = this.getBlockInfo(blockId);\n const newConfig = extractConfig(spec.config);\n\n const persistBlockPack = () => {\n this.setBlockField(\n blockId,\n \"blockPack\",\n Pl.wrapInHolder(this.tx, createBlockPack(this.tx, spec)),\n \"NotReady\",\n );\n };\n\n const applyStorageAndDeriveArgs = (storageJson: string) => {\n persistBlockPack();\n this.setBlockStorageRaw(blockId, storageJson);\n const deriveArgsResult = this.projectHelper.deriveArgsFromStorage(newConfig, storageJson);\n if (!deriveArgsResult.error) {\n this.setBlockFieldObj(\n blockId,\n \"currentArgs\",\n this.createJsonFieldValue(deriveArgsResult.value),\n );\n const prerunArgs = this.projectHelper.derivePrerunArgsFromStorage(newConfig, storageJson);\n if (prerunArgs !== undefined) {\n this.setBlockFieldObj(\n blockId,\n \"currentPrerunArgs\",\n this.createJsonFieldValue(prerunArgs),\n );\n } else {\n this.deleteBlockFields(blockId, \"currentPrerunArgs\");\n }\n } else {\n this.deleteBlockFields(blockId, \"currentArgs\");\n this.deleteBlockFields(blockId, \"currentPrerunArgs\");\n }\n };\n\n if (newClearState !== undefined) {\n // State is being reset - no migration needed\n const supportsStorageFromVM = newConfig.modelAPIVersion === BLOCK_STORAGE_FACADE_VERSION;\n\n if (supportsStorageFromVM) {\n // V2+: Get initial storage directly from VM and derive args from it\n const initialStorageJson = this.projectHelper.getInitialStorageInVM(newConfig);\n applyStorageAndDeriveArgs(initialStorageJson);\n this.blocksWithChangedInputs.add(blockId);\n this.updateLastModified();\n } else {\n // V1: Use setStates with legacy state format\n persistBlockPack();\n this.setStates([{ modelAPIVersion: 1, blockId, state: newClearState.state }]);\n }\n } else {\n // State is being preserved - run migrations if needed via VM\n // Only Model API v2 blocks support migrations\n const supportsStateMigrations = newConfig.modelAPIVersion === BLOCK_STORAGE_FACADE_VERSION;\n\n if (supportsStateMigrations) {\n const currentStorageJson = info.blockStorageJson;\n\n // Attempt migration BEFORE persisting block pack — on failure,\n // block stays on old version (no inconsistent new-code/old-storage state)\n const migrationResult = this.projectHelper.migrateStorageInVM(\n newConfig,\n currentStorageJson,\n );\n\n if (migrationResult.error !== undefined) {\n throw new Error(\n `[migrateBlockPack] Block ${blockId} migration failed: ${migrationResult.error}`,\n );\n }\n\n this.projectHelper.logger.info(\n `[migrateBlockPack] Block ${blockId}: ${migrationResult.info}`,\n );\n applyStorageAndDeriveArgs(migrationResult.newStorageJson);\n } else {\n // Legacy blocks (modelAPIVersion 1): persist block pack, set prerunArgs = currentArgs\n persistBlockPack();\n if (info.fields.currentArgs !== undefined) {\n this.setBlockFieldObj(blockId, \"currentPrerunArgs\", info.fields.currentArgs);\n }\n }\n\n this.blocksWithChangedInputs.add(blockId);\n\n // resetting staging outputs for all downstream blocks\n this.getStagingGraph().traverse(\"downstream\", [blockId], ({ id }) => this.resetStaging(id));\n }\n\n // also reset or limbo all downstream productions\n if (info.productionRendered)\n this.getActualProductionGraph().traverse(\"downstream\", [blockId], ({ id }) =>\n this.resetOrLimboProduction(id),\n );\n\n this.updateLastModified();\n }\n\n //\n // Render\n //\n\n public renderProduction(blockIds: string[], addUpstreams: boolean = false): Set<string> {\n const blockIdsSet = new Set(blockIds);\n\n const prodGraph = this.getPendingProductionGraph();\n if (addUpstreams)\n // adding all upstreams automatically\n prodGraph.traverse(\"upstream\", blockIds, (node) => {\n blockIdsSet.add(node.id);\n });\n else\n // checking that targets contain all upstreams\n for (const blockId of blockIdsSet) {\n const node = prodGraph.nodes.get(blockId);\n if (node === undefined) throw new Error(`Can't find block with id: ${blockId}`);\n for (const upstream of node.upstream)\n if (!blockIdsSet.has(upstream))\n throw new Error(\"Can't render blocks not including all upstreams.\");\n }\n\n // traversing in topological order and rendering target blocks\n const rendered = new Set<string>();\n for (const block of allBlocks(this.structure)) {\n if (!blockIdsSet.has(block.id)) continue;\n\n let render =\n this.getBlockInfo(block.id).requireProductionRendering || this.blocksInLimbo.has(block.id);\n\n if (!render)\n for (const upstream of prodGraph.nodes.get(block.id)!.upstream)\n if (rendered.has(upstream)) {\n render = true;\n break;\n }\n\n if (render) {\n this.renderProductionFor(block.id);\n rendered.add(block.id);\n }\n }\n\n const renderedArray = [...rendered];\n\n // sending to limbo all downstream blocks\n prodGraph.traverse(\"downstream\", renderedArray, (node) => {\n if (rendered.has(node.id))\n // don't send to limbo blocks that were just rendered\n return;\n this.resetOrLimboProduction(node.id);\n });\n\n // resetting staging outputs for all downstream blocks\n this.getStagingGraph().traverse(\"downstream\", renderedArray, ({ id }) => {\n // don't reset staging of the first rendered block\n if (renderedArray[0] !== id) this.resetStaging(id);\n });\n\n if (rendered.size > 0) this.updateLastModified();\n\n return rendered;\n }\n\n /** Stops running blocks from the list and modify states of other blocks\n * accordingly */\n public stopProduction(...blockIds: string[]) {\n const activeProdGraph = this.getActualProductionGraph();\n\n // we will stop all blocks listed in request and all their downstreams\n const queue = new Denque(blockIds);\n const queued = new Set(blockIds);\n const stopped: string[] = [];\n\n while (!queue.isEmpty()) {\n const blockId = queue.shift()!;\n const fields = this.getBlockInfo(blockId).fields;\n\n if (fields.prodOutput?.status === \"Ready\" && fields.prodCtx?.status === \"Ready\")\n // skipping finished blocks\n continue;\n\n if (this.deleteBlockFields(blockId, \"prodOutput\", \"prodCtx\", \"prodUiCtx\", \"prodArgs\")) {\n // was actually stopped\n stopped.push(blockId);\n\n // will try to stop all its downstreams\n for (const downstream of activeProdGraph.traverseIdsExcludingRoots(\"downstream\", blockId)) {\n if (queued.has(downstream)) continue;\n queue.push(downstream);\n queued.add(downstream);\n }\n }\n }\n\n // blocks under stopped blocks, but having finished production results, goes to limbo\n for (const blockId of activeProdGraph.traverseIdsExcludingRoots(\"downstream\", ...stopped))\n this.resetOrLimboProduction(blockId);\n\n // reset staging outputs for all downstream blocks\n this.getStagingGraph().traverse(\"downstream\", stopped, ({ id }) => this.resetStaging(id));\n }\n\n private traverseWithStagingLag(cb: (blockId: string, lag: number) => void) {\n const lags = new Map<string, number>();\n const stagingGraph = this.getStagingGraph();\n stagingGraph.nodes.forEach((node) => {\n const info = this.getBlockInfo(node.id);\n // Use requireStagingRendering to check both: staging exists AND prerunArgs hasn't changed\n const requiresRendering = info.requireStagingRendering;\n let lag = requiresRendering ? 1 : 0;\n node.upstream.forEach((upstream) => {\n const upstreamLag = lags.get(upstream)!;\n if (upstreamLag === 0) return;\n lag = Math.max(upstreamLag + 1, lag);\n });\n if (!requiresRendering && info.stagingRendered) {\n // console.log(`[traverseWithStagingLag] SKIP staging for ${node.id} - prerunArgs unchanged`);\n }\n cb(node.id, lag);\n lags.set(node.id, lag);\n });\n }\n\n /** @param stagingRenderingRate rate in blocks per second */\n private refreshStagings(stagingRenderingRate?: number) {\n const elapsed = Date.now() - this.renderingState.stagingRefreshTimestamp;\n const lagThreshold =\n stagingRenderingRate === undefined\n ? undefined\n : 1 + Math.max(0, (elapsed * stagingRenderingRate) / 1000);\n let rendered = 0;\n this.traverseWithStagingLag((blockId, lag) => {\n if (lag === 0)\n // meaning staging already rendered\n return;\n if (lagThreshold === undefined || lag <= lagThreshold) {\n try {\n this.renderStagingFor(blockId);\n rendered++;\n } catch (e) {\n this.projectHelper.logger.error(\n new Error(`[refreshStagings] renderStagingFor failed for ${blockId}`, { cause: e }),\n );\n }\n }\n });\n if (rendered > 0) this.resetStagingRefreshTimestamp();\n }\n\n //\n // Meta\n //\n\n /** Updates project metadata */\n public setMeta(meta: ProjectMeta): void {\n this.meta = meta;\n this.metaChanged = true;\n this.updateLastModified();\n }\n\n //\n // Maintenance\n //\n\n /** @param stagingRenderingRate rate in blocks per second */\n public doRefresh(stagingRenderingRate?: number) {\n this.refreshStagings(stagingRenderingRate);\n this.blockInfos.forEach((blockInfo) => {\n if (\n blockInfo.fields.prodCtx?.status === \"Ready\" &&\n blockInfo.fields.prodOutput?.status === \"Ready\"\n )\n this.deleteBlockFields(\n blockInfo.id,\n \"prodOutputPrevious\",\n \"prodCtxPrevious\",\n \"prodUiCtxPrevious\",\n );\n if (\n blockInfo.fields.stagingCtx?.status === \"Ready\" &&\n blockInfo.fields.stagingOutput?.status === \"Ready\"\n )\n this.deleteBlockFields(\n blockInfo.id,\n \"stagingOutputPrevious\",\n \"stagingCtxPrevious\",\n \"stagingUiCtxPrevious\",\n );\n });\n }\n\n private assignAuthorMarkers() {\n const markerStr = this.author ? JSON.stringify(this.author) : undefined;\n\n for (const blockId of this.blocksWithChangedInputs)\n if (markerStr === undefined) this.tx.deleteKValue(this.rid, blockArgsAuthorKey(blockId));\n else this.tx.setKValue(this.rid, blockArgsAuthorKey(blockId), markerStr);\n\n if (this.metaChanged || this.structureChanged) {\n if (markerStr === undefined) this.tx.deleteKValue(this.rid, ProjectStructureAuthorKey);\n else this.tx.setKValue(this.rid, ProjectStructureAuthorKey, markerStr);\n }\n }\n\n public save() {\n if (!this.wasModified) return;\n\n if (this.lastModifiedChanged)\n this.tx.setKValue(this.rid, ProjectLastModifiedTimestamp, JSON.stringify(this.lastModified));\n\n if (this.structureChanged)\n this.tx.setKValue(this.rid, ProjectStructureKey, JSON.stringify(this.struct));\n\n if (this.renderingStateChanged)\n this.tx.setKValue(\n this.rid,\n BlockRenderingStateKey,\n JSON.stringify({\n ...this.renderingState,\n blocksInLimbo: [...this.blocksInLimbo],\n } as ProjectRenderingState),\n );\n\n if (this.metaChanged) this.tx.setKValue(this.rid, ProjectMetaKey, JSON.stringify(this.meta));\n\n this.assignAuthorMarkers();\n }\n\n public static async load(\n projectHelper: ProjectHelper,\n tx: PlTransaction,\n rid: ResourceId,\n author?: AuthorMarker,\n ): Promise<ProjectMutator> {\n //\n // Sending initial requests to read project state (start of round-trip #1)\n //\n\n const fullResourceStateP = tx.getResourceData(rid, true);\n const schemaP = tx.getKValueJson<string>(rid, SchemaVersionKey);\n const lastModifiedP = tx.getKValueJson<number>(rid, ProjectLastModifiedTimestamp);\n const metaP = tx.getKValueJson<ProjectMeta>(rid, ProjectMetaKey);\n const structureP = tx.getKValueJson<ProjectStructure>(rid, ProjectStructureKey);\n const renderingStateP = tx.getKValueJson<ProjectRenderingState>(rid, BlockRenderingStateKey);\n\n const fullResourceState = await fullResourceStateP;\n\n // loading field information\n const blockInfoStates = new Map<string, BlockInfoState>();\n for (const f of fullResourceState.fields) {\n const projectField = parseProjectField(f.name);\n\n // processing only fields with known structure\n if (projectField === undefined) continue;\n\n let info = blockInfoStates.get(projectField.blockId);\n if (info === undefined) {\n info = {\n id: projectField.blockId,\n fields: {},\n };\n blockInfoStates.set(projectField.blockId, info);\n }\n\n info.fields[projectField.fieldName] = isNullResourceId(f.value)\n ? { modCount: 0 }\n : { modCount: 0, ref: f.value };\n }\n\n //\n // Roundtrip #1 not yet finished, but as soon as field list is received,\n // we can start sending requests to read states of referenced resources\n // (start of round-trip #2)\n //\n\n const blockFieldRequests: [\n BlockInfoState,\n ProjectField[\"fieldName\"],\n BlockFieldState,\n Promise<BasicResourceData | ResourceData>,\n ][] = [];\n blockInfoStates.forEach((info) => {\n const fields = info.fields;\n for (const [fName, state] of Object.entries(fields)) {\n if (state.ref === undefined) continue;\n if (!isResource(state.ref) || isResourceRef(state.ref))\n throw new Error(\"unexpected behaviour\");\n const fieldName = fName as ProjectField[\"fieldName\"];\n blockFieldRequests.push([\n info,\n fieldName,\n state,\n tx.getResourceData(state.ref, fieldName == \"blockPack\"),\n ]);\n }\n });\n\n // loading jsons\n const [schema, lastModified, meta, structure, { stagingRefreshTimestamp, blocksInLimbo }] =\n await Promise.all([schemaP, lastModifiedP, metaP, structureP, renderingStateP]);\n\n // Checking schema version of the project\n if (schema !== SchemaVersionCurrent) {\n if (Number(schema) < Number(SchemaVersionCurrent))\n throw new UiError(\n `Can't perform this action on this project because it has older schema. Try (re)loading the project to update it.`,\n );\n else\n throw new UiError(\n `Can't perform this action on this project because it has newer schema. Upgrade your desktop app to the latest version.`,\n );\n }\n\n //\n // <- at this point we have all the responses from round-trip #1\n //\n\n //\n // Receiving responses from round-trip #2 and sending requests to read block pack descriptions\n // (start of round-trip #3)\n //\n\n const blockPackRequests: [BlockInfoState, Promise<BasicResourceData>][] = [];\n for (const [info, fieldName, state, response] of blockFieldRequests) {\n const result = await response;\n state.value = result.data;\n if (isNotNullResourceId(result.error)) state.status = \"Error\";\n else if (result.resourceReady || isNotNullResourceId(result.originalResourceId))\n state.status = \"Ready\";\n else state.status = \"NotReady\";\n\n // For block pack we need to traverse the ref field from the resource data\n if (fieldName === \"blockPack\") {\n const refField = (result as ResourceData).fields.find((f) => f.name === Pl.HolderRefField);\n if (refField === undefined) throw new Error(\"Block pack ref field is missing\");\n blockPackRequests.push([\n info,\n tx.getResourceData(ensureResourceIdNotNull(refField.value), false),\n ]);\n }\n }\n\n //\n // <- at this point we have all the responses from round-trip #2\n //\n\n for (const [info, response] of blockPackRequests) {\n const result = await response;\n const bpInfo = cachedDeserialize<BlockPackInfo>(notEmpty(result.data));\n info.blockConfig = extractConfig(bpInfo.config);\n info.blockPack = bpInfo.source;\n }\n\n //\n // <- at this point we have all the responses from round-trip #3\n //\n\n // loading ctx export template to check if we already have cached materialized template in our project\n const ctxExportTplEnvelope = await getPreparedExportTemplateEnvelope();\n\n // expected field name\n const ctxExportTplCacheFieldName = getServiceTemplateField(ctxExportTplEnvelope.hash);\n const ctxExportTplField = fullResourceState.fields.find(\n (f) => f.name === ctxExportTplCacheFieldName,\n );\n let ctxExportTplHolder: AnyResourceRef;\n if (ctxExportTplField !== undefined)\n ctxExportTplHolder = ensureResourceIdNotNull(ctxExportTplField.value);\n else {\n ctxExportTplHolder = Pl.wrapInHolder(tx, loadTemplate(tx, ctxExportTplEnvelope.spec));\n tx.createField(\n field(rid, getServiceTemplateField(ctxExportTplEnvelope.hash)),\n \"Dynamic\",\n ctxExportTplHolder,\n );\n }\n\n const renderingState = { stagingRefreshTimestamp };\n const blocksInLimboSet = new Set(blocksInLimbo);\n\n const blockInfos = new Map<string, BlockInfo>();\n blockInfoStates.forEach(({ id, fields, blockConfig, blockPack }) =>\n blockInfos.set(\n id,\n new BlockInfo(id, fields, notEmpty(blockConfig), notEmpty(blockPack), projectHelper.logger),\n ),\n );\n\n // check consistency of project state\n const blockInStruct = new Set<string>();\n for (const b of allBlocks(structure)) {\n if (!blockInfos.has(b.id))\n throw new Error(`Inconsistent project structure: no inputs for ${b.id}`);\n blockInStruct.add(b.id);\n }\n blockInfos.forEach((info) => {\n if (!blockInStruct.has(info.id))\n throw new Error(`Inconsistent project structure: no structure entry for ${info.id}`);\n });\n\n const prj = new ProjectMutator(\n rid,\n tx,\n author,\n schema,\n lastModified,\n meta,\n structure,\n renderingState,\n blocksInLimboSet,\n blockInfos,\n ctxExportTplHolder,\n projectHelper,\n );\n\n prj.fixProblemsAndMigrate();\n\n return prj;\n }\n}\n\nexport interface ProjectState {\n schema: string;\n structure: ProjectStructure;\n renderingState: Omit<ProjectRenderingState, \"blocksInLimbo\">;\n blocksInLimbo: Set<string>;\n blockInfos: Map<string, BlockInfo>;\n}\n\nexport async function createProject(\n tx: PlTransaction,\n meta: ProjectMeta = InitialBlockMeta,\n): Promise<AnyResourceRef> {\n const prj = tx.createEphemeral(ProjectResourceType);\n tx.lock(prj);\n const ts = String(Date.now());\n tx.setKValue(prj, SchemaVersionKey, JSON.stringify(SchemaVersionCurrent));\n tx.setKValue(prj, ProjectCreatedTimestamp, ts);\n tx.setKValue(prj, ProjectLastModifiedTimestamp, ts);\n tx.setKValue(prj, ProjectMetaKey, JSON.stringify(meta));\n tx.setKValue(prj, ProjectStructureKey, JSON.stringify(InitialBlockStructure));\n tx.setKValue(prj, BlockRenderingStateKey, JSON.stringify(InitialProjectRenderingState));\n const ctxExportTplEnvelope = await getPreparedExportTemplateEnvelope();\n tx.createField(\n field(prj, getServiceTemplateField(ctxExportTplEnvelope.hash)),\n \"Dynamic\",\n Pl.wrapInHolder(tx, loadTemplate(tx, ctxExportTplEnvelope.spec)),\n );\n return prj;\n}\n\nexport async function withProject<T>(\n projectHelper: ProjectHelper,\n txOrPl: PlTransaction | PlClient,\n rid: ResourceId,\n cb: (p: ProjectMutator) => T | Promise<T>,\n ops?: Partial<TxOps>,\n): Promise<T> {\n return withProjectAuthored(projectHelper, txOrPl, rid, undefined, cb, ops);\n}\n\nexport async function withProjectAuthored<T>(\n projectHelper: ProjectHelper,\n txOrPl: PlTransaction | PlClient,\n rid: ResourceId,\n author: AuthorMarker | undefined,\n cb: (p: ProjectMutator) => T | Promise<T>,\n ops: Partial<TxOps> = {},\n): Promise<T> {\n if (txOrPl instanceof PlClient) {\n return await txOrPl.withWriteTx(\n \"ProjectAction\" + (ops.name ? `: ${ops.name}` : \"\"),\n async (tx) => {\n const mut = await ProjectMutator.load(projectHelper, tx, rid, author);\n const result = await cb(mut);\n if (!mut.wasModified)\n // skipping save and commit altogether if no modifications were actually made\n return result;\n mut.save();\n await tx.commit();\n if (getDebugFlags().logProjectMutationStat) console.log(JSON.stringify(tx.stat));\n return result;\n },\n ops,\n );\n } else {\n const mut = await ProjectMutator.load(projectHelper, txOrPl, rid, author);\n const result = await cb(mut);\n mut.save();\n return result;\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"project.cjs","names":["ConsoleLoggerAdapter","Pl","BlockPackTemplateField","InitialBlockSettings","stagingGraph","productionGraph","allBlocks","projectFieldName","BLOCK_STORAGE_FACADE_VERSION","createBContextFromUpstreams","exportContext","createRenderHeavyBlock","createBlockPack","FieldsToDuplicate","graphDiff","Denque","blockArgsAuthorKey","ProjectStructureAuthorKey","ProjectLastModifiedTimestamp","ProjectStructureKey","BlockRenderingStateKey","ProjectMetaKey","SchemaVersionKey","parseProjectField","SchemaVersionCurrent","UiError","getPreparedExportTemplateEnvelope","getServiceTemplateField","loadTemplate","InitialBlockMeta","ProjectResourceType","ProjectCreatedTimestamp","InitialBlockStructure","InitialProjectRenderingState","PlClient","getDebugFlags"],"sources":["../../src/mutator/project.ts"],"sourcesContent":["import type {\n AnyRef,\n AnyResourceRef,\n BasicResourceData,\n PlTransaction,\n ResourceData,\n ResourceId,\n TxOps,\n} from \"@milaboratories/pl-client\";\nimport {\n ensureResourceIdNotNull,\n field,\n isNotNullResourceId,\n isNullResourceId,\n isResource,\n isResourceId,\n isResourceRef,\n Pl,\n PlClient,\n} from \"@milaboratories/pl-client\";\nimport { createRenderHeavyBlock, createBContextFromUpstreams } from \"./template/render_block\";\nimport type {\n Block,\n ProjectStructure,\n ProjectField,\n ProjectRenderingState,\n} from \"../model/project_model\";\nimport {\n BlockRenderingStateKey,\n ProjectStructureKey,\n parseProjectField,\n projectFieldName,\n SchemaVersionCurrent,\n SchemaVersionKey,\n ProjectResourceType,\n InitialBlockStructure,\n InitialProjectRenderingState,\n ProjectMetaKey,\n InitialBlockMeta,\n blockArgsAuthorKey,\n ProjectLastModifiedTimestamp,\n ProjectCreatedTimestamp,\n ProjectStructureAuthorKey,\n getServiceTemplateField,\n FieldsToDuplicate,\n} from \"../model/project_model\";\nimport { BlockPackTemplateField, createBlockPack } from \"./block-pack/block_pack\";\nimport type { BlockGraph, ProductionGraphBlockInfo } from \"../model/project_model_util\";\nimport { allBlocks, graphDiff, productionGraph, stagingGraph } from \"../model/project_model_util\";\nimport type { BlockPackSpecPrepared } from \"../model\";\nimport type {\n AuthorMarker,\n BlockPackSpec,\n BlockSettings,\n ProjectMeta,\n} from \"@milaboratories/pl-model-middle-layer\";\nimport { InitialBlockSettings } from \"@milaboratories/pl-model-middle-layer\";\nimport Denque from \"denque\";\nimport { exportContext, getPreparedExportTemplateEnvelope } from \"./context_export\";\nimport { loadTemplate } from \"./template/template_loading\";\nimport {\n cachedDeserialize,\n notEmpty,\n canonicalJsonBytes,\n cachedDecode,\n type MiLogger,\n ConsoleLoggerAdapter,\n} from \"@milaboratories/ts-helpers\";\nimport { gzipSync } from \"node:zlib\";\nimport type { ProjectHelper } from \"../model/project_helper\";\nimport {\n extractConfig,\n UiError,\n BLOCK_STORAGE_FACADE_VERSION,\n type BlockConfig,\n} from \"@platforma-sdk/model\";\nimport { getDebugFlags } from \"../debug\";\nimport type { BlockPackInfo } from \"../model/block_pack\";\n\ntype FieldStatus = \"NotReady\" | \"Ready\" | \"Error\";\n\ninterface BlockFieldState {\n modCount: number;\n ref?: AnyRef;\n status?: FieldStatus;\n value?: Uint8Array;\n}\n\ntype BlockFieldStates = Partial<Record<ProjectField[\"fieldName\"], BlockFieldState>>;\ntype BlockFieldStateValue = Omit<BlockFieldState, \"modCount\">;\n\ninterface BlockInfoState {\n readonly id: string;\n readonly fields: BlockFieldStates;\n blockConfig?: BlockConfig;\n blockPack?: BlockPackSpec;\n}\n\nfunction cached<ModId, T>(modIdCb: () => ModId, valueCb: () => T): () => T {\n let initialized = false;\n let lastModId: ModId | undefined = undefined;\n let value: T | undefined = undefined;\n return () => {\n if (!initialized) {\n initialized = true;\n lastModId = modIdCb();\n value = valueCb();\n return value;\n }\n const currentModId = modIdCb();\n if (lastModId !== currentModId) {\n lastModId = currentModId;\n value = valueCb();\n }\n return valueCb();\n };\n}\n\nclass BlockInfo {\n constructor(\n public readonly id: string,\n public readonly fields: BlockFieldStates,\n public readonly config: BlockConfig,\n public readonly source: BlockPackSpec,\n private readonly logger: MiLogger = new ConsoleLoggerAdapter(),\n ) {}\n\n public check() {\n // state assertions\n\n if ((this.fields.prodOutput === undefined) !== (this.fields.prodCtx === undefined))\n throw new Error(\"inconsistent prod fields\");\n\n if ((this.fields.stagingOutput === undefined) !== (this.fields.stagingCtx === undefined))\n throw new Error(\"inconsistent stage fields\");\n\n if (\n (this.fields.prodOutputPrevious === undefined) !==\n (this.fields.prodCtxPrevious === undefined)\n )\n throw new Error(\"inconsistent prod cache fields\");\n\n if (\n (this.fields.stagingOutputPrevious === undefined) !==\n (this.fields.stagingCtxPrevious === undefined)\n )\n throw new Error(\"inconsistent stage cache fields\");\n\n if (this.fields.blockPack === undefined) throw new Error(\"no block pack field\");\n\n if (this.fields.blockStorage === undefined) throw new Error(\"no block storage field\");\n }\n\n private readonly currentArgsC = cached(\n () => this.fields.currentArgs?.modCount,\n () => {\n const bin = this.fields.currentArgs?.value;\n if (bin === undefined) return undefined;\n return cachedDeserialize(bin);\n },\n );\n\n private readonly blockStorageC = cached(\n () => this.fields.blockStorage!.modCount,\n () => {\n const bin = this.fields.blockStorage?.value;\n if (bin === undefined) return undefined;\n return cachedDeserialize<Record<string, unknown>>(bin);\n },\n );\n\n private readonly blockStorageJ = cached(\n () => this.fields.blockStorage!.modCount,\n () => {\n const bin = this.fields.blockStorage?.value;\n if (bin === undefined) return undefined;\n return cachedDecode(bin);\n },\n );\n\n private readonly prodArgsC = cached(\n () => this.fields.prodArgs?.modCount,\n () => {\n const bin = this.fields.prodArgs?.value;\n if (bin === undefined) return undefined;\n return cachedDeserialize(bin);\n },\n );\n\n private readonly currentPrerunArgsC = cached(\n () => this.fields.currentPrerunArgs?.modCount,\n () => {\n const bin = this.fields.currentPrerunArgs?.value;\n if (bin === undefined) return undefined;\n return cachedDeserialize(bin);\n },\n );\n\n get currentArgs(): unknown {\n return this.currentArgsC();\n }\n\n get blockStorage(): unknown {\n try {\n return this.blockStorageC();\n } catch (e) {\n this.logger.error(new Error(`Error getting blockStorage for ${this.id}`, { cause: e }));\n return undefined;\n }\n }\n\n get blockStorageJson() {\n return this.blockStorageJ();\n }\n\n get currentPrerunArgs(): unknown {\n return this.currentPrerunArgsC();\n }\n\n get stagingRendered(): boolean {\n return this.fields.stagingCtx !== undefined;\n }\n\n get productionRendered(): boolean {\n return this.fields.prodCtx !== undefined;\n }\n\n get productionHasErrors(): boolean {\n return this.fields.prodUiCtx?.status === \"Error\";\n }\n\n private readonly productionStaleC: () => boolean = cached(\n () => `${this.fields.currentArgs!.modCount}_${this.fields.prodArgs?.modCount}`,\n () =>\n this.fields.prodArgs === undefined ||\n Buffer.compare(this.fields.currentArgs!.value!, this.fields.prodArgs.value!) !== 0,\n );\n\n get requireProductionRendering(): boolean {\n return !this.productionRendered || this.productionStaleC() || this.productionHasErrors;\n }\n\n /** Returns true if staging should be re-rendered (stagingCtx is not set) */\n get requireStagingRendering(): boolean {\n // No staging needed if currentPrerunArgs is undefined (args derivation failed)\n if (this.fields.currentPrerunArgs === undefined) return false;\n return !this.stagingRendered;\n }\n\n get prodArgs(): unknown {\n return this.prodArgsC();\n }\n\n public getTemplate(tx: PlTransaction): AnyRef {\n return tx.getFutureFieldValue(\n Pl.unwrapHolder(tx, this.fields.blockPack!.ref!),\n BlockPackTemplateField,\n \"Input\",\n );\n }\n}\n\n/**\n * Specification for creating a new block.\n * Discriminated union based on `storageMode`.\n */\n/** Specification for creating a new block. Discriminated union based on `storageMode`. */\nexport type NewBlockSpec =\n | { storageMode: \"fromModel\"; blockPack: BlockPackSpecPrepared }\n | { storageMode: \"legacy\"; blockPack: BlockPackSpecPrepared; legacyState: string };\n\nconst NoNewBlocks = (blockId: string) => {\n throw new Error(`No new block info for ${blockId}`);\n};\n\n/**\n * Request to set block state using unified state format.\n * For v3 blocks: state is the block's state\n * For v1/v2 blocks: state should be { args, uiState } format\n */\nexport type SetStatesRequest =\n | {\n blockId: string;\n /** The unified state to set */\n state: unknown;\n modelAPIVersion: 1;\n }\n | {\n blockId: string;\n /** Storage operation payload - middle layer is agnostic to specific operations */\n payload: { operation: string; value: unknown };\n modelAPIVersion: 2;\n };\n\nexport type ClearState = {\n state: unknown;\n};\n\nexport class ProjectMutator {\n private globalModCount = 0;\n private fieldsChanged: boolean = false;\n\n //\n // Change trackers\n //\n\n private lastModifiedChanged = false;\n private structureChanged = false;\n private metaChanged = false;\n private renderingStateChanged = false;\n\n /** Set blocks will be assigned current mutator author marker on save */\n private readonly blocksWithChangedInputs = new Set<string>();\n\n constructor(\n public readonly rid: ResourceId,\n private readonly tx: PlTransaction,\n private readonly author: AuthorMarker | undefined,\n private readonly schema: string,\n private lastModified: number,\n private meta: ProjectMeta,\n private struct: ProjectStructure,\n private readonly renderingState: Omit<ProjectRenderingState, \"blocksInLimbo\">,\n private readonly blocksInLimbo: Set<string>,\n private readonly blockInfos: Map<string, BlockInfo>,\n private readonly ctxExportTplHolder: AnyResourceRef,\n private readonly projectHelper: ProjectHelper,\n ) {}\n\n private fixProblemsAndMigrate() {\n // Fix inconsistent production fields\n this.blockInfos.forEach((blockInfo) => {\n if (\n blockInfo.fields.prodArgs === undefined ||\n blockInfo.fields.prodOutput === undefined ||\n blockInfo.fields.prodCtx === undefined\n )\n this.deleteBlockFields(blockInfo.id, \"prodArgs\", \"prodOutput\", \"prodCtx\", \"prodUiCtx\");\n });\n\n // Fix inconsistent staging fields\n this.blockInfos.forEach((blockInfo) => {\n if (blockInfo.fields.stagingOutput === undefined || blockInfo.fields.stagingCtx === undefined)\n this.deleteBlockFields(blockInfo.id, \"stagingOutput\", \"stagingCtx\", \"stagingUiCtx\");\n });\n\n // Fix inconsistent cache fields\n this.blockInfos.forEach((blockInfo) => {\n if (\n blockInfo.fields.prodOutputPrevious === undefined ||\n blockInfo.fields.prodCtxPrevious === undefined\n )\n this.deleteBlockFields(\n blockInfo.id,\n \"prodOutputPrevious\",\n \"prodCtxPrevious\",\n \"prodUiCtxPrevious\",\n );\n if (\n blockInfo.fields.stagingOutputPrevious === undefined ||\n blockInfo.fields.stagingCtxPrevious === undefined\n )\n this.deleteBlockFields(\n blockInfo.id,\n \"stagingOutputPrevious\",\n \"stagingCtxPrevious\",\n \"stagingUiCtxPrevious\",\n );\n });\n\n // Migration for addition of block settings field\n let initialBlockSettings: Omit<BlockFieldState, \"modCount\"> | undefined;\n this.blockInfos.forEach((blockInfo) => {\n if (blockInfo.fields.blockSettings === undefined) {\n if (initialBlockSettings === undefined)\n initialBlockSettings = this.createJsonFieldValue(InitialBlockSettings);\n this.setBlockFieldObj(blockInfo.id, \"blockSettings\", initialBlockSettings);\n }\n });\n\n // Validate after fixes\n this.blockInfos.forEach((info) => info.check());\n }\n\n get wasModified(): boolean {\n return (\n this.lastModifiedChanged ||\n this.structureChanged ||\n this.fieldsChanged ||\n this.metaChanged ||\n this.renderingStateChanged\n );\n }\n\n get structure(): ProjectStructure {\n return JSON.parse(JSON.stringify(this.struct)) as ProjectStructure;\n }\n\n //\n // Graph calculation\n //\n\n private stagingGraph: BlockGraph | undefined = undefined;\n private pendingProductionGraph: BlockGraph | undefined = undefined;\n private actualProductionGraph: BlockGraph | undefined = undefined;\n\n private getStagingGraph(): BlockGraph {\n if (this.stagingGraph === undefined) this.stagingGraph = stagingGraph(this.struct);\n return this.stagingGraph;\n }\n\n private getProductionGraphBlockInfo(\n blockId: string,\n prod: boolean,\n ): ProductionGraphBlockInfo | undefined {\n const bInfo = this.getBlockInfo(blockId);\n\n let argsField: BlockFieldState | undefined;\n let args: unknown;\n\n if (prod) {\n if (bInfo.fields.prodArgs === undefined) return undefined;\n argsField = bInfo.fields.prodArgs;\n args = bInfo.prodArgs;\n } else {\n argsField = bInfo.fields.currentArgs;\n args = bInfo.currentArgs;\n }\n\n // Can't compute enrichment targets without args\n if (argsField === undefined) {\n return { args, enrichmentTargets: undefined };\n }\n\n const blockPackField = notEmpty(bInfo.fields.blockPack);\n\n if (isResourceId(argsField.ref!) && isResourceId(blockPackField.ref!))\n return {\n args,\n enrichmentTargets: this.projectHelper.getEnrichmentTargets(\n () => bInfo.config,\n () => args,\n { argsRid: argsField.ref, blockPackRid: blockPackField.ref },\n ),\n };\n else\n return {\n args,\n enrichmentTargets: this.projectHelper.getEnrichmentTargets(\n () => bInfo.config,\n () => args,\n ),\n };\n }\n\n private getPendingProductionGraph(): BlockGraph {\n if (this.pendingProductionGraph === undefined)\n this.pendingProductionGraph = productionGraph(this.struct, (blockId) =>\n this.getProductionGraphBlockInfo(blockId, false),\n );\n return this.pendingProductionGraph;\n }\n\n private getActualProductionGraph(): BlockGraph {\n if (this.actualProductionGraph === undefined)\n this.actualProductionGraph = productionGraph(this.struct, (blockId) =>\n this.getProductionGraphBlockInfo(blockId, true),\n );\n return this.actualProductionGraph;\n }\n\n //\n // Generic helpers to interact with project state\n //\n\n private getBlockInfo(blockId: string): BlockInfo {\n const info = this.blockInfos.get(blockId);\n if (info === undefined) throw new Error(`No such block: ${blockId}`);\n return info;\n }\n\n /** Create a plain JSON resource value from a JS object (no compression). */\n private createJsonFieldValue(obj: unknown): BlockFieldStateValue {\n const value = Buffer.from(JSON.stringify(obj));\n const ref = this.tx.createValue(Pl.JsonObject, value);\n return { ref, value, status: \"Ready\" };\n }\n\n /** Create a plain JSON resource value from a pre-serialized JSON string (no compression). */\n private createJsonFieldValueFromContent(json: string): BlockFieldStateValue {\n const value = Buffer.from(json);\n const ref = this.tx.createValue(Pl.JsonObject, value);\n return { ref, value, status: \"Ready\" };\n }\n\n /** Create a gzip-compressed JSON resource value from a JS object (compressed if >= 16KB). */\n private createGzJsonFieldValue(obj: unknown): BlockFieldStateValue {\n const jsonBytes = canonicalJsonBytes(obj);\n return this.createGzJsonFieldValueFromBytes(jsonBytes);\n }\n\n /** Create a gzip-compressed JSON resource value from a pre-serialized JSON string (compressed if >= 16KB). */\n private createGzJsonFieldValueFromContent(json: string): BlockFieldStateValue {\n return this.createGzJsonFieldValueFromBytes(Buffer.from(json));\n }\n\n private createGzJsonFieldValueFromBytes(jsonBytes: Uint8Array): BlockFieldStateValue {\n const gzipThreshold = 16_384;\n if (jsonBytes.length >= gzipThreshold) {\n const data = gzipSync(jsonBytes);\n const ref = this.tx.createValue(Pl.JsonGzObject, data);\n return { ref, value: data, status: \"Ready\" };\n }\n const ref = this.tx.createValue(Pl.JsonObject, jsonBytes);\n return { ref, value: jsonBytes, status: \"Ready\" };\n }\n\n private getBlock(blockId: string): Block {\n for (const block of allBlocks(this.struct)) if (block.id === blockId) return block;\n throw new Error(\"block not found\");\n }\n\n private setBlockFieldObj(\n blockId: string,\n fieldName: keyof BlockFieldStates,\n state: BlockFieldStateValue,\n ) {\n const fid = field(this.rid, projectFieldName(blockId, fieldName));\n\n if (state.ref === undefined) throw new Error(\"Can't set value with empty ref\");\n\n if (this.getBlockInfo(blockId).fields[fieldName] === undefined)\n this.tx.createField(fid, \"Dynamic\", state.ref);\n else this.tx.setField(fid, state.ref);\n\n this.getBlockInfo(blockId).fields[fieldName] = {\n modCount: this.globalModCount++,\n ...state,\n };\n\n this.fieldsChanged = true;\n }\n\n private setBlockField(\n blockId: string,\n fieldName: keyof BlockFieldStates,\n ref: AnyRef,\n status: FieldStatus,\n value?: Uint8Array,\n ) {\n this.setBlockFieldObj(blockId, fieldName, { ref, status, value });\n }\n\n private deleteBlockFields(blockId: string, ...fieldNames: (keyof BlockFieldStates)[]): boolean {\n let deleted = false;\n const info = this.getBlockInfo(blockId);\n for (const fieldName of fieldNames) {\n const fields = info.fields;\n if (!(fieldName in fields)) continue;\n this.tx.removeField(field(this.rid, projectFieldName(blockId, fieldName)));\n delete fields[fieldName];\n this.fieldsChanged = true;\n deleted = true;\n }\n return deleted;\n }\n\n private updateLastModified() {\n this.lastModified = Date.now();\n this.lastModifiedChanged = true;\n }\n\n //\n // Main project actions\n //\n\n private resetStagingRefreshTimestamp() {\n this.renderingState.stagingRefreshTimestamp = Date.now();\n this.renderingStateChanged = true;\n }\n\n private resetStaging(blockId: string): void {\n const fields = this.getBlockInfo(blockId).fields;\n if (\n fields.stagingOutput?.status === \"Ready\" &&\n fields.stagingCtx?.status === \"Ready\" &&\n fields.stagingUiCtx?.status === \"Ready\"\n ) {\n this.setBlockFieldObj(blockId, \"stagingOutputPrevious\", fields.stagingOutput);\n this.setBlockFieldObj(blockId, \"stagingCtxPrevious\", fields.stagingCtx);\n this.setBlockFieldObj(blockId, \"stagingUiCtxPrevious\", fields.stagingUiCtx);\n }\n if (this.deleteBlockFields(blockId, \"stagingOutput\", \"stagingCtx\", \"stagingUiCtx\"))\n this.resetStagingRefreshTimestamp();\n }\n\n private resetProduction(blockId: string): void {\n const fields = this.getBlockInfo(blockId).fields;\n if (\n fields.prodOutput?.status === \"Ready\" &&\n fields.prodCtx?.status === \"Ready\" &&\n fields.prodUiCtx?.status === \"Ready\"\n ) {\n this.setBlockFieldObj(blockId, \"prodOutputPrevious\", fields.prodOutput);\n this.setBlockFieldObj(blockId, \"prodCtxPrevious\", fields.prodCtx);\n this.setBlockFieldObj(blockId, \"prodUiCtxPrevious\", fields.prodUiCtx);\n }\n this.deleteBlockFields(blockId, \"prodOutput\", \"prodCtx\", \"prodUiCtx\", \"prodArgs\");\n }\n\n /** Running blocks are reset, already computed moved to limbo. Returns if\n * either of the actions were actually performed.\n * This method ensures the block is left in a consistent state that passes check() constraints. */\n private resetOrLimboProduction(blockId: string): boolean {\n const fields = this.getBlockInfo(blockId).fields;\n\n // Check if we can safely move to limbo (both core production fields are ready)\n if (fields.prodOutput?.status === \"Ready\" && fields.prodCtx?.status === \"Ready\") {\n if (this.blocksInLimbo.has(blockId))\n // we are already in limbo\n return false;\n\n // limbo - keep the ready production results but clean up cache\n this.blocksInLimbo.add(blockId);\n this.renderingStateChanged = true;\n\n // doing some gc - clean up previous cache fields\n this.deleteBlockFields(blockId, \"prodOutputPrevious\", \"prodCtxPrevious\", \"prodUiCtxPrevious\");\n\n return true;\n } else {\n // reset - clean up any partial/inconsistent production stat\n return this.deleteBlockFields(\n blockId,\n \"prodOutput\",\n \"prodCtx\",\n \"prodUiCtx\",\n \"prodArgs\",\n \"prodOutputPrevious\",\n \"prodCtxPrevious\",\n \"prodUiCtxPrevious\",\n );\n }\n }\n\n /**\n * Gets current block state and merges with partial updates.\n * Used by legacy v1/v2 methods like setBlockArgs and setUiState.\n *\n * @param blockId The block to get state for\n * @param partialUpdate Partial state to merge (e.g. { args } or { uiState })\n * @returns Merged state in unified format { args, uiState }\n */\n public mergeBlockState(\n blockId: string,\n partialUpdate: { args?: unknown; uiState?: unknown },\n ): { args?: unknown; uiState?: unknown } {\n const info = this.getBlockInfo(blockId);\n const currentState = info.blockStorage as { args?: unknown; uiState?: unknown } | undefined;\n if (currentState === undefined) {\n throw new Error(`Cannot merge block state for ${blockId}: blockStorage is unavailable`);\n }\n return { ...currentState, ...partialUpdate };\n }\n\n /**\n * Sets raw block storage content directly (for testing purposes).\n * This bypasses all normalization and VM transformations.\n *\n * @param blockId The block to set storage for\n * @param rawStorageJson Raw storage as JSON string\n */\n public setBlockStorageRaw(blockId: string, rawStorageJson: string): void {\n this.setBlockFieldObj(\n blockId,\n \"blockStorage\",\n this.createGzJsonFieldValueFromContent(rawStorageJson),\n );\n this.blocksWithChangedInputs.add(blockId);\n this.updateLastModified();\n }\n\n /**\n * Resets a v2+ block to its initial storage state.\n * Gets initial storage from VM and derives args from it.\n *\n * For v1 blocks, use setStates() instead.\n *\n * @param blockId The block to reset\n */\n public resetToInitialStorage(blockId: string): void {\n const info = this.getBlockInfo(blockId);\n const blockConfig = info.config;\n\n if (blockConfig.modelAPIVersion !== BLOCK_STORAGE_FACADE_VERSION) {\n throw new Error(\"resetToInitialStorage is only supported for model API version 2\");\n }\n\n // Get initial storage from VM\n const initialStorageJson = this.projectHelper.getInitialStorageInVM(blockConfig);\n this.setBlockStorageRaw(blockId, initialStorageJson);\n\n // Derive args from storage - set or clear currentArgs based on derivation result\n const deriveArgsResult = this.projectHelper.deriveArgsFromStorage(\n blockConfig,\n initialStorageJson,\n );\n if (!deriveArgsResult.error) {\n this.setBlockFieldObj(\n blockId,\n \"currentArgs\",\n this.createJsonFieldValue(deriveArgsResult.value),\n );\n // Derive prerunArgs from storage\n const prerunArgs = this.projectHelper.derivePrerunArgsFromStorage(\n blockConfig,\n initialStorageJson,\n );\n if (prerunArgs !== undefined) {\n this.setBlockFieldObj(blockId, \"currentPrerunArgs\", this.createJsonFieldValue(prerunArgs));\n } else {\n this.deleteBlockFields(blockId, \"currentPrerunArgs\");\n }\n } else {\n if (info.fields.currentPrerunArgs !== undefined) {\n this.projectHelper.logger.warn(\n `[staging] ${blockId}: currentPrerunArgs cleared (args derivation failed)`,\n );\n }\n this.deleteBlockFields(blockId, \"currentArgs\");\n this.deleteBlockFields(blockId, \"currentPrerunArgs\");\n }\n }\n\n /** Optimally sets inputs for multiple blocks in one go */\n public setStates(requests: SetStatesRequest[]) {\n const changedArgs: string[] = [];\n let somethingChanged = false;\n for (const req of requests) {\n const info = this.getBlockInfo(req.blockId);\n let blockChanged = false;\n\n const blockConfig = info.config;\n // modelAPIVersion === 2 means BlockModelV3 with .args() lambda for deriving args\n\n if (req.modelAPIVersion !== blockConfig.modelAPIVersion) {\n throw new Error(\n `Model API version mismatch for block ${req.blockId}: ${req.modelAPIVersion} !== ${blockConfig.modelAPIVersion}`,\n );\n }\n\n // Derive args from storage using the block's config.args() callback\n let args: unknown;\n let prerunArgs: unknown;\n\n if (req.modelAPIVersion === BLOCK_STORAGE_FACADE_VERSION) {\n const currentStorageJson = info.blockStorageJson;\n if (currentStorageJson === undefined) {\n throw new Error(`Block ${req.blockId} has no blockStorage - this should not happen`);\n }\n\n // Apply the state update to storage\n const updatedStorageJson = this.projectHelper.applyStorageUpdateInVM(\n blockConfig,\n currentStorageJson,\n req.payload,\n );\n\n this.setBlockFieldObj(\n req.blockId,\n \"blockStorage\",\n this.createGzJsonFieldValueFromContent(updatedStorageJson),\n );\n\n // Derive args directly from storage (VM extracts data internally)\n const derivedArgsResult = this.projectHelper.deriveArgsFromStorage(\n blockConfig,\n updatedStorageJson,\n );\n if (derivedArgsResult.error) {\n args = undefined;\n prerunArgs = undefined;\n } else {\n args = derivedArgsResult.value;\n // Derive prerunArgs from storage, or fall back to args\n prerunArgs = this.projectHelper.derivePrerunArgsFromStorage(\n blockConfig,\n updatedStorageJson,\n );\n }\n } else {\n this.setBlockFieldObj(req.blockId, \"blockStorage\", this.createGzJsonFieldValue(req.state));\n if (req.state !== null && typeof req.state === \"object\" && \"args\" in req.state) {\n args = (req.state as { args: unknown }).args;\n } else {\n args = req.state;\n }\n // For the legacy blocks, prerunArgs = args (same as production args)\n prerunArgs = args;\n }\n\n // Set or clear currentArgs based on derivation result\n // NB: currentArgs must NOT be gzipped — they are read by Tengo workflows which can't decompress\n if (args !== undefined) {\n const currentArgsData = canonicalJsonBytes(args);\n const argsPartRef = this.tx.createValue(Pl.JsonObject, currentArgsData);\n this.setBlockField(req.blockId, \"currentArgs\", argsPartRef, \"Ready\", currentArgsData);\n } else {\n this.deleteBlockFields(req.blockId, \"currentArgs\");\n }\n\n // Set currentPrerunArgs field and check if it actually changed\n // NB: currentPrerunArgs must NOT be gzipped — they are read by Tengo workflows which can't decompress\n let prerunArgsChanged = false;\n if (prerunArgs !== undefined) {\n const prerunArgsData = canonicalJsonBytes(prerunArgs);\n const oldPrerunArgsData = info.fields.currentPrerunArgs?.value;\n // Check if prerunArgs actually changed\n if (\n oldPrerunArgsData === undefined ||\n Buffer.compare(oldPrerunArgsData, prerunArgsData) !== 0\n ) {\n prerunArgsChanged = true;\n }\n const prerunArgsRef = this.tx.createValue(Pl.JsonObject, prerunArgsData);\n this.setBlockField(\n req.blockId,\n \"currentPrerunArgs\",\n prerunArgsRef,\n \"Ready\",\n prerunArgsData,\n );\n } else {\n this.deleteBlockFields(req.blockId, \"currentPrerunArgs\");\n }\n\n blockChanged = true;\n // Only add to changedArgs if prerunArgs changed - this controls staging reset\n if (prerunArgsChanged) {\n changedArgs.push(req.blockId);\n }\n\n if (blockChanged) {\n // will be assigned our author marker\n this.blocksWithChangedInputs.add(req.blockId);\n somethingChanged = true;\n }\n }\n\n // resetting staging outputs for all downstream blocks\n this.getStagingGraph().traverse(\"downstream\", changedArgs, ({ id }) => this.resetStaging(id));\n\n if (somethingChanged) this.updateLastModified();\n }\n\n public setBlockSettings(blockId: string, newValue: BlockSettings): void {\n this.setBlockFieldObj(blockId, \"blockSettings\", this.createJsonFieldValue(newValue));\n this.updateLastModified();\n }\n\n private createProdCtx(upstream: Set<string>): AnyRef {\n const upstreamContexts: AnyRef[] = [];\n upstream.forEach((id) => {\n const info = this.getBlockInfo(id);\n if (info.fields[\"prodCtx\"]?.ref === undefined)\n throw new Error(\"One of the upstreams staging is not rendered.\");\n upstreamContexts.push(Pl.unwrapHolder(this.tx, info.fields[\"prodCtx\"].ref));\n });\n return createBContextFromUpstreams(this.tx, upstreamContexts);\n }\n\n private createStagingCtx(upstream: Set<string>): AnyRef {\n const upstreamContexts: AnyRef[] = [];\n upstream.forEach((id) => {\n const info = this.getBlockInfo(id);\n if (info.fields[\"stagingCtx\"]?.ref !== undefined) {\n upstreamContexts.push(Pl.unwrapHolder(this.tx, info.fields[\"stagingCtx\"].ref));\n } else if (info.fields.currentPrerunArgs !== undefined) {\n // Upstream has currentPrerunArgs but no staging — this is an inconsistency\n throw new Error(`Upstream ${id} staging is not rendered but has currentPrerunArgs set.`);\n }\n // Blocks without currentPrerunArgs (e.g. block model doesn't define prerunArgs, or args\n // derivation failed) never get stagingCtx. Use prodCtx if available.\n if (info.fields[\"prodCtx\"]?.ref !== undefined)\n upstreamContexts.push(Pl.unwrapHolder(this.tx, info.fields[\"prodCtx\"].ref));\n });\n return createBContextFromUpstreams(this.tx, upstreamContexts);\n }\n\n private exportCtx(ctx: AnyRef): AnyRef {\n return exportContext(this.tx, Pl.unwrapHolder(this.tx, this.ctxExportTplHolder), ctx);\n }\n\n /**\n * Renders staging for a block using currentPrerunArgs.\n * If currentPrerunArgs is not set (prerunArgs returned undefined), skips staging for this block.\n */\n private renderStagingFor(blockId: string) {\n const info = this.getBlockInfo(blockId);\n\n // Check BEFORE resetStaging: if currentPrerunArgs is not set (e.g. prerunArgs() returned undefined\n // because inputs aren't ready, or args derivation failed), skip without clearing existing staging.\n // Otherwise resetStaging would delete stagingCtx, and downstream blocks that reference this block\n // as an upstream would fail in createStagingCtx.\n const prerunArgsRef = info.fields.currentPrerunArgs?.ref;\n if (prerunArgsRef === undefined) {\n return;\n }\n\n this.resetStaging(blockId);\n\n const ctx = this.createStagingCtx(this.getStagingGraph().nodes.get(blockId)!.upstream);\n\n if (this.getBlock(blockId).renderingMode !== \"Heavy\") throw new Error(\"not supported yet\");\n\n const tpl = info.getTemplate(this.tx);\n\n // Use currentPrerunArgs for staging rendering\n const results = createRenderHeavyBlock(this.tx, tpl, {\n args: prerunArgsRef,\n blockId: this.tx.createValue(Pl.JsonString, JSON.stringify(blockId)),\n isProduction: this.tx.createValue(Pl.JsonBool, JSON.stringify(false)),\n context: ctx,\n });\n\n // Here we set the staging ctx to the input context of the staging workflow, not the output because exports\n // of one staging context should stay within the same block, and not travel downstream.\n // We may change this decision in the future if wanted to support traveling staging exports downstream.\n this.setBlockField(blockId, \"stagingCtx\", Pl.wrapInEphHolder(this.tx, ctx), \"NotReady\");\n\n // Yet the staging UI Ctx is the output context of the staging workflow, because it is used to form the result pool\n // thus creating a certain discrepancy between staging workflow context behavior and desktop's result pool.\n this.setBlockField(blockId, \"stagingUiCtx\", this.exportCtx(results.context), \"NotReady\");\n this.setBlockField(blockId, \"stagingOutput\", results.result, \"NotReady\");\n }\n\n private renderProductionFor(blockId: string) {\n this.resetProduction(blockId);\n\n const info = this.getBlockInfo(blockId);\n\n // Can't render production if currentArgs is not set\n if (info.fields.currentArgs === undefined) {\n throw new Error(`Can't render production for block ${blockId}: currentArgs not set`);\n }\n\n const ctx = this.createProdCtx(this.getPendingProductionGraph().nodes.get(blockId)!.upstream);\n\n if (this.getBlock(blockId).renderingMode === \"Light\")\n throw new Error(\"Can't render production for light block.\");\n\n const tpl = info.getTemplate(this.tx);\n\n const results = createRenderHeavyBlock(this.tx, tpl, {\n args: info.fields.currentArgs.ref!,\n blockId: this.tx.createValue(Pl.JsonString, JSON.stringify(blockId)),\n isProduction: this.tx.createValue(Pl.JsonBool, JSON.stringify(true)),\n context: ctx,\n });\n this.setBlockField(\n blockId,\n \"prodCtx\",\n Pl.wrapInEphHolder(this.tx, results.context),\n \"NotReady\",\n );\n this.setBlockField(blockId, \"prodUiCtx\", this.exportCtx(results.context), \"NotReady\");\n this.setBlockField(blockId, \"prodOutput\", results.result, \"NotReady\");\n\n // saving inputs for which we rendered the production\n this.setBlockFieldObj(blockId, \"prodArgs\", info.fields.currentArgs);\n\n // removing block from limbo as we juts rendered fresh production for it\n if (this.blocksInLimbo.delete(blockId)) this.renderingStateChanged = true;\n }\n\n //\n // Structure changes\n //\n\n private initializeNewBlock(blockId: string, spec: NewBlockSpec): void {\n const info = new BlockInfo(\n blockId,\n {},\n extractConfig(spec.blockPack.config),\n spec.blockPack.source,\n this.projectHelper.logger,\n );\n this.blockInfos.set(blockId, info);\n\n // block pack\n const bp = createBlockPack(this.tx, spec.blockPack);\n this.setBlockField(blockId, \"blockPack\", Pl.wrapInHolder(this.tx, bp), \"NotReady\");\n\n // settings\n this.setBlockFieldObj(\n blockId,\n \"blockSettings\",\n this.createJsonFieldValue(InitialBlockSettings),\n );\n\n const blockConfig = info.config;\n\n let args: unknown;\n let prerunArgs: unknown;\n let storageToWrite: string;\n\n if (spec.storageMode === \"fromModel\") {\n // Model API v2+: get initial storage and derive args from it\n storageToWrite = this.projectHelper.getInitialStorageInVM(blockConfig);\n\n // Derive args directly from storage (VM extracts data internally)\n const deriveArgsResult = this.projectHelper.deriveArgsFromStorage(\n blockConfig,\n storageToWrite,\n );\n if (deriveArgsResult.error) {\n args = undefined;\n prerunArgs = undefined;\n } else {\n args = deriveArgsResult.value;\n prerunArgs = this.projectHelper.derivePrerunArgsFromStorage(blockConfig, storageToWrite);\n }\n } else if (spec.storageMode === \"legacy\") {\n // Model API v1: use legacyState from spec\n const parsedState = JSON.parse(spec.legacyState);\n args = parsedState.args;\n if (args === undefined) {\n throw new Error(\"args is undefined in legacyState\");\n }\n prerunArgs = args;\n storageToWrite = spec.legacyState;\n } else {\n throw new Error(`Unknown storageMode: ${(spec as NewBlockSpec).storageMode}`);\n }\n\n // currentArgs\n if (args !== undefined) {\n this.setBlockFieldObj(blockId, \"currentArgs\", this.createJsonFieldValue(args));\n }\n\n // currentPrerunArgs\n if (prerunArgs !== undefined) {\n this.setBlockFieldObj(blockId, \"currentPrerunArgs\", this.createJsonFieldValue(prerunArgs));\n }\n\n // blockStorage\n this.setBlockFieldObj(\n blockId,\n \"blockStorage\",\n this.createGzJsonFieldValueFromContent(storageToWrite),\n );\n\n // checking structure\n info.check();\n }\n\n private getFieldNamesToDuplicate(blockId: string): Set<ProjectField[\"fieldName\"]> {\n const fields = this.getBlockInfo(blockId).fields;\n\n const diff = <T>(setA: Set<T>, setB: Set<T>): Set<T> =>\n new Set([...setA].filter((x) => !setB.has(x)));\n\n // Check if we can safely move to limbo (both core production fields are ready)\n if (fields.prodOutput?.status === \"Ready\" && fields.prodCtx?.status === \"Ready\") {\n if (this.blocksInLimbo.has(blockId))\n // we are already in limbo\n return FieldsToDuplicate;\n\n return diff(\n FieldsToDuplicate,\n new Set([\"prodOutputPrevious\", \"prodCtxPrevious\", \"prodUiCtxPrevious\"]),\n );\n } else {\n return diff(\n FieldsToDuplicate,\n new Set([\n \"prodOutput\",\n \"prodCtx\",\n \"prodUiCtx\",\n \"prodArgs\",\n \"prodOutputPrevious\",\n \"prodCtxPrevious\",\n \"prodUiCtxPrevious\",\n ]),\n );\n }\n }\n\n private initializeBlockDuplicate(blockId: string, originalBlockInfo: BlockInfo) {\n const info = new BlockInfo(\n blockId,\n {},\n originalBlockInfo.config,\n originalBlockInfo.source,\n this.projectHelper.logger,\n );\n\n this.blockInfos.set(blockId, info);\n\n const fieldNamesToDuplicate = this.getFieldNamesToDuplicate(blockId);\n\n // Copy all fields from original block to new block by sharing references\n for (const [fieldName, fieldState] of Object.entries(originalBlockInfo.fields)) {\n if (\n fieldNamesToDuplicate.has(fieldName as ProjectField[\"fieldName\"]) &&\n fieldState &&\n fieldState.ref\n ) {\n this.setBlockFieldObj(blockId, fieldName as keyof BlockFieldStates, {\n ref: fieldState.ref,\n status: fieldState.status,\n value: fieldState.value,\n });\n }\n }\n\n this.resetOrLimboProduction(blockId);\n\n info.check();\n }\n\n /** Very generic method, better check for more specialized case-specific methods first. */\n public updateStructure(\n newStructure: ProjectStructure,\n newBlockInitializer: (blockId: string) => void = NoNewBlocks,\n ): void {\n const currentStagingGraph = this.getStagingGraph();\n const currentActualProductionGraph = this.getActualProductionGraph();\n\n const newStagingGraph = stagingGraph(newStructure);\n\n const stagingDiff = graphDiff(currentStagingGraph, newStagingGraph);\n\n // removing blocks\n for (const blockId of stagingDiff.onlyInA) {\n const { fields } = this.getBlockInfo(blockId);\n this.deleteBlockFields(blockId, ...(Object.keys(fields) as ProjectField[\"fieldName\"][]));\n this.blockInfos.delete(blockId);\n if (this.blocksInLimbo.delete(blockId)) this.renderingStateChanged = true;\n }\n\n // creating new blocks\n for (const blockId of stagingDiff.onlyInB) {\n newBlockInitializer(blockId);\n }\n\n // resetting stagings affected by topology change\n for (const blockId of stagingDiff.different) this.resetStaging(blockId);\n\n // new actual production graph without new blocks\n const newActualProductionGraph = productionGraph(newStructure, (blockId) =>\n this.getProductionGraphBlockInfo(blockId, true),\n );\n\n const prodDiff = graphDiff(currentActualProductionGraph, newActualProductionGraph);\n\n // applying changes due to topology change in production to affected nodes and\n // all their downstreams\n currentActualProductionGraph.traverse(\"downstream\", [...prodDiff.different], (node) => {\n this.resetOrLimboProduction(node.id);\n });\n\n if (\n stagingDiff.onlyInB.size > 0 ||\n stagingDiff.onlyInA.size > 0 ||\n stagingDiff.different.size > 0\n )\n this.resetStagingRefreshTimestamp();\n\n this.struct = newStructure;\n this.structureChanged = true;\n this.stagingGraph = undefined;\n this.pendingProductionGraph = undefined;\n this.actualProductionGraph = undefined;\n\n this.updateLastModified();\n }\n\n //\n // Structure change helpers\n //\n\n public addBlock(block: Block, spec: NewBlockSpec, before?: string): void {\n const newStruct = this.structure; // copy current structure\n if (before === undefined) {\n // adding as a very last block\n newStruct.groups[newStruct.groups.length - 1].blocks.push(block);\n } else {\n let done = false;\n for (const group of newStruct.groups) {\n const idx = group.blocks.findIndex((b) => b.id === before);\n if (idx < 0) continue;\n group.blocks.splice(idx, 0, block);\n done = true;\n break;\n }\n if (!done) throw new Error(`Can't find element with id: ${before}`);\n }\n this.updateStructure(newStruct, (blockId) => {\n if (blockId !== block.id) throw new Error(\"Unexpected\");\n this.initializeNewBlock(blockId, spec);\n });\n }\n\n /**\n * Duplicates an existing block by copying all its fields and structure.\n * This method creates a deep copy of the block at the mutator level.\n *\n * @param originalBlockId id of the block to duplicate\n * @param newBlockId id for the new duplicated block\n * @param after id of the block to insert new block after\n */\n public duplicateBlock(originalBlockId: string, newBlockId: string, after?: string): void {\n // Get the original block from structure\n const originalBlock = this.getBlock(originalBlockId);\n const originalBlockInfo = this.getBlockInfo(originalBlockId);\n\n // Create new block in structure\n const newBlock: Block = {\n id: newBlockId,\n label: originalBlock.label,\n renderingMode: originalBlock.renderingMode,\n };\n\n // Add the new block to structure\n const newStruct = this.structure; // copy current structure\n if (after === undefined) {\n // adding as a very last block\n newStruct.groups[newStruct.groups.length - 1].blocks.push(newBlock);\n } else {\n let done = false;\n for (const group of newStruct.groups) {\n const idx = group.blocks.findIndex((b) => b.id === after);\n if (idx < 0) continue;\n group.blocks.splice(idx + 1, 0, newBlock);\n done = true;\n break;\n }\n if (!done) throw new Error(`Can't find element with id: ${after}`);\n }\n\n this.updateStructure(newStruct, (blockId) => {\n if (blockId !== newBlockId) throw new Error(\"Unexpected\");\n this.initializeBlockDuplicate(blockId, originalBlockInfo);\n });\n }\n\n public deleteBlock(blockId: string): void {\n const newStruct = this.structure; // copy current structure\n let done = false;\n for (const group of newStruct.groups) {\n const idx = group.blocks.findIndex((b) => b.id === blockId);\n if (idx < 0) continue;\n group.blocks.splice(idx, 1);\n done = true;\n break;\n }\n if (!done) throw new Error(`Can't find element with id: ${blockId}`);\n this.updateStructure(newStruct);\n }\n\n //\n // Block-pack migration\n //\n\n public migrateBlockPack(\n blockId: string,\n spec: BlockPackSpecPrepared,\n newClearState?: ClearState,\n ): void {\n const info = this.getBlockInfo(blockId);\n const newConfig = extractConfig(spec.config);\n\n const persistBlockPack = () => {\n this.setBlockField(\n blockId,\n \"blockPack\",\n Pl.wrapInHolder(this.tx, createBlockPack(this.tx, spec)),\n \"NotReady\",\n );\n };\n\n const applyStorageAndDeriveArgs = (storageJson: string) => {\n persistBlockPack();\n this.setBlockStorageRaw(blockId, storageJson);\n const deriveArgsResult = this.projectHelper.deriveArgsFromStorage(newConfig, storageJson);\n if (!deriveArgsResult.error) {\n this.setBlockFieldObj(\n blockId,\n \"currentArgs\",\n this.createJsonFieldValue(deriveArgsResult.value),\n );\n const prerunArgs = this.projectHelper.derivePrerunArgsFromStorage(newConfig, storageJson);\n if (prerunArgs !== undefined) {\n this.setBlockFieldObj(\n blockId,\n \"currentPrerunArgs\",\n this.createJsonFieldValue(prerunArgs),\n );\n } else {\n this.deleteBlockFields(blockId, \"currentPrerunArgs\");\n }\n } else {\n this.deleteBlockFields(blockId, \"currentArgs\");\n this.deleteBlockFields(blockId, \"currentPrerunArgs\");\n }\n };\n\n if (newClearState !== undefined) {\n // State is being reset - no migration needed\n const supportsStorageFromVM = newConfig.modelAPIVersion === BLOCK_STORAGE_FACADE_VERSION;\n\n if (supportsStorageFromVM) {\n // V2+: Get initial storage directly from VM and derive args from it\n const initialStorageJson = this.projectHelper.getInitialStorageInVM(newConfig);\n applyStorageAndDeriveArgs(initialStorageJson);\n this.blocksWithChangedInputs.add(blockId);\n this.updateLastModified();\n } else {\n // V1: Use setStates with legacy state format\n persistBlockPack();\n this.setStates([{ modelAPIVersion: 1, blockId, state: newClearState.state }]);\n }\n } else {\n // State is being preserved - run migrations if needed via VM\n // Only Model API v2 blocks support migrations\n const supportsStateMigrations = newConfig.modelAPIVersion === BLOCK_STORAGE_FACADE_VERSION;\n\n if (supportsStateMigrations) {\n const currentStorageJson = info.blockStorageJson;\n\n // Attempt migration BEFORE persisting block pack — on failure,\n // block stays on old version (no inconsistent new-code/old-storage state)\n const migrationResult = this.projectHelper.migrateStorageInVM(\n newConfig,\n currentStorageJson,\n );\n\n if (migrationResult.error !== undefined) {\n throw new Error(\n `[migrateBlockPack] Block ${blockId} migration failed: ${migrationResult.error}`,\n );\n }\n\n this.projectHelper.logger.info(\n `[migrateBlockPack] Block ${blockId}: ${migrationResult.info}`,\n );\n applyStorageAndDeriveArgs(migrationResult.newStorageJson);\n } else {\n // Legacy blocks (modelAPIVersion 1): persist block pack, set prerunArgs = currentArgs\n persistBlockPack();\n if (info.fields.currentArgs !== undefined) {\n this.setBlockFieldObj(blockId, \"currentPrerunArgs\", info.fields.currentArgs);\n }\n }\n\n this.blocksWithChangedInputs.add(blockId);\n\n // resetting staging outputs for all downstream blocks\n this.getStagingGraph().traverse(\"downstream\", [blockId], ({ id }) => this.resetStaging(id));\n }\n\n // also reset or limbo all downstream productions\n if (info.productionRendered)\n this.getActualProductionGraph().traverse(\"downstream\", [blockId], ({ id }) =>\n this.resetOrLimboProduction(id),\n );\n\n this.updateLastModified();\n }\n\n //\n // Render\n //\n\n public renderProduction(blockIds: string[], addUpstreams: boolean = false): Set<string> {\n const blockIdsSet = new Set(blockIds);\n\n const prodGraph = this.getPendingProductionGraph();\n if (addUpstreams)\n // adding all upstreams automatically\n prodGraph.traverse(\"upstream\", blockIds, (node) => {\n blockIdsSet.add(node.id);\n });\n else\n // checking that targets contain all upstreams\n for (const blockId of blockIdsSet) {\n const node = prodGraph.nodes.get(blockId);\n if (node === undefined) throw new Error(`Can't find block with id: ${blockId}`);\n for (const upstream of node.upstream)\n if (!blockIdsSet.has(upstream))\n throw new Error(\"Can't render blocks not including all upstreams.\");\n }\n\n // traversing in topological order and rendering target blocks\n const rendered = new Set<string>();\n for (const block of allBlocks(this.structure)) {\n if (!blockIdsSet.has(block.id)) continue;\n\n let render =\n this.getBlockInfo(block.id).requireProductionRendering || this.blocksInLimbo.has(block.id);\n\n if (!render)\n for (const upstream of prodGraph.nodes.get(block.id)!.upstream)\n if (rendered.has(upstream)) {\n render = true;\n break;\n }\n\n if (render) {\n this.renderProductionFor(block.id);\n rendered.add(block.id);\n }\n }\n\n const renderedArray = [...rendered];\n\n // sending to limbo all downstream blocks\n prodGraph.traverse(\"downstream\", renderedArray, (node) => {\n if (rendered.has(node.id))\n // don't send to limbo blocks that were just rendered\n return;\n this.resetOrLimboProduction(node.id);\n });\n\n // resetting staging outputs for all downstream blocks\n this.getStagingGraph().traverse(\"downstream\", renderedArray, ({ id }) => {\n // don't reset staging of the first rendered block\n if (renderedArray[0] !== id) this.resetStaging(id);\n });\n\n if (rendered.size > 0) this.updateLastModified();\n\n return rendered;\n }\n\n /** Stops running blocks from the list and modify states of other blocks\n * accordingly */\n public stopProduction(...blockIds: string[]) {\n const activeProdGraph = this.getActualProductionGraph();\n\n // we will stop all blocks listed in request and all their downstreams\n const queue = new Denque(blockIds);\n const queued = new Set(blockIds);\n const stopped: string[] = [];\n\n while (!queue.isEmpty()) {\n const blockId = queue.shift()!;\n const fields = this.getBlockInfo(blockId).fields;\n\n if (fields.prodOutput?.status === \"Ready\" && fields.prodCtx?.status === \"Ready\")\n // skipping finished blocks\n continue;\n\n if (this.deleteBlockFields(blockId, \"prodOutput\", \"prodCtx\", \"prodUiCtx\", \"prodArgs\")) {\n // was actually stopped\n stopped.push(blockId);\n\n // will try to stop all its downstreams\n for (const downstream of activeProdGraph.traverseIdsExcludingRoots(\"downstream\", blockId)) {\n if (queued.has(downstream)) continue;\n queue.push(downstream);\n queued.add(downstream);\n }\n }\n }\n\n // blocks under stopped blocks, but having finished production results, goes to limbo\n for (const blockId of activeProdGraph.traverseIdsExcludingRoots(\"downstream\", ...stopped))\n this.resetOrLimboProduction(blockId);\n\n // reset staging outputs for all downstream blocks\n this.getStagingGraph().traverse(\"downstream\", stopped, ({ id }) => this.resetStaging(id));\n }\n\n private traverseWithStagingLag(cb: (blockId: string, lag: number) => void) {\n const lags = new Map<string, number>();\n const stagingGraph = this.getStagingGraph();\n stagingGraph.nodes.forEach((node) => {\n const info = this.getBlockInfo(node.id);\n // Use requireStagingRendering to check both: staging exists AND prerunArgs hasn't changed\n const requiresRendering = info.requireStagingRendering;\n let lag = requiresRendering ? 1 : 0;\n node.upstream.forEach((upstream) => {\n const upstreamLag = lags.get(upstream)!;\n if (upstreamLag === 0) return;\n lag = Math.max(upstreamLag + 1, lag);\n });\n if (!requiresRendering && info.stagingRendered) {\n // console.log(`[traverseWithStagingLag] SKIP staging for ${node.id} - prerunArgs unchanged`);\n }\n cb(node.id, lag);\n lags.set(node.id, lag);\n });\n }\n\n /** @param stagingRenderingRate rate in blocks per second */\n private refreshStagings(stagingRenderingRate?: number) {\n const elapsed = Date.now() - this.renderingState.stagingRefreshTimestamp;\n const lagThreshold =\n stagingRenderingRate === undefined\n ? undefined\n : 1 + Math.max(0, (elapsed * stagingRenderingRate) / 1000);\n let rendered = 0;\n this.traverseWithStagingLag((blockId, lag) => {\n if (lag === 0)\n // meaning staging already rendered\n return;\n if (lagThreshold === undefined || lag <= lagThreshold) {\n try {\n this.renderStagingFor(blockId);\n rendered++;\n } catch (e) {\n this.projectHelper.logger.error(\n new Error(`[refreshStagings] renderStagingFor failed for ${blockId}`, { cause: e }),\n );\n }\n }\n });\n if (rendered > 0) this.resetStagingRefreshTimestamp();\n }\n\n //\n // Meta\n //\n\n /** Updates project metadata */\n public setMeta(meta: ProjectMeta): void {\n this.meta = meta;\n this.metaChanged = true;\n this.updateLastModified();\n }\n\n //\n // Maintenance\n //\n\n /** @param stagingRenderingRate rate in blocks per second */\n public doRefresh(stagingRenderingRate?: number) {\n this.refreshStagings(stagingRenderingRate);\n this.blockInfos.forEach((blockInfo) => {\n if (\n blockInfo.fields.prodCtx?.status === \"Ready\" &&\n blockInfo.fields.prodOutput?.status === \"Ready\"\n )\n this.deleteBlockFields(\n blockInfo.id,\n \"prodOutputPrevious\",\n \"prodCtxPrevious\",\n \"prodUiCtxPrevious\",\n );\n if (\n blockInfo.fields.stagingCtx?.status === \"Ready\" &&\n blockInfo.fields.stagingOutput?.status === \"Ready\"\n )\n this.deleteBlockFields(\n blockInfo.id,\n \"stagingOutputPrevious\",\n \"stagingCtxPrevious\",\n \"stagingUiCtxPrevious\",\n );\n });\n }\n\n private assignAuthorMarkers() {\n const markerStr = this.author ? JSON.stringify(this.author) : undefined;\n\n for (const blockId of this.blocksWithChangedInputs)\n if (markerStr === undefined) this.tx.deleteKValue(this.rid, blockArgsAuthorKey(blockId));\n else this.tx.setKValue(this.rid, blockArgsAuthorKey(blockId), markerStr);\n\n if (this.metaChanged || this.structureChanged) {\n if (markerStr === undefined) this.tx.deleteKValue(this.rid, ProjectStructureAuthorKey);\n else this.tx.setKValue(this.rid, ProjectStructureAuthorKey, markerStr);\n }\n }\n\n public save() {\n if (!this.wasModified) return;\n\n if (this.lastModifiedChanged)\n this.tx.setKValue(this.rid, ProjectLastModifiedTimestamp, JSON.stringify(this.lastModified));\n\n if (this.structureChanged)\n this.tx.setKValue(this.rid, ProjectStructureKey, JSON.stringify(this.struct));\n\n if (this.renderingStateChanged)\n this.tx.setKValue(\n this.rid,\n BlockRenderingStateKey,\n JSON.stringify({\n ...this.renderingState,\n blocksInLimbo: [...this.blocksInLimbo],\n } as ProjectRenderingState),\n );\n\n if (this.metaChanged) this.tx.setKValue(this.rid, ProjectMetaKey, JSON.stringify(this.meta));\n\n this.assignAuthorMarkers();\n }\n\n public static async load(\n projectHelper: ProjectHelper,\n tx: PlTransaction,\n rid: ResourceId,\n author?: AuthorMarker,\n ): Promise<ProjectMutator> {\n //\n // Sending initial requests to read project state (start of round-trip #1)\n //\n\n const fullResourceStateP = tx.getResourceData(rid, true);\n const schemaP = tx.getKValueJson<string>(rid, SchemaVersionKey);\n const lastModifiedP = tx.getKValueJson<number>(rid, ProjectLastModifiedTimestamp);\n const metaP = tx.getKValueJson<ProjectMeta>(rid, ProjectMetaKey);\n const structureP = tx.getKValueJson<ProjectStructure>(rid, ProjectStructureKey);\n const renderingStateP = tx.getKValueJson<ProjectRenderingState>(rid, BlockRenderingStateKey);\n\n const fullResourceState = await fullResourceStateP;\n\n // loading field information\n const blockInfoStates = new Map<string, BlockInfoState>();\n for (const f of fullResourceState.fields) {\n const projectField = parseProjectField(f.name);\n\n // processing only fields with known structure\n if (projectField === undefined) continue;\n\n let info = blockInfoStates.get(projectField.blockId);\n if (info === undefined) {\n info = {\n id: projectField.blockId,\n fields: {},\n };\n blockInfoStates.set(projectField.blockId, info);\n }\n\n info.fields[projectField.fieldName] = isNullResourceId(f.value)\n ? { modCount: 0 }\n : { modCount: 0, ref: f.value };\n }\n\n //\n // Roundtrip #1 not yet finished, but as soon as field list is received,\n // we can start sending requests to read states of referenced resources\n // (start of round-trip #2)\n //\n\n const blockFieldRequests: [\n BlockInfoState,\n ProjectField[\"fieldName\"],\n BlockFieldState,\n Promise<BasicResourceData | ResourceData>,\n ][] = [];\n blockInfoStates.forEach((info) => {\n const fields = info.fields;\n for (const [fName, state] of Object.entries(fields)) {\n if (state.ref === undefined) continue;\n if (!isResource(state.ref) || isResourceRef(state.ref))\n throw new Error(\"unexpected behaviour\");\n const fieldName = fName as ProjectField[\"fieldName\"];\n blockFieldRequests.push([\n info,\n fieldName,\n state,\n tx.getResourceData(state.ref, fieldName == \"blockPack\"),\n ]);\n }\n });\n\n // loading jsons\n const [schema, lastModified, meta, structure, { stagingRefreshTimestamp, blocksInLimbo }] =\n await Promise.all([schemaP, lastModifiedP, metaP, structureP, renderingStateP]);\n\n // Checking schema version of the project\n if (schema !== SchemaVersionCurrent) {\n if (Number(schema) < Number(SchemaVersionCurrent))\n throw new UiError(\n `Can't perform this action on this project because it has older schema. Try (re)loading the project to update it.`,\n );\n else\n throw new UiError(\n `Can't perform this action on this project because it has newer schema. Upgrade your desktop app to the latest version.`,\n );\n }\n\n //\n // <- at this point we have all the responses from round-trip #1\n //\n\n //\n // Receiving responses from round-trip #2 and sending requests to read block pack descriptions\n // (start of round-trip #3)\n //\n\n const blockPackRequests: [BlockInfoState, Promise<BasicResourceData>][] = [];\n for (const [info, fieldName, state, response] of blockFieldRequests) {\n const result = await response;\n state.value = result.data;\n if (isNotNullResourceId(result.error)) state.status = \"Error\";\n else if (result.resourceReady || isNotNullResourceId(result.originalResourceId))\n state.status = \"Ready\";\n else state.status = \"NotReady\";\n\n // For block pack we need to traverse the ref field from the resource data\n if (fieldName === \"blockPack\") {\n const refField = (result as ResourceData).fields.find((f) => f.name === Pl.HolderRefField);\n if (refField === undefined) throw new Error(\"Block pack ref field is missing\");\n blockPackRequests.push([\n info,\n tx.getResourceData(ensureResourceIdNotNull(refField.value), false),\n ]);\n }\n }\n\n //\n // <- at this point we have all the responses from round-trip #2\n //\n\n for (const [info, response] of blockPackRequests) {\n const result = await response;\n const bpInfo = cachedDeserialize<BlockPackInfo>(notEmpty(result.data));\n info.blockConfig = extractConfig(bpInfo.config);\n info.blockPack = bpInfo.source;\n }\n\n //\n // <- at this point we have all the responses from round-trip #3\n //\n\n // loading ctx export template to check if we already have cached materialized template in our project\n const ctxExportTplEnvelope = await getPreparedExportTemplateEnvelope();\n\n // expected field name\n const ctxExportTplCacheFieldName = getServiceTemplateField(ctxExportTplEnvelope.hash);\n const ctxExportTplField = fullResourceState.fields.find(\n (f) => f.name === ctxExportTplCacheFieldName,\n );\n let ctxExportTplHolder: AnyResourceRef;\n if (ctxExportTplField !== undefined)\n ctxExportTplHolder = ensureResourceIdNotNull(ctxExportTplField.value);\n else {\n ctxExportTplHolder = Pl.wrapInHolder(tx, loadTemplate(tx, ctxExportTplEnvelope.spec));\n tx.createField(\n field(rid, getServiceTemplateField(ctxExportTplEnvelope.hash)),\n \"Dynamic\",\n ctxExportTplHolder,\n );\n }\n\n const renderingState = { stagingRefreshTimestamp };\n const blocksInLimboSet = new Set(blocksInLimbo);\n\n const blockInfos = new Map<string, BlockInfo>();\n blockInfoStates.forEach(({ id, fields, blockConfig, blockPack }) =>\n blockInfos.set(\n id,\n new BlockInfo(id, fields, notEmpty(blockConfig), notEmpty(blockPack), projectHelper.logger),\n ),\n );\n\n // check consistency of project state\n const blockInStruct = new Set<string>();\n for (const b of allBlocks(structure)) {\n if (!blockInfos.has(b.id))\n throw new Error(`Inconsistent project structure: no inputs for ${b.id}`);\n blockInStruct.add(b.id);\n }\n blockInfos.forEach((info) => {\n if (!blockInStruct.has(info.id))\n throw new Error(`Inconsistent project structure: no structure entry for ${info.id}`);\n });\n\n const prj = new ProjectMutator(\n rid,\n tx,\n author,\n schema,\n lastModified,\n meta,\n structure,\n renderingState,\n blocksInLimboSet,\n blockInfos,\n ctxExportTplHolder,\n projectHelper,\n );\n\n prj.fixProblemsAndMigrate();\n\n return prj;\n }\n}\n\nexport interface ProjectState {\n schema: string;\n structure: ProjectStructure;\n renderingState: Omit<ProjectRenderingState, \"blocksInLimbo\">;\n blocksInLimbo: Set<string>;\n blockInfos: Map<string, BlockInfo>;\n}\n\nexport async function createProject(\n tx: PlTransaction,\n meta: ProjectMeta = InitialBlockMeta,\n): Promise<AnyResourceRef> {\n const prj = tx.createEphemeral(ProjectResourceType);\n tx.lock(prj);\n const ts = String(Date.now());\n tx.setKValue(prj, SchemaVersionKey, JSON.stringify(SchemaVersionCurrent));\n tx.setKValue(prj, ProjectCreatedTimestamp, ts);\n tx.setKValue(prj, ProjectLastModifiedTimestamp, ts);\n tx.setKValue(prj, ProjectMetaKey, JSON.stringify(meta));\n tx.setKValue(prj, ProjectStructureKey, JSON.stringify(InitialBlockStructure));\n tx.setKValue(prj, BlockRenderingStateKey, JSON.stringify(InitialProjectRenderingState));\n const ctxExportTplEnvelope = await getPreparedExportTemplateEnvelope();\n tx.createField(\n field(prj, getServiceTemplateField(ctxExportTplEnvelope.hash)),\n \"Dynamic\",\n Pl.wrapInHolder(tx, loadTemplate(tx, ctxExportTplEnvelope.spec)),\n );\n return prj;\n}\n\nexport async function withProject<T>(\n projectHelper: ProjectHelper,\n txOrPl: PlTransaction | PlClient,\n rid: ResourceId,\n cb: (p: ProjectMutator) => T | Promise<T>,\n ops?: Partial<TxOps>,\n): Promise<T> {\n return withProjectAuthored(projectHelper, txOrPl, rid, undefined, cb, ops);\n}\n\nexport async function withProjectAuthored<T>(\n projectHelper: ProjectHelper,\n txOrPl: PlTransaction | PlClient,\n rid: ResourceId,\n author: AuthorMarker | undefined,\n cb: (p: ProjectMutator) => T | Promise<T>,\n ops: Partial<TxOps> = {},\n): Promise<T> {\n if (txOrPl instanceof PlClient) {\n return await txOrPl.withWriteTx(\n \"ProjectAction\" + (ops.name ? `: ${ops.name}` : \"\"),\n async (tx) => {\n const mut = await ProjectMutator.load(projectHelper, tx, rid, author);\n const result = await cb(mut);\n if (!mut.wasModified)\n // skipping save and commit altogether if no modifications were actually made\n return result;\n mut.save();\n await tx.commit();\n if (getDebugFlags().logProjectMutationStat) console.log(JSON.stringify(tx.stat));\n return result;\n },\n ops,\n );\n } else {\n const mut = await ProjectMutator.load(projectHelper, txOrPl, rid, author);\n const result = await cb(mut);\n mut.save();\n return result;\n }\n}\n"],"mappings":"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"}
|
package/dist/mutator/project.js
CHANGED
|
@@ -10,6 +10,7 @@ import { InitialBlockSettings } from "@milaboratories/pl-model-middle-layer";
|
|
|
10
10
|
import { ConsoleLoggerAdapter, cachedDecode, cachedDeserialize, canonicalJsonBytes, notEmpty } from "@milaboratories/ts-helpers";
|
|
11
11
|
import { Pl, PlClient, ensureResourceIdNotNull, field, isNotNullResourceId, isNullResourceId, isResource, isResourceId, isResourceRef } from "@milaboratories/pl-client";
|
|
12
12
|
import Denque from "denque";
|
|
13
|
+
import { gzipSync } from "node:zlib";
|
|
13
14
|
|
|
14
15
|
//#region src/mutator/project.ts
|
|
15
16
|
function cached(modIdCb, valueCb) {
|
|
@@ -215,17 +216,47 @@ var ProjectMutator = class ProjectMutator {
|
|
|
215
216
|
if (info === void 0) throw new Error(`No such block: ${blockId}`);
|
|
216
217
|
return info;
|
|
217
218
|
}
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
const value = Buffer.from(
|
|
219
|
+
/** Create a plain JSON resource value from a JS object (no compression). */
|
|
220
|
+
createJsonFieldValue(obj) {
|
|
221
|
+
const value = Buffer.from(JSON.stringify(obj));
|
|
221
222
|
return {
|
|
222
223
|
ref: this.tx.createValue(Pl.JsonObject, value),
|
|
223
224
|
value,
|
|
224
225
|
status: "Ready"
|
|
225
226
|
};
|
|
226
227
|
}
|
|
227
|
-
|
|
228
|
-
|
|
228
|
+
/** Create a plain JSON resource value from a pre-serialized JSON string (no compression). */
|
|
229
|
+
createJsonFieldValueFromContent(json) {
|
|
230
|
+
const value = Buffer.from(json);
|
|
231
|
+
return {
|
|
232
|
+
ref: this.tx.createValue(Pl.JsonObject, value),
|
|
233
|
+
value,
|
|
234
|
+
status: "Ready"
|
|
235
|
+
};
|
|
236
|
+
}
|
|
237
|
+
/** Create a gzip-compressed JSON resource value from a JS object (compressed if >= 16KB). */
|
|
238
|
+
createGzJsonFieldValue(obj) {
|
|
239
|
+
const jsonBytes = canonicalJsonBytes(obj);
|
|
240
|
+
return this.createGzJsonFieldValueFromBytes(jsonBytes);
|
|
241
|
+
}
|
|
242
|
+
/** Create a gzip-compressed JSON resource value from a pre-serialized JSON string (compressed if >= 16KB). */
|
|
243
|
+
createGzJsonFieldValueFromContent(json) {
|
|
244
|
+
return this.createGzJsonFieldValueFromBytes(Buffer.from(json));
|
|
245
|
+
}
|
|
246
|
+
createGzJsonFieldValueFromBytes(jsonBytes) {
|
|
247
|
+
if (jsonBytes.length >= 16384) {
|
|
248
|
+
const data = gzipSync(jsonBytes);
|
|
249
|
+
return {
|
|
250
|
+
ref: this.tx.createValue(Pl.JsonGzObject, data),
|
|
251
|
+
value: data,
|
|
252
|
+
status: "Ready"
|
|
253
|
+
};
|
|
254
|
+
}
|
|
255
|
+
return {
|
|
256
|
+
ref: this.tx.createValue(Pl.JsonObject, jsonBytes),
|
|
257
|
+
value: jsonBytes,
|
|
258
|
+
status: "Ready"
|
|
259
|
+
};
|
|
229
260
|
}
|
|
230
261
|
getBlock(blockId) {
|
|
231
262
|
for (const block of allBlocks(this.struct)) if (block.id === blockId) return block;
|
|
@@ -325,7 +356,7 @@ var ProjectMutator = class ProjectMutator {
|
|
|
325
356
|
* @param rawStorageJson Raw storage as JSON string
|
|
326
357
|
*/
|
|
327
358
|
setBlockStorageRaw(blockId, rawStorageJson) {
|
|
328
|
-
this.setBlockFieldObj(blockId, "blockStorage", this.
|
|
359
|
+
this.setBlockFieldObj(blockId, "blockStorage", this.createGzJsonFieldValueFromContent(rawStorageJson));
|
|
329
360
|
this.blocksWithChangedInputs.add(blockId);
|
|
330
361
|
this.updateLastModified();
|
|
331
362
|
}
|
|
@@ -370,7 +401,7 @@ var ProjectMutator = class ProjectMutator {
|
|
|
370
401
|
const currentStorageJson = info.blockStorageJson;
|
|
371
402
|
if (currentStorageJson === void 0) throw new Error(`Block ${req.blockId} has no blockStorage - this should not happen`);
|
|
372
403
|
const updatedStorageJson = this.projectHelper.applyStorageUpdateInVM(blockConfig, currentStorageJson, req.payload);
|
|
373
|
-
this.setBlockFieldObj(req.blockId, "blockStorage", this.
|
|
404
|
+
this.setBlockFieldObj(req.blockId, "blockStorage", this.createGzJsonFieldValueFromContent(updatedStorageJson));
|
|
374
405
|
const derivedArgsResult = this.projectHelper.deriveArgsFromStorage(blockConfig, updatedStorageJson);
|
|
375
406
|
if (derivedArgsResult.error) {
|
|
376
407
|
args = void 0;
|
|
@@ -380,7 +411,7 @@ var ProjectMutator = class ProjectMutator {
|
|
|
380
411
|
prerunArgs = this.projectHelper.derivePrerunArgsFromStorage(blockConfig, updatedStorageJson);
|
|
381
412
|
}
|
|
382
413
|
} else {
|
|
383
|
-
this.setBlockFieldObj(req.blockId, "blockStorage", this.
|
|
414
|
+
this.setBlockFieldObj(req.blockId, "blockStorage", this.createGzJsonFieldValue(req.state));
|
|
384
415
|
if (req.state !== null && typeof req.state === "object" && "args" in req.state) args = req.state.args;
|
|
385
416
|
else args = req.state;
|
|
386
417
|
prerunArgs = args;
|
|
@@ -503,7 +534,7 @@ var ProjectMutator = class ProjectMutator {
|
|
|
503
534
|
} else throw new Error(`Unknown storageMode: ${spec.storageMode}`);
|
|
504
535
|
if (args !== void 0) this.setBlockFieldObj(blockId, "currentArgs", this.createJsonFieldValue(args));
|
|
505
536
|
if (prerunArgs !== void 0) this.setBlockFieldObj(blockId, "currentPrerunArgs", this.createJsonFieldValue(prerunArgs));
|
|
506
|
-
this.setBlockFieldObj(blockId, "blockStorage", this.
|
|
537
|
+
this.setBlockFieldObj(blockId, "blockStorage", this.createGzJsonFieldValueFromContent(storageToWrite));
|
|
507
538
|
info.check();
|
|
508
539
|
}
|
|
509
540
|
getFieldNamesToDuplicate(blockId) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"project.js","names":[],"sources":["../../src/mutator/project.ts"],"sourcesContent":["import type {\n AnyRef,\n AnyResourceRef,\n BasicResourceData,\n PlTransaction,\n ResourceData,\n ResourceId,\n TxOps,\n} from \"@milaboratories/pl-client\";\nimport {\n ensureResourceIdNotNull,\n field,\n isNotNullResourceId,\n isNullResourceId,\n isResource,\n isResourceId,\n isResourceRef,\n Pl,\n PlClient,\n} from \"@milaboratories/pl-client\";\nimport { createRenderHeavyBlock, createBContextFromUpstreams } from \"./template/render_block\";\nimport type {\n Block,\n ProjectStructure,\n ProjectField,\n ProjectRenderingState,\n} from \"../model/project_model\";\nimport {\n BlockRenderingStateKey,\n ProjectStructureKey,\n parseProjectField,\n projectFieldName,\n SchemaVersionCurrent,\n SchemaVersionKey,\n ProjectResourceType,\n InitialBlockStructure,\n InitialProjectRenderingState,\n ProjectMetaKey,\n InitialBlockMeta,\n blockArgsAuthorKey,\n ProjectLastModifiedTimestamp,\n ProjectCreatedTimestamp,\n ProjectStructureAuthorKey,\n getServiceTemplateField,\n FieldsToDuplicate,\n} from \"../model/project_model\";\nimport { BlockPackTemplateField, createBlockPack } from \"./block-pack/block_pack\";\nimport type { BlockGraph, ProductionGraphBlockInfo } from \"../model/project_model_util\";\nimport { allBlocks, graphDiff, productionGraph, stagingGraph } from \"../model/project_model_util\";\nimport type { BlockPackSpecPrepared } from \"../model\";\nimport type {\n AuthorMarker,\n BlockPackSpec,\n BlockSettings,\n ProjectMeta,\n} from \"@milaboratories/pl-model-middle-layer\";\nimport { InitialBlockSettings } from \"@milaboratories/pl-model-middle-layer\";\nimport Denque from \"denque\";\nimport { exportContext, getPreparedExportTemplateEnvelope } from \"./context_export\";\nimport { loadTemplate } from \"./template/template_loading\";\nimport {\n cachedDeserialize,\n notEmpty,\n canonicalJsonBytes,\n cachedDecode,\n type MiLogger,\n ConsoleLoggerAdapter,\n} from \"@milaboratories/ts-helpers\";\nimport type { ProjectHelper } from \"../model/project_helper\";\nimport {\n extractConfig,\n UiError,\n BLOCK_STORAGE_FACADE_VERSION,\n type BlockConfig,\n} from \"@platforma-sdk/model\";\nimport { getDebugFlags } from \"../debug\";\nimport type { BlockPackInfo } from \"../model/block_pack\";\n\ntype FieldStatus = \"NotReady\" | \"Ready\" | \"Error\";\n\ninterface BlockFieldState {\n modCount: number;\n ref?: AnyRef;\n status?: FieldStatus;\n value?: Uint8Array;\n}\n\ntype BlockFieldStates = Partial<Record<ProjectField[\"fieldName\"], BlockFieldState>>;\ntype BlockFieldStateValue = Omit<BlockFieldState, \"modCount\">;\n\ninterface BlockInfoState {\n readonly id: string;\n readonly fields: BlockFieldStates;\n blockConfig?: BlockConfig;\n blockPack?: BlockPackSpec;\n}\n\nfunction cached<ModId, T>(modIdCb: () => ModId, valueCb: () => T): () => T {\n let initialized = false;\n let lastModId: ModId | undefined = undefined;\n let value: T | undefined = undefined;\n return () => {\n if (!initialized) {\n initialized = true;\n lastModId = modIdCb();\n value = valueCb();\n return value;\n }\n const currentModId = modIdCb();\n if (lastModId !== currentModId) {\n lastModId = currentModId;\n value = valueCb();\n }\n return valueCb();\n };\n}\n\nclass BlockInfo {\n constructor(\n public readonly id: string,\n public readonly fields: BlockFieldStates,\n public readonly config: BlockConfig,\n public readonly source: BlockPackSpec,\n private readonly logger: MiLogger = new ConsoleLoggerAdapter(),\n ) {}\n\n public check() {\n // state assertions\n\n if ((this.fields.prodOutput === undefined) !== (this.fields.prodCtx === undefined))\n throw new Error(\"inconsistent prod fields\");\n\n if ((this.fields.stagingOutput === undefined) !== (this.fields.stagingCtx === undefined))\n throw new Error(\"inconsistent stage fields\");\n\n if (\n (this.fields.prodOutputPrevious === undefined) !==\n (this.fields.prodCtxPrevious === undefined)\n )\n throw new Error(\"inconsistent prod cache fields\");\n\n if (\n (this.fields.stagingOutputPrevious === undefined) !==\n (this.fields.stagingCtxPrevious === undefined)\n )\n throw new Error(\"inconsistent stage cache fields\");\n\n if (this.fields.blockPack === undefined) throw new Error(\"no block pack field\");\n\n if (this.fields.blockStorage === undefined) throw new Error(\"no block storage field\");\n }\n\n private readonly currentArgsC = cached(\n () => this.fields.currentArgs?.modCount,\n () => {\n const bin = this.fields.currentArgs?.value;\n if (bin === undefined) return undefined;\n return cachedDeserialize(bin);\n },\n );\n\n private readonly blockStorageC = cached(\n () => this.fields.blockStorage!.modCount,\n () => {\n const bin = this.fields.blockStorage?.value;\n if (bin === undefined) return undefined;\n return cachedDeserialize<Record<string, unknown>>(bin);\n },\n );\n\n private readonly blockStorageJ = cached(\n () => this.fields.blockStorage!.modCount,\n () => {\n const bin = this.fields.blockStorage?.value;\n if (bin === undefined) return undefined;\n return cachedDecode(bin);\n },\n );\n\n private readonly prodArgsC = cached(\n () => this.fields.prodArgs?.modCount,\n () => {\n const bin = this.fields.prodArgs?.value;\n if (bin === undefined) return undefined;\n return cachedDeserialize(bin);\n },\n );\n\n private readonly currentPrerunArgsC = cached(\n () => this.fields.currentPrerunArgs?.modCount,\n () => {\n const bin = this.fields.currentPrerunArgs?.value;\n if (bin === undefined) return undefined;\n return cachedDeserialize(bin);\n },\n );\n\n get currentArgs(): unknown {\n return this.currentArgsC();\n }\n\n get blockStorage(): unknown {\n try {\n return this.blockStorageC();\n } catch (e) {\n this.logger.error(new Error(`Error getting blockStorage for ${this.id}`, { cause: e }));\n return undefined;\n }\n }\n\n get blockStorageJson() {\n return this.blockStorageJ();\n }\n\n get currentPrerunArgs(): unknown {\n return this.currentPrerunArgsC();\n }\n\n get stagingRendered(): boolean {\n return this.fields.stagingCtx !== undefined;\n }\n\n get productionRendered(): boolean {\n return this.fields.prodCtx !== undefined;\n }\n\n get productionHasErrors(): boolean {\n return this.fields.prodUiCtx?.status === \"Error\";\n }\n\n private readonly productionStaleC: () => boolean = cached(\n () => `${this.fields.currentArgs!.modCount}_${this.fields.prodArgs?.modCount}`,\n () =>\n this.fields.prodArgs === undefined ||\n Buffer.compare(this.fields.currentArgs!.value!, this.fields.prodArgs.value!) !== 0,\n );\n\n get requireProductionRendering(): boolean {\n return !this.productionRendered || this.productionStaleC() || this.productionHasErrors;\n }\n\n /** Returns true if staging should be re-rendered (stagingCtx is not set) */\n get requireStagingRendering(): boolean {\n // No staging needed if currentPrerunArgs is undefined (args derivation failed)\n if (this.fields.currentPrerunArgs === undefined) return false;\n return !this.stagingRendered;\n }\n\n get prodArgs(): unknown {\n return this.prodArgsC();\n }\n\n public getTemplate(tx: PlTransaction): AnyRef {\n return tx.getFutureFieldValue(\n Pl.unwrapHolder(tx, this.fields.blockPack!.ref!),\n BlockPackTemplateField,\n \"Input\",\n );\n }\n}\n\n/**\n * Specification for creating a new block.\n * Discriminated union based on `storageMode`.\n */\n/** Specification for creating a new block. Discriminated union based on `storageMode`. */\nexport type NewBlockSpec =\n | { storageMode: \"fromModel\"; blockPack: BlockPackSpecPrepared }\n | { storageMode: \"legacy\"; blockPack: BlockPackSpecPrepared; legacyState: string };\n\nconst NoNewBlocks = (blockId: string) => {\n throw new Error(`No new block info for ${blockId}`);\n};\n\n/**\n * Request to set block state using unified state format.\n * For v3 blocks: state is the block's state\n * For v1/v2 blocks: state should be { args, uiState } format\n */\nexport type SetStatesRequest =\n | {\n blockId: string;\n /** The unified state to set */\n state: unknown;\n modelAPIVersion: 1;\n }\n | {\n blockId: string;\n /** Storage operation payload - middle layer is agnostic to specific operations */\n payload: { operation: string; value: unknown };\n modelAPIVersion: 2;\n };\n\nexport type ClearState = {\n state: unknown;\n};\n\nexport class ProjectMutator {\n private globalModCount = 0;\n private fieldsChanged: boolean = false;\n\n //\n // Change trackers\n //\n\n private lastModifiedChanged = false;\n private structureChanged = false;\n private metaChanged = false;\n private renderingStateChanged = false;\n\n /** Set blocks will be assigned current mutator author marker on save */\n private readonly blocksWithChangedInputs = new Set<string>();\n\n constructor(\n public readonly rid: ResourceId,\n private readonly tx: PlTransaction,\n private readonly author: AuthorMarker | undefined,\n private readonly schema: string,\n private lastModified: number,\n private meta: ProjectMeta,\n private struct: ProjectStructure,\n private readonly renderingState: Omit<ProjectRenderingState, \"blocksInLimbo\">,\n private readonly blocksInLimbo: Set<string>,\n private readonly blockInfos: Map<string, BlockInfo>,\n private readonly ctxExportTplHolder: AnyResourceRef,\n private readonly projectHelper: ProjectHelper,\n ) {}\n\n private fixProblemsAndMigrate() {\n // Fix inconsistent production fields\n this.blockInfos.forEach((blockInfo) => {\n if (\n blockInfo.fields.prodArgs === undefined ||\n blockInfo.fields.prodOutput === undefined ||\n blockInfo.fields.prodCtx === undefined\n )\n this.deleteBlockFields(blockInfo.id, \"prodArgs\", \"prodOutput\", \"prodCtx\", \"prodUiCtx\");\n });\n\n // Fix inconsistent staging fields\n this.blockInfos.forEach((blockInfo) => {\n if (blockInfo.fields.stagingOutput === undefined || blockInfo.fields.stagingCtx === undefined)\n this.deleteBlockFields(blockInfo.id, \"stagingOutput\", \"stagingCtx\", \"stagingUiCtx\");\n });\n\n // Fix inconsistent cache fields\n this.blockInfos.forEach((blockInfo) => {\n if (\n blockInfo.fields.prodOutputPrevious === undefined ||\n blockInfo.fields.prodCtxPrevious === undefined\n )\n this.deleteBlockFields(\n blockInfo.id,\n \"prodOutputPrevious\",\n \"prodCtxPrevious\",\n \"prodUiCtxPrevious\",\n );\n if (\n blockInfo.fields.stagingOutputPrevious === undefined ||\n blockInfo.fields.stagingCtxPrevious === undefined\n )\n this.deleteBlockFields(\n blockInfo.id,\n \"stagingOutputPrevious\",\n \"stagingCtxPrevious\",\n \"stagingUiCtxPrevious\",\n );\n });\n\n // Migration for addition of block settings field\n let initialBlockSettings: Omit<BlockFieldState, \"modCount\"> | undefined;\n this.blockInfos.forEach((blockInfo) => {\n if (blockInfo.fields.blockSettings === undefined) {\n if (initialBlockSettings === undefined)\n initialBlockSettings = this.createJsonFieldValue(InitialBlockSettings);\n this.setBlockFieldObj(blockInfo.id, \"blockSettings\", initialBlockSettings);\n }\n });\n\n // Validate after fixes\n this.blockInfos.forEach((info) => info.check());\n }\n\n get wasModified(): boolean {\n return (\n this.lastModifiedChanged ||\n this.structureChanged ||\n this.fieldsChanged ||\n this.metaChanged ||\n this.renderingStateChanged\n );\n }\n\n get structure(): ProjectStructure {\n return JSON.parse(JSON.stringify(this.struct)) as ProjectStructure;\n }\n\n //\n // Graph calculation\n //\n\n private stagingGraph: BlockGraph | undefined = undefined;\n private pendingProductionGraph: BlockGraph | undefined = undefined;\n private actualProductionGraph: BlockGraph | undefined = undefined;\n\n private getStagingGraph(): BlockGraph {\n if (this.stagingGraph === undefined) this.stagingGraph = stagingGraph(this.struct);\n return this.stagingGraph;\n }\n\n private getProductionGraphBlockInfo(\n blockId: string,\n prod: boolean,\n ): ProductionGraphBlockInfo | undefined {\n const bInfo = this.getBlockInfo(blockId);\n\n let argsField: BlockFieldState | undefined;\n let args: unknown;\n\n if (prod) {\n if (bInfo.fields.prodArgs === undefined) return undefined;\n argsField = bInfo.fields.prodArgs;\n args = bInfo.prodArgs;\n } else {\n argsField = bInfo.fields.currentArgs;\n args = bInfo.currentArgs;\n }\n\n // Can't compute enrichment targets without args\n if (argsField === undefined) {\n return { args, enrichmentTargets: undefined };\n }\n\n const blockPackField = notEmpty(bInfo.fields.blockPack);\n\n if (isResourceId(argsField.ref!) && isResourceId(blockPackField.ref!))\n return {\n args,\n enrichmentTargets: this.projectHelper.getEnrichmentTargets(\n () => bInfo.config,\n () => args,\n { argsRid: argsField.ref, blockPackRid: blockPackField.ref },\n ),\n };\n else\n return {\n args,\n enrichmentTargets: this.projectHelper.getEnrichmentTargets(\n () => bInfo.config,\n () => args,\n ),\n };\n }\n\n private getPendingProductionGraph(): BlockGraph {\n if (this.pendingProductionGraph === undefined)\n this.pendingProductionGraph = productionGraph(this.struct, (blockId) =>\n this.getProductionGraphBlockInfo(blockId, false),\n );\n return this.pendingProductionGraph;\n }\n\n private getActualProductionGraph(): BlockGraph {\n if (this.actualProductionGraph === undefined)\n this.actualProductionGraph = productionGraph(this.struct, (blockId) =>\n this.getProductionGraphBlockInfo(blockId, true),\n );\n return this.actualProductionGraph;\n }\n\n //\n // Generic helpers to interact with project state\n //\n\n private getBlockInfo(blockId: string): BlockInfo {\n const info = this.blockInfos.get(blockId);\n if (info === undefined) throw new Error(`No such block: ${blockId}`);\n return info;\n }\n\n private createJsonFieldValueByContent(content: string): BlockFieldStateValue {\n if (content === undefined) throw new Error(\"content is undefined\");\n const value = Buffer.from(content);\n const ref = this.tx.createValue(Pl.JsonObject, value);\n return { ref, value, status: \"Ready\" };\n }\n\n private createJsonFieldValue(obj: unknown): BlockFieldStateValue {\n return this.createJsonFieldValueByContent(JSON.stringify(obj));\n }\n\n private getBlock(blockId: string): Block {\n for (const block of allBlocks(this.struct)) if (block.id === blockId) return block;\n throw new Error(\"block not found\");\n }\n\n private setBlockFieldObj(\n blockId: string,\n fieldName: keyof BlockFieldStates,\n state: BlockFieldStateValue,\n ) {\n const fid = field(this.rid, projectFieldName(blockId, fieldName));\n\n if (state.ref === undefined) throw new Error(\"Can't set value with empty ref\");\n\n if (this.getBlockInfo(blockId).fields[fieldName] === undefined)\n this.tx.createField(fid, \"Dynamic\", state.ref);\n else this.tx.setField(fid, state.ref);\n\n this.getBlockInfo(blockId).fields[fieldName] = {\n modCount: this.globalModCount++,\n ...state,\n };\n\n this.fieldsChanged = true;\n }\n\n private setBlockField(\n blockId: string,\n fieldName: keyof BlockFieldStates,\n ref: AnyRef,\n status: FieldStatus,\n value?: Uint8Array,\n ) {\n this.setBlockFieldObj(blockId, fieldName, { ref, status, value });\n }\n\n private deleteBlockFields(blockId: string, ...fieldNames: (keyof BlockFieldStates)[]): boolean {\n let deleted = false;\n const info = this.getBlockInfo(blockId);\n for (const fieldName of fieldNames) {\n const fields = info.fields;\n if (!(fieldName in fields)) continue;\n this.tx.removeField(field(this.rid, projectFieldName(blockId, fieldName)));\n delete fields[fieldName];\n this.fieldsChanged = true;\n deleted = true;\n }\n return deleted;\n }\n\n private updateLastModified() {\n this.lastModified = Date.now();\n this.lastModifiedChanged = true;\n }\n\n //\n // Main project actions\n //\n\n private resetStagingRefreshTimestamp() {\n this.renderingState.stagingRefreshTimestamp = Date.now();\n this.renderingStateChanged = true;\n }\n\n private resetStaging(blockId: string): void {\n const fields = this.getBlockInfo(blockId).fields;\n if (\n fields.stagingOutput?.status === \"Ready\" &&\n fields.stagingCtx?.status === \"Ready\" &&\n fields.stagingUiCtx?.status === \"Ready\"\n ) {\n this.setBlockFieldObj(blockId, \"stagingOutputPrevious\", fields.stagingOutput);\n this.setBlockFieldObj(blockId, \"stagingCtxPrevious\", fields.stagingCtx);\n this.setBlockFieldObj(blockId, \"stagingUiCtxPrevious\", fields.stagingUiCtx);\n }\n if (this.deleteBlockFields(blockId, \"stagingOutput\", \"stagingCtx\", \"stagingUiCtx\"))\n this.resetStagingRefreshTimestamp();\n }\n\n private resetProduction(blockId: string): void {\n const fields = this.getBlockInfo(blockId).fields;\n if (\n fields.prodOutput?.status === \"Ready\" &&\n fields.prodCtx?.status === \"Ready\" &&\n fields.prodUiCtx?.status === \"Ready\"\n ) {\n this.setBlockFieldObj(blockId, \"prodOutputPrevious\", fields.prodOutput);\n this.setBlockFieldObj(blockId, \"prodCtxPrevious\", fields.prodCtx);\n this.setBlockFieldObj(blockId, \"prodUiCtxPrevious\", fields.prodUiCtx);\n }\n this.deleteBlockFields(blockId, \"prodOutput\", \"prodCtx\", \"prodUiCtx\", \"prodArgs\");\n }\n\n /** Running blocks are reset, already computed moved to limbo. Returns if\n * either of the actions were actually performed.\n * This method ensures the block is left in a consistent state that passes check() constraints. */\n private resetOrLimboProduction(blockId: string): boolean {\n const fields = this.getBlockInfo(blockId).fields;\n\n // Check if we can safely move to limbo (both core production fields are ready)\n if (fields.prodOutput?.status === \"Ready\" && fields.prodCtx?.status === \"Ready\") {\n if (this.blocksInLimbo.has(blockId))\n // we are already in limbo\n return false;\n\n // limbo - keep the ready production results but clean up cache\n this.blocksInLimbo.add(blockId);\n this.renderingStateChanged = true;\n\n // doing some gc - clean up previous cache fields\n this.deleteBlockFields(blockId, \"prodOutputPrevious\", \"prodCtxPrevious\", \"prodUiCtxPrevious\");\n\n return true;\n } else {\n // reset - clean up any partial/inconsistent production stat\n return this.deleteBlockFields(\n blockId,\n \"prodOutput\",\n \"prodCtx\",\n \"prodUiCtx\",\n \"prodArgs\",\n \"prodOutputPrevious\",\n \"prodCtxPrevious\",\n \"prodUiCtxPrevious\",\n );\n }\n }\n\n /**\n * Gets current block state and merges with partial updates.\n * Used by legacy v1/v2 methods like setBlockArgs and setUiState.\n *\n * @param blockId The block to get state for\n * @param partialUpdate Partial state to merge (e.g. { args } or { uiState })\n * @returns Merged state in unified format { args, uiState }\n */\n public mergeBlockState(\n blockId: string,\n partialUpdate: { args?: unknown; uiState?: unknown },\n ): { args?: unknown; uiState?: unknown } {\n const info = this.getBlockInfo(blockId);\n const currentState = info.blockStorage as { args?: unknown; uiState?: unknown } | undefined;\n if (currentState === undefined) {\n throw new Error(`Cannot merge block state for ${blockId}: blockStorage is unavailable`);\n }\n return { ...currentState, ...partialUpdate };\n }\n\n /**\n * Sets raw block storage content directly (for testing purposes).\n * This bypasses all normalization and VM transformations.\n *\n * @param blockId The block to set storage for\n * @param rawStorageJson Raw storage as JSON string\n */\n public setBlockStorageRaw(blockId: string, rawStorageJson: string): void {\n this.setBlockFieldObj(\n blockId,\n \"blockStorage\",\n this.createJsonFieldValueByContent(rawStorageJson),\n );\n this.blocksWithChangedInputs.add(blockId);\n this.updateLastModified();\n }\n\n /**\n * Resets a v2+ block to its initial storage state.\n * Gets initial storage from VM and derives args from it.\n *\n * For v1 blocks, use setStates() instead.\n *\n * @param blockId The block to reset\n */\n public resetToInitialStorage(blockId: string): void {\n const info = this.getBlockInfo(blockId);\n const blockConfig = info.config;\n\n if (blockConfig.modelAPIVersion !== BLOCK_STORAGE_FACADE_VERSION) {\n throw new Error(\"resetToInitialStorage is only supported for model API version 2\");\n }\n\n // Get initial storage from VM\n const initialStorageJson = this.projectHelper.getInitialStorageInVM(blockConfig);\n this.setBlockStorageRaw(blockId, initialStorageJson);\n\n // Derive args from storage - set or clear currentArgs based on derivation result\n const deriveArgsResult = this.projectHelper.deriveArgsFromStorage(\n blockConfig,\n initialStorageJson,\n );\n if (!deriveArgsResult.error) {\n this.setBlockFieldObj(\n blockId,\n \"currentArgs\",\n this.createJsonFieldValue(deriveArgsResult.value),\n );\n // Derive prerunArgs from storage\n const prerunArgs = this.projectHelper.derivePrerunArgsFromStorage(\n blockConfig,\n initialStorageJson,\n );\n if (prerunArgs !== undefined) {\n this.setBlockFieldObj(blockId, \"currentPrerunArgs\", this.createJsonFieldValue(prerunArgs));\n } else {\n this.deleteBlockFields(blockId, \"currentPrerunArgs\");\n }\n } else {\n if (info.fields.currentPrerunArgs !== undefined) {\n this.projectHelper.logger.warn(\n `[staging] ${blockId}: currentPrerunArgs cleared (args derivation failed)`,\n );\n }\n this.deleteBlockFields(blockId, \"currentArgs\");\n this.deleteBlockFields(blockId, \"currentPrerunArgs\");\n }\n }\n\n /** Optimally sets inputs for multiple blocks in one go */\n public setStates(requests: SetStatesRequest[]) {\n const changedArgs: string[] = [];\n let somethingChanged = false;\n for (const req of requests) {\n const info = this.getBlockInfo(req.blockId);\n let blockChanged = false;\n\n const blockConfig = info.config;\n // modelAPIVersion === 2 means BlockModelV3 with .args() lambda for deriving args\n\n if (req.modelAPIVersion !== blockConfig.modelAPIVersion) {\n throw new Error(\n `Model API version mismatch for block ${req.blockId}: ${req.modelAPIVersion} !== ${blockConfig.modelAPIVersion}`,\n );\n }\n\n // Derive args from storage using the block's config.args() callback\n let args: unknown;\n let prerunArgs: unknown;\n\n if (req.modelAPIVersion === BLOCK_STORAGE_FACADE_VERSION) {\n const currentStorageJson = info.blockStorageJson;\n if (currentStorageJson === undefined) {\n throw new Error(`Block ${req.blockId} has no blockStorage - this should not happen`);\n }\n\n // Apply the state update to storage\n const updatedStorageJson = this.projectHelper.applyStorageUpdateInVM(\n blockConfig,\n currentStorageJson,\n req.payload,\n );\n\n this.setBlockFieldObj(\n req.blockId,\n \"blockStorage\",\n this.createJsonFieldValueByContent(updatedStorageJson),\n );\n\n // Derive args directly from storage (VM extracts data internally)\n const derivedArgsResult = this.projectHelper.deriveArgsFromStorage(\n blockConfig,\n updatedStorageJson,\n );\n if (derivedArgsResult.error) {\n args = undefined;\n prerunArgs = undefined;\n } else {\n args = derivedArgsResult.value;\n // Derive prerunArgs from storage, or fall back to args\n prerunArgs = this.projectHelper.derivePrerunArgsFromStorage(\n blockConfig,\n updatedStorageJson,\n );\n }\n } else {\n this.setBlockFieldObj(req.blockId, \"blockStorage\", this.createJsonFieldValue(req.state));\n if (req.state !== null && typeof req.state === \"object\" && \"args\" in req.state) {\n args = (req.state as { args: unknown }).args;\n } else {\n args = req.state;\n }\n // For the legacy blocks, prerunArgs = args (same as production args)\n prerunArgs = args;\n }\n\n // Set or clear currentArgs based on derivation result\n if (args !== undefined) {\n const currentArgsData = canonicalJsonBytes(args);\n const argsPartRef = this.tx.createValue(Pl.JsonObject, currentArgsData);\n this.setBlockField(req.blockId, \"currentArgs\", argsPartRef, \"Ready\", currentArgsData);\n } else {\n this.deleteBlockFields(req.blockId, \"currentArgs\");\n }\n\n // Set currentPrerunArgs field and check if it actually changed\n let prerunArgsChanged = false;\n if (prerunArgs !== undefined) {\n const prerunArgsData = canonicalJsonBytes(prerunArgs);\n const oldPrerunArgsData = info.fields.currentPrerunArgs?.value;\n // Check if prerunArgs actually changed\n if (\n oldPrerunArgsData === undefined ||\n Buffer.compare(oldPrerunArgsData, prerunArgsData) !== 0\n ) {\n prerunArgsChanged = true;\n }\n const prerunArgsRef = this.tx.createValue(Pl.JsonObject, prerunArgsData);\n this.setBlockField(\n req.blockId,\n \"currentPrerunArgs\",\n prerunArgsRef,\n \"Ready\",\n prerunArgsData,\n );\n } else {\n this.deleteBlockFields(req.blockId, \"currentPrerunArgs\");\n }\n\n blockChanged = true;\n // Only add to changedArgs if prerunArgs changed - this controls staging reset\n if (prerunArgsChanged) {\n changedArgs.push(req.blockId);\n }\n\n if (blockChanged) {\n // will be assigned our author marker\n this.blocksWithChangedInputs.add(req.blockId);\n somethingChanged = true;\n }\n }\n\n // resetting staging outputs for all downstream blocks\n this.getStagingGraph().traverse(\"downstream\", changedArgs, ({ id }) => this.resetStaging(id));\n\n if (somethingChanged) this.updateLastModified();\n }\n\n public setBlockSettings(blockId: string, newValue: BlockSettings): void {\n this.setBlockFieldObj(blockId, \"blockSettings\", this.createJsonFieldValue(newValue));\n this.updateLastModified();\n }\n\n private createProdCtx(upstream: Set<string>): AnyRef {\n const upstreamContexts: AnyRef[] = [];\n upstream.forEach((id) => {\n const info = this.getBlockInfo(id);\n if (info.fields[\"prodCtx\"]?.ref === undefined)\n throw new Error(\"One of the upstreams staging is not rendered.\");\n upstreamContexts.push(Pl.unwrapHolder(this.tx, info.fields[\"prodCtx\"].ref));\n });\n return createBContextFromUpstreams(this.tx, upstreamContexts);\n }\n\n private createStagingCtx(upstream: Set<string>): AnyRef {\n const upstreamContexts: AnyRef[] = [];\n upstream.forEach((id) => {\n const info = this.getBlockInfo(id);\n if (info.fields[\"stagingCtx\"]?.ref !== undefined) {\n upstreamContexts.push(Pl.unwrapHolder(this.tx, info.fields[\"stagingCtx\"].ref));\n } else if (info.fields.currentPrerunArgs !== undefined) {\n // Upstream has currentPrerunArgs but no staging — this is an inconsistency\n throw new Error(`Upstream ${id} staging is not rendered but has currentPrerunArgs set.`);\n }\n // Blocks without currentPrerunArgs (e.g. block model doesn't define prerunArgs, or args\n // derivation failed) never get stagingCtx. Use prodCtx if available.\n if (info.fields[\"prodCtx\"]?.ref !== undefined)\n upstreamContexts.push(Pl.unwrapHolder(this.tx, info.fields[\"prodCtx\"].ref));\n });\n return createBContextFromUpstreams(this.tx, upstreamContexts);\n }\n\n private exportCtx(ctx: AnyRef): AnyRef {\n return exportContext(this.tx, Pl.unwrapHolder(this.tx, this.ctxExportTplHolder), ctx);\n }\n\n /**\n * Renders staging for a block using currentPrerunArgs.\n * If currentPrerunArgs is not set (prerunArgs returned undefined), skips staging for this block.\n */\n private renderStagingFor(blockId: string) {\n const info = this.getBlockInfo(blockId);\n\n // Check BEFORE resetStaging: if currentPrerunArgs is not set (e.g. prerunArgs() returned undefined\n // because inputs aren't ready, or args derivation failed), skip without clearing existing staging.\n // Otherwise resetStaging would delete stagingCtx, and downstream blocks that reference this block\n // as an upstream would fail in createStagingCtx.\n const prerunArgsRef = info.fields.currentPrerunArgs?.ref;\n if (prerunArgsRef === undefined) {\n return;\n }\n\n this.resetStaging(blockId);\n\n const ctx = this.createStagingCtx(this.getStagingGraph().nodes.get(blockId)!.upstream);\n\n if (this.getBlock(blockId).renderingMode !== \"Heavy\") throw new Error(\"not supported yet\");\n\n const tpl = info.getTemplate(this.tx);\n\n // Use currentPrerunArgs for staging rendering\n const results = createRenderHeavyBlock(this.tx, tpl, {\n args: prerunArgsRef,\n blockId: this.tx.createValue(Pl.JsonString, JSON.stringify(blockId)),\n isProduction: this.tx.createValue(Pl.JsonBool, JSON.stringify(false)),\n context: ctx,\n });\n\n // Here we set the staging ctx to the input context of the staging workflow, not the output because exports\n // of one staging context should stay within the same block, and not travel downstream.\n // We may change this decision in the future if wanted to support traveling staging exports downstream.\n this.setBlockField(blockId, \"stagingCtx\", Pl.wrapInEphHolder(this.tx, ctx), \"NotReady\");\n\n // Yet the staging UI Ctx is the output context of the staging workflow, because it is used to form the result pool\n // thus creating a certain discrepancy between staging workflow context behavior and desktop's result pool.\n this.setBlockField(blockId, \"stagingUiCtx\", this.exportCtx(results.context), \"NotReady\");\n this.setBlockField(blockId, \"stagingOutput\", results.result, \"NotReady\");\n }\n\n private renderProductionFor(blockId: string) {\n this.resetProduction(blockId);\n\n const info = this.getBlockInfo(blockId);\n\n // Can't render production if currentArgs is not set\n if (info.fields.currentArgs === undefined) {\n throw new Error(`Can't render production for block ${blockId}: currentArgs not set`);\n }\n\n const ctx = this.createProdCtx(this.getPendingProductionGraph().nodes.get(blockId)!.upstream);\n\n if (this.getBlock(blockId).renderingMode === \"Light\")\n throw new Error(\"Can't render production for light block.\");\n\n const tpl = info.getTemplate(this.tx);\n\n const results = createRenderHeavyBlock(this.tx, tpl, {\n args: info.fields.currentArgs.ref!,\n blockId: this.tx.createValue(Pl.JsonString, JSON.stringify(blockId)),\n isProduction: this.tx.createValue(Pl.JsonBool, JSON.stringify(true)),\n context: ctx,\n });\n this.setBlockField(\n blockId,\n \"prodCtx\",\n Pl.wrapInEphHolder(this.tx, results.context),\n \"NotReady\",\n );\n this.setBlockField(blockId, \"prodUiCtx\", this.exportCtx(results.context), \"NotReady\");\n this.setBlockField(blockId, \"prodOutput\", results.result, \"NotReady\");\n\n // saving inputs for which we rendered the production\n this.setBlockFieldObj(blockId, \"prodArgs\", info.fields.currentArgs);\n\n // removing block from limbo as we juts rendered fresh production for it\n if (this.blocksInLimbo.delete(blockId)) this.renderingStateChanged = true;\n }\n\n //\n // Structure changes\n //\n\n private initializeNewBlock(blockId: string, spec: NewBlockSpec): void {\n const info = new BlockInfo(\n blockId,\n {},\n extractConfig(spec.blockPack.config),\n spec.blockPack.source,\n this.projectHelper.logger,\n );\n this.blockInfos.set(blockId, info);\n\n // block pack\n const bp = createBlockPack(this.tx, spec.blockPack);\n this.setBlockField(blockId, \"blockPack\", Pl.wrapInHolder(this.tx, bp), \"NotReady\");\n\n // settings\n this.setBlockFieldObj(\n blockId,\n \"blockSettings\",\n this.createJsonFieldValue(InitialBlockSettings),\n );\n\n const blockConfig = info.config;\n\n let args: unknown;\n let prerunArgs: unknown;\n let storageToWrite: string;\n\n if (spec.storageMode === \"fromModel\") {\n // Model API v2+: get initial storage and derive args from it\n storageToWrite = this.projectHelper.getInitialStorageInVM(blockConfig);\n\n // Derive args directly from storage (VM extracts data internally)\n const deriveArgsResult = this.projectHelper.deriveArgsFromStorage(\n blockConfig,\n storageToWrite,\n );\n if (deriveArgsResult.error) {\n args = undefined;\n prerunArgs = undefined;\n } else {\n args = deriveArgsResult.value;\n prerunArgs = this.projectHelper.derivePrerunArgsFromStorage(blockConfig, storageToWrite);\n }\n } else if (spec.storageMode === \"legacy\") {\n // Model API v1: use legacyState from spec\n const parsedState = JSON.parse(spec.legacyState);\n args = parsedState.args;\n if (args === undefined) {\n throw new Error(\"args is undefined in legacyState\");\n }\n prerunArgs = args;\n storageToWrite = spec.legacyState;\n } else {\n throw new Error(`Unknown storageMode: ${(spec as NewBlockSpec).storageMode}`);\n }\n\n // currentArgs\n if (args !== undefined) {\n this.setBlockFieldObj(blockId, \"currentArgs\", this.createJsonFieldValue(args));\n }\n\n // currentPrerunArgs\n if (prerunArgs !== undefined) {\n this.setBlockFieldObj(blockId, \"currentPrerunArgs\", this.createJsonFieldValue(prerunArgs));\n }\n\n // blockStorage\n this.setBlockFieldObj(\n blockId,\n \"blockStorage\",\n this.createJsonFieldValueByContent(storageToWrite),\n );\n\n // checking structure\n info.check();\n }\n\n private getFieldNamesToDuplicate(blockId: string): Set<ProjectField[\"fieldName\"]> {\n const fields = this.getBlockInfo(blockId).fields;\n\n const diff = <T>(setA: Set<T>, setB: Set<T>): Set<T> =>\n new Set([...setA].filter((x) => !setB.has(x)));\n\n // Check if we can safely move to limbo (both core production fields are ready)\n if (fields.prodOutput?.status === \"Ready\" && fields.prodCtx?.status === \"Ready\") {\n if (this.blocksInLimbo.has(blockId))\n // we are already in limbo\n return FieldsToDuplicate;\n\n return diff(\n FieldsToDuplicate,\n new Set([\"prodOutputPrevious\", \"prodCtxPrevious\", \"prodUiCtxPrevious\"]),\n );\n } else {\n return diff(\n FieldsToDuplicate,\n new Set([\n \"prodOutput\",\n \"prodCtx\",\n \"prodUiCtx\",\n \"prodArgs\",\n \"prodOutputPrevious\",\n \"prodCtxPrevious\",\n \"prodUiCtxPrevious\",\n ]),\n );\n }\n }\n\n private initializeBlockDuplicate(blockId: string, originalBlockInfo: BlockInfo) {\n const info = new BlockInfo(\n blockId,\n {},\n originalBlockInfo.config,\n originalBlockInfo.source,\n this.projectHelper.logger,\n );\n\n this.blockInfos.set(blockId, info);\n\n const fieldNamesToDuplicate = this.getFieldNamesToDuplicate(blockId);\n\n // Copy all fields from original block to new block by sharing references\n for (const [fieldName, fieldState] of Object.entries(originalBlockInfo.fields)) {\n if (\n fieldNamesToDuplicate.has(fieldName as ProjectField[\"fieldName\"]) &&\n fieldState &&\n fieldState.ref\n ) {\n this.setBlockFieldObj(blockId, fieldName as keyof BlockFieldStates, {\n ref: fieldState.ref,\n status: fieldState.status,\n value: fieldState.value,\n });\n }\n }\n\n this.resetOrLimboProduction(blockId);\n\n info.check();\n }\n\n /** Very generic method, better check for more specialized case-specific methods first. */\n public updateStructure(\n newStructure: ProjectStructure,\n newBlockInitializer: (blockId: string) => void = NoNewBlocks,\n ): void {\n const currentStagingGraph = this.getStagingGraph();\n const currentActualProductionGraph = this.getActualProductionGraph();\n\n const newStagingGraph = stagingGraph(newStructure);\n\n const stagingDiff = graphDiff(currentStagingGraph, newStagingGraph);\n\n // removing blocks\n for (const blockId of stagingDiff.onlyInA) {\n const { fields } = this.getBlockInfo(blockId);\n this.deleteBlockFields(blockId, ...(Object.keys(fields) as ProjectField[\"fieldName\"][]));\n this.blockInfos.delete(blockId);\n if (this.blocksInLimbo.delete(blockId)) this.renderingStateChanged = true;\n }\n\n // creating new blocks\n for (const blockId of stagingDiff.onlyInB) {\n newBlockInitializer(blockId);\n }\n\n // resetting stagings affected by topology change\n for (const blockId of stagingDiff.different) this.resetStaging(blockId);\n\n // new actual production graph without new blocks\n const newActualProductionGraph = productionGraph(newStructure, (blockId) =>\n this.getProductionGraphBlockInfo(blockId, true),\n );\n\n const prodDiff = graphDiff(currentActualProductionGraph, newActualProductionGraph);\n\n // applying changes due to topology change in production to affected nodes and\n // all their downstreams\n currentActualProductionGraph.traverse(\"downstream\", [...prodDiff.different], (node) => {\n this.resetOrLimboProduction(node.id);\n });\n\n if (\n stagingDiff.onlyInB.size > 0 ||\n stagingDiff.onlyInA.size > 0 ||\n stagingDiff.different.size > 0\n )\n this.resetStagingRefreshTimestamp();\n\n this.struct = newStructure;\n this.structureChanged = true;\n this.stagingGraph = undefined;\n this.pendingProductionGraph = undefined;\n this.actualProductionGraph = undefined;\n\n this.updateLastModified();\n }\n\n //\n // Structure change helpers\n //\n\n public addBlock(block: Block, spec: NewBlockSpec, before?: string): void {\n const newStruct = this.structure; // copy current structure\n if (before === undefined) {\n // adding as a very last block\n newStruct.groups[newStruct.groups.length - 1].blocks.push(block);\n } else {\n let done = false;\n for (const group of newStruct.groups) {\n const idx = group.blocks.findIndex((b) => b.id === before);\n if (idx < 0) continue;\n group.blocks.splice(idx, 0, block);\n done = true;\n break;\n }\n if (!done) throw new Error(`Can't find element with id: ${before}`);\n }\n this.updateStructure(newStruct, (blockId) => {\n if (blockId !== block.id) throw new Error(\"Unexpected\");\n this.initializeNewBlock(blockId, spec);\n });\n }\n\n /**\n * Duplicates an existing block by copying all its fields and structure.\n * This method creates a deep copy of the block at the mutator level.\n *\n * @param originalBlockId id of the block to duplicate\n * @param newBlockId id for the new duplicated block\n * @param after id of the block to insert new block after\n */\n public duplicateBlock(originalBlockId: string, newBlockId: string, after?: string): void {\n // Get the original block from structure\n const originalBlock = this.getBlock(originalBlockId);\n const originalBlockInfo = this.getBlockInfo(originalBlockId);\n\n // Create new block in structure\n const newBlock: Block = {\n id: newBlockId,\n label: originalBlock.label,\n renderingMode: originalBlock.renderingMode,\n };\n\n // Add the new block to structure\n const newStruct = this.structure; // copy current structure\n if (after === undefined) {\n // adding as a very last block\n newStruct.groups[newStruct.groups.length - 1].blocks.push(newBlock);\n } else {\n let done = false;\n for (const group of newStruct.groups) {\n const idx = group.blocks.findIndex((b) => b.id === after);\n if (idx < 0) continue;\n group.blocks.splice(idx + 1, 0, newBlock);\n done = true;\n break;\n }\n if (!done) throw new Error(`Can't find element with id: ${after}`);\n }\n\n this.updateStructure(newStruct, (blockId) => {\n if (blockId !== newBlockId) throw new Error(\"Unexpected\");\n this.initializeBlockDuplicate(blockId, originalBlockInfo);\n });\n }\n\n public deleteBlock(blockId: string): void {\n const newStruct = this.structure; // copy current structure\n let done = false;\n for (const group of newStruct.groups) {\n const idx = group.blocks.findIndex((b) => b.id === blockId);\n if (idx < 0) continue;\n group.blocks.splice(idx, 1);\n done = true;\n break;\n }\n if (!done) throw new Error(`Can't find element with id: ${blockId}`);\n this.updateStructure(newStruct);\n }\n\n //\n // Block-pack migration\n //\n\n public migrateBlockPack(\n blockId: string,\n spec: BlockPackSpecPrepared,\n newClearState?: ClearState,\n ): void {\n const info = this.getBlockInfo(blockId);\n const newConfig = extractConfig(spec.config);\n\n const persistBlockPack = () => {\n this.setBlockField(\n blockId,\n \"blockPack\",\n Pl.wrapInHolder(this.tx, createBlockPack(this.tx, spec)),\n \"NotReady\",\n );\n };\n\n const applyStorageAndDeriveArgs = (storageJson: string) => {\n persistBlockPack();\n this.setBlockStorageRaw(blockId, storageJson);\n const deriveArgsResult = this.projectHelper.deriveArgsFromStorage(newConfig, storageJson);\n if (!deriveArgsResult.error) {\n this.setBlockFieldObj(\n blockId,\n \"currentArgs\",\n this.createJsonFieldValue(deriveArgsResult.value),\n );\n const prerunArgs = this.projectHelper.derivePrerunArgsFromStorage(newConfig, storageJson);\n if (prerunArgs !== undefined) {\n this.setBlockFieldObj(\n blockId,\n \"currentPrerunArgs\",\n this.createJsonFieldValue(prerunArgs),\n );\n } else {\n this.deleteBlockFields(blockId, \"currentPrerunArgs\");\n }\n } else {\n this.deleteBlockFields(blockId, \"currentArgs\");\n this.deleteBlockFields(blockId, \"currentPrerunArgs\");\n }\n };\n\n if (newClearState !== undefined) {\n // State is being reset - no migration needed\n const supportsStorageFromVM = newConfig.modelAPIVersion === BLOCK_STORAGE_FACADE_VERSION;\n\n if (supportsStorageFromVM) {\n // V2+: Get initial storage directly from VM and derive args from it\n const initialStorageJson = this.projectHelper.getInitialStorageInVM(newConfig);\n applyStorageAndDeriveArgs(initialStorageJson);\n this.blocksWithChangedInputs.add(blockId);\n this.updateLastModified();\n } else {\n // V1: Use setStates with legacy state format\n persistBlockPack();\n this.setStates([{ modelAPIVersion: 1, blockId, state: newClearState.state }]);\n }\n } else {\n // State is being preserved - run migrations if needed via VM\n // Only Model API v2 blocks support migrations\n const supportsStateMigrations = newConfig.modelAPIVersion === BLOCK_STORAGE_FACADE_VERSION;\n\n if (supportsStateMigrations) {\n const currentStorageJson = info.blockStorageJson;\n\n // Attempt migration BEFORE persisting block pack — on failure,\n // block stays on old version (no inconsistent new-code/old-storage state)\n const migrationResult = this.projectHelper.migrateStorageInVM(\n newConfig,\n currentStorageJson,\n );\n\n if (migrationResult.error !== undefined) {\n throw new Error(\n `[migrateBlockPack] Block ${blockId} migration failed: ${migrationResult.error}`,\n );\n }\n\n this.projectHelper.logger.info(\n `[migrateBlockPack] Block ${blockId}: ${migrationResult.info}`,\n );\n applyStorageAndDeriveArgs(migrationResult.newStorageJson);\n } else {\n // Legacy blocks (modelAPIVersion 1): persist block pack, set prerunArgs = currentArgs\n persistBlockPack();\n if (info.fields.currentArgs !== undefined) {\n this.setBlockFieldObj(blockId, \"currentPrerunArgs\", info.fields.currentArgs);\n }\n }\n\n this.blocksWithChangedInputs.add(blockId);\n\n // resetting staging outputs for all downstream blocks\n this.getStagingGraph().traverse(\"downstream\", [blockId], ({ id }) => this.resetStaging(id));\n }\n\n // also reset or limbo all downstream productions\n if (info.productionRendered)\n this.getActualProductionGraph().traverse(\"downstream\", [blockId], ({ id }) =>\n this.resetOrLimboProduction(id),\n );\n\n this.updateLastModified();\n }\n\n //\n // Render\n //\n\n public renderProduction(blockIds: string[], addUpstreams: boolean = false): Set<string> {\n const blockIdsSet = new Set(blockIds);\n\n const prodGraph = this.getPendingProductionGraph();\n if (addUpstreams)\n // adding all upstreams automatically\n prodGraph.traverse(\"upstream\", blockIds, (node) => {\n blockIdsSet.add(node.id);\n });\n else\n // checking that targets contain all upstreams\n for (const blockId of blockIdsSet) {\n const node = prodGraph.nodes.get(blockId);\n if (node === undefined) throw new Error(`Can't find block with id: ${blockId}`);\n for (const upstream of node.upstream)\n if (!blockIdsSet.has(upstream))\n throw new Error(\"Can't render blocks not including all upstreams.\");\n }\n\n // traversing in topological order and rendering target blocks\n const rendered = new Set<string>();\n for (const block of allBlocks(this.structure)) {\n if (!blockIdsSet.has(block.id)) continue;\n\n let render =\n this.getBlockInfo(block.id).requireProductionRendering || this.blocksInLimbo.has(block.id);\n\n if (!render)\n for (const upstream of prodGraph.nodes.get(block.id)!.upstream)\n if (rendered.has(upstream)) {\n render = true;\n break;\n }\n\n if (render) {\n this.renderProductionFor(block.id);\n rendered.add(block.id);\n }\n }\n\n const renderedArray = [...rendered];\n\n // sending to limbo all downstream blocks\n prodGraph.traverse(\"downstream\", renderedArray, (node) => {\n if (rendered.has(node.id))\n // don't send to limbo blocks that were just rendered\n return;\n this.resetOrLimboProduction(node.id);\n });\n\n // resetting staging outputs for all downstream blocks\n this.getStagingGraph().traverse(\"downstream\", renderedArray, ({ id }) => {\n // don't reset staging of the first rendered block\n if (renderedArray[0] !== id) this.resetStaging(id);\n });\n\n if (rendered.size > 0) this.updateLastModified();\n\n return rendered;\n }\n\n /** Stops running blocks from the list and modify states of other blocks\n * accordingly */\n public stopProduction(...blockIds: string[]) {\n const activeProdGraph = this.getActualProductionGraph();\n\n // we will stop all blocks listed in request and all their downstreams\n const queue = new Denque(blockIds);\n const queued = new Set(blockIds);\n const stopped: string[] = [];\n\n while (!queue.isEmpty()) {\n const blockId = queue.shift()!;\n const fields = this.getBlockInfo(blockId).fields;\n\n if (fields.prodOutput?.status === \"Ready\" && fields.prodCtx?.status === \"Ready\")\n // skipping finished blocks\n continue;\n\n if (this.deleteBlockFields(blockId, \"prodOutput\", \"prodCtx\", \"prodUiCtx\", \"prodArgs\")) {\n // was actually stopped\n stopped.push(blockId);\n\n // will try to stop all its downstreams\n for (const downstream of activeProdGraph.traverseIdsExcludingRoots(\"downstream\", blockId)) {\n if (queued.has(downstream)) continue;\n queue.push(downstream);\n queued.add(downstream);\n }\n }\n }\n\n // blocks under stopped blocks, but having finished production results, goes to limbo\n for (const blockId of activeProdGraph.traverseIdsExcludingRoots(\"downstream\", ...stopped))\n this.resetOrLimboProduction(blockId);\n\n // reset staging outputs for all downstream blocks\n this.getStagingGraph().traverse(\"downstream\", stopped, ({ id }) => this.resetStaging(id));\n }\n\n private traverseWithStagingLag(cb: (blockId: string, lag: number) => void) {\n const lags = new Map<string, number>();\n const stagingGraph = this.getStagingGraph();\n stagingGraph.nodes.forEach((node) => {\n const info = this.getBlockInfo(node.id);\n // Use requireStagingRendering to check both: staging exists AND prerunArgs hasn't changed\n const requiresRendering = info.requireStagingRendering;\n let lag = requiresRendering ? 1 : 0;\n node.upstream.forEach((upstream) => {\n const upstreamLag = lags.get(upstream)!;\n if (upstreamLag === 0) return;\n lag = Math.max(upstreamLag + 1, lag);\n });\n if (!requiresRendering && info.stagingRendered) {\n // console.log(`[traverseWithStagingLag] SKIP staging for ${node.id} - prerunArgs unchanged`);\n }\n cb(node.id, lag);\n lags.set(node.id, lag);\n });\n }\n\n /** @param stagingRenderingRate rate in blocks per second */\n private refreshStagings(stagingRenderingRate?: number) {\n const elapsed = Date.now() - this.renderingState.stagingRefreshTimestamp;\n const lagThreshold =\n stagingRenderingRate === undefined\n ? undefined\n : 1 + Math.max(0, (elapsed * stagingRenderingRate) / 1000);\n let rendered = 0;\n this.traverseWithStagingLag((blockId, lag) => {\n if (lag === 0)\n // meaning staging already rendered\n return;\n if (lagThreshold === undefined || lag <= lagThreshold) {\n try {\n this.renderStagingFor(blockId);\n rendered++;\n } catch (e) {\n this.projectHelper.logger.error(\n new Error(`[refreshStagings] renderStagingFor failed for ${blockId}`, { cause: e }),\n );\n }\n }\n });\n if (rendered > 0) this.resetStagingRefreshTimestamp();\n }\n\n //\n // Meta\n //\n\n /** Updates project metadata */\n public setMeta(meta: ProjectMeta): void {\n this.meta = meta;\n this.metaChanged = true;\n this.updateLastModified();\n }\n\n //\n // Maintenance\n //\n\n /** @param stagingRenderingRate rate in blocks per second */\n public doRefresh(stagingRenderingRate?: number) {\n this.refreshStagings(stagingRenderingRate);\n this.blockInfos.forEach((blockInfo) => {\n if (\n blockInfo.fields.prodCtx?.status === \"Ready\" &&\n blockInfo.fields.prodOutput?.status === \"Ready\"\n )\n this.deleteBlockFields(\n blockInfo.id,\n \"prodOutputPrevious\",\n \"prodCtxPrevious\",\n \"prodUiCtxPrevious\",\n );\n if (\n blockInfo.fields.stagingCtx?.status === \"Ready\" &&\n blockInfo.fields.stagingOutput?.status === \"Ready\"\n )\n this.deleteBlockFields(\n blockInfo.id,\n \"stagingOutputPrevious\",\n \"stagingCtxPrevious\",\n \"stagingUiCtxPrevious\",\n );\n });\n }\n\n private assignAuthorMarkers() {\n const markerStr = this.author ? JSON.stringify(this.author) : undefined;\n\n for (const blockId of this.blocksWithChangedInputs)\n if (markerStr === undefined) this.tx.deleteKValue(this.rid, blockArgsAuthorKey(blockId));\n else this.tx.setKValue(this.rid, blockArgsAuthorKey(blockId), markerStr);\n\n if (this.metaChanged || this.structureChanged) {\n if (markerStr === undefined) this.tx.deleteKValue(this.rid, ProjectStructureAuthorKey);\n else this.tx.setKValue(this.rid, ProjectStructureAuthorKey, markerStr);\n }\n }\n\n public save() {\n if (!this.wasModified) return;\n\n if (this.lastModifiedChanged)\n this.tx.setKValue(this.rid, ProjectLastModifiedTimestamp, JSON.stringify(this.lastModified));\n\n if (this.structureChanged)\n this.tx.setKValue(this.rid, ProjectStructureKey, JSON.stringify(this.struct));\n\n if (this.renderingStateChanged)\n this.tx.setKValue(\n this.rid,\n BlockRenderingStateKey,\n JSON.stringify({\n ...this.renderingState,\n blocksInLimbo: [...this.blocksInLimbo],\n } as ProjectRenderingState),\n );\n\n if (this.metaChanged) this.tx.setKValue(this.rid, ProjectMetaKey, JSON.stringify(this.meta));\n\n this.assignAuthorMarkers();\n }\n\n public static async load(\n projectHelper: ProjectHelper,\n tx: PlTransaction,\n rid: ResourceId,\n author?: AuthorMarker,\n ): Promise<ProjectMutator> {\n //\n // Sending initial requests to read project state (start of round-trip #1)\n //\n\n const fullResourceStateP = tx.getResourceData(rid, true);\n const schemaP = tx.getKValueJson<string>(rid, SchemaVersionKey);\n const lastModifiedP = tx.getKValueJson<number>(rid, ProjectLastModifiedTimestamp);\n const metaP = tx.getKValueJson<ProjectMeta>(rid, ProjectMetaKey);\n const structureP = tx.getKValueJson<ProjectStructure>(rid, ProjectStructureKey);\n const renderingStateP = tx.getKValueJson<ProjectRenderingState>(rid, BlockRenderingStateKey);\n\n const fullResourceState = await fullResourceStateP;\n\n // loading field information\n const blockInfoStates = new Map<string, BlockInfoState>();\n for (const f of fullResourceState.fields) {\n const projectField = parseProjectField(f.name);\n\n // processing only fields with known structure\n if (projectField === undefined) continue;\n\n let info = blockInfoStates.get(projectField.blockId);\n if (info === undefined) {\n info = {\n id: projectField.blockId,\n fields: {},\n };\n blockInfoStates.set(projectField.blockId, info);\n }\n\n info.fields[projectField.fieldName] = isNullResourceId(f.value)\n ? { modCount: 0 }\n : { modCount: 0, ref: f.value };\n }\n\n //\n // Roundtrip #1 not yet finished, but as soon as field list is received,\n // we can start sending requests to read states of referenced resources\n // (start of round-trip #2)\n //\n\n const blockFieldRequests: [\n BlockInfoState,\n ProjectField[\"fieldName\"],\n BlockFieldState,\n Promise<BasicResourceData | ResourceData>,\n ][] = [];\n blockInfoStates.forEach((info) => {\n const fields = info.fields;\n for (const [fName, state] of Object.entries(fields)) {\n if (state.ref === undefined) continue;\n if (!isResource(state.ref) || isResourceRef(state.ref))\n throw new Error(\"unexpected behaviour\");\n const fieldName = fName as ProjectField[\"fieldName\"];\n blockFieldRequests.push([\n info,\n fieldName,\n state,\n tx.getResourceData(state.ref, fieldName == \"blockPack\"),\n ]);\n }\n });\n\n // loading jsons\n const [schema, lastModified, meta, structure, { stagingRefreshTimestamp, blocksInLimbo }] =\n await Promise.all([schemaP, lastModifiedP, metaP, structureP, renderingStateP]);\n\n // Checking schema version of the project\n if (schema !== SchemaVersionCurrent) {\n if (Number(schema) < Number(SchemaVersionCurrent))\n throw new UiError(\n `Can't perform this action on this project because it has older schema. Try (re)loading the project to update it.`,\n );\n else\n throw new UiError(\n `Can't perform this action on this project because it has newer schema. Upgrade your desktop app to the latest version.`,\n );\n }\n\n //\n // <- at this point we have all the responses from round-trip #1\n //\n\n //\n // Receiving responses from round-trip #2 and sending requests to read block pack descriptions\n // (start of round-trip #3)\n //\n\n const blockPackRequests: [BlockInfoState, Promise<BasicResourceData>][] = [];\n for (const [info, fieldName, state, response] of blockFieldRequests) {\n const result = await response;\n state.value = result.data;\n if (isNotNullResourceId(result.error)) state.status = \"Error\";\n else if (result.resourceReady || isNotNullResourceId(result.originalResourceId))\n state.status = \"Ready\";\n else state.status = \"NotReady\";\n\n // For block pack we need to traverse the ref field from the resource data\n if (fieldName === \"blockPack\") {\n const refField = (result as ResourceData).fields.find((f) => f.name === Pl.HolderRefField);\n if (refField === undefined) throw new Error(\"Block pack ref field is missing\");\n blockPackRequests.push([\n info,\n tx.getResourceData(ensureResourceIdNotNull(refField.value), false),\n ]);\n }\n }\n\n //\n // <- at this point we have all the responses from round-trip #2\n //\n\n for (const [info, response] of blockPackRequests) {\n const result = await response;\n const bpInfo = cachedDeserialize<BlockPackInfo>(notEmpty(result.data));\n info.blockConfig = extractConfig(bpInfo.config);\n info.blockPack = bpInfo.source;\n }\n\n //\n // <- at this point we have all the responses from round-trip #3\n //\n\n // loading ctx export template to check if we already have cached materialized template in our project\n const ctxExportTplEnvelope = await getPreparedExportTemplateEnvelope();\n\n // expected field name\n const ctxExportTplCacheFieldName = getServiceTemplateField(ctxExportTplEnvelope.hash);\n const ctxExportTplField = fullResourceState.fields.find(\n (f) => f.name === ctxExportTplCacheFieldName,\n );\n let ctxExportTplHolder: AnyResourceRef;\n if (ctxExportTplField !== undefined)\n ctxExportTplHolder = ensureResourceIdNotNull(ctxExportTplField.value);\n else {\n ctxExportTplHolder = Pl.wrapInHolder(tx, loadTemplate(tx, ctxExportTplEnvelope.spec));\n tx.createField(\n field(rid, getServiceTemplateField(ctxExportTplEnvelope.hash)),\n \"Dynamic\",\n ctxExportTplHolder,\n );\n }\n\n const renderingState = { stagingRefreshTimestamp };\n const blocksInLimboSet = new Set(blocksInLimbo);\n\n const blockInfos = new Map<string, BlockInfo>();\n blockInfoStates.forEach(({ id, fields, blockConfig, blockPack }) =>\n blockInfos.set(\n id,\n new BlockInfo(id, fields, notEmpty(blockConfig), notEmpty(blockPack), projectHelper.logger),\n ),\n );\n\n // check consistency of project state\n const blockInStruct = new Set<string>();\n for (const b of allBlocks(structure)) {\n if (!blockInfos.has(b.id))\n throw new Error(`Inconsistent project structure: no inputs for ${b.id}`);\n blockInStruct.add(b.id);\n }\n blockInfos.forEach((info) => {\n if (!blockInStruct.has(info.id))\n throw new Error(`Inconsistent project structure: no structure entry for ${info.id}`);\n });\n\n const prj = new ProjectMutator(\n rid,\n tx,\n author,\n schema,\n lastModified,\n meta,\n structure,\n renderingState,\n blocksInLimboSet,\n blockInfos,\n ctxExportTplHolder,\n projectHelper,\n );\n\n prj.fixProblemsAndMigrate();\n\n return prj;\n }\n}\n\nexport interface ProjectState {\n schema: string;\n structure: ProjectStructure;\n renderingState: Omit<ProjectRenderingState, \"blocksInLimbo\">;\n blocksInLimbo: Set<string>;\n blockInfos: Map<string, BlockInfo>;\n}\n\nexport async function createProject(\n tx: PlTransaction,\n meta: ProjectMeta = InitialBlockMeta,\n): Promise<AnyResourceRef> {\n const prj = tx.createEphemeral(ProjectResourceType);\n tx.lock(prj);\n const ts = String(Date.now());\n tx.setKValue(prj, SchemaVersionKey, JSON.stringify(SchemaVersionCurrent));\n tx.setKValue(prj, ProjectCreatedTimestamp, ts);\n tx.setKValue(prj, ProjectLastModifiedTimestamp, ts);\n tx.setKValue(prj, ProjectMetaKey, JSON.stringify(meta));\n tx.setKValue(prj, ProjectStructureKey, JSON.stringify(InitialBlockStructure));\n tx.setKValue(prj, BlockRenderingStateKey, JSON.stringify(InitialProjectRenderingState));\n const ctxExportTplEnvelope = await getPreparedExportTemplateEnvelope();\n tx.createField(\n field(prj, getServiceTemplateField(ctxExportTplEnvelope.hash)),\n \"Dynamic\",\n Pl.wrapInHolder(tx, loadTemplate(tx, ctxExportTplEnvelope.spec)),\n );\n return prj;\n}\n\nexport async function withProject<T>(\n projectHelper: ProjectHelper,\n txOrPl: PlTransaction | PlClient,\n rid: ResourceId,\n cb: (p: ProjectMutator) => T | Promise<T>,\n ops?: Partial<TxOps>,\n): Promise<T> {\n return withProjectAuthored(projectHelper, txOrPl, rid, undefined, cb, ops);\n}\n\nexport async function withProjectAuthored<T>(\n projectHelper: ProjectHelper,\n txOrPl: PlTransaction | PlClient,\n rid: ResourceId,\n author: AuthorMarker | undefined,\n cb: (p: ProjectMutator) => T | Promise<T>,\n ops: Partial<TxOps> = {},\n): Promise<T> {\n if (txOrPl instanceof PlClient) {\n return await txOrPl.withWriteTx(\n \"ProjectAction\" + (ops.name ? `: ${ops.name}` : \"\"),\n async (tx) => {\n const mut = await ProjectMutator.load(projectHelper, tx, rid, author);\n const result = await cb(mut);\n if (!mut.wasModified)\n // skipping save and commit altogether if no modifications were actually made\n return result;\n mut.save();\n await tx.commit();\n if (getDebugFlags().logProjectMutationStat) console.log(JSON.stringify(tx.stat));\n return result;\n },\n ops,\n );\n } else {\n const mut = await ProjectMutator.load(projectHelper, txOrPl, rid, author);\n const result = await cb(mut);\n mut.save();\n return result;\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"project.js","names":[],"sources":["../../src/mutator/project.ts"],"sourcesContent":["import type {\n AnyRef,\n AnyResourceRef,\n BasicResourceData,\n PlTransaction,\n ResourceData,\n ResourceId,\n TxOps,\n} from \"@milaboratories/pl-client\";\nimport {\n ensureResourceIdNotNull,\n field,\n isNotNullResourceId,\n isNullResourceId,\n isResource,\n isResourceId,\n isResourceRef,\n Pl,\n PlClient,\n} from \"@milaboratories/pl-client\";\nimport { createRenderHeavyBlock, createBContextFromUpstreams } from \"./template/render_block\";\nimport type {\n Block,\n ProjectStructure,\n ProjectField,\n ProjectRenderingState,\n} from \"../model/project_model\";\nimport {\n BlockRenderingStateKey,\n ProjectStructureKey,\n parseProjectField,\n projectFieldName,\n SchemaVersionCurrent,\n SchemaVersionKey,\n ProjectResourceType,\n InitialBlockStructure,\n InitialProjectRenderingState,\n ProjectMetaKey,\n InitialBlockMeta,\n blockArgsAuthorKey,\n ProjectLastModifiedTimestamp,\n ProjectCreatedTimestamp,\n ProjectStructureAuthorKey,\n getServiceTemplateField,\n FieldsToDuplicate,\n} from \"../model/project_model\";\nimport { BlockPackTemplateField, createBlockPack } from \"./block-pack/block_pack\";\nimport type { BlockGraph, ProductionGraphBlockInfo } from \"../model/project_model_util\";\nimport { allBlocks, graphDiff, productionGraph, stagingGraph } from \"../model/project_model_util\";\nimport type { BlockPackSpecPrepared } from \"../model\";\nimport type {\n AuthorMarker,\n BlockPackSpec,\n BlockSettings,\n ProjectMeta,\n} from \"@milaboratories/pl-model-middle-layer\";\nimport { InitialBlockSettings } from \"@milaboratories/pl-model-middle-layer\";\nimport Denque from \"denque\";\nimport { exportContext, getPreparedExportTemplateEnvelope } from \"./context_export\";\nimport { loadTemplate } from \"./template/template_loading\";\nimport {\n cachedDeserialize,\n notEmpty,\n canonicalJsonBytes,\n cachedDecode,\n type MiLogger,\n ConsoleLoggerAdapter,\n} from \"@milaboratories/ts-helpers\";\nimport { gzipSync } from \"node:zlib\";\nimport type { ProjectHelper } from \"../model/project_helper\";\nimport {\n extractConfig,\n UiError,\n BLOCK_STORAGE_FACADE_VERSION,\n type BlockConfig,\n} from \"@platforma-sdk/model\";\nimport { getDebugFlags } from \"../debug\";\nimport type { BlockPackInfo } from \"../model/block_pack\";\n\ntype FieldStatus = \"NotReady\" | \"Ready\" | \"Error\";\n\ninterface BlockFieldState {\n modCount: number;\n ref?: AnyRef;\n status?: FieldStatus;\n value?: Uint8Array;\n}\n\ntype BlockFieldStates = Partial<Record<ProjectField[\"fieldName\"], BlockFieldState>>;\ntype BlockFieldStateValue = Omit<BlockFieldState, \"modCount\">;\n\ninterface BlockInfoState {\n readonly id: string;\n readonly fields: BlockFieldStates;\n blockConfig?: BlockConfig;\n blockPack?: BlockPackSpec;\n}\n\nfunction cached<ModId, T>(modIdCb: () => ModId, valueCb: () => T): () => T {\n let initialized = false;\n let lastModId: ModId | undefined = undefined;\n let value: T | undefined = undefined;\n return () => {\n if (!initialized) {\n initialized = true;\n lastModId = modIdCb();\n value = valueCb();\n return value;\n }\n const currentModId = modIdCb();\n if (lastModId !== currentModId) {\n lastModId = currentModId;\n value = valueCb();\n }\n return valueCb();\n };\n}\n\nclass BlockInfo {\n constructor(\n public readonly id: string,\n public readonly fields: BlockFieldStates,\n public readonly config: BlockConfig,\n public readonly source: BlockPackSpec,\n private readonly logger: MiLogger = new ConsoleLoggerAdapter(),\n ) {}\n\n public check() {\n // state assertions\n\n if ((this.fields.prodOutput === undefined) !== (this.fields.prodCtx === undefined))\n throw new Error(\"inconsistent prod fields\");\n\n if ((this.fields.stagingOutput === undefined) !== (this.fields.stagingCtx === undefined))\n throw new Error(\"inconsistent stage fields\");\n\n if (\n (this.fields.prodOutputPrevious === undefined) !==\n (this.fields.prodCtxPrevious === undefined)\n )\n throw new Error(\"inconsistent prod cache fields\");\n\n if (\n (this.fields.stagingOutputPrevious === undefined) !==\n (this.fields.stagingCtxPrevious === undefined)\n )\n throw new Error(\"inconsistent stage cache fields\");\n\n if (this.fields.blockPack === undefined) throw new Error(\"no block pack field\");\n\n if (this.fields.blockStorage === undefined) throw new Error(\"no block storage field\");\n }\n\n private readonly currentArgsC = cached(\n () => this.fields.currentArgs?.modCount,\n () => {\n const bin = this.fields.currentArgs?.value;\n if (bin === undefined) return undefined;\n return cachedDeserialize(bin);\n },\n );\n\n private readonly blockStorageC = cached(\n () => this.fields.blockStorage!.modCount,\n () => {\n const bin = this.fields.blockStorage?.value;\n if (bin === undefined) return undefined;\n return cachedDeserialize<Record<string, unknown>>(bin);\n },\n );\n\n private readonly blockStorageJ = cached(\n () => this.fields.blockStorage!.modCount,\n () => {\n const bin = this.fields.blockStorage?.value;\n if (bin === undefined) return undefined;\n return cachedDecode(bin);\n },\n );\n\n private readonly prodArgsC = cached(\n () => this.fields.prodArgs?.modCount,\n () => {\n const bin = this.fields.prodArgs?.value;\n if (bin === undefined) return undefined;\n return cachedDeserialize(bin);\n },\n );\n\n private readonly currentPrerunArgsC = cached(\n () => this.fields.currentPrerunArgs?.modCount,\n () => {\n const bin = this.fields.currentPrerunArgs?.value;\n if (bin === undefined) return undefined;\n return cachedDeserialize(bin);\n },\n );\n\n get currentArgs(): unknown {\n return this.currentArgsC();\n }\n\n get blockStorage(): unknown {\n try {\n return this.blockStorageC();\n } catch (e) {\n this.logger.error(new Error(`Error getting blockStorage for ${this.id}`, { cause: e }));\n return undefined;\n }\n }\n\n get blockStorageJson() {\n return this.blockStorageJ();\n }\n\n get currentPrerunArgs(): unknown {\n return this.currentPrerunArgsC();\n }\n\n get stagingRendered(): boolean {\n return this.fields.stagingCtx !== undefined;\n }\n\n get productionRendered(): boolean {\n return this.fields.prodCtx !== undefined;\n }\n\n get productionHasErrors(): boolean {\n return this.fields.prodUiCtx?.status === \"Error\";\n }\n\n private readonly productionStaleC: () => boolean = cached(\n () => `${this.fields.currentArgs!.modCount}_${this.fields.prodArgs?.modCount}`,\n () =>\n this.fields.prodArgs === undefined ||\n Buffer.compare(this.fields.currentArgs!.value!, this.fields.prodArgs.value!) !== 0,\n );\n\n get requireProductionRendering(): boolean {\n return !this.productionRendered || this.productionStaleC() || this.productionHasErrors;\n }\n\n /** Returns true if staging should be re-rendered (stagingCtx is not set) */\n get requireStagingRendering(): boolean {\n // No staging needed if currentPrerunArgs is undefined (args derivation failed)\n if (this.fields.currentPrerunArgs === undefined) return false;\n return !this.stagingRendered;\n }\n\n get prodArgs(): unknown {\n return this.prodArgsC();\n }\n\n public getTemplate(tx: PlTransaction): AnyRef {\n return tx.getFutureFieldValue(\n Pl.unwrapHolder(tx, this.fields.blockPack!.ref!),\n BlockPackTemplateField,\n \"Input\",\n );\n }\n}\n\n/**\n * Specification for creating a new block.\n * Discriminated union based on `storageMode`.\n */\n/** Specification for creating a new block. Discriminated union based on `storageMode`. */\nexport type NewBlockSpec =\n | { storageMode: \"fromModel\"; blockPack: BlockPackSpecPrepared }\n | { storageMode: \"legacy\"; blockPack: BlockPackSpecPrepared; legacyState: string };\n\nconst NoNewBlocks = (blockId: string) => {\n throw new Error(`No new block info for ${blockId}`);\n};\n\n/**\n * Request to set block state using unified state format.\n * For v3 blocks: state is the block's state\n * For v1/v2 blocks: state should be { args, uiState } format\n */\nexport type SetStatesRequest =\n | {\n blockId: string;\n /** The unified state to set */\n state: unknown;\n modelAPIVersion: 1;\n }\n | {\n blockId: string;\n /** Storage operation payload - middle layer is agnostic to specific operations */\n payload: { operation: string; value: unknown };\n modelAPIVersion: 2;\n };\n\nexport type ClearState = {\n state: unknown;\n};\n\nexport class ProjectMutator {\n private globalModCount = 0;\n private fieldsChanged: boolean = false;\n\n //\n // Change trackers\n //\n\n private lastModifiedChanged = false;\n private structureChanged = false;\n private metaChanged = false;\n private renderingStateChanged = false;\n\n /** Set blocks will be assigned current mutator author marker on save */\n private readonly blocksWithChangedInputs = new Set<string>();\n\n constructor(\n public readonly rid: ResourceId,\n private readonly tx: PlTransaction,\n private readonly author: AuthorMarker | undefined,\n private readonly schema: string,\n private lastModified: number,\n private meta: ProjectMeta,\n private struct: ProjectStructure,\n private readonly renderingState: Omit<ProjectRenderingState, \"blocksInLimbo\">,\n private readonly blocksInLimbo: Set<string>,\n private readonly blockInfos: Map<string, BlockInfo>,\n private readonly ctxExportTplHolder: AnyResourceRef,\n private readonly projectHelper: ProjectHelper,\n ) {}\n\n private fixProblemsAndMigrate() {\n // Fix inconsistent production fields\n this.blockInfos.forEach((blockInfo) => {\n if (\n blockInfo.fields.prodArgs === undefined ||\n blockInfo.fields.prodOutput === undefined ||\n blockInfo.fields.prodCtx === undefined\n )\n this.deleteBlockFields(blockInfo.id, \"prodArgs\", \"prodOutput\", \"prodCtx\", \"prodUiCtx\");\n });\n\n // Fix inconsistent staging fields\n this.blockInfos.forEach((blockInfo) => {\n if (blockInfo.fields.stagingOutput === undefined || blockInfo.fields.stagingCtx === undefined)\n this.deleteBlockFields(blockInfo.id, \"stagingOutput\", \"stagingCtx\", \"stagingUiCtx\");\n });\n\n // Fix inconsistent cache fields\n this.blockInfos.forEach((blockInfo) => {\n if (\n blockInfo.fields.prodOutputPrevious === undefined ||\n blockInfo.fields.prodCtxPrevious === undefined\n )\n this.deleteBlockFields(\n blockInfo.id,\n \"prodOutputPrevious\",\n \"prodCtxPrevious\",\n \"prodUiCtxPrevious\",\n );\n if (\n blockInfo.fields.stagingOutputPrevious === undefined ||\n blockInfo.fields.stagingCtxPrevious === undefined\n )\n this.deleteBlockFields(\n blockInfo.id,\n \"stagingOutputPrevious\",\n \"stagingCtxPrevious\",\n \"stagingUiCtxPrevious\",\n );\n });\n\n // Migration for addition of block settings field\n let initialBlockSettings: Omit<BlockFieldState, \"modCount\"> | undefined;\n this.blockInfos.forEach((blockInfo) => {\n if (blockInfo.fields.blockSettings === undefined) {\n if (initialBlockSettings === undefined)\n initialBlockSettings = this.createJsonFieldValue(InitialBlockSettings);\n this.setBlockFieldObj(blockInfo.id, \"blockSettings\", initialBlockSettings);\n }\n });\n\n // Validate after fixes\n this.blockInfos.forEach((info) => info.check());\n }\n\n get wasModified(): boolean {\n return (\n this.lastModifiedChanged ||\n this.structureChanged ||\n this.fieldsChanged ||\n this.metaChanged ||\n this.renderingStateChanged\n );\n }\n\n get structure(): ProjectStructure {\n return JSON.parse(JSON.stringify(this.struct)) as ProjectStructure;\n }\n\n //\n // Graph calculation\n //\n\n private stagingGraph: BlockGraph | undefined = undefined;\n private pendingProductionGraph: BlockGraph | undefined = undefined;\n private actualProductionGraph: BlockGraph | undefined = undefined;\n\n private getStagingGraph(): BlockGraph {\n if (this.stagingGraph === undefined) this.stagingGraph = stagingGraph(this.struct);\n return this.stagingGraph;\n }\n\n private getProductionGraphBlockInfo(\n blockId: string,\n prod: boolean,\n ): ProductionGraphBlockInfo | undefined {\n const bInfo = this.getBlockInfo(blockId);\n\n let argsField: BlockFieldState | undefined;\n let args: unknown;\n\n if (prod) {\n if (bInfo.fields.prodArgs === undefined) return undefined;\n argsField = bInfo.fields.prodArgs;\n args = bInfo.prodArgs;\n } else {\n argsField = bInfo.fields.currentArgs;\n args = bInfo.currentArgs;\n }\n\n // Can't compute enrichment targets without args\n if (argsField === undefined) {\n return { args, enrichmentTargets: undefined };\n }\n\n const blockPackField = notEmpty(bInfo.fields.blockPack);\n\n if (isResourceId(argsField.ref!) && isResourceId(blockPackField.ref!))\n return {\n args,\n enrichmentTargets: this.projectHelper.getEnrichmentTargets(\n () => bInfo.config,\n () => args,\n { argsRid: argsField.ref, blockPackRid: blockPackField.ref },\n ),\n };\n else\n return {\n args,\n enrichmentTargets: this.projectHelper.getEnrichmentTargets(\n () => bInfo.config,\n () => args,\n ),\n };\n }\n\n private getPendingProductionGraph(): BlockGraph {\n if (this.pendingProductionGraph === undefined)\n this.pendingProductionGraph = productionGraph(this.struct, (blockId) =>\n this.getProductionGraphBlockInfo(blockId, false),\n );\n return this.pendingProductionGraph;\n }\n\n private getActualProductionGraph(): BlockGraph {\n if (this.actualProductionGraph === undefined)\n this.actualProductionGraph = productionGraph(this.struct, (blockId) =>\n this.getProductionGraphBlockInfo(blockId, true),\n );\n return this.actualProductionGraph;\n }\n\n //\n // Generic helpers to interact with project state\n //\n\n private getBlockInfo(blockId: string): BlockInfo {\n const info = this.blockInfos.get(blockId);\n if (info === undefined) throw new Error(`No such block: ${blockId}`);\n return info;\n }\n\n /** Create a plain JSON resource value from a JS object (no compression). */\n private createJsonFieldValue(obj: unknown): BlockFieldStateValue {\n const value = Buffer.from(JSON.stringify(obj));\n const ref = this.tx.createValue(Pl.JsonObject, value);\n return { ref, value, status: \"Ready\" };\n }\n\n /** Create a plain JSON resource value from a pre-serialized JSON string (no compression). */\n private createJsonFieldValueFromContent(json: string): BlockFieldStateValue {\n const value = Buffer.from(json);\n const ref = this.tx.createValue(Pl.JsonObject, value);\n return { ref, value, status: \"Ready\" };\n }\n\n /** Create a gzip-compressed JSON resource value from a JS object (compressed if >= 16KB). */\n private createGzJsonFieldValue(obj: unknown): BlockFieldStateValue {\n const jsonBytes = canonicalJsonBytes(obj);\n return this.createGzJsonFieldValueFromBytes(jsonBytes);\n }\n\n /** Create a gzip-compressed JSON resource value from a pre-serialized JSON string (compressed if >= 16KB). */\n private createGzJsonFieldValueFromContent(json: string): BlockFieldStateValue {\n return this.createGzJsonFieldValueFromBytes(Buffer.from(json));\n }\n\n private createGzJsonFieldValueFromBytes(jsonBytes: Uint8Array): BlockFieldStateValue {\n const gzipThreshold = 16_384;\n if (jsonBytes.length >= gzipThreshold) {\n const data = gzipSync(jsonBytes);\n const ref = this.tx.createValue(Pl.JsonGzObject, data);\n return { ref, value: data, status: \"Ready\" };\n }\n const ref = this.tx.createValue(Pl.JsonObject, jsonBytes);\n return { ref, value: jsonBytes, status: \"Ready\" };\n }\n\n private getBlock(blockId: string): Block {\n for (const block of allBlocks(this.struct)) if (block.id === blockId) return block;\n throw new Error(\"block not found\");\n }\n\n private setBlockFieldObj(\n blockId: string,\n fieldName: keyof BlockFieldStates,\n state: BlockFieldStateValue,\n ) {\n const fid = field(this.rid, projectFieldName(blockId, fieldName));\n\n if (state.ref === undefined) throw new Error(\"Can't set value with empty ref\");\n\n if (this.getBlockInfo(blockId).fields[fieldName] === undefined)\n this.tx.createField(fid, \"Dynamic\", state.ref);\n else this.tx.setField(fid, state.ref);\n\n this.getBlockInfo(blockId).fields[fieldName] = {\n modCount: this.globalModCount++,\n ...state,\n };\n\n this.fieldsChanged = true;\n }\n\n private setBlockField(\n blockId: string,\n fieldName: keyof BlockFieldStates,\n ref: AnyRef,\n status: FieldStatus,\n value?: Uint8Array,\n ) {\n this.setBlockFieldObj(blockId, fieldName, { ref, status, value });\n }\n\n private deleteBlockFields(blockId: string, ...fieldNames: (keyof BlockFieldStates)[]): boolean {\n let deleted = false;\n const info = this.getBlockInfo(blockId);\n for (const fieldName of fieldNames) {\n const fields = info.fields;\n if (!(fieldName in fields)) continue;\n this.tx.removeField(field(this.rid, projectFieldName(blockId, fieldName)));\n delete fields[fieldName];\n this.fieldsChanged = true;\n deleted = true;\n }\n return deleted;\n }\n\n private updateLastModified() {\n this.lastModified = Date.now();\n this.lastModifiedChanged = true;\n }\n\n //\n // Main project actions\n //\n\n private resetStagingRefreshTimestamp() {\n this.renderingState.stagingRefreshTimestamp = Date.now();\n this.renderingStateChanged = true;\n }\n\n private resetStaging(blockId: string): void {\n const fields = this.getBlockInfo(blockId).fields;\n if (\n fields.stagingOutput?.status === \"Ready\" &&\n fields.stagingCtx?.status === \"Ready\" &&\n fields.stagingUiCtx?.status === \"Ready\"\n ) {\n this.setBlockFieldObj(blockId, \"stagingOutputPrevious\", fields.stagingOutput);\n this.setBlockFieldObj(blockId, \"stagingCtxPrevious\", fields.stagingCtx);\n this.setBlockFieldObj(blockId, \"stagingUiCtxPrevious\", fields.stagingUiCtx);\n }\n if (this.deleteBlockFields(blockId, \"stagingOutput\", \"stagingCtx\", \"stagingUiCtx\"))\n this.resetStagingRefreshTimestamp();\n }\n\n private resetProduction(blockId: string): void {\n const fields = this.getBlockInfo(blockId).fields;\n if (\n fields.prodOutput?.status === \"Ready\" &&\n fields.prodCtx?.status === \"Ready\" &&\n fields.prodUiCtx?.status === \"Ready\"\n ) {\n this.setBlockFieldObj(blockId, \"prodOutputPrevious\", fields.prodOutput);\n this.setBlockFieldObj(blockId, \"prodCtxPrevious\", fields.prodCtx);\n this.setBlockFieldObj(blockId, \"prodUiCtxPrevious\", fields.prodUiCtx);\n }\n this.deleteBlockFields(blockId, \"prodOutput\", \"prodCtx\", \"prodUiCtx\", \"prodArgs\");\n }\n\n /** Running blocks are reset, already computed moved to limbo. Returns if\n * either of the actions were actually performed.\n * This method ensures the block is left in a consistent state that passes check() constraints. */\n private resetOrLimboProduction(blockId: string): boolean {\n const fields = this.getBlockInfo(blockId).fields;\n\n // Check if we can safely move to limbo (both core production fields are ready)\n if (fields.prodOutput?.status === \"Ready\" && fields.prodCtx?.status === \"Ready\") {\n if (this.blocksInLimbo.has(blockId))\n // we are already in limbo\n return false;\n\n // limbo - keep the ready production results but clean up cache\n this.blocksInLimbo.add(blockId);\n this.renderingStateChanged = true;\n\n // doing some gc - clean up previous cache fields\n this.deleteBlockFields(blockId, \"prodOutputPrevious\", \"prodCtxPrevious\", \"prodUiCtxPrevious\");\n\n return true;\n } else {\n // reset - clean up any partial/inconsistent production stat\n return this.deleteBlockFields(\n blockId,\n \"prodOutput\",\n \"prodCtx\",\n \"prodUiCtx\",\n \"prodArgs\",\n \"prodOutputPrevious\",\n \"prodCtxPrevious\",\n \"prodUiCtxPrevious\",\n );\n }\n }\n\n /**\n * Gets current block state and merges with partial updates.\n * Used by legacy v1/v2 methods like setBlockArgs and setUiState.\n *\n * @param blockId The block to get state for\n * @param partialUpdate Partial state to merge (e.g. { args } or { uiState })\n * @returns Merged state in unified format { args, uiState }\n */\n public mergeBlockState(\n blockId: string,\n partialUpdate: { args?: unknown; uiState?: unknown },\n ): { args?: unknown; uiState?: unknown } {\n const info = this.getBlockInfo(blockId);\n const currentState = info.blockStorage as { args?: unknown; uiState?: unknown } | undefined;\n if (currentState === undefined) {\n throw new Error(`Cannot merge block state for ${blockId}: blockStorage is unavailable`);\n }\n return { ...currentState, ...partialUpdate };\n }\n\n /**\n * Sets raw block storage content directly (for testing purposes).\n * This bypasses all normalization and VM transformations.\n *\n * @param blockId The block to set storage for\n * @param rawStorageJson Raw storage as JSON string\n */\n public setBlockStorageRaw(blockId: string, rawStorageJson: string): void {\n this.setBlockFieldObj(\n blockId,\n \"blockStorage\",\n this.createGzJsonFieldValueFromContent(rawStorageJson),\n );\n this.blocksWithChangedInputs.add(blockId);\n this.updateLastModified();\n }\n\n /**\n * Resets a v2+ block to its initial storage state.\n * Gets initial storage from VM and derives args from it.\n *\n * For v1 blocks, use setStates() instead.\n *\n * @param blockId The block to reset\n */\n public resetToInitialStorage(blockId: string): void {\n const info = this.getBlockInfo(blockId);\n const blockConfig = info.config;\n\n if (blockConfig.modelAPIVersion !== BLOCK_STORAGE_FACADE_VERSION) {\n throw new Error(\"resetToInitialStorage is only supported for model API version 2\");\n }\n\n // Get initial storage from VM\n const initialStorageJson = this.projectHelper.getInitialStorageInVM(blockConfig);\n this.setBlockStorageRaw(blockId, initialStorageJson);\n\n // Derive args from storage - set or clear currentArgs based on derivation result\n const deriveArgsResult = this.projectHelper.deriveArgsFromStorage(\n blockConfig,\n initialStorageJson,\n );\n if (!deriveArgsResult.error) {\n this.setBlockFieldObj(\n blockId,\n \"currentArgs\",\n this.createJsonFieldValue(deriveArgsResult.value),\n );\n // Derive prerunArgs from storage\n const prerunArgs = this.projectHelper.derivePrerunArgsFromStorage(\n blockConfig,\n initialStorageJson,\n );\n if (prerunArgs !== undefined) {\n this.setBlockFieldObj(blockId, \"currentPrerunArgs\", this.createJsonFieldValue(prerunArgs));\n } else {\n this.deleteBlockFields(blockId, \"currentPrerunArgs\");\n }\n } else {\n if (info.fields.currentPrerunArgs !== undefined) {\n this.projectHelper.logger.warn(\n `[staging] ${blockId}: currentPrerunArgs cleared (args derivation failed)`,\n );\n }\n this.deleteBlockFields(blockId, \"currentArgs\");\n this.deleteBlockFields(blockId, \"currentPrerunArgs\");\n }\n }\n\n /** Optimally sets inputs for multiple blocks in one go */\n public setStates(requests: SetStatesRequest[]) {\n const changedArgs: string[] = [];\n let somethingChanged = false;\n for (const req of requests) {\n const info = this.getBlockInfo(req.blockId);\n let blockChanged = false;\n\n const blockConfig = info.config;\n // modelAPIVersion === 2 means BlockModelV3 with .args() lambda for deriving args\n\n if (req.modelAPIVersion !== blockConfig.modelAPIVersion) {\n throw new Error(\n `Model API version mismatch for block ${req.blockId}: ${req.modelAPIVersion} !== ${blockConfig.modelAPIVersion}`,\n );\n }\n\n // Derive args from storage using the block's config.args() callback\n let args: unknown;\n let prerunArgs: unknown;\n\n if (req.modelAPIVersion === BLOCK_STORAGE_FACADE_VERSION) {\n const currentStorageJson = info.blockStorageJson;\n if (currentStorageJson === undefined) {\n throw new Error(`Block ${req.blockId} has no blockStorage - this should not happen`);\n }\n\n // Apply the state update to storage\n const updatedStorageJson = this.projectHelper.applyStorageUpdateInVM(\n blockConfig,\n currentStorageJson,\n req.payload,\n );\n\n this.setBlockFieldObj(\n req.blockId,\n \"blockStorage\",\n this.createGzJsonFieldValueFromContent(updatedStorageJson),\n );\n\n // Derive args directly from storage (VM extracts data internally)\n const derivedArgsResult = this.projectHelper.deriveArgsFromStorage(\n blockConfig,\n updatedStorageJson,\n );\n if (derivedArgsResult.error) {\n args = undefined;\n prerunArgs = undefined;\n } else {\n args = derivedArgsResult.value;\n // Derive prerunArgs from storage, or fall back to args\n prerunArgs = this.projectHelper.derivePrerunArgsFromStorage(\n blockConfig,\n updatedStorageJson,\n );\n }\n } else {\n this.setBlockFieldObj(req.blockId, \"blockStorage\", this.createGzJsonFieldValue(req.state));\n if (req.state !== null && typeof req.state === \"object\" && \"args\" in req.state) {\n args = (req.state as { args: unknown }).args;\n } else {\n args = req.state;\n }\n // For the legacy blocks, prerunArgs = args (same as production args)\n prerunArgs = args;\n }\n\n // Set or clear currentArgs based on derivation result\n // NB: currentArgs must NOT be gzipped — they are read by Tengo workflows which can't decompress\n if (args !== undefined) {\n const currentArgsData = canonicalJsonBytes(args);\n const argsPartRef = this.tx.createValue(Pl.JsonObject, currentArgsData);\n this.setBlockField(req.blockId, \"currentArgs\", argsPartRef, \"Ready\", currentArgsData);\n } else {\n this.deleteBlockFields(req.blockId, \"currentArgs\");\n }\n\n // Set currentPrerunArgs field and check if it actually changed\n // NB: currentPrerunArgs must NOT be gzipped — they are read by Tengo workflows which can't decompress\n let prerunArgsChanged = false;\n if (prerunArgs !== undefined) {\n const prerunArgsData = canonicalJsonBytes(prerunArgs);\n const oldPrerunArgsData = info.fields.currentPrerunArgs?.value;\n // Check if prerunArgs actually changed\n if (\n oldPrerunArgsData === undefined ||\n Buffer.compare(oldPrerunArgsData, prerunArgsData) !== 0\n ) {\n prerunArgsChanged = true;\n }\n const prerunArgsRef = this.tx.createValue(Pl.JsonObject, prerunArgsData);\n this.setBlockField(\n req.blockId,\n \"currentPrerunArgs\",\n prerunArgsRef,\n \"Ready\",\n prerunArgsData,\n );\n } else {\n this.deleteBlockFields(req.blockId, \"currentPrerunArgs\");\n }\n\n blockChanged = true;\n // Only add to changedArgs if prerunArgs changed - this controls staging reset\n if (prerunArgsChanged) {\n changedArgs.push(req.blockId);\n }\n\n if (blockChanged) {\n // will be assigned our author marker\n this.blocksWithChangedInputs.add(req.blockId);\n somethingChanged = true;\n }\n }\n\n // resetting staging outputs for all downstream blocks\n this.getStagingGraph().traverse(\"downstream\", changedArgs, ({ id }) => this.resetStaging(id));\n\n if (somethingChanged) this.updateLastModified();\n }\n\n public setBlockSettings(blockId: string, newValue: BlockSettings): void {\n this.setBlockFieldObj(blockId, \"blockSettings\", this.createJsonFieldValue(newValue));\n this.updateLastModified();\n }\n\n private createProdCtx(upstream: Set<string>): AnyRef {\n const upstreamContexts: AnyRef[] = [];\n upstream.forEach((id) => {\n const info = this.getBlockInfo(id);\n if (info.fields[\"prodCtx\"]?.ref === undefined)\n throw new Error(\"One of the upstreams staging is not rendered.\");\n upstreamContexts.push(Pl.unwrapHolder(this.tx, info.fields[\"prodCtx\"].ref));\n });\n return createBContextFromUpstreams(this.tx, upstreamContexts);\n }\n\n private createStagingCtx(upstream: Set<string>): AnyRef {\n const upstreamContexts: AnyRef[] = [];\n upstream.forEach((id) => {\n const info = this.getBlockInfo(id);\n if (info.fields[\"stagingCtx\"]?.ref !== undefined) {\n upstreamContexts.push(Pl.unwrapHolder(this.tx, info.fields[\"stagingCtx\"].ref));\n } else if (info.fields.currentPrerunArgs !== undefined) {\n // Upstream has currentPrerunArgs but no staging — this is an inconsistency\n throw new Error(`Upstream ${id} staging is not rendered but has currentPrerunArgs set.`);\n }\n // Blocks without currentPrerunArgs (e.g. block model doesn't define prerunArgs, or args\n // derivation failed) never get stagingCtx. Use prodCtx if available.\n if (info.fields[\"prodCtx\"]?.ref !== undefined)\n upstreamContexts.push(Pl.unwrapHolder(this.tx, info.fields[\"prodCtx\"].ref));\n });\n return createBContextFromUpstreams(this.tx, upstreamContexts);\n }\n\n private exportCtx(ctx: AnyRef): AnyRef {\n return exportContext(this.tx, Pl.unwrapHolder(this.tx, this.ctxExportTplHolder), ctx);\n }\n\n /**\n * Renders staging for a block using currentPrerunArgs.\n * If currentPrerunArgs is not set (prerunArgs returned undefined), skips staging for this block.\n */\n private renderStagingFor(blockId: string) {\n const info = this.getBlockInfo(blockId);\n\n // Check BEFORE resetStaging: if currentPrerunArgs is not set (e.g. prerunArgs() returned undefined\n // because inputs aren't ready, or args derivation failed), skip without clearing existing staging.\n // Otherwise resetStaging would delete stagingCtx, and downstream blocks that reference this block\n // as an upstream would fail in createStagingCtx.\n const prerunArgsRef = info.fields.currentPrerunArgs?.ref;\n if (prerunArgsRef === undefined) {\n return;\n }\n\n this.resetStaging(blockId);\n\n const ctx = this.createStagingCtx(this.getStagingGraph().nodes.get(blockId)!.upstream);\n\n if (this.getBlock(blockId).renderingMode !== \"Heavy\") throw new Error(\"not supported yet\");\n\n const tpl = info.getTemplate(this.tx);\n\n // Use currentPrerunArgs for staging rendering\n const results = createRenderHeavyBlock(this.tx, tpl, {\n args: prerunArgsRef,\n blockId: this.tx.createValue(Pl.JsonString, JSON.stringify(blockId)),\n isProduction: this.tx.createValue(Pl.JsonBool, JSON.stringify(false)),\n context: ctx,\n });\n\n // Here we set the staging ctx to the input context of the staging workflow, not the output because exports\n // of one staging context should stay within the same block, and not travel downstream.\n // We may change this decision in the future if wanted to support traveling staging exports downstream.\n this.setBlockField(blockId, \"stagingCtx\", Pl.wrapInEphHolder(this.tx, ctx), \"NotReady\");\n\n // Yet the staging UI Ctx is the output context of the staging workflow, because it is used to form the result pool\n // thus creating a certain discrepancy between staging workflow context behavior and desktop's result pool.\n this.setBlockField(blockId, \"stagingUiCtx\", this.exportCtx(results.context), \"NotReady\");\n this.setBlockField(blockId, \"stagingOutput\", results.result, \"NotReady\");\n }\n\n private renderProductionFor(blockId: string) {\n this.resetProduction(blockId);\n\n const info = this.getBlockInfo(blockId);\n\n // Can't render production if currentArgs is not set\n if (info.fields.currentArgs === undefined) {\n throw new Error(`Can't render production for block ${blockId}: currentArgs not set`);\n }\n\n const ctx = this.createProdCtx(this.getPendingProductionGraph().nodes.get(blockId)!.upstream);\n\n if (this.getBlock(blockId).renderingMode === \"Light\")\n throw new Error(\"Can't render production for light block.\");\n\n const tpl = info.getTemplate(this.tx);\n\n const results = createRenderHeavyBlock(this.tx, tpl, {\n args: info.fields.currentArgs.ref!,\n blockId: this.tx.createValue(Pl.JsonString, JSON.stringify(blockId)),\n isProduction: this.tx.createValue(Pl.JsonBool, JSON.stringify(true)),\n context: ctx,\n });\n this.setBlockField(\n blockId,\n \"prodCtx\",\n Pl.wrapInEphHolder(this.tx, results.context),\n \"NotReady\",\n );\n this.setBlockField(blockId, \"prodUiCtx\", this.exportCtx(results.context), \"NotReady\");\n this.setBlockField(blockId, \"prodOutput\", results.result, \"NotReady\");\n\n // saving inputs for which we rendered the production\n this.setBlockFieldObj(blockId, \"prodArgs\", info.fields.currentArgs);\n\n // removing block from limbo as we juts rendered fresh production for it\n if (this.blocksInLimbo.delete(blockId)) this.renderingStateChanged = true;\n }\n\n //\n // Structure changes\n //\n\n private initializeNewBlock(blockId: string, spec: NewBlockSpec): void {\n const info = new BlockInfo(\n blockId,\n {},\n extractConfig(spec.blockPack.config),\n spec.blockPack.source,\n this.projectHelper.logger,\n );\n this.blockInfos.set(blockId, info);\n\n // block pack\n const bp = createBlockPack(this.tx, spec.blockPack);\n this.setBlockField(blockId, \"blockPack\", Pl.wrapInHolder(this.tx, bp), \"NotReady\");\n\n // settings\n this.setBlockFieldObj(\n blockId,\n \"blockSettings\",\n this.createJsonFieldValue(InitialBlockSettings),\n );\n\n const blockConfig = info.config;\n\n let args: unknown;\n let prerunArgs: unknown;\n let storageToWrite: string;\n\n if (spec.storageMode === \"fromModel\") {\n // Model API v2+: get initial storage and derive args from it\n storageToWrite = this.projectHelper.getInitialStorageInVM(blockConfig);\n\n // Derive args directly from storage (VM extracts data internally)\n const deriveArgsResult = this.projectHelper.deriveArgsFromStorage(\n blockConfig,\n storageToWrite,\n );\n if (deriveArgsResult.error) {\n args = undefined;\n prerunArgs = undefined;\n } else {\n args = deriveArgsResult.value;\n prerunArgs = this.projectHelper.derivePrerunArgsFromStorage(blockConfig, storageToWrite);\n }\n } else if (spec.storageMode === \"legacy\") {\n // Model API v1: use legacyState from spec\n const parsedState = JSON.parse(spec.legacyState);\n args = parsedState.args;\n if (args === undefined) {\n throw new Error(\"args is undefined in legacyState\");\n }\n prerunArgs = args;\n storageToWrite = spec.legacyState;\n } else {\n throw new Error(`Unknown storageMode: ${(spec as NewBlockSpec).storageMode}`);\n }\n\n // currentArgs\n if (args !== undefined) {\n this.setBlockFieldObj(blockId, \"currentArgs\", this.createJsonFieldValue(args));\n }\n\n // currentPrerunArgs\n if (prerunArgs !== undefined) {\n this.setBlockFieldObj(blockId, \"currentPrerunArgs\", this.createJsonFieldValue(prerunArgs));\n }\n\n // blockStorage\n this.setBlockFieldObj(\n blockId,\n \"blockStorage\",\n this.createGzJsonFieldValueFromContent(storageToWrite),\n );\n\n // checking structure\n info.check();\n }\n\n private getFieldNamesToDuplicate(blockId: string): Set<ProjectField[\"fieldName\"]> {\n const fields = this.getBlockInfo(blockId).fields;\n\n const diff = <T>(setA: Set<T>, setB: Set<T>): Set<T> =>\n new Set([...setA].filter((x) => !setB.has(x)));\n\n // Check if we can safely move to limbo (both core production fields are ready)\n if (fields.prodOutput?.status === \"Ready\" && fields.prodCtx?.status === \"Ready\") {\n if (this.blocksInLimbo.has(blockId))\n // we are already in limbo\n return FieldsToDuplicate;\n\n return diff(\n FieldsToDuplicate,\n new Set([\"prodOutputPrevious\", \"prodCtxPrevious\", \"prodUiCtxPrevious\"]),\n );\n } else {\n return diff(\n FieldsToDuplicate,\n new Set([\n \"prodOutput\",\n \"prodCtx\",\n \"prodUiCtx\",\n \"prodArgs\",\n \"prodOutputPrevious\",\n \"prodCtxPrevious\",\n \"prodUiCtxPrevious\",\n ]),\n );\n }\n }\n\n private initializeBlockDuplicate(blockId: string, originalBlockInfo: BlockInfo) {\n const info = new BlockInfo(\n blockId,\n {},\n originalBlockInfo.config,\n originalBlockInfo.source,\n this.projectHelper.logger,\n );\n\n this.blockInfos.set(blockId, info);\n\n const fieldNamesToDuplicate = this.getFieldNamesToDuplicate(blockId);\n\n // Copy all fields from original block to new block by sharing references\n for (const [fieldName, fieldState] of Object.entries(originalBlockInfo.fields)) {\n if (\n fieldNamesToDuplicate.has(fieldName as ProjectField[\"fieldName\"]) &&\n fieldState &&\n fieldState.ref\n ) {\n this.setBlockFieldObj(blockId, fieldName as keyof BlockFieldStates, {\n ref: fieldState.ref,\n status: fieldState.status,\n value: fieldState.value,\n });\n }\n }\n\n this.resetOrLimboProduction(blockId);\n\n info.check();\n }\n\n /** Very generic method, better check for more specialized case-specific methods first. */\n public updateStructure(\n newStructure: ProjectStructure,\n newBlockInitializer: (blockId: string) => void = NoNewBlocks,\n ): void {\n const currentStagingGraph = this.getStagingGraph();\n const currentActualProductionGraph = this.getActualProductionGraph();\n\n const newStagingGraph = stagingGraph(newStructure);\n\n const stagingDiff = graphDiff(currentStagingGraph, newStagingGraph);\n\n // removing blocks\n for (const blockId of stagingDiff.onlyInA) {\n const { fields } = this.getBlockInfo(blockId);\n this.deleteBlockFields(blockId, ...(Object.keys(fields) as ProjectField[\"fieldName\"][]));\n this.blockInfos.delete(blockId);\n if (this.blocksInLimbo.delete(blockId)) this.renderingStateChanged = true;\n }\n\n // creating new blocks\n for (const blockId of stagingDiff.onlyInB) {\n newBlockInitializer(blockId);\n }\n\n // resetting stagings affected by topology change\n for (const blockId of stagingDiff.different) this.resetStaging(blockId);\n\n // new actual production graph without new blocks\n const newActualProductionGraph = productionGraph(newStructure, (blockId) =>\n this.getProductionGraphBlockInfo(blockId, true),\n );\n\n const prodDiff = graphDiff(currentActualProductionGraph, newActualProductionGraph);\n\n // applying changes due to topology change in production to affected nodes and\n // all their downstreams\n currentActualProductionGraph.traverse(\"downstream\", [...prodDiff.different], (node) => {\n this.resetOrLimboProduction(node.id);\n });\n\n if (\n stagingDiff.onlyInB.size > 0 ||\n stagingDiff.onlyInA.size > 0 ||\n stagingDiff.different.size > 0\n )\n this.resetStagingRefreshTimestamp();\n\n this.struct = newStructure;\n this.structureChanged = true;\n this.stagingGraph = undefined;\n this.pendingProductionGraph = undefined;\n this.actualProductionGraph = undefined;\n\n this.updateLastModified();\n }\n\n //\n // Structure change helpers\n //\n\n public addBlock(block: Block, spec: NewBlockSpec, before?: string): void {\n const newStruct = this.structure; // copy current structure\n if (before === undefined) {\n // adding as a very last block\n newStruct.groups[newStruct.groups.length - 1].blocks.push(block);\n } else {\n let done = false;\n for (const group of newStruct.groups) {\n const idx = group.blocks.findIndex((b) => b.id === before);\n if (idx < 0) continue;\n group.blocks.splice(idx, 0, block);\n done = true;\n break;\n }\n if (!done) throw new Error(`Can't find element with id: ${before}`);\n }\n this.updateStructure(newStruct, (blockId) => {\n if (blockId !== block.id) throw new Error(\"Unexpected\");\n this.initializeNewBlock(blockId, spec);\n });\n }\n\n /**\n * Duplicates an existing block by copying all its fields and structure.\n * This method creates a deep copy of the block at the mutator level.\n *\n * @param originalBlockId id of the block to duplicate\n * @param newBlockId id for the new duplicated block\n * @param after id of the block to insert new block after\n */\n public duplicateBlock(originalBlockId: string, newBlockId: string, after?: string): void {\n // Get the original block from structure\n const originalBlock = this.getBlock(originalBlockId);\n const originalBlockInfo = this.getBlockInfo(originalBlockId);\n\n // Create new block in structure\n const newBlock: Block = {\n id: newBlockId,\n label: originalBlock.label,\n renderingMode: originalBlock.renderingMode,\n };\n\n // Add the new block to structure\n const newStruct = this.structure; // copy current structure\n if (after === undefined) {\n // adding as a very last block\n newStruct.groups[newStruct.groups.length - 1].blocks.push(newBlock);\n } else {\n let done = false;\n for (const group of newStruct.groups) {\n const idx = group.blocks.findIndex((b) => b.id === after);\n if (idx < 0) continue;\n group.blocks.splice(idx + 1, 0, newBlock);\n done = true;\n break;\n }\n if (!done) throw new Error(`Can't find element with id: ${after}`);\n }\n\n this.updateStructure(newStruct, (blockId) => {\n if (blockId !== newBlockId) throw new Error(\"Unexpected\");\n this.initializeBlockDuplicate(blockId, originalBlockInfo);\n });\n }\n\n public deleteBlock(blockId: string): void {\n const newStruct = this.structure; // copy current structure\n let done = false;\n for (const group of newStruct.groups) {\n const idx = group.blocks.findIndex((b) => b.id === blockId);\n if (idx < 0) continue;\n group.blocks.splice(idx, 1);\n done = true;\n break;\n }\n if (!done) throw new Error(`Can't find element with id: ${blockId}`);\n this.updateStructure(newStruct);\n }\n\n //\n // Block-pack migration\n //\n\n public migrateBlockPack(\n blockId: string,\n spec: BlockPackSpecPrepared,\n newClearState?: ClearState,\n ): void {\n const info = this.getBlockInfo(blockId);\n const newConfig = extractConfig(spec.config);\n\n const persistBlockPack = () => {\n this.setBlockField(\n blockId,\n \"blockPack\",\n Pl.wrapInHolder(this.tx, createBlockPack(this.tx, spec)),\n \"NotReady\",\n );\n };\n\n const applyStorageAndDeriveArgs = (storageJson: string) => {\n persistBlockPack();\n this.setBlockStorageRaw(blockId, storageJson);\n const deriveArgsResult = this.projectHelper.deriveArgsFromStorage(newConfig, storageJson);\n if (!deriveArgsResult.error) {\n this.setBlockFieldObj(\n blockId,\n \"currentArgs\",\n this.createJsonFieldValue(deriveArgsResult.value),\n );\n const prerunArgs = this.projectHelper.derivePrerunArgsFromStorage(newConfig, storageJson);\n if (prerunArgs !== undefined) {\n this.setBlockFieldObj(\n blockId,\n \"currentPrerunArgs\",\n this.createJsonFieldValue(prerunArgs),\n );\n } else {\n this.deleteBlockFields(blockId, \"currentPrerunArgs\");\n }\n } else {\n this.deleteBlockFields(blockId, \"currentArgs\");\n this.deleteBlockFields(blockId, \"currentPrerunArgs\");\n }\n };\n\n if (newClearState !== undefined) {\n // State is being reset - no migration needed\n const supportsStorageFromVM = newConfig.modelAPIVersion === BLOCK_STORAGE_FACADE_VERSION;\n\n if (supportsStorageFromVM) {\n // V2+: Get initial storage directly from VM and derive args from it\n const initialStorageJson = this.projectHelper.getInitialStorageInVM(newConfig);\n applyStorageAndDeriveArgs(initialStorageJson);\n this.blocksWithChangedInputs.add(blockId);\n this.updateLastModified();\n } else {\n // V1: Use setStates with legacy state format\n persistBlockPack();\n this.setStates([{ modelAPIVersion: 1, blockId, state: newClearState.state }]);\n }\n } else {\n // State is being preserved - run migrations if needed via VM\n // Only Model API v2 blocks support migrations\n const supportsStateMigrations = newConfig.modelAPIVersion === BLOCK_STORAGE_FACADE_VERSION;\n\n if (supportsStateMigrations) {\n const currentStorageJson = info.blockStorageJson;\n\n // Attempt migration BEFORE persisting block pack — on failure,\n // block stays on old version (no inconsistent new-code/old-storage state)\n const migrationResult = this.projectHelper.migrateStorageInVM(\n newConfig,\n currentStorageJson,\n );\n\n if (migrationResult.error !== undefined) {\n throw new Error(\n `[migrateBlockPack] Block ${blockId} migration failed: ${migrationResult.error}`,\n );\n }\n\n this.projectHelper.logger.info(\n `[migrateBlockPack] Block ${blockId}: ${migrationResult.info}`,\n );\n applyStorageAndDeriveArgs(migrationResult.newStorageJson);\n } else {\n // Legacy blocks (modelAPIVersion 1): persist block pack, set prerunArgs = currentArgs\n persistBlockPack();\n if (info.fields.currentArgs !== undefined) {\n this.setBlockFieldObj(blockId, \"currentPrerunArgs\", info.fields.currentArgs);\n }\n }\n\n this.blocksWithChangedInputs.add(blockId);\n\n // resetting staging outputs for all downstream blocks\n this.getStagingGraph().traverse(\"downstream\", [blockId], ({ id }) => this.resetStaging(id));\n }\n\n // also reset or limbo all downstream productions\n if (info.productionRendered)\n this.getActualProductionGraph().traverse(\"downstream\", [blockId], ({ id }) =>\n this.resetOrLimboProduction(id),\n );\n\n this.updateLastModified();\n }\n\n //\n // Render\n //\n\n public renderProduction(blockIds: string[], addUpstreams: boolean = false): Set<string> {\n const blockIdsSet = new Set(blockIds);\n\n const prodGraph = this.getPendingProductionGraph();\n if (addUpstreams)\n // adding all upstreams automatically\n prodGraph.traverse(\"upstream\", blockIds, (node) => {\n blockIdsSet.add(node.id);\n });\n else\n // checking that targets contain all upstreams\n for (const blockId of blockIdsSet) {\n const node = prodGraph.nodes.get(blockId);\n if (node === undefined) throw new Error(`Can't find block with id: ${blockId}`);\n for (const upstream of node.upstream)\n if (!blockIdsSet.has(upstream))\n throw new Error(\"Can't render blocks not including all upstreams.\");\n }\n\n // traversing in topological order and rendering target blocks\n const rendered = new Set<string>();\n for (const block of allBlocks(this.structure)) {\n if (!blockIdsSet.has(block.id)) continue;\n\n let render =\n this.getBlockInfo(block.id).requireProductionRendering || this.blocksInLimbo.has(block.id);\n\n if (!render)\n for (const upstream of prodGraph.nodes.get(block.id)!.upstream)\n if (rendered.has(upstream)) {\n render = true;\n break;\n }\n\n if (render) {\n this.renderProductionFor(block.id);\n rendered.add(block.id);\n }\n }\n\n const renderedArray = [...rendered];\n\n // sending to limbo all downstream blocks\n prodGraph.traverse(\"downstream\", renderedArray, (node) => {\n if (rendered.has(node.id))\n // don't send to limbo blocks that were just rendered\n return;\n this.resetOrLimboProduction(node.id);\n });\n\n // resetting staging outputs for all downstream blocks\n this.getStagingGraph().traverse(\"downstream\", renderedArray, ({ id }) => {\n // don't reset staging of the first rendered block\n if (renderedArray[0] !== id) this.resetStaging(id);\n });\n\n if (rendered.size > 0) this.updateLastModified();\n\n return rendered;\n }\n\n /** Stops running blocks from the list and modify states of other blocks\n * accordingly */\n public stopProduction(...blockIds: string[]) {\n const activeProdGraph = this.getActualProductionGraph();\n\n // we will stop all blocks listed in request and all their downstreams\n const queue = new Denque(blockIds);\n const queued = new Set(blockIds);\n const stopped: string[] = [];\n\n while (!queue.isEmpty()) {\n const blockId = queue.shift()!;\n const fields = this.getBlockInfo(blockId).fields;\n\n if (fields.prodOutput?.status === \"Ready\" && fields.prodCtx?.status === \"Ready\")\n // skipping finished blocks\n continue;\n\n if (this.deleteBlockFields(blockId, \"prodOutput\", \"prodCtx\", \"prodUiCtx\", \"prodArgs\")) {\n // was actually stopped\n stopped.push(blockId);\n\n // will try to stop all its downstreams\n for (const downstream of activeProdGraph.traverseIdsExcludingRoots(\"downstream\", blockId)) {\n if (queued.has(downstream)) continue;\n queue.push(downstream);\n queued.add(downstream);\n }\n }\n }\n\n // blocks under stopped blocks, but having finished production results, goes to limbo\n for (const blockId of activeProdGraph.traverseIdsExcludingRoots(\"downstream\", ...stopped))\n this.resetOrLimboProduction(blockId);\n\n // reset staging outputs for all downstream blocks\n this.getStagingGraph().traverse(\"downstream\", stopped, ({ id }) => this.resetStaging(id));\n }\n\n private traverseWithStagingLag(cb: (blockId: string, lag: number) => void) {\n const lags = new Map<string, number>();\n const stagingGraph = this.getStagingGraph();\n stagingGraph.nodes.forEach((node) => {\n const info = this.getBlockInfo(node.id);\n // Use requireStagingRendering to check both: staging exists AND prerunArgs hasn't changed\n const requiresRendering = info.requireStagingRendering;\n let lag = requiresRendering ? 1 : 0;\n node.upstream.forEach((upstream) => {\n const upstreamLag = lags.get(upstream)!;\n if (upstreamLag === 0) return;\n lag = Math.max(upstreamLag + 1, lag);\n });\n if (!requiresRendering && info.stagingRendered) {\n // console.log(`[traverseWithStagingLag] SKIP staging for ${node.id} - prerunArgs unchanged`);\n }\n cb(node.id, lag);\n lags.set(node.id, lag);\n });\n }\n\n /** @param stagingRenderingRate rate in blocks per second */\n private refreshStagings(stagingRenderingRate?: number) {\n const elapsed = Date.now() - this.renderingState.stagingRefreshTimestamp;\n const lagThreshold =\n stagingRenderingRate === undefined\n ? undefined\n : 1 + Math.max(0, (elapsed * stagingRenderingRate) / 1000);\n let rendered = 0;\n this.traverseWithStagingLag((blockId, lag) => {\n if (lag === 0)\n // meaning staging already rendered\n return;\n if (lagThreshold === undefined || lag <= lagThreshold) {\n try {\n this.renderStagingFor(blockId);\n rendered++;\n } catch (e) {\n this.projectHelper.logger.error(\n new Error(`[refreshStagings] renderStagingFor failed for ${blockId}`, { cause: e }),\n );\n }\n }\n });\n if (rendered > 0) this.resetStagingRefreshTimestamp();\n }\n\n //\n // Meta\n //\n\n /** Updates project metadata */\n public setMeta(meta: ProjectMeta): void {\n this.meta = meta;\n this.metaChanged = true;\n this.updateLastModified();\n }\n\n //\n // Maintenance\n //\n\n /** @param stagingRenderingRate rate in blocks per second */\n public doRefresh(stagingRenderingRate?: number) {\n this.refreshStagings(stagingRenderingRate);\n this.blockInfos.forEach((blockInfo) => {\n if (\n blockInfo.fields.prodCtx?.status === \"Ready\" &&\n blockInfo.fields.prodOutput?.status === \"Ready\"\n )\n this.deleteBlockFields(\n blockInfo.id,\n \"prodOutputPrevious\",\n \"prodCtxPrevious\",\n \"prodUiCtxPrevious\",\n );\n if (\n blockInfo.fields.stagingCtx?.status === \"Ready\" &&\n blockInfo.fields.stagingOutput?.status === \"Ready\"\n )\n this.deleteBlockFields(\n blockInfo.id,\n \"stagingOutputPrevious\",\n \"stagingCtxPrevious\",\n \"stagingUiCtxPrevious\",\n );\n });\n }\n\n private assignAuthorMarkers() {\n const markerStr = this.author ? JSON.stringify(this.author) : undefined;\n\n for (const blockId of this.blocksWithChangedInputs)\n if (markerStr === undefined) this.tx.deleteKValue(this.rid, blockArgsAuthorKey(blockId));\n else this.tx.setKValue(this.rid, blockArgsAuthorKey(blockId), markerStr);\n\n if (this.metaChanged || this.structureChanged) {\n if (markerStr === undefined) this.tx.deleteKValue(this.rid, ProjectStructureAuthorKey);\n else this.tx.setKValue(this.rid, ProjectStructureAuthorKey, markerStr);\n }\n }\n\n public save() {\n if (!this.wasModified) return;\n\n if (this.lastModifiedChanged)\n this.tx.setKValue(this.rid, ProjectLastModifiedTimestamp, JSON.stringify(this.lastModified));\n\n if (this.structureChanged)\n this.tx.setKValue(this.rid, ProjectStructureKey, JSON.stringify(this.struct));\n\n if (this.renderingStateChanged)\n this.tx.setKValue(\n this.rid,\n BlockRenderingStateKey,\n JSON.stringify({\n ...this.renderingState,\n blocksInLimbo: [...this.blocksInLimbo],\n } as ProjectRenderingState),\n );\n\n if (this.metaChanged) this.tx.setKValue(this.rid, ProjectMetaKey, JSON.stringify(this.meta));\n\n this.assignAuthorMarkers();\n }\n\n public static async load(\n projectHelper: ProjectHelper,\n tx: PlTransaction,\n rid: ResourceId,\n author?: AuthorMarker,\n ): Promise<ProjectMutator> {\n //\n // Sending initial requests to read project state (start of round-trip #1)\n //\n\n const fullResourceStateP = tx.getResourceData(rid, true);\n const schemaP = tx.getKValueJson<string>(rid, SchemaVersionKey);\n const lastModifiedP = tx.getKValueJson<number>(rid, ProjectLastModifiedTimestamp);\n const metaP = tx.getKValueJson<ProjectMeta>(rid, ProjectMetaKey);\n const structureP = tx.getKValueJson<ProjectStructure>(rid, ProjectStructureKey);\n const renderingStateP = tx.getKValueJson<ProjectRenderingState>(rid, BlockRenderingStateKey);\n\n const fullResourceState = await fullResourceStateP;\n\n // loading field information\n const blockInfoStates = new Map<string, BlockInfoState>();\n for (const f of fullResourceState.fields) {\n const projectField = parseProjectField(f.name);\n\n // processing only fields with known structure\n if (projectField === undefined) continue;\n\n let info = blockInfoStates.get(projectField.blockId);\n if (info === undefined) {\n info = {\n id: projectField.blockId,\n fields: {},\n };\n blockInfoStates.set(projectField.blockId, info);\n }\n\n info.fields[projectField.fieldName] = isNullResourceId(f.value)\n ? { modCount: 0 }\n : { modCount: 0, ref: f.value };\n }\n\n //\n // Roundtrip #1 not yet finished, but as soon as field list is received,\n // we can start sending requests to read states of referenced resources\n // (start of round-trip #2)\n //\n\n const blockFieldRequests: [\n BlockInfoState,\n ProjectField[\"fieldName\"],\n BlockFieldState,\n Promise<BasicResourceData | ResourceData>,\n ][] = [];\n blockInfoStates.forEach((info) => {\n const fields = info.fields;\n for (const [fName, state] of Object.entries(fields)) {\n if (state.ref === undefined) continue;\n if (!isResource(state.ref) || isResourceRef(state.ref))\n throw new Error(\"unexpected behaviour\");\n const fieldName = fName as ProjectField[\"fieldName\"];\n blockFieldRequests.push([\n info,\n fieldName,\n state,\n tx.getResourceData(state.ref, fieldName == \"blockPack\"),\n ]);\n }\n });\n\n // loading jsons\n const [schema, lastModified, meta, structure, { stagingRefreshTimestamp, blocksInLimbo }] =\n await Promise.all([schemaP, lastModifiedP, metaP, structureP, renderingStateP]);\n\n // Checking schema version of the project\n if (schema !== SchemaVersionCurrent) {\n if (Number(schema) < Number(SchemaVersionCurrent))\n throw new UiError(\n `Can't perform this action on this project because it has older schema. Try (re)loading the project to update it.`,\n );\n else\n throw new UiError(\n `Can't perform this action on this project because it has newer schema. Upgrade your desktop app to the latest version.`,\n );\n }\n\n //\n // <- at this point we have all the responses from round-trip #1\n //\n\n //\n // Receiving responses from round-trip #2 and sending requests to read block pack descriptions\n // (start of round-trip #3)\n //\n\n const blockPackRequests: [BlockInfoState, Promise<BasicResourceData>][] = [];\n for (const [info, fieldName, state, response] of blockFieldRequests) {\n const result = await response;\n state.value = result.data;\n if (isNotNullResourceId(result.error)) state.status = \"Error\";\n else if (result.resourceReady || isNotNullResourceId(result.originalResourceId))\n state.status = \"Ready\";\n else state.status = \"NotReady\";\n\n // For block pack we need to traverse the ref field from the resource data\n if (fieldName === \"blockPack\") {\n const refField = (result as ResourceData).fields.find((f) => f.name === Pl.HolderRefField);\n if (refField === undefined) throw new Error(\"Block pack ref field is missing\");\n blockPackRequests.push([\n info,\n tx.getResourceData(ensureResourceIdNotNull(refField.value), false),\n ]);\n }\n }\n\n //\n // <- at this point we have all the responses from round-trip #2\n //\n\n for (const [info, response] of blockPackRequests) {\n const result = await response;\n const bpInfo = cachedDeserialize<BlockPackInfo>(notEmpty(result.data));\n info.blockConfig = extractConfig(bpInfo.config);\n info.blockPack = bpInfo.source;\n }\n\n //\n // <- at this point we have all the responses from round-trip #3\n //\n\n // loading ctx export template to check if we already have cached materialized template in our project\n const ctxExportTplEnvelope = await getPreparedExportTemplateEnvelope();\n\n // expected field name\n const ctxExportTplCacheFieldName = getServiceTemplateField(ctxExportTplEnvelope.hash);\n const ctxExportTplField = fullResourceState.fields.find(\n (f) => f.name === ctxExportTplCacheFieldName,\n );\n let ctxExportTplHolder: AnyResourceRef;\n if (ctxExportTplField !== undefined)\n ctxExportTplHolder = ensureResourceIdNotNull(ctxExportTplField.value);\n else {\n ctxExportTplHolder = Pl.wrapInHolder(tx, loadTemplate(tx, ctxExportTplEnvelope.spec));\n tx.createField(\n field(rid, getServiceTemplateField(ctxExportTplEnvelope.hash)),\n \"Dynamic\",\n ctxExportTplHolder,\n );\n }\n\n const renderingState = { stagingRefreshTimestamp };\n const blocksInLimboSet = new Set(blocksInLimbo);\n\n const blockInfos = new Map<string, BlockInfo>();\n blockInfoStates.forEach(({ id, fields, blockConfig, blockPack }) =>\n blockInfos.set(\n id,\n new BlockInfo(id, fields, notEmpty(blockConfig), notEmpty(blockPack), projectHelper.logger),\n ),\n );\n\n // check consistency of project state\n const blockInStruct = new Set<string>();\n for (const b of allBlocks(structure)) {\n if (!blockInfos.has(b.id))\n throw new Error(`Inconsistent project structure: no inputs for ${b.id}`);\n blockInStruct.add(b.id);\n }\n blockInfos.forEach((info) => {\n if (!blockInStruct.has(info.id))\n throw new Error(`Inconsistent project structure: no structure entry for ${info.id}`);\n });\n\n const prj = new ProjectMutator(\n rid,\n tx,\n author,\n schema,\n lastModified,\n meta,\n structure,\n renderingState,\n blocksInLimboSet,\n blockInfos,\n ctxExportTplHolder,\n projectHelper,\n );\n\n prj.fixProblemsAndMigrate();\n\n return prj;\n }\n}\n\nexport interface ProjectState {\n schema: string;\n structure: ProjectStructure;\n renderingState: Omit<ProjectRenderingState, \"blocksInLimbo\">;\n blocksInLimbo: Set<string>;\n blockInfos: Map<string, BlockInfo>;\n}\n\nexport async function createProject(\n tx: PlTransaction,\n meta: ProjectMeta = InitialBlockMeta,\n): Promise<AnyResourceRef> {\n const prj = tx.createEphemeral(ProjectResourceType);\n tx.lock(prj);\n const ts = String(Date.now());\n tx.setKValue(prj, SchemaVersionKey, JSON.stringify(SchemaVersionCurrent));\n tx.setKValue(prj, ProjectCreatedTimestamp, ts);\n tx.setKValue(prj, ProjectLastModifiedTimestamp, ts);\n tx.setKValue(prj, ProjectMetaKey, JSON.stringify(meta));\n tx.setKValue(prj, ProjectStructureKey, JSON.stringify(InitialBlockStructure));\n tx.setKValue(prj, BlockRenderingStateKey, JSON.stringify(InitialProjectRenderingState));\n const ctxExportTplEnvelope = await getPreparedExportTemplateEnvelope();\n tx.createField(\n field(prj, getServiceTemplateField(ctxExportTplEnvelope.hash)),\n \"Dynamic\",\n Pl.wrapInHolder(tx, loadTemplate(tx, ctxExportTplEnvelope.spec)),\n );\n return prj;\n}\n\nexport async function withProject<T>(\n projectHelper: ProjectHelper,\n txOrPl: PlTransaction | PlClient,\n rid: ResourceId,\n cb: (p: ProjectMutator) => T | Promise<T>,\n ops?: Partial<TxOps>,\n): Promise<T> {\n return withProjectAuthored(projectHelper, txOrPl, rid, undefined, cb, ops);\n}\n\nexport async function withProjectAuthored<T>(\n projectHelper: ProjectHelper,\n txOrPl: PlTransaction | PlClient,\n rid: ResourceId,\n author: AuthorMarker | undefined,\n cb: (p: ProjectMutator) => T | Promise<T>,\n ops: Partial<TxOps> = {},\n): Promise<T> {\n if (txOrPl instanceof PlClient) {\n return await txOrPl.withWriteTx(\n \"ProjectAction\" + (ops.name ? `: ${ops.name}` : \"\"),\n async (tx) => {\n const mut = await ProjectMutator.load(projectHelper, tx, rid, author);\n const result = await cb(mut);\n if (!mut.wasModified)\n // skipping save and commit altogether if no modifications were actually made\n return result;\n mut.save();\n await tx.commit();\n if (getDebugFlags().logProjectMutationStat) console.log(JSON.stringify(tx.stat));\n return result;\n },\n ops,\n );\n } else {\n const mut = await ProjectMutator.load(projectHelper, txOrPl, rid, author);\n const result = await cb(mut);\n mut.save();\n return result;\n }\n}\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@milaboratories/pl-middle-layer",
|
|
3
|
-
"version": "1.48.
|
|
3
|
+
"version": "1.48.24",
|
|
4
4
|
"description": "Pl Middle Layer",
|
|
5
5
|
"keywords": [],
|
|
6
6
|
"license": "UNLICENSED",
|
|
@@ -31,20 +31,20 @@
|
|
|
31
31
|
"zod": "~3.23.8",
|
|
32
32
|
"@milaboratories/computable": "2.8.6",
|
|
33
33
|
"@milaboratories/pf-driver": "1.0.65",
|
|
34
|
-
"@milaboratories/pl-deployments": "2.15.22",
|
|
35
|
-
"@milaboratories/pl-errors": "1.1.72",
|
|
36
34
|
"@milaboratories/pl-client": "2.17.10",
|
|
35
|
+
"@milaboratories/pl-deployments": "2.15.22",
|
|
37
36
|
"@milaboratories/pl-drivers": "1.11.64",
|
|
38
|
-
"@milaboratories/pl-
|
|
37
|
+
"@milaboratories/pl-errors": "1.1.72",
|
|
39
38
|
"@milaboratories/pl-model-backend": "1.1.57",
|
|
40
|
-
"@milaboratories/pl-model-middle-layer": "1.12.12",
|
|
41
39
|
"@milaboratories/pl-model-common": "1.25.3",
|
|
42
|
-
"@milaboratories/
|
|
43
|
-
"@milaboratories/ts-helpers": "1.7.3",
|
|
40
|
+
"@milaboratories/pl-model-middle-layer": "1.12.12",
|
|
44
41
|
"@milaboratories/pl-tree": "1.8.50",
|
|
42
|
+
"@milaboratories/pl-http": "1.2.4",
|
|
43
|
+
"@milaboratories/ts-helpers": "1.7.3",
|
|
45
44
|
"@platforma-sdk/model": "1.58.22",
|
|
46
|
-
"@platforma-sdk/
|
|
47
|
-
"@
|
|
45
|
+
"@platforma-sdk/workflow-tengo": "5.9.1",
|
|
46
|
+
"@milaboratories/resolve-helper": "1.1.3",
|
|
47
|
+
"@platforma-sdk/block-tools": "2.6.68"
|
|
48
48
|
},
|
|
49
49
|
"devDependencies": {
|
|
50
50
|
"@types/node": "~24.5.2",
|
|
@@ -54,8 +54,8 @@
|
|
|
54
54
|
"typescript": "~5.9.3",
|
|
55
55
|
"vitest": "^4.0.18",
|
|
56
56
|
"@milaboratories/build-configs": "1.5.2",
|
|
57
|
-
"@milaboratories/ts-
|
|
58
|
-
"@milaboratories/ts-
|
|
57
|
+
"@milaboratories/ts-builder": "1.3.0",
|
|
58
|
+
"@milaboratories/ts-configs": "1.2.2"
|
|
59
59
|
},
|
|
60
60
|
"engines": {
|
|
61
61
|
"node": ">=22.19.0"
|
package/src/mutator/project.ts
CHANGED
|
@@ -66,6 +66,7 @@ import {
|
|
|
66
66
|
type MiLogger,
|
|
67
67
|
ConsoleLoggerAdapter,
|
|
68
68
|
} from "@milaboratories/ts-helpers";
|
|
69
|
+
import { gzipSync } from "node:zlib";
|
|
69
70
|
import type { ProjectHelper } from "../model/project_helper";
|
|
70
71
|
import {
|
|
71
72
|
extractConfig,
|
|
@@ -478,15 +479,40 @@ export class ProjectMutator {
|
|
|
478
479
|
return info;
|
|
479
480
|
}
|
|
480
481
|
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
const value = Buffer.from(
|
|
482
|
+
/** Create a plain JSON resource value from a JS object (no compression). */
|
|
483
|
+
private createJsonFieldValue(obj: unknown): BlockFieldStateValue {
|
|
484
|
+
const value = Buffer.from(JSON.stringify(obj));
|
|
484
485
|
const ref = this.tx.createValue(Pl.JsonObject, value);
|
|
485
486
|
return { ref, value, status: "Ready" };
|
|
486
487
|
}
|
|
487
488
|
|
|
488
|
-
|
|
489
|
-
|
|
489
|
+
/** Create a plain JSON resource value from a pre-serialized JSON string (no compression). */
|
|
490
|
+
private createJsonFieldValueFromContent(json: string): BlockFieldStateValue {
|
|
491
|
+
const value = Buffer.from(json);
|
|
492
|
+
const ref = this.tx.createValue(Pl.JsonObject, value);
|
|
493
|
+
return { ref, value, status: "Ready" };
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
/** Create a gzip-compressed JSON resource value from a JS object (compressed if >= 16KB). */
|
|
497
|
+
private createGzJsonFieldValue(obj: unknown): BlockFieldStateValue {
|
|
498
|
+
const jsonBytes = canonicalJsonBytes(obj);
|
|
499
|
+
return this.createGzJsonFieldValueFromBytes(jsonBytes);
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
/** Create a gzip-compressed JSON resource value from a pre-serialized JSON string (compressed if >= 16KB). */
|
|
503
|
+
private createGzJsonFieldValueFromContent(json: string): BlockFieldStateValue {
|
|
504
|
+
return this.createGzJsonFieldValueFromBytes(Buffer.from(json));
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
private createGzJsonFieldValueFromBytes(jsonBytes: Uint8Array): BlockFieldStateValue {
|
|
508
|
+
const gzipThreshold = 16_384;
|
|
509
|
+
if (jsonBytes.length >= gzipThreshold) {
|
|
510
|
+
const data = gzipSync(jsonBytes);
|
|
511
|
+
const ref = this.tx.createValue(Pl.JsonGzObject, data);
|
|
512
|
+
return { ref, value: data, status: "Ready" };
|
|
513
|
+
}
|
|
514
|
+
const ref = this.tx.createValue(Pl.JsonObject, jsonBytes);
|
|
515
|
+
return { ref, value: jsonBytes, status: "Ready" };
|
|
490
516
|
}
|
|
491
517
|
|
|
492
518
|
private getBlock(blockId: string): Block {
|
|
@@ -648,7 +674,7 @@ export class ProjectMutator {
|
|
|
648
674
|
this.setBlockFieldObj(
|
|
649
675
|
blockId,
|
|
650
676
|
"blockStorage",
|
|
651
|
-
this.
|
|
677
|
+
this.createGzJsonFieldValueFromContent(rawStorageJson),
|
|
652
678
|
);
|
|
653
679
|
this.blocksWithChangedInputs.add(blockId);
|
|
654
680
|
this.updateLastModified();
|
|
@@ -743,7 +769,7 @@ export class ProjectMutator {
|
|
|
743
769
|
this.setBlockFieldObj(
|
|
744
770
|
req.blockId,
|
|
745
771
|
"blockStorage",
|
|
746
|
-
this.
|
|
772
|
+
this.createGzJsonFieldValueFromContent(updatedStorageJson),
|
|
747
773
|
);
|
|
748
774
|
|
|
749
775
|
// Derive args directly from storage (VM extracts data internally)
|
|
@@ -763,7 +789,7 @@ export class ProjectMutator {
|
|
|
763
789
|
);
|
|
764
790
|
}
|
|
765
791
|
} else {
|
|
766
|
-
this.setBlockFieldObj(req.blockId, "blockStorage", this.
|
|
792
|
+
this.setBlockFieldObj(req.blockId, "blockStorage", this.createGzJsonFieldValue(req.state));
|
|
767
793
|
if (req.state !== null && typeof req.state === "object" && "args" in req.state) {
|
|
768
794
|
args = (req.state as { args: unknown }).args;
|
|
769
795
|
} else {
|
|
@@ -774,6 +800,7 @@ export class ProjectMutator {
|
|
|
774
800
|
}
|
|
775
801
|
|
|
776
802
|
// Set or clear currentArgs based on derivation result
|
|
803
|
+
// NB: currentArgs must NOT be gzipped — they are read by Tengo workflows which can't decompress
|
|
777
804
|
if (args !== undefined) {
|
|
778
805
|
const currentArgsData = canonicalJsonBytes(args);
|
|
779
806
|
const argsPartRef = this.tx.createValue(Pl.JsonObject, currentArgsData);
|
|
@@ -783,6 +810,7 @@ export class ProjectMutator {
|
|
|
783
810
|
}
|
|
784
811
|
|
|
785
812
|
// Set currentPrerunArgs field and check if it actually changed
|
|
813
|
+
// NB: currentPrerunArgs must NOT be gzipped — they are read by Tengo workflows which can't decompress
|
|
786
814
|
let prerunArgsChanged = false;
|
|
787
815
|
if (prerunArgs !== undefined) {
|
|
788
816
|
const prerunArgsData = canonicalJsonBytes(prerunArgs);
|
|
@@ -1019,7 +1047,7 @@ export class ProjectMutator {
|
|
|
1019
1047
|
this.setBlockFieldObj(
|
|
1020
1048
|
blockId,
|
|
1021
1049
|
"blockStorage",
|
|
1022
|
-
this.
|
|
1050
|
+
this.createGzJsonFieldValueFromContent(storageToWrite),
|
|
1023
1051
|
);
|
|
1024
1052
|
|
|
1025
1053
|
// checking structure
|