@milaboratories/pl-middle-layer 1.67.5 → 1.68.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (106) hide show
  1. package/dist/block_registry/registry-v2-provider.d.ts +1 -3
  2. package/dist/block_registry/registry-v2-provider.d.ts.map +1 -1
  3. package/dist/block_registry/registry.d.ts +5 -9
  4. package/dist/block_registry/registry.d.ts.map +1 -1
  5. package/dist/block_registry/template_provider.d.ts +3 -5
  6. package/dist/block_registry/template_provider.d.ts.map +1 -1
  7. package/dist/block_registry/watcher.d.ts +4 -6
  8. package/dist/block_registry/watcher.d.ts.map +1 -1
  9. package/dist/block_registry/well_known_registries.d.ts +3 -5
  10. package/dist/block_registry/well_known_registries.d.ts.map +1 -1
  11. package/dist/index.d.ts +6 -2
  12. package/dist/middle_layer/build_stamp.cjs +34 -0
  13. package/dist/middle_layer/build_stamp.cjs.map +1 -0
  14. package/dist/middle_layer/build_stamp.js +34 -0
  15. package/dist/middle_layer/build_stamp.js.map +1 -0
  16. package/dist/middle_layer/driver_kit.d.ts +3 -4
  17. package/dist/middle_layer/driver_kit.d.ts.map +1 -1
  18. package/dist/middle_layer/index.d.ts +3 -2
  19. package/dist/middle_layer/middle_layer.cjs +48 -0
  20. package/dist/middle_layer/middle_layer.cjs.map +1 -1
  21. package/dist/middle_layer/middle_layer.d.ts +23 -4
  22. package/dist/middle_layer/middle_layer.d.ts.map +1 -1
  23. package/dist/middle_layer/middle_layer.js +48 -0
  24. package/dist/middle_layer/middle_layer.js.map +1 -1
  25. package/dist/middle_layer/ops.cjs +8 -2
  26. package/dist/middle_layer/ops.cjs.map +1 -1
  27. package/dist/middle_layer/ops.d.ts +70 -26
  28. package/dist/middle_layer/ops.d.ts.map +1 -1
  29. package/dist/middle_layer/ops.js +8 -2
  30. package/dist/middle_layer/ops.js.map +1 -1
  31. package/dist/middle_layer/project.cjs +163 -8
  32. package/dist/middle_layer/project.cjs.map +1 -1
  33. package/dist/middle_layer/project.d.ts +56 -7
  34. package/dist/middle_layer/project.d.ts.map +1 -1
  35. package/dist/middle_layer/project.js +165 -11
  36. package/dist/middle_layer/project.js.map +1 -1
  37. package/dist/middle_layer/project_list.d.ts +5 -3
  38. package/dist/middle_layer/project_list.d.ts.map +1 -1
  39. package/dist/middle_layer/sharing_list.d.ts +3 -4
  40. package/dist/middle_layer/sharing_list.d.ts.map +1 -1
  41. package/dist/middle_layer/tree_snapshot_store.cjs +283 -0
  42. package/dist/middle_layer/tree_snapshot_store.cjs.map +1 -0
  43. package/dist/middle_layer/tree_snapshot_store.d.ts +143 -0
  44. package/dist/middle_layer/tree_snapshot_store.d.ts.map +1 -0
  45. package/dist/middle_layer/tree_snapshot_store.js +280 -0
  46. package/dist/middle_layer/tree_snapshot_store.js.map +1 -0
  47. package/dist/middle_layer/types.d.ts +1 -3
  48. package/dist/middle_layer/types.d.ts.map +1 -1
  49. package/dist/model/block_pack_spec.d.ts +13 -15
  50. package/dist/model/block_pack_spec.d.ts.map +1 -1
  51. package/dist/model/frontend.d.ts +1 -2
  52. package/dist/model/frontend.d.ts.map +1 -1
  53. package/dist/model/project_helper.d.ts +2 -4
  54. package/dist/model/project_helper.d.ts.map +1 -1
  55. package/dist/model/project_model.d.ts +12 -12
  56. package/dist/model/project_model.d.ts.map +1 -1
  57. package/dist/model/sharing_model.d.ts +24 -26
  58. package/dist/model/sharing_model.d.ts.map +1 -1
  59. package/dist/model/template_apply.d.ts +9 -8
  60. package/dist/model/template_apply.d.ts.map +1 -1
  61. package/dist/model/template_export.d.ts +2 -2
  62. package/dist/model/template_export.d.ts.map +1 -1
  63. package/dist/model/template_parser.d.ts +2 -4
  64. package/dist/model/template_parser.d.ts.map +1 -1
  65. package/dist/model/template_resolve.d.ts +10 -11
  66. package/dist/model/template_resolve.d.ts.map +1 -1
  67. package/dist/model/template_serializer.d.ts +6 -5
  68. package/dist/model/template_serializer.d.ts.map +1 -1
  69. package/dist/model/template_spec.d.ts +7 -9
  70. package/dist/model/template_spec.d.ts.map +1 -1
  71. package/dist/mutator/block-pack/block_pack.d.ts +2 -3
  72. package/dist/mutator/block-pack/block_pack.d.ts.map +1 -1
  73. package/dist/mutator/project.cjs +20 -3
  74. package/dist/mutator/project.cjs.map +1 -1
  75. package/dist/mutator/project.d.ts +4 -3
  76. package/dist/mutator/project.d.ts.map +1 -1
  77. package/dist/mutator/project.js +20 -3
  78. package/dist/mutator/project.js.map +1 -1
  79. package/dist/mutator/template/render_template.d.ts +1 -3
  80. package/dist/mutator/template/render_template.d.ts.map +1 -1
  81. package/dist/mutator/template/template_cache.d.ts +15 -16
  82. package/dist/mutator/template/template_cache.d.ts.map +1 -1
  83. package/dist/mutator/template/template_loading.d.ts +10 -12
  84. package/dist/mutator/template/template_loading.d.ts.map +1 -1
  85. package/dist/network_check/network_check.d.ts +3 -5
  86. package/dist/network_check/network_check.d.ts.map +1 -1
  87. package/dist/pool/data.d.ts +2 -4
  88. package/dist/pool/data.d.ts.map +1 -1
  89. package/dist/pool/driver.d.ts +6 -6
  90. package/dist/pool/driver.d.ts.map +1 -1
  91. package/dist/pool/index.d.ts +1 -0
  92. package/dist/pool/p_object_collection.d.ts +1 -3
  93. package/dist/pool/p_object_collection.d.ts.map +1 -1
  94. package/dist/pool/result_pool.d.ts +3 -1
  95. package/dist/worker/worker.d.ts +1 -1
  96. package/package.json +14 -14
  97. package/src/middle_layer/build_stamp.ts +36 -0
  98. package/src/middle_layer/index.ts +1 -0
  99. package/src/middle_layer/middle_layer.ts +77 -0
  100. package/src/middle_layer/ops.ts +46 -1
  101. package/src/middle_layer/project.ts +234 -14
  102. package/src/middle_layer/project_failsafe.test.ts +47 -0
  103. package/src/middle_layer/tree_snapshot_scenarios.test.ts +337 -0
  104. package/src/middle_layer/tree_snapshot_store.test.ts +331 -0
  105. package/src/middle_layer/tree_snapshot_store.ts +419 -0
  106. package/src/mutator/project.ts +27 -5
@@ -1 +1 @@
1
- {"version":3,"file":"project.cjs","names":["NavigationStates","projectOverview","projectOverviewLight","activeConfigs","withProject","cacheBlockPackTemplate","BLOCK_STORAGE_FACADE_VERSION","withProjectAuthored","DefaultRetryOptions","projectFieldName","Pl","blockOutputs","Computable","getBlockParameters","frontendData","applyProjectMigrations","SynchronizedTreeState","fs","treeFilter","ResourceTypeName","ResourceTypePrefix"],"sources":["../../src/middle_layer/project.ts"],"sourcesContent":["import type { MiddleLayerEnvironment } from \"./middle_layer\";\nimport type {\n FieldData,\n Filter,\n OptionalAnyResourceId,\n PlClient,\n SignedResourceId,\n} from \"@milaboratories/pl-client\";\nimport {\n DefaultRetryOptions,\n ensureSignedResourceIdNotNull,\n field,\n isNotFoundError,\n isTimeoutOrCancelError,\n Pl,\n resourceIdToString,\n ResourceTypeName,\n ResourceTypePrefix,\n treeFilter,\n} from \"@milaboratories/pl-client\";\nimport type { ComputableStableDefined, ComputableValueOrErrors } from \"@milaboratories/computable\";\nimport { Computable } from \"@milaboratories/computable\";\nimport { projectOverview } from \"./project_overview\";\nimport type { BlockPackSpecAny } from \"../model\";\nimport { randomUUID } from \"node:crypto\";\nimport { withProject, withProjectAuthored } from \"../mutator/project\";\nimport type { ExtendedResourceData, PruningFunction } from \"@milaboratories/pl-tree\";\nimport { SynchronizedTreeState, treeDumpStats } from \"@milaboratories/pl-tree\";\nimport { setTimeout } from \"node:timers/promises\";\nimport { frontendData } from \"./frontend_path\";\nimport type { NavigationState } from \"@milaboratories/pl-model-common\";\nimport { getBlockParameters, blockOutputs } from \"./block\";\nimport type { FrontendData } from \"../model/frontend\";\nimport type { ProjectId, ProjectStructure } from \"../model/project_model\";\nimport { projectFieldName } from \"../model/project_model\";\nimport {\n cachedDeserialize,\n notEmpty,\n type MiLogger,\n createInfiniteRetryState,\n nextInfiniteRetryState,\n type InfiniteRetryState,\n} from \"@milaboratories/ts-helpers\";\nimport type { BlockPackInfo } from \"../model/block_pack\";\nimport type {\n ProjectOverview,\n AuthorMarker,\n BlockSettings,\n BlockStateInternalV3,\n} from \"@milaboratories/pl-model-middle-layer\";\nimport { activeConfigs } from \"./active_cfg\";\nimport { NavigationStates } from \"./navigation_states\";\nimport { extractConfig, BLOCK_STORAGE_FACADE_VERSION } from \"@platforma-sdk/model\";\nimport fs from \"node:fs/promises\";\nimport canonicalize from \"canonicalize\";\nimport type { ProjectOverviewLight } from \"./project_overview_light\";\nimport { projectOverviewLight } from \"./project_overview_light\";\nimport { applyProjectMigrations } from \"../mutator/migration\";\nimport { cacheBlockPackTemplate } from \"../mutator/template/template_cache\";\n\ntype BlockStateComputables = {\n readonly fullState: Computable<BlockStateInternalV3>;\n};\n\nfunction stringifyForDump(object: unknown): string {\n return JSON.stringify(object, (key, value) => {\n if (typeof value === \"bigint\") return resourceIdToString(value as OptionalAnyResourceId);\n else if (\n ArrayBuffer.isView(value) ||\n value instanceof Int8Array ||\n value instanceof Uint8Array ||\n value instanceof Uint8ClampedArray ||\n value instanceof Int16Array ||\n value instanceof Uint16Array ||\n value instanceof Int32Array ||\n value instanceof Uint32Array ||\n value instanceof Float32Array ||\n value instanceof Float64Array ||\n value instanceof BigInt64Array ||\n value instanceof BigUint64Array\n )\n return Buffer.from(value.buffer, value.byteOffset, value.byteLength).toString(\"base64\");\n else if (Buffer.isBuffer(value)) return value.toString(\"base64\");\n\n return value;\n });\n}\n\n/** Data access object, to manipulate and read single opened (!) project data. */\nexport class Project {\n /** Data for the left panel, contain basic information about block status. */\n public readonly overview: ComputableStableDefined<ProjectOverview>;\n private readonly overviewLight: Computable<ProjectOverviewLight>;\n\n private readonly navigationStates = new NavigationStates();\n // null is set for deleted blocks\n private readonly blockComputables = new Map<string, BlockStateComputables | null>();\n\n private readonly blockFrontends = new Map<string, ComputableStableDefined<FrontendData>>();\n private readonly activeConfigs: Computable<unknown[]>;\n private readonly refreshLoopResult: Promise<void>;\n\n private readonly abortController = new AbortController();\n\n private get destroyed() {\n return this.abortController.signal.aborted;\n }\n\n constructor(\n private readonly env: MiddleLayerEnvironment,\n public readonly id: ProjectId /* Project ID, exposed to outer consumers, who work with ML */,\n readonly rid: SignedResourceId /* Contains signature, not exposed outside middle layer. */,\n private readonly projectTree: SynchronizedTreeState,\n ) {\n this.overview = projectOverview(\n projectTree.entry(),\n this.navigationStates,\n env,\n ).withPreCalculatedValueTree();\n this.overviewLight = projectOverviewLight(projectTree.entry()).withPreCalculatedValueTree();\n this.refreshLoopResult = this.refreshLoop();\n this.refreshLoopResult.catch((err) => {\n env.logger.warn(new Error(\"Error during refresh loop\", { cause: err })); // TODO (safe voiding for now)\n });\n this.activeConfigs = activeConfigs(projectTree.entry(), env);\n }\n\n get projectLockId(): string {\n return \"project:\" + this.id.toString();\n }\n\n private async refreshLoop(): Promise<void> {\n let retryState: InfiniteRetryState | undefined;\n while (!this.destroyed) {\n try {\n await withProject(\n this.env.projectHelper,\n this.env.pl,\n this.rid,\n (prj) => {\n prj.doRefresh();\n },\n { name: \"doRefresh\", lockId: this.projectLockId },\n );\n await this.activeConfigs.getValue();\n await setTimeout(this.env.ops.projectRefreshInterval, undefined, {\n signal: this.abortController.signal,\n });\n\n // Block computables housekeeping\n const overviewLight = await this.overviewLight.getValue();\n const existingBlocks = new Set(overviewLight.listOfBlocks);\n // Doing cleanup for deleted blocks\n for (const blockId of this.blockComputables.keys()) {\n if (!existingBlocks.has(blockId)) {\n const computable = this.blockComputables.get(blockId);\n if (computable !== undefined && computable !== null) computable.fullState.resetState();\n this.blockComputables.set(blockId, null);\n }\n }\n retryState = undefined;\n } catch (e: unknown) {\n // If we're destroyed, exit gracefully regardless of error type\n if (this.destroyed) break;\n\n if (isNotFoundError(e)) {\n this.env.logger.warn(\n \"project refresh routine terminated, because project was externally deleted\",\n );\n break;\n } else if (isTimeoutOrCancelError(e)) {\n // Timeout during normal operation, continue the loop\n } else {\n retryState = retryState\n ? nextInfiniteRetryState(retryState)\n : createInfiniteRetryState({\n type: \"exponentialWithMaxDelayBackoff\",\n initialDelay: 1000,\n maxDelay: 60_000,\n backoffMultiplier: 2,\n jitter: 0,\n });\n this.env.logger.error(\n new Error(`[refreshLoop] unexpected exception, retrying in ${retryState.nextDelay}ms`, {\n cause: e,\n }),\n );\n try {\n await setTimeout(retryState.nextDelay, undefined, {\n signal: this.abortController.signal,\n });\n } catch {\n // Aborted during retry delay, will exit via while condition or destroyed check\n break;\n }\n }\n }\n }\n }\n\n /**\n * Adds new block to the project.\n *\n * @param blockLabel block label / title visible to the user\n * @param blockPackSpec object describing the \"block type\", read more in the type docs\n * @param before id of the block to insert new block before\n * @param blockId internal id to be assigned for the block, this arg can be omitted\n * then, randomly generated UUID will be assigned automatically\n *\n * @return returns newly created block id\n * */\n public async addBlock(\n blockLabel: string,\n blockPackSpec: BlockPackSpecAny,\n before?: string,\n author: AuthorMarker | undefined = undefined,\n blockId: string = randomUUID(),\n ): Promise<string> {\n const preparedBp = await this.env.bpPreparer.prepare(blockPackSpec);\n const blockCfg = extractConfig(preparedBp.config);\n\n this.env.runtimeCapabilities.throwIfIncompatible(blockCfg.featureFlags);\n throwIfMissingServerCapabilities(this.env.pl, preparedBp.requiredCapabilities);\n\n // Pre-materialize template via cache (separate transaction(s))\n const cachedBp = await cacheBlockPackTemplate(this.env.pl, preparedBp);\n\n // Build NewBlockSpec based on model API version\n const newBlockSpec =\n blockCfg.modelAPIVersion === BLOCK_STORAGE_FACADE_VERSION\n ? { storageMode: \"fromModel\" as const, blockPack: cachedBp }\n : {\n storageMode: \"legacy\" as const,\n blockPack: cachedBp,\n legacyState: canonicalize({\n args: blockCfg.initialArgs,\n uiState: blockCfg.initialUiState,\n })!,\n };\n\n await withProjectAuthored(\n this.env.projectHelper,\n this.env.pl,\n this.rid,\n author,\n (mut) => {\n return mut.addBlock(\n {\n id: blockId,\n label: blockLabel,\n renderingMode: blockCfg.renderingMode,\n },\n newBlockSpec,\n before,\n );\n },\n {\n retryOptions: {\n ...DefaultRetryOptions,\n backoffMultiplier: DefaultRetryOptions.backoffMultiplier * 1.1,\n },\n name: \"addBlock\",\n lockId: this.projectLockId,\n },\n );\n\n await this.projectTree.refreshState();\n\n return blockId;\n }\n\n /**\n * Duplicates an existing block by copying all its fields and state.\n * This method works at the mutator level for efficient block copying.\n *\n * @param originalBlockId id of the block to duplicate\n * @param before id of the block to insert new block before\n * @param author author marker for the duplication operation\n * @param newBlockId internal id to be assigned for the duplicated block,\n * if omitted, a randomly generated UUID will be assigned\n *\n * @return returns newly created block id\n * */\n public async duplicateBlock(\n originalBlockId: string,\n before?: string,\n author: AuthorMarker | undefined = undefined,\n newBlockId: string = randomUUID(),\n ): Promise<string> {\n await withProjectAuthored(\n this.env.projectHelper,\n this.env.pl,\n this.rid,\n author,\n (mut) => mut.duplicateBlock(originalBlockId, newBlockId, before),\n { name: \"duplicateBlock\", lockId: this.projectLockId },\n );\n await this.projectTree.refreshState();\n\n return newBlockId;\n }\n\n /**\n * Update block to new block pack, optionally resetting args and ui state to\n * initial values\n * */\n public async updateBlockPack(\n blockId: string,\n blockPackSpec: BlockPackSpecAny,\n resetArgs: boolean = false,\n author?: AuthorMarker,\n ): Promise<void> {\n const preparedBp = await this.env.bpPreparer.prepare(blockPackSpec);\n const blockCfg = extractConfig(preparedBp.config);\n\n this.env.runtimeCapabilities.throwIfIncompatible(blockCfg.featureFlags);\n throwIfMissingServerCapabilities(this.env.pl, preparedBp.requiredCapabilities);\n\n // Pre-materialize template via cache (separate transaction(s))\n const cachedBp = await cacheBlockPackTemplate(this.env.pl, preparedBp);\n\n // resetState signals to mutator to reset storage\n // For v2+ blocks: mutator gets initial storage directly via getInitialStorageInVM\n // For v1 blocks: we pass the legacy state format\n const resetState = resetArgs\n ? {\n state:\n blockCfg.modelAPIVersion === 1\n ? { args: blockCfg.initialArgs, uiState: blockCfg.initialUiState }\n : {},\n }\n : undefined;\n await withProjectAuthored(\n this.env.projectHelper,\n this.env.pl,\n this.rid,\n author,\n (mut) => mut.migrateBlockPack(blockId, cachedBp, resetState),\n { name: \"updateBlockPack\", lockId: this.projectLockId },\n );\n await this.projectTree.refreshState();\n }\n\n /** Deletes a block with all associated data. */\n public async deleteBlock(blockId: string, author?: AuthorMarker): Promise<void> {\n await withProjectAuthored(\n this.env.projectHelper,\n this.env.pl,\n this.rid,\n author,\n (mut) => mut.deleteBlock(blockId),\n { name: \"deleteBlock\", lockId: this.projectLockId },\n );\n this.navigationStates.deleteBlock(blockId);\n await this.projectTree.refreshState();\n }\n\n /**\n * Updates block order according to the given array of block ids.\n *\n * Provided array must contain exactly the same set of ids current project cosists of,\n * an error will be thrown instead.\n */\n public async reorderBlocks(blocks: string[], author?: AuthorMarker): Promise<void> {\n await withProjectAuthored(\n this.env.projectHelper,\n this.env.pl,\n this.rid,\n author,\n (mut) => {\n const currentStructure = mut.structure;\n if (currentStructure.groups.length !== 1)\n throw new Error(\"Unexpected project structure, non-singular block group\");\n const currentGroup = currentStructure.groups[0];\n if (currentGroup.blocks.length !== blocks.length)\n throw new Error(`Length mismatch: ${currentGroup.blocks.length} !== ${blocks.length}`);\n if (new Set<string>(blocks).size !== blocks.length) throw new Error(`Repeated block ids`);\n const newStructure: ProjectStructure = {\n groups: [\n {\n id: currentGroup.id,\n label: currentGroup.label,\n blocks: blocks.map((blockId) => {\n const block = currentGroup.blocks.find((b) => b.id === blockId);\n if (block === undefined) throw new Error(`Can't find block: ${blockId}`);\n return block;\n }),\n },\n ],\n };\n mut.updateStructure(newStructure);\n },\n { name: \"reorderBlocks\", lockId: this.projectLockId },\n );\n await this.projectTree.refreshState();\n }\n\n /**\n * Renders production part of the block starting all connected heavy computations.\n * Upstream blocks of the specified block will be started automatically if in\n * stale state.\n * */\n public async runBlock(blockId: string): Promise<void> {\n await withProject(\n this.env.projectHelper,\n this.env.pl,\n this.rid,\n (mut) => mut.renderProduction([blockId], true),\n { name: \"runBlock\", lockId: this.projectLockId },\n );\n await this.projectTree.refreshState();\n }\n\n /**\n * Stops the block if it is running by destroying its production state. All\n * its downstreams will also be destroyed or moved to limbo if already\n * calculated.\n * */\n public async stopBlock(blockId: string): Promise<void> {\n await withProject(\n this.env.projectHelper,\n this.env.pl,\n this.rid,\n (mut) => mut.stopProduction(blockId),\n { name: \"stopBlock\", lockId: this.projectLockId },\n );\n await this.projectTree.refreshState();\n }\n\n /**\n * @deprecated Use mutateBlockStorage() for V3 blocks.\n * Sets block args, and changes whole project state accordingly.\n * Along with setting arguments one can specify author marker, that will be\n * transactionally associated with the block, to facilitate conflict resolution\n * in collaborative editing scenario.\n * */\n public async setBlockArgs(blockId: string, args: unknown, author?: AuthorMarker) {\n await withProjectAuthored(\n this.env.projectHelper,\n this.env.pl,\n this.rid,\n author,\n (mut) => {\n const state = mut.mergeBlockState(blockId, { args });\n mut.setStates([{ modelAPIVersion: 1, blockId, state }]);\n },\n { name: \"setBlockArgs\", lockId: this.projectLockId },\n );\n await this.projectTree.refreshState();\n }\n\n /**\n * @deprecated Use mutateBlockStorage() for V3 blocks.\n * Sets ui block state associated with the block.\n * Along with setting arguments one can specify author marker, that will be\n * transactionally associated with the block, to facilitate conflict resolution\n * in collaborative editing scenario.\n * */\n public async setUiState(blockId: string, uiState: unknown, author?: AuthorMarker) {\n await withProjectAuthored(\n this.env.projectHelper,\n this.env.pl,\n this.rid,\n author,\n (mut) => {\n const state = mut.mergeBlockState(blockId, { uiState });\n mut.setStates([{ modelAPIVersion: 1, blockId, state }]);\n },\n { name: \"setUiState\", lockId: this.projectLockId },\n );\n await this.projectTree.refreshState();\n }\n\n /**\n * @deprecated Use mutateBlockStorage() for V3 blocks.\n * Sets block args and ui state, and changes the whole project state accordingly.\n * Along with setting arguments one can specify author marker, that will be\n * transactionally associated with the block, to facilitate conflict resolution\n * in collaborative editing scenario.\n * */\n public async setBlockArgsAndUiState(\n blockId: string,\n args: unknown, // keep for v1/v2 compatibility\n uiState: unknown, // keep for v1/v2 compatibility\n author?: AuthorMarker,\n ) {\n // Normalize to unified state format { args, uiState } for v1/v2 blocks\n const state = { args, uiState };\n await withProjectAuthored(\n this.env.projectHelper,\n this.env.pl,\n this.rid,\n author,\n (mut) => {\n mut.setStates([{ modelAPIVersion: 1, blockId, state }]);\n },\n { name: \"setBlockArgsAndUiState\", lockId: this.projectLockId },\n );\n await this.projectTree.refreshState();\n }\n\n /**\n * Sets navigation state.\n * */\n //\n public async setNavigationState(blockId: string, state: NavigationState): Promise<void> {\n this.navigationStates.setState(blockId, state);\n }\n\n /**\n * Mutates block storage for Model API v3 blocks.\n * Applies a storage operation (e.g., 'update-data') which triggers\n * args derivation (args(data) and prerunArgs(data)).\n * The derived args are stored atomically with the data.\n *\n * @param blockId - The block ID\n * @param payload - Storage mutation payload with operation and value\n * @param author - Optional author marker for collaborative editing\n */\n public async mutateBlockStorage(\n blockId: string,\n payload: { operation: string; value: unknown },\n author?: AuthorMarker,\n ) {\n await withProjectAuthored(\n this.env.projectHelper,\n this.env.pl,\n this.rid,\n author,\n (mut) => mut.setStates([{ modelAPIVersion: 2, blockId, payload }]),\n { name: \"mutateBlockStorage\", lockId: this.projectLockId },\n );\n await this.projectTree.refreshState();\n }\n\n /** Update block settings */\n public async setBlockSettings(blockId: string, newValue: BlockSettings) {\n await withProjectAuthored(\n this.env.projectHelper,\n this.env.pl,\n this.rid,\n undefined,\n (mut) => {\n mut.setBlockSettings(blockId, newValue);\n },\n { name: \"setBlockSettings\" },\n );\n await this.projectTree.refreshState();\n }\n\n /**\n * Sets raw block storage content directly.\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 async setBlockStorageRaw(blockId: string, rawStorageJson: string): Promise<void> {\n await withProjectAuthored(\n this.env.projectHelper,\n this.env.pl,\n this.rid,\n undefined,\n (mut) => {\n mut.setBlockStorageRaw(blockId, rawStorageJson);\n },\n { name: \"setBlockStorageRaw\" },\n );\n await this.projectTree.refreshState();\n }\n\n /** Resets arguments and ui state of the block to initial state */\n public async resetBlockArgsAndUiState(blockId: string, author?: AuthorMarker): Promise<void> {\n await this.env.pl.withWriteTx(\"BlockInputsReset\", async (tx) => {\n // reading default arg values from block pack\n const bpHolderRid = ensureSignedResourceIdNotNull(\n (await tx.getField(field(this.rid, projectFieldName(blockId, \"blockPack\")))).value,\n );\n const bpRid = ensureSignedResourceIdNotNull(\n (await tx.getField(field(bpHolderRid, Pl.HolderRefField))).value,\n );\n const bpData = await tx.getResourceData(bpRid, false);\n const config = extractConfig(cachedDeserialize<BlockPackInfo>(notEmpty(bpData.data)).config);\n\n await withProjectAuthored(\n this.env.projectHelper,\n tx,\n this.rid,\n author,\n (prj) => {\n if (config.modelAPIVersion === BLOCK_STORAGE_FACADE_VERSION) {\n // V2+: Reset to initial storage via VM\n prj.resetToInitialStorage(blockId);\n } else {\n // V1: Use legacy state format\n const initialState = { args: config.initialArgs, uiState: config.initialUiState };\n prj.setStates([{ modelAPIVersion: 1, blockId, state: initialState }]);\n }\n },\n { name: \"resetBlockArgsAndUiState\", lockId: this.projectLockId },\n );\n await tx.commit();\n });\n await this.projectTree.refreshState();\n }\n\n private getBlockComputables(blockId: string): BlockStateComputables {\n const cached = this.blockComputables.get(blockId);\n if (cached === null) throw new Error(`Block ${blockId} is deleted`);\n if (cached === undefined) {\n // state consists of inputs (args + ui state) and outputs\n const outputs = blockOutputs(this.projectTree.entry(), blockId, this.env);\n const fullState = Computable.make(\n (ctx) => {\n return {\n parameters: getBlockParameters(this.projectTree.entry(), blockId, ctx),\n outputs,\n navigationState: this.navigationStates.getState(blockId),\n overview: this.overview,\n };\n },\n {\n postprocessValue: (v) => {\n const blockOverview = v.overview?.blocks?.find((b) => b.id == blockId);\n const sdkVersion = blockOverview?.sdkVersion;\n const storageDebugView = blockOverview?.storageDebugView;\n const toString = sdkVersion && shouldStillUseStringErrors(sdkVersion);\n const newOutputs =\n toString && v.outputs !== undefined ? convertErrorsToStrings(v.outputs) : v.outputs;\n\n return {\n ...v.parameters,\n outputs: newOutputs,\n navigationState: v.navigationState,\n storageDebugView,\n } as BlockStateInternalV3;\n },\n },\n );\n\n const computables: BlockStateComputables = {\n fullState: fullState.withPreCalculatedValueTree(),\n };\n\n this.blockComputables.set(blockId, computables);\n\n return computables;\n }\n return cached;\n }\n\n /**\n * Returns a computable, that can be used to retrieve and watch full block state,\n * including outputs, arguments, ui state.\n * */\n public getBlockState(blockId: string): Computable<BlockStateInternalV3> {\n return this.getBlockComputables(blockId).fullState;\n }\n\n /**\n * Returns a computable, that can be used to retrieve and watch path of the\n * folder containing frontend code.\n * */\n public getBlockFrontend(blockId: string): ComputableStableDefined<FrontendData> {\n const cached = this.blockFrontends.get(blockId);\n if (cached === undefined) {\n const fd = frontendData(\n this.projectTree.entry(),\n blockId,\n this.env,\n ).withPreCalculatedValueTree();\n this.blockFrontends.set(blockId, fd);\n return fd;\n }\n return cached;\n }\n\n /** Called by middle layer on close */\n public async destroy(): Promise<void> {\n // terminating the project service loop\n this.abortController.abort();\n try {\n await this.refreshLoopResult;\n } catch (e: unknown) {\n // Error was already logged in the constructor's catch handler, but log again for context\n this.env.logger.warn(\n new Error(\"Refresh loop had terminated with error before destroy\", { cause: e }),\n );\n }\n\n // terminating the synchronized project tree\n try {\n await this.projectTree.terminate();\n } catch (e: unknown) {\n // TODO: SynchronizedTreeState.terminate() can throw if mainLoop had an error before termination\n // Log error but continue cleanup - we must clean up remaining resources\n this.env.logger.warn(new Error(\"Project tree termination failed\", { cause: e }));\n }\n\n // the following will deregister all external resource holders, like\n // downloaded files, running uploads and alike\n this.overview.resetState();\n this.blockFrontends.forEach((c) => c.resetState());\n this.blockComputables.forEach((c) => {\n if (c !== null) c.fullState.resetState();\n });\n this.activeConfigs.resetState();\n }\n\n /** @deprecated */\n public async destroyAndAwaitTermination(): Promise<void> {\n await this.destroy();\n }\n\n public dumpState(): ExtendedResourceData[] {\n return this.projectTree.dumpState();\n }\n\n public static async init(\n env: MiddleLayerEnvironment,\n id: ProjectId,\n rid: SignedResourceId,\n ): Promise<Project> {\n // Applying migrations to the project resource, if needed\n await applyProjectMigrations(env.pl, rid);\n\n // Doing a no-op mutation to apply all migration and schema fixes\n await withProject(env.projectHelper, env.pl, rid, (_) => {}, { name: \"init\" });\n\n // Loading project tree\n const projectTree = await SynchronizedTreeState.init(\n env.pl,\n rid,\n {\n ...env.ops.defaultTreeOptions,\n pruning: projectTreePruning(env.logger),\n fieldFilter: projectTreeFieldFilter(),\n traverseStopRules: projectTreeTraverseStopRules(),\n },\n env.logger,\n );\n\n if (env.ops.debugOps.dumpInitialTreeState) {\n const state = projectTree.dumpState();\n state.sort((a, b) => (b.data?.byteLength ?? 0) - (a.data?.byteLength ?? 0));\n const stats = treeDumpStats(state);\n await fs.writeFile(`${resourceIdToString(rid)}.json`, stringifyForDump(state));\n await fs.writeFile(`${resourceIdToString(rid)}.stats.json`, stringifyForDump(stats));\n }\n\n return new Project(env, id, rid, projectTree);\n }\n}\n\nexport function projectTreePruning(logger: MiLogger): PruningFunction {\n return (r: ExtendedResourceData): FieldData[] => {\n if (r.fields.length > 1000)\n logger.warn(\n `resource with excessive field count: type=${r.type.name} id=${r.id} fields=${r.fields.length}` +\n ` names=[${r.fields\n .slice(0, 10)\n .map((f) => f.name)\n .join(\", \")}, ...]`,\n );\n if (r.type.name.startsWith(\"StreamWorkdir/\")) return [];\n switch (r.type.name) {\n case \"BlockPackCustom\":\n return r.fields.filter((f) => f.name !== \"template\");\n case \"UserProject\":\n return r.fields.filter((f) => !f.name.startsWith(\"__serviceTemplate\"));\n case \"Blob\":\n return [];\n default:\n return r.fields;\n }\n };\n}\n\n/** ResourceTree analogue of projectTreePruning() used by modern backend path. */\nexport function projectTreeFieldFilter(): Filter {\n return treeFilter.not(\n treeFilter.or(\n // StreamWorkdir/* — pruned entirely\n treeFilter.resourceTypeMatch(\"^StreamWorkdir/\"),\n // BlockPackCustom: drop `template`\n treeFilter.and(\n treeFilter.resourceTypeEq(\"BlockPackCustom\"),\n treeFilter.fieldNameEq(\"template\"),\n ),\n // UserProject: drop `__serviceTemplate*`\n treeFilter.and(\n treeFilter.resourceTypeEq(\"UserProject\"),\n treeFilter.fieldNameMatch(\"^__serviceTemplate\"),\n ),\n // Blob — pruned entirely\n treeFilter.resourceTypeEq(\"Blob\"),\n ),\n );\n}\n\n/**\n * Stop-rules for the ResourceTree backend path.\n *\n * Mirrors every case of DefaultFinalResourceDataPredicate in the same order.\n * The mapping from BFS predicate logic to backend filter conditions:\n *\n * BFS predicate always true\n * → no readyOrDuplicateOrError guard; backend stops traversal unconditionally.\n *\n * BFS predicate: readyOrDuplicateOrError(r)\n * → readyOrDuplicateOrError(): stops when resource_ready_for_calculation,\n * is_duplicate, or has_errors is true — exactly mirroring the BFS predicate.\n *\n * BFS predicate: readyAndHasAllOutputsFilled(r)\n * → isFinal(true) + allOutputsFinal(true).\n *\n * BFS predicate always false (UserProject, Projects, ClientRoot)\n * → no entry here; traversal always continues into them.\n */\nexport function projectTreeTraverseStopRules(): Filter {\n return treeFilter.or(\n // BFS: readyOrDuplicateOrError(r) AND (fields===undefined OR error OR stream.value===downloadable.value).\n // datactl sets stream field to point at the same resource as downloadable once processing\n // is complete, so stream.value===downloadable.value is the \"done\" signal.\n treeFilter.and(\n treeFilter.resourceTypeEq(ResourceTypeName.StreamManager),\n treeFilter.readyOrDuplicateOrError(),\n ),\n // BFS: readyOrDuplicateOrError(r)\n treeFilter.and(\n treeFilter.resourceTypeEq(ResourceTypeName.StdMap),\n treeFilter.readyOrDuplicateOrError(),\n ),\n treeFilter.and(\n treeFilter.resourceTypeEq(ResourceTypeName.StdMapSlash),\n treeFilter.readyOrDuplicateOrError(),\n ),\n treeFilter.and(\n treeFilter.resourceTypeEq(ResourceTypeName.EphStdMap),\n treeFilter.readyOrDuplicateOrError(),\n ),\n treeFilter.and(\n treeFilter.resourceTypeEq(ResourceTypeName.PFrame),\n treeFilter.readyOrDuplicateOrError(),\n ),\n treeFilter.and(\n treeFilter.resourceTypeEq(ResourceTypeName.ParquetChunk),\n treeFilter.readyOrDuplicateOrError(),\n ),\n treeFilter.and(\n treeFilter.resourceTypeEq(ResourceTypeName.BContext),\n treeFilter.readyOrDuplicateOrError(),\n ),\n treeFilter.and(\n treeFilter.resourceTypeEq(ResourceTypeName.BlockPackCustom),\n treeFilter.readyOrDuplicateOrError(),\n ),\n treeFilter.and(\n treeFilter.resourceTypeEq(ResourceTypeName.BinaryMap),\n treeFilter.readyOrDuplicateOrError(),\n ),\n treeFilter.and(\n treeFilter.resourceTypeEq(ResourceTypeName.BinaryValue),\n treeFilter.readyOrDuplicateOrError(),\n ),\n treeFilter.and(\n treeFilter.resourceTypeEq(ResourceTypeName.BlobMap),\n treeFilter.readyOrDuplicateOrError(),\n ),\n treeFilter.and(\n treeFilter.resourceTypeEq(ResourceTypeName.BResolveSingle),\n treeFilter.readyOrDuplicateOrError(),\n ),\n treeFilter.and(\n treeFilter.resourceTypeEq(ResourceTypeName.BResolveSingleNoResult),\n treeFilter.readyOrDuplicateOrError(),\n ),\n treeFilter.and(\n treeFilter.resourceTypeEq(ResourceTypeName.BQueryResult),\n treeFilter.readyOrDuplicateOrError(),\n ),\n treeFilter.and(\n treeFilter.resourceTypeEq(ResourceTypeName.TengoTemplate),\n treeFilter.readyOrDuplicateOrError(),\n ),\n treeFilter.and(\n treeFilter.resourceTypeEq(ResourceTypeName.TengoLib),\n treeFilter.readyOrDuplicateOrError(),\n ),\n treeFilter.and(\n treeFilter.resourceTypeEq(ResourceTypeName.SoftwareInfo),\n treeFilter.readyOrDuplicateOrError(),\n ),\n treeFilter.and(\n treeFilter.resourceTypeEq(ResourceTypeName.Dummy),\n treeFilter.readyOrDuplicateOrError(),\n ),\n // BFS: r.type.version === \"1\" → always true → no state guard needed\n treeFilter.resourceTypeEq(ResourceTypeName.JsonResourceError),\n // BFS: return true (unconditionally) → no readyOrDuplicateOrError guard needed\n treeFilter.resourceTypeEq(ResourceTypeName.JsonObject),\n treeFilter.resourceTypeEq(ResourceTypeName.JsonGzObject),\n treeFilter.resourceTypeEq(ResourceTypeName.JsonString),\n treeFilter.resourceTypeEq(ResourceTypeName.JsonArray),\n treeFilter.resourceTypeEq(ResourceTypeName.JsonNumber),\n treeFilter.resourceTypeEq(ResourceTypeName.BContextEnd),\n treeFilter.resourceTypeEq(ResourceTypeName.FrontendFromUrl),\n treeFilter.resourceTypeEq(ResourceTypeName.FrontendFromFolder),\n treeFilter.resourceTypeEq(ResourceTypeName.BObjectSpec),\n treeFilter.resourceTypeEq(ResourceTypeName.Blob),\n treeFilter.resourceTypeEq(ResourceTypeName.Null),\n treeFilter.resourceTypeEq(ResourceTypeName.Binary),\n treeFilter.resourceTypeEq(ResourceTypeName.LSProvider),\n treeFilter.resourceTypeEq(ResourceTypeName.WorkingDirectory),\n // BFS default branch: startsWith prefix → return true → no guard needed\n treeFilter.resourceTypeMatch(\"^\" + ResourceTypePrefix.Blob),\n treeFilter.resourceTypeMatch(\"^\" + ResourceTypePrefix.LS),\n treeFilter.resourceTypeMatch(\"^\" + ResourceTypePrefix.WorkingDirectory),\n treeFilter.resourceTypeMatch(\"^\" + ResourceTypePrefix.StorageSpaceAllocation),\n // BFS default branch: readyAndHasAllOutputsFilled → readyOrDuplicateOrError() + outputsLocked(true) + allOutputsFinal(true)\n treeFilter.and(\n treeFilter.resourceTypeMatch(\"^\" + ResourceTypePrefix.BlobUpload),\n treeFilter.readyOrDuplicateOrError(),\n treeFilter.outputsLocked(true),\n treeFilter.allOutputsFinal(true),\n ),\n treeFilter.and(\n treeFilter.resourceTypeMatch(\"^\" + ResourceTypePrefix.BlobIndex),\n treeFilter.readyOrDuplicateOrError(),\n treeFilter.outputsLocked(true),\n treeFilter.allOutputsFinal(true),\n ),\n // BFS default branch: readyOrDuplicateOrError\n treeFilter.and(\n treeFilter.resourceTypeMatch(\"^\" + ResourceTypePrefix.PColumnData),\n treeFilter.readyOrDuplicateOrError(),\n ),\n treeFilter.and(\n treeFilter.resourceTypeMatch(\"^\" + ResourceTypePrefix.StreamWorkdir),\n treeFilter.readyOrDuplicateOrError(),\n ),\n );\n}\n\n/** Returns true if sdk version of the block is old and we need to convert\n * ErrorLike errors to strings like it was.\n * We need it for keeping old blocks and new UI compatibility. */\nfunction shouldStillUseStringErrors(sdkVersion: string): boolean {\n return !isVersionGreater(sdkVersion, \"1.26.0\");\n}\n\n/** Checks if sdk version is greater that a target version. */\nfunction isVersionGreater(sdkVersion: string, targetVersion: string): boolean {\n const version = sdkVersion.split(\".\").map(Number);\n const target = targetVersion.split(\".\").map(Number);\n\n return (\n version[0] > target[0] ||\n (version[0] === target[0] && version[1] > target[1]) ||\n (version[0] === target[0] && version[1] === target[1] && version[2] > target[2])\n );\n}\n\n/** Converts ErrorLike errors to strings in the outputs like it was in old ML versions. */\nfunction convertErrorsToStrings(\n outputs: Record<string, ComputableValueOrErrors<unknown>>,\n): Record<string, ComputableValueOrErrors<unknown>> {\n const result: Record<string, ComputableValueOrErrors<unknown>> = {};\n for (const [key, val] of Object.entries(outputs)) {\n if (val.ok) {\n result[key] = val;\n continue;\n }\n\n result[key] = {\n ok: false,\n errors: val.errors.map((e) => {\n if (typeof e === \"string\") {\n return e;\n } else if (e.type == \"PlError\" && e.fullMessage !== undefined) {\n return e.fullMessage;\n }\n return e.message;\n }),\n moreErrors: val.moreErrors,\n };\n }\n\n return result;\n}\n\n/** Throws when the connected backend doesn't advertise every capability the\n * block-pack requires (as declared in `meta.requiredCapabilities`).\n *\n * The matching set is the desktop's install gate moved server-side so both\n * the UI (`AddBlockModal`) and direct middle-layer callers (the MCP server's\n * `add_block` tool, programmatic block installs, tests) reject incompatible\n * blocks consistently. */\nexport function throwIfMissingServerCapabilities(\n pl: PlClient,\n requiredCapabilities: readonly string[] | undefined,\n): void {\n if (!requiredCapabilities || requiredCapabilities.length === 0) return;\n const advertised = (pl.serverInfo.capabilities ?? []) as readonly string[];\n const filterFn = (c: string) => !advertised.includes(c);\n if (!requiredCapabilities.some(filterFn)) return;\n const missing = requiredCapabilities.filter(filterFn);\n throw new Error(\n `Block cannot be added: connected backend does not advertise capabilities ` +\n `${JSON.stringify(missing)}. ` +\n `Backend advertises ${JSON.stringify(advertised)}. ` +\n `Upgrade the backend or remove the requirement from the block manifest.`,\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"project.cjs","names":["NavigationStates","projectOverview","projectOverviewLight","activeConfigs","withProject","cacheBlockPackTemplate","BLOCK_STORAGE_FACADE_VERSION","withProjectAuthored","DefaultRetryOptions","projectFieldName","Pl","blockOutputs","Computable","getBlockParameters","frontendData","applyProjectMigrations","fs","SynchronizedTreeState","TreeStateUpdateError","treeFilter","ResourceTypeName","ResourceTypePrefix"],"sources":["../../src/middle_layer/project.ts"],"sourcesContent":["import type { MiddleLayerEnvironment } from \"./middle_layer\";\nimport type {\n FieldData,\n Filter,\n OptionalAnyResourceId,\n PlClient,\n SignedResourceId,\n} from \"@milaboratories/pl-client\";\nimport {\n DefaultRetryOptions,\n ensureSignedResourceIdNotNull,\n field,\n isNotFoundError,\n isPermissionDenied,\n isTimeoutOrCancelError,\n isUnauthenticated,\n parseSignedResourceId,\n Pl,\n resourceIdToString,\n ResourceTypeName,\n ResourceTypePrefix,\n treeFilter,\n} from \"@milaboratories/pl-client\";\nimport type { ComputableStableDefined, ComputableValueOrErrors } from \"@milaboratories/computable\";\nimport { Computable } from \"@milaboratories/computable\";\nimport { projectOverview } from \"./project_overview\";\nimport type { BlockPackSpecAny } from \"../model\";\nimport { randomUUID } from \"node:crypto\";\nimport { withProject, withProjectAuthored } from \"../mutator/project\";\nimport type { ExtendedResourceData, PruningFunction } from \"@milaboratories/pl-tree\";\nimport {\n SynchronizedTreeState,\n treeDumpStats,\n TreeStateUpdateError,\n} from \"@milaboratories/pl-tree\";\nimport type { TreeSnapshotStore } from \"./tree_snapshot_store\";\nimport { setTimeout } from \"node:timers/promises\";\nimport { frontendData } from \"./frontend_path\";\nimport type { NavigationState } from \"@milaboratories/pl-model-common\";\nimport { getBlockParameters, blockOutputs } from \"./block\";\nimport type { FrontendData } from \"../model/frontend\";\nimport type { ProjectId, ProjectStructure } from \"../model/project_model\";\nimport { projectFieldName } from \"../model/project_model\";\nimport {\n cachedDeserialize,\n notEmpty,\n type MiLogger,\n createInfiniteRetryState,\n nextInfiniteRetryState,\n type InfiniteRetryState,\n} from \"@milaboratories/ts-helpers\";\nimport type { BlockPackInfo } from \"../model/block_pack\";\nimport type {\n ProjectOverview,\n AuthorMarker,\n BlockSettings,\n BlockStateInternalV3,\n} from \"@milaboratories/pl-model-middle-layer\";\nimport { activeConfigs } from \"./active_cfg\";\nimport { NavigationStates } from \"./navigation_states\";\nimport { extractConfig, BLOCK_STORAGE_FACADE_VERSION } from \"@platforma-sdk/model\";\nimport fs from \"node:fs/promises\";\nimport canonicalize from \"canonicalize\";\nimport type { ProjectOverviewLight } from \"./project_overview_light\";\nimport { projectOverviewLight } from \"./project_overview_light\";\nimport { applyProjectMigrations } from \"../mutator/migration\";\nimport { cacheBlockPackTemplate } from \"../mutator/template/template_cache\";\n\ntype BlockStateComputables = {\n readonly fullState: Computable<BlockStateInternalV3>;\n};\n\nfunction stringifyForDump(object: unknown): string {\n return JSON.stringify(object, (key, value) => {\n if (typeof value === \"bigint\") return resourceIdToString(value as OptionalAnyResourceId);\n else if (\n ArrayBuffer.isView(value) ||\n value instanceof Int8Array ||\n value instanceof Uint8Array ||\n value instanceof Uint8ClampedArray ||\n value instanceof Int16Array ||\n value instanceof Uint16Array ||\n value instanceof Int32Array ||\n value instanceof Uint32Array ||\n value instanceof Float32Array ||\n value instanceof Float64Array ||\n value instanceof BigInt64Array ||\n value instanceof BigUint64Array\n )\n return Buffer.from(value.buffer, value.byteOffset, value.byteLength).toString(\"base64\");\n else if (Buffer.isBuffer(value)) return value.toString(\"base64\");\n\n return value;\n });\n}\n\n/** Data access object, to manipulate and read single opened (!) project data. */\nexport class Project {\n /** Data for the left panel, contain basic information about block status. */\n public readonly overview: ComputableStableDefined<ProjectOverview>;\n private readonly overviewLight: Computable<ProjectOverviewLight>;\n\n private readonly navigationStates = new NavigationStates();\n // null is set for deleted blocks\n private readonly blockComputables = new Map<string, BlockStateComputables | null>();\n\n private readonly blockFrontends = new Map<string, ComputableStableDefined<FrontendData>>();\n private readonly activeConfigs: Computable<unknown[]>;\n private readonly refreshLoopResult: Promise<void>;\n\n private readonly abortController = new AbortController();\n\n /** Tree change generation as of the snapshot currently on disk, or -1 when this session has\n * not written one. Compared against the tree's current generation to skip writing a mirror\n * that has not moved, which is what makes a project left open and idle go quiet. */\n private snapshotGeneration: number;\n\n /** When a snapshot was last attempted, for the periodic write's wall-clock gate.\n *\n * Zero, not the construction time, so the first write lands on the first maintenance pass\n * after the tree has settled rather than a full interval later. Sessions shorter than one\n * interval are the common case for a desktop app that is quit with a project still open, and\n * seeding this to now would leave every one of them with nothing on disk. Set on every\n * attempt, successful or not, so a persistently failing write retries at the interval rather\n * than on every pass of the loop. */\n private lastSnapshotAt = 0;\n\n private get destroyed() {\n return this.abortController.signal.aborted;\n }\n\n constructor(\n private readonly env: MiddleLayerEnvironment,\n public readonly id: ProjectId /* Project ID, exposed to outer consumers, who work with ML */,\n readonly rid: SignedResourceId /* Contains signature, not exposed outside middle layer. */,\n private readonly projectTree: SynchronizedTreeState,\n /** Whether this tree was seeded from a snapshot. When it was, the file on disk already\n * holds generation 0, so an idle warm reopen writes nothing at all. */\n restoredFromSnapshot: boolean = false,\n ) {\n this.snapshotGeneration = restoredFromSnapshot ? 0 : -1;\n this.overview = projectOverview(\n projectTree.entry(),\n this.navigationStates,\n env,\n ).withPreCalculatedValueTree();\n this.overviewLight = projectOverviewLight(projectTree.entry()).withPreCalculatedValueTree();\n this.refreshLoopResult = this.refreshLoop();\n this.refreshLoopResult.catch((err) => {\n env.logger.warn(new Error(\"Error during refresh loop\", { cause: err })); // TODO (safe voiding for now)\n });\n this.activeConfigs = activeConfigs(projectTree.entry(), env);\n }\n\n get projectLockId(): string {\n return \"project:\" + this.id.toString();\n }\n\n /**\n * Periodic snapshot write, carried on the maintenance loop rather than a timer of its own.\n *\n * Gated on the tree having changed since the last snapshot, so a project left open and idle\n * writes once and then goes quiet, and on wall clock, so a project changing continuously\n * writes at most once per interval.\n */\n private async maybeWriteSnapshot(): Promise<void> {\n const store = this.env.treeSnapshots;\n if (store === undefined) return;\n\n const generation = this.projectTree.changeGeneration;\n if (generation === this.snapshotGeneration) return;\n if (Date.now() - this.lastSnapshotAt < this.env.ops.treeSnapshotOps.writeInterval) return;\n\n await this.writeSnapshot(store, generation);\n }\n\n /**\n * Starts the close-boundary snapshot and returns without waiting for the write.\n *\n * On top of the periodic write, since closing is a natural point to persist. Change-gated but\n * not interval-gated: rewriting a mirror that has not moved is pure waste, but a mirror that\n * has moved is worth keeping however recently the last write happened.\n *\n * The **capture is synchronous and happens here**, before the caller destroys the tree,\n * because destroying it invalidates it and a later capture would be refused. Only the encode\n * and the write are deferred: they are up to ten megabytes of work, and project switching\n * should not wait for them. Deferring is safe only because a capture is a copy rather than a\n * view of the tree.\n *\n * The returned promise never rejects. The caller is expected to keep it so it can be drained\n * at shutdown, not to await it here.\n */\n public snapshotOnClose(): Promise<void> {\n const store = this.env.treeSnapshots;\n if (store === undefined) return Promise.resolve();\n\n const generation = this.projectTree.changeGeneration;\n if (generation === this.snapshotGeneration) return Promise.resolve();\n\n let snapshot;\n try {\n snapshot = this.projectTree.capture(parseSignedResourceId(this.rid).signature);\n } catch (e: unknown) {\n this.env.logger.warn(\n new Error(`failed to capture tree snapshot for project ${this.id} on close`, { cause: e }),\n );\n return Promise.resolve();\n }\n\n this.lastSnapshotAt = Date.now();\n\n // Queued behind any in-flight periodic write rather than racing it. Both would land\n // atomically, but the loser would be a wasted encode of the same mirror.\n const previous = this.snapshotInFlight ?? Promise.resolve();\n const write = previous.then(async () => {\n if (this.snapshotGeneration >= generation) return; // the in-flight write covered it\n if (await store.write(this.rid, snapshot)) this.snapshotGeneration = generation;\n });\n\n this.snapshotInFlight = write.finally(() => {\n this.snapshotInFlight = undefined;\n });\n return this.snapshotInFlight;\n }\n\n /** In-flight snapshot write, if any. Both triggers can fire close together (the close write\n * lands while the loop is mid-write), and encoding ten megabytes twice for the same mirror\n * is worth avoiding. */\n private snapshotInFlight: Promise<void> | undefined;\n\n /** Serializes writes, and skips one that the in-flight write has already made redundant. */\n private async writeSnapshot(store: TreeSnapshotStore, generation: number): Promise<void> {\n // A loop, not a single check: with three or more callers, re-checking only once would let\n // a waiter install its own promise over another's and clear the field while that write is\n // still running. Two callers is the most that can happen today, so this is a guard against\n // the next caller rather than a live fix.\n while (this.snapshotInFlight !== undefined) {\n await this.snapshotInFlight;\n if (this.snapshotGeneration >= generation) return;\n }\n\n this.snapshotInFlight = this.captureAndWrite(store, generation).finally(() => {\n this.snapshotInFlight = undefined;\n });\n await this.snapshotInFlight;\n }\n\n /** Captures and writes, never throwing: a snapshot is an optimisation and must not fail\n * whatever triggered it. */\n private async captureAndWrite(store: TreeSnapshotStore, generation: number): Promise<void> {\n // Recorded before the attempt and regardless of its outcome, so a failing disk is retried\n // once per interval instead of on every pass of the maintenance loop.\n this.lastSnapshotAt = Date.now();\n try {\n // The root's signature is the session witness a later open compares against.\n const snapshot = this.projectTree.capture(parseSignedResourceId(this.rid).signature);\n\n // Only a real write advances the change gate. Marking the generation persisted after a\n // failed write would tell both triggers the tree is already on disk, so one transient\n // I/O error would cost the rest of the session, close write included.\n if (await store.write(this.rid, snapshot)) this.snapshotGeneration = generation;\n } catch (e: unknown) {\n this.env.logger.warn(\n new Error(`failed to capture tree snapshot for project ${this.id}`, { cause: e }),\n );\n }\n }\n\n private async refreshLoop(): Promise<void> {\n let retryState: InfiniteRetryState | undefined;\n while (!this.destroyed) {\n try {\n await withProject(\n this.env.projectHelper,\n this.env.pl,\n this.rid,\n (prj) => {\n prj.doRefresh();\n },\n { name: \"doRefresh\", lockId: this.projectLockId },\n );\n await this.activeConfigs.getValue();\n await setTimeout(this.env.ops.projectRefreshInterval, undefined, {\n signal: this.abortController.signal,\n });\n\n await this.maybeWriteSnapshot();\n\n // Block computables housekeeping\n const overviewLight = await this.overviewLight.getValue();\n const existingBlocks = new Set(overviewLight.listOfBlocks);\n // Doing cleanup for deleted blocks\n for (const blockId of this.blockComputables.keys()) {\n if (!existingBlocks.has(blockId)) {\n const computable = this.blockComputables.get(blockId);\n if (computable !== undefined && computable !== null) computable.fullState.resetState();\n this.blockComputables.set(blockId, null);\n }\n }\n retryState = undefined;\n } catch (e: unknown) {\n // If we're destroyed, exit gracefully regardless of error type\n if (this.destroyed) break;\n\n if (isNotFoundError(e)) {\n this.env.logger.warn(\n \"project refresh routine terminated, because project was externally deleted\",\n );\n break;\n } else if (isTimeoutOrCancelError(e)) {\n // Timeout during normal operation, continue the loop\n } else {\n retryState = retryState\n ? nextInfiniteRetryState(retryState)\n : createInfiniteRetryState({\n type: \"exponentialWithMaxDelayBackoff\",\n initialDelay: 1000,\n maxDelay: 60_000,\n backoffMultiplier: 2,\n jitter: 0,\n });\n this.env.logger.error(\n new Error(`[refreshLoop] unexpected exception, retrying in ${retryState.nextDelay}ms`, {\n cause: e,\n }),\n );\n try {\n await setTimeout(retryState.nextDelay, undefined, {\n signal: this.abortController.signal,\n });\n } catch {\n // Aborted during retry delay, will exit via while condition or destroyed check\n break;\n }\n }\n }\n }\n }\n\n /**\n * Adds new block to the project.\n *\n * @param blockLabel block label / title visible to the user\n * @param blockPackSpec object describing the \"block type\", read more in the type docs\n * @param before id of the block to insert new block before\n * @param blockId internal id to be assigned for the block, this arg can be omitted\n * then, randomly generated UUID will be assigned automatically\n *\n * @return returns newly created block id\n * */\n public async addBlock(\n blockLabel: string,\n blockPackSpec: BlockPackSpecAny,\n before?: string,\n author: AuthorMarker | undefined = undefined,\n blockId: string = randomUUID(),\n ): Promise<string> {\n const preparedBp = await this.env.bpPreparer.prepare(blockPackSpec);\n const blockCfg = extractConfig(preparedBp.config);\n\n this.env.runtimeCapabilities.throwIfIncompatible(blockCfg.featureFlags);\n throwIfMissingServerCapabilities(this.env.pl, preparedBp.requiredCapabilities);\n\n // Pre-materialize template via cache (separate transaction(s))\n const cachedBp = await cacheBlockPackTemplate(this.env.pl, preparedBp);\n\n // Build NewBlockSpec based on model API version\n const newBlockSpec =\n blockCfg.modelAPIVersion === BLOCK_STORAGE_FACADE_VERSION\n ? { storageMode: \"fromModel\" as const, blockPack: cachedBp }\n : {\n storageMode: \"legacy\" as const,\n blockPack: cachedBp,\n legacyState: canonicalize({\n args: blockCfg.initialArgs,\n uiState: blockCfg.initialUiState,\n })!,\n };\n\n await withProjectAuthored(\n this.env.projectHelper,\n this.env.pl,\n this.rid,\n author,\n (mut) => {\n return mut.addBlock(\n {\n id: blockId,\n label: blockLabel,\n renderingMode: blockCfg.renderingMode,\n },\n newBlockSpec,\n before,\n );\n },\n {\n retryOptions: {\n ...DefaultRetryOptions,\n backoffMultiplier: DefaultRetryOptions.backoffMultiplier * 1.1,\n },\n name: \"addBlock\",\n lockId: this.projectLockId,\n },\n );\n\n await this.projectTree.refreshState();\n\n return blockId;\n }\n\n /**\n * Duplicates an existing block by copying all its fields and state.\n * This method works at the mutator level for efficient block copying.\n *\n * @param originalBlockId id of the block to duplicate\n * @param before id of the block to insert new block before\n * @param author author marker for the duplication operation\n * @param newBlockId internal id to be assigned for the duplicated block,\n * if omitted, a randomly generated UUID will be assigned\n *\n * @return returns newly created block id\n * */\n public async duplicateBlock(\n originalBlockId: string,\n before?: string,\n author: AuthorMarker | undefined = undefined,\n newBlockId: string = randomUUID(),\n ): Promise<string> {\n await withProjectAuthored(\n this.env.projectHelper,\n this.env.pl,\n this.rid,\n author,\n (mut) => mut.duplicateBlock(originalBlockId, newBlockId, before),\n { name: \"duplicateBlock\", lockId: this.projectLockId },\n );\n await this.projectTree.refreshState();\n\n return newBlockId;\n }\n\n /**\n * Update block to new block pack, optionally resetting args and ui state to\n * initial values\n * */\n public async updateBlockPack(\n blockId: string,\n blockPackSpec: BlockPackSpecAny,\n resetArgs: boolean = false,\n author?: AuthorMarker,\n ): Promise<void> {\n const preparedBp = await this.env.bpPreparer.prepare(blockPackSpec);\n const blockCfg = extractConfig(preparedBp.config);\n\n this.env.runtimeCapabilities.throwIfIncompatible(blockCfg.featureFlags);\n throwIfMissingServerCapabilities(this.env.pl, preparedBp.requiredCapabilities);\n\n // Pre-materialize template via cache (separate transaction(s))\n const cachedBp = await cacheBlockPackTemplate(this.env.pl, preparedBp);\n\n // resetState signals to mutator to reset storage\n // For v2+ blocks: mutator gets initial storage directly via getInitialStorageInVM\n // For v1 blocks: we pass the legacy state format\n const resetState = resetArgs\n ? {\n state:\n blockCfg.modelAPIVersion === 1\n ? { args: blockCfg.initialArgs, uiState: blockCfg.initialUiState }\n : {},\n }\n : undefined;\n await withProjectAuthored(\n this.env.projectHelper,\n this.env.pl,\n this.rid,\n author,\n (mut) => mut.migrateBlockPack(blockId, cachedBp, resetState),\n { name: \"updateBlockPack\", lockId: this.projectLockId },\n );\n await this.projectTree.refreshState();\n }\n\n /** Deletes a block with all associated data. */\n public async deleteBlock(blockId: string, author?: AuthorMarker): Promise<void> {\n await withProjectAuthored(\n this.env.projectHelper,\n this.env.pl,\n this.rid,\n author,\n (mut) => mut.deleteBlock(blockId),\n { name: \"deleteBlock\", lockId: this.projectLockId },\n );\n this.navigationStates.deleteBlock(blockId);\n await this.projectTree.refreshState();\n }\n\n /**\n * Updates block order according to the given array of block ids.\n *\n * Provided array must contain exactly the same set of ids current project cosists of,\n * an error will be thrown instead.\n */\n public async reorderBlocks(blocks: string[], author?: AuthorMarker): Promise<void> {\n await withProjectAuthored(\n this.env.projectHelper,\n this.env.pl,\n this.rid,\n author,\n (mut) => {\n const currentStructure = mut.structure;\n if (currentStructure.groups.length !== 1)\n throw new Error(\"Unexpected project structure, non-singular block group\");\n const currentGroup = currentStructure.groups[0];\n if (currentGroup.blocks.length !== blocks.length)\n throw new Error(`Length mismatch: ${currentGroup.blocks.length} !== ${blocks.length}`);\n if (new Set<string>(blocks).size !== blocks.length) throw new Error(`Repeated block ids`);\n const newStructure: ProjectStructure = {\n groups: [\n {\n id: currentGroup.id,\n label: currentGroup.label,\n blocks: blocks.map((blockId) => {\n const block = currentGroup.blocks.find((b) => b.id === blockId);\n if (block === undefined) throw new Error(`Can't find block: ${blockId}`);\n return block;\n }),\n },\n ],\n };\n mut.updateStructure(newStructure);\n },\n { name: \"reorderBlocks\", lockId: this.projectLockId },\n );\n await this.projectTree.refreshState();\n }\n\n /**\n * Renders production part of the block starting all connected heavy computations.\n * Upstream blocks of the specified block will be started automatically if in\n * stale state.\n * */\n public async runBlock(blockId: string): Promise<void> {\n await withProject(\n this.env.projectHelper,\n this.env.pl,\n this.rid,\n (mut) => mut.renderProduction([blockId], true),\n { name: \"runBlock\", lockId: this.projectLockId },\n );\n await this.projectTree.refreshState();\n }\n\n /**\n * Stops the block if it is running by destroying its production state. All\n * its downstreams will also be destroyed or moved to limbo if already\n * calculated.\n * */\n public async stopBlock(blockId: string): Promise<void> {\n await withProject(\n this.env.projectHelper,\n this.env.pl,\n this.rid,\n (mut) => mut.stopProduction(blockId),\n { name: \"stopBlock\", lockId: this.projectLockId },\n );\n await this.projectTree.refreshState();\n }\n\n /**\n * @deprecated Use mutateBlockStorage() for V3 blocks.\n * Sets block args, and changes whole project state accordingly.\n * Along with setting arguments one can specify author marker, that will be\n * transactionally associated with the block, to facilitate conflict resolution\n * in collaborative editing scenario.\n * */\n public async setBlockArgs(blockId: string, args: unknown, author?: AuthorMarker) {\n await withProjectAuthored(\n this.env.projectHelper,\n this.env.pl,\n this.rid,\n author,\n (mut) => {\n const state = mut.mergeBlockState(blockId, { args });\n mut.setStates([{ modelAPIVersion: 1, blockId, state }]);\n },\n { name: \"setBlockArgs\", lockId: this.projectLockId },\n );\n await this.projectTree.refreshState();\n }\n\n /**\n * @deprecated Use mutateBlockStorage() for V3 blocks.\n * Sets ui block state associated with the block.\n * Along with setting arguments one can specify author marker, that will be\n * transactionally associated with the block, to facilitate conflict resolution\n * in collaborative editing scenario.\n * */\n public async setUiState(blockId: string, uiState: unknown, author?: AuthorMarker) {\n await withProjectAuthored(\n this.env.projectHelper,\n this.env.pl,\n this.rid,\n author,\n (mut) => {\n const state = mut.mergeBlockState(blockId, { uiState });\n mut.setStates([{ modelAPIVersion: 1, blockId, state }]);\n },\n { name: \"setUiState\", lockId: this.projectLockId },\n );\n await this.projectTree.refreshState();\n }\n\n /**\n * @deprecated Use mutateBlockStorage() for V3 blocks.\n * Sets block args and ui state, and changes the whole project state accordingly.\n * Along with setting arguments one can specify author marker, that will be\n * transactionally associated with the block, to facilitate conflict resolution\n * in collaborative editing scenario.\n * */\n public async setBlockArgsAndUiState(\n blockId: string,\n args: unknown, // keep for v1/v2 compatibility\n uiState: unknown, // keep for v1/v2 compatibility\n author?: AuthorMarker,\n ) {\n // Normalize to unified state format { args, uiState } for v1/v2 blocks\n const state = { args, uiState };\n await withProjectAuthored(\n this.env.projectHelper,\n this.env.pl,\n this.rid,\n author,\n (mut) => {\n mut.setStates([{ modelAPIVersion: 1, blockId, state }]);\n },\n { name: \"setBlockArgsAndUiState\", lockId: this.projectLockId },\n );\n await this.projectTree.refreshState();\n }\n\n /**\n * Sets navigation state.\n * */\n //\n public async setNavigationState(blockId: string, state: NavigationState): Promise<void> {\n this.navigationStates.setState(blockId, state);\n }\n\n /**\n * Mutates block storage for Model API v3 blocks.\n * Applies a storage operation (e.g., 'update-data') which triggers\n * args derivation (args(data) and prerunArgs(data)).\n * The derived args are stored atomically with the data.\n *\n * @param blockId - The block ID\n * @param payload - Storage mutation payload with operation and value\n * @param author - Optional author marker for collaborative editing\n */\n public async mutateBlockStorage(\n blockId: string,\n payload: { operation: string; value: unknown },\n author?: AuthorMarker,\n ) {\n await withProjectAuthored(\n this.env.projectHelper,\n this.env.pl,\n this.rid,\n author,\n (mut) => mut.setStates([{ modelAPIVersion: 2, blockId, payload }]),\n { name: \"mutateBlockStorage\", lockId: this.projectLockId },\n );\n await this.projectTree.refreshState();\n }\n\n /** Update block settings */\n public async setBlockSettings(blockId: string, newValue: BlockSettings) {\n await withProjectAuthored(\n this.env.projectHelper,\n this.env.pl,\n this.rid,\n undefined,\n (mut) => {\n mut.setBlockSettings(blockId, newValue);\n },\n { name: \"setBlockSettings\" },\n );\n await this.projectTree.refreshState();\n }\n\n /**\n * Sets raw block storage content directly.\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 async setBlockStorageRaw(blockId: string, rawStorageJson: string): Promise<void> {\n await withProjectAuthored(\n this.env.projectHelper,\n this.env.pl,\n this.rid,\n undefined,\n (mut) => {\n mut.setBlockStorageRaw(blockId, rawStorageJson);\n },\n { name: \"setBlockStorageRaw\" },\n );\n await this.projectTree.refreshState();\n }\n\n /** Resets arguments and ui state of the block to initial state */\n public async resetBlockArgsAndUiState(blockId: string, author?: AuthorMarker): Promise<void> {\n await this.env.pl.withWriteTx(\"BlockInputsReset\", async (tx) => {\n // reading default arg values from block pack\n const bpHolderRid = ensureSignedResourceIdNotNull(\n (await tx.getField(field(this.rid, projectFieldName(blockId, \"blockPack\")))).value,\n );\n const bpRid = ensureSignedResourceIdNotNull(\n (await tx.getField(field(bpHolderRid, Pl.HolderRefField))).value,\n );\n const bpData = await tx.getResourceData(bpRid, false);\n const config = extractConfig(cachedDeserialize<BlockPackInfo>(notEmpty(bpData.data)).config);\n\n await withProjectAuthored(\n this.env.projectHelper,\n tx,\n this.rid,\n author,\n (prj) => {\n if (config.modelAPIVersion === BLOCK_STORAGE_FACADE_VERSION) {\n // V2+: Reset to initial storage via VM\n prj.resetToInitialStorage(blockId);\n } else {\n // V1: Use legacy state format\n const initialState = { args: config.initialArgs, uiState: config.initialUiState };\n prj.setStates([{ modelAPIVersion: 1, blockId, state: initialState }]);\n }\n },\n { name: \"resetBlockArgsAndUiState\", lockId: this.projectLockId },\n );\n await tx.commit();\n });\n await this.projectTree.refreshState();\n }\n\n private getBlockComputables(blockId: string): BlockStateComputables {\n const cached = this.blockComputables.get(blockId);\n if (cached === null) throw new Error(`Block ${blockId} is deleted`);\n if (cached === undefined) {\n // state consists of inputs (args + ui state) and outputs\n const outputs = blockOutputs(this.projectTree.entry(), blockId, this.env);\n const fullState = Computable.make(\n (ctx) => {\n return {\n parameters: getBlockParameters(this.projectTree.entry(), blockId, ctx),\n outputs,\n navigationState: this.navigationStates.getState(blockId),\n overview: this.overview,\n };\n },\n {\n postprocessValue: (v) => {\n const blockOverview = v.overview?.blocks?.find((b) => b.id == blockId);\n const sdkVersion = blockOverview?.sdkVersion;\n const storageDebugView = blockOverview?.storageDebugView;\n const toString = sdkVersion && shouldStillUseStringErrors(sdkVersion);\n const newOutputs =\n toString && v.outputs !== undefined ? convertErrorsToStrings(v.outputs) : v.outputs;\n\n return {\n ...v.parameters,\n outputs: newOutputs,\n navigationState: v.navigationState,\n storageDebugView,\n } as BlockStateInternalV3;\n },\n },\n );\n\n const computables: BlockStateComputables = {\n fullState: fullState.withPreCalculatedValueTree(),\n };\n\n this.blockComputables.set(blockId, computables);\n\n return computables;\n }\n return cached;\n }\n\n /**\n * Returns a computable, that can be used to retrieve and watch full block state,\n * including outputs, arguments, ui state.\n * */\n public getBlockState(blockId: string): Computable<BlockStateInternalV3> {\n return this.getBlockComputables(blockId).fullState;\n }\n\n /**\n * Returns a computable, that can be used to retrieve and watch path of the\n * folder containing frontend code.\n * */\n public getBlockFrontend(blockId: string): ComputableStableDefined<FrontendData> {\n const cached = this.blockFrontends.get(blockId);\n if (cached === undefined) {\n const fd = frontendData(\n this.projectTree.entry(),\n blockId,\n this.env,\n ).withPreCalculatedValueTree();\n this.blockFrontends.set(blockId, fd);\n return fd;\n }\n return cached;\n }\n\n /** Called by middle layer on close */\n public async destroy(): Promise<void> {\n // terminating the project service loop\n this.abortController.abort();\n try {\n await this.refreshLoopResult;\n } catch (e: unknown) {\n // Error was already logged in the constructor's catch handler, but log again for context\n this.env.logger.warn(\n new Error(\"Refresh loop had terminated with error before destroy\", { cause: e }),\n );\n }\n\n // terminating the synchronized project tree\n try {\n await this.projectTree.terminate();\n } catch (e: unknown) {\n // TODO: SynchronizedTreeState.terminate() can throw if mainLoop had an error before termination\n // Log error but continue cleanup - we must clean up remaining resources\n this.env.logger.warn(new Error(\"Project tree termination failed\", { cause: e }));\n }\n\n // the following will deregister all external resource holders, like\n // downloaded files, running uploads and alike\n this.overview.resetState();\n this.blockFrontends.forEach((c) => c.resetState());\n this.blockComputables.forEach((c) => {\n if (c !== null) c.fullState.resetState();\n });\n this.activeConfigs.resetState();\n }\n\n /** @deprecated */\n public async destroyAndAwaitTermination(): Promise<void> {\n await this.destroy();\n }\n\n public dumpState(): ExtendedResourceData[] {\n return this.projectTree.dumpState();\n }\n\n public static async init(\n env: MiddleLayerEnvironment,\n id: ProjectId,\n rid: SignedResourceId,\n ): Promise<Project> {\n // Applying migrations to the project resource, if needed\n await applyProjectMigrations(env.pl, rid);\n\n // Doing a no-op mutation to apply all migration and schema fixes\n await withProject(env.projectHelper, env.pl, rid, (_) => {}, { name: \"init\" });\n\n // Loading project tree, warm from a persisted mirror when one is usable\n const { tree: projectTree, restored } = await loadProjectTree(env, rid);\n\n if (env.ops.debugOps.dumpInitialTreeState) {\n const state = projectTree.dumpState();\n state.sort((a, b) => (b.data?.byteLength ?? 0) - (a.data?.byteLength ?? 0));\n const stats = treeDumpStats(state);\n await fs.writeFile(`${resourceIdToString(rid)}.json`, stringifyForDump(state));\n await fs.writeFile(`${resourceIdToString(rid)}.stats.json`, stringifyForDump(stats));\n }\n\n return new Project(env, id, rid, projectTree, restored);\n }\n}\n\n/**\n * Opens the project tree, seeded from a persisted mirror when there is a usable one.\n *\n * Carries the fail-safe: if the restored tree fails its first refresh on authentication,\n * permission or an inconsistency, the snapshot is deleted and the open is retried cold. Once,\n * and only for that first refresh, so a genuinely dead session still surfaces as itself rather\n * than being masked as a slow open.\n *\n * The fail-safe is what bounds every case the cache key does not cover: a rotated master\n * secret, a revoked grant, a snapshot valid in itself but no longer matching what the backend\n * will serve. Without it, an explicit-root tree propagates the refresh failure rather than\n * healing, so the project would fail to open on every attempt until someone deleted the cache\n * directory by hand.\n */\nasync function loadProjectTree(\n env: MiddleLayerEnvironment,\n rid: SignedResourceId,\n): Promise<{ tree: SynchronizedTreeState; restored: boolean }> {\n const treeOps = {\n ...env.ops.defaultTreeOptions,\n pruning: projectTreePruning(env.logger),\n fieldFilter: projectTreeFieldFilter(),\n traverseStopRules: projectTreeTraverseStopRules(),\n };\n const cold = async () => ({\n tree: await SynchronizedTreeState.init(env.pl, rid, treeOps, env.logger),\n restored: false,\n });\n\n const store = env.treeSnapshots;\n if (store === undefined) return await cold();\n\n const snapshot = await store.read(rid);\n if (!snapshot.ok) {\n env.logger.info(`project tree opening cold, snapshot miss: ${snapshot.miss}`);\n return await cold();\n }\n\n try {\n const tree = await SynchronizedTreeState.init(\n env.pl,\n rid,\n { ...treeOps, restoreFrom: snapshot.tree },\n env.logger,\n );\n\n // Read from the tree rather than assumed: a snapshot can be handed over and still be\n // refused, in which case this open was cold and the file on disk does not describe the\n // tree we now hold.\n const restored = tree.wasRestoredFromSnapshot;\n if (restored) store.noteRestored();\n else env.logger.info(\"project tree opening cold: the snapshot was not applied\");\n\n return { tree, restored };\n } catch (e: unknown) {\n // Retry cold on ANY failure of the warm open, not only on the classified ones. A cold open\n // is exactly what this code did before snapshots existed, so the retry cannot regress\n // anything, whereas rethrowing here leaves a project that fails to open on every attempt\n // until someone deletes the cache directory by hand: the snapshot stays on disk and the\n // next open restores it and fails the same way. That is the outcome this fail-safe exists\n // to prevent, and the error classes that can reach here are not a closed set.\n env.logger.warn(\n new Error(\"restored project tree failed its first refresh, opening cold\", { cause: e }),\n );\n\n // Deleting is reserved for failures that implicate the snapshot itself. Anything else (a\n // timeout, a dropped connection) says nothing about the file, and throwing it away would\n // destroy a mirror that is still good, along with the evidence a later signature refresh\n // would repair.\n if (isSnapshotFailsafeError(e)) await store.discard(rid);\n\n return await cold();\n }\n}\n\n/** The failures that implicate the snapshot rather than the link or the session: a rotated\n * master secret, a revoked grant, or state the tree cannot reconcile. Only these delete the\n * file; every other failure still falls back to a cold open, it just keeps the file.\n *\n * The cause chain is walked because a wrapper anywhere between the tree update and here would\n * otherwise silently disarm the inconsistency arm. `isUnauthenticated` and `isPermissionDenied`\n * do their own one-level unwrapping. */\nexport function isSnapshotFailsafeError(e: unknown): boolean {\n if (isUnauthenticated(e) || isPermissionDenied(e)) return true;\n for (let cause: unknown = e, depth = 0; cause !== undefined && depth < 8; depth++) {\n if (cause instanceof TreeStateUpdateError) return true;\n cause = (cause as { cause?: unknown } | null)?.cause;\n }\n return false;\n}\n\nexport function projectTreePruning(logger: MiLogger): PruningFunction {\n return (r: ExtendedResourceData): FieldData[] => {\n if (r.fields.length > 1000)\n logger.warn(\n `resource with excessive field count: type=${r.type.name} id=${r.id} fields=${r.fields.length}` +\n ` names=[${r.fields\n .slice(0, 10)\n .map((f) => f.name)\n .join(\", \")}, ...]`,\n );\n if (r.type.name.startsWith(\"StreamWorkdir/\")) return [];\n switch (r.type.name) {\n case \"BlockPackCustom\":\n return r.fields.filter((f) => f.name !== \"template\");\n case \"UserProject\":\n return r.fields.filter((f) => !f.name.startsWith(\"__serviceTemplate\"));\n case \"Blob\":\n return [];\n default:\n return r.fields;\n }\n };\n}\n\n/** ResourceTree analogue of projectTreePruning() used by modern backend path. */\nexport function projectTreeFieldFilter(): Filter {\n return treeFilter.not(\n treeFilter.or(\n // StreamWorkdir/* — pruned entirely\n treeFilter.resourceTypeMatch(\"^StreamWorkdir/\"),\n // BlockPackCustom: drop `template`\n treeFilter.and(\n treeFilter.resourceTypeEq(\"BlockPackCustom\"),\n treeFilter.fieldNameEq(\"template\"),\n ),\n // UserProject: drop `__serviceTemplate*`\n treeFilter.and(\n treeFilter.resourceTypeEq(\"UserProject\"),\n treeFilter.fieldNameMatch(\"^__serviceTemplate\"),\n ),\n // Blob — pruned entirely\n treeFilter.resourceTypeEq(\"Blob\"),\n ),\n );\n}\n\n/**\n * Stop-rules for the ResourceTree backend path.\n *\n * Mirrors every case of DefaultFinalResourceDataPredicate in the same order.\n * The mapping from BFS predicate logic to backend filter conditions:\n *\n * BFS predicate always true\n * → no readyOrDuplicateOrError guard; backend stops traversal unconditionally.\n *\n * BFS predicate: readyOrDuplicateOrError(r)\n * → readyOrDuplicateOrError(): stops when resource_ready_for_calculation,\n * is_duplicate, or has_errors is true — exactly mirroring the BFS predicate.\n *\n * BFS predicate: readyAndHasAllOutputsFilled(r)\n * → isFinal(true) + allOutputsFinal(true).\n *\n * BFS predicate always false (UserProject, Projects, ClientRoot)\n * → no entry here; traversal always continues into them.\n */\nexport function projectTreeTraverseStopRules(): Filter {\n return treeFilter.or(\n // BFS: readyOrDuplicateOrError(r) AND (fields===undefined OR error OR stream.value===downloadable.value).\n // datactl sets stream field to point at the same resource as downloadable once processing\n // is complete, so stream.value===downloadable.value is the \"done\" signal.\n treeFilter.and(\n treeFilter.resourceTypeEq(ResourceTypeName.StreamManager),\n treeFilter.readyOrDuplicateOrError(),\n ),\n // BFS: readyOrDuplicateOrError(r)\n treeFilter.and(\n treeFilter.resourceTypeEq(ResourceTypeName.StdMap),\n treeFilter.readyOrDuplicateOrError(),\n ),\n treeFilter.and(\n treeFilter.resourceTypeEq(ResourceTypeName.StdMapSlash),\n treeFilter.readyOrDuplicateOrError(),\n ),\n treeFilter.and(\n treeFilter.resourceTypeEq(ResourceTypeName.EphStdMap),\n treeFilter.readyOrDuplicateOrError(),\n ),\n treeFilter.and(\n treeFilter.resourceTypeEq(ResourceTypeName.PFrame),\n treeFilter.readyOrDuplicateOrError(),\n ),\n treeFilter.and(\n treeFilter.resourceTypeEq(ResourceTypeName.ParquetChunk),\n treeFilter.readyOrDuplicateOrError(),\n ),\n treeFilter.and(\n treeFilter.resourceTypeEq(ResourceTypeName.BContext),\n treeFilter.readyOrDuplicateOrError(),\n ),\n treeFilter.and(\n treeFilter.resourceTypeEq(ResourceTypeName.BlockPackCustom),\n treeFilter.readyOrDuplicateOrError(),\n ),\n treeFilter.and(\n treeFilter.resourceTypeEq(ResourceTypeName.BinaryMap),\n treeFilter.readyOrDuplicateOrError(),\n ),\n treeFilter.and(\n treeFilter.resourceTypeEq(ResourceTypeName.BinaryValue),\n treeFilter.readyOrDuplicateOrError(),\n ),\n treeFilter.and(\n treeFilter.resourceTypeEq(ResourceTypeName.BlobMap),\n treeFilter.readyOrDuplicateOrError(),\n ),\n treeFilter.and(\n treeFilter.resourceTypeEq(ResourceTypeName.BResolveSingle),\n treeFilter.readyOrDuplicateOrError(),\n ),\n treeFilter.and(\n treeFilter.resourceTypeEq(ResourceTypeName.BResolveSingleNoResult),\n treeFilter.readyOrDuplicateOrError(),\n ),\n treeFilter.and(\n treeFilter.resourceTypeEq(ResourceTypeName.BQueryResult),\n treeFilter.readyOrDuplicateOrError(),\n ),\n treeFilter.and(\n treeFilter.resourceTypeEq(ResourceTypeName.TengoTemplate),\n treeFilter.readyOrDuplicateOrError(),\n ),\n treeFilter.and(\n treeFilter.resourceTypeEq(ResourceTypeName.TengoLib),\n treeFilter.readyOrDuplicateOrError(),\n ),\n treeFilter.and(\n treeFilter.resourceTypeEq(ResourceTypeName.SoftwareInfo),\n treeFilter.readyOrDuplicateOrError(),\n ),\n treeFilter.and(\n treeFilter.resourceTypeEq(ResourceTypeName.Dummy),\n treeFilter.readyOrDuplicateOrError(),\n ),\n // BFS: r.type.version === \"1\" → always true → no state guard needed\n treeFilter.resourceTypeEq(ResourceTypeName.JsonResourceError),\n // BFS: return true (unconditionally) → no readyOrDuplicateOrError guard needed\n treeFilter.resourceTypeEq(ResourceTypeName.JsonObject),\n treeFilter.resourceTypeEq(ResourceTypeName.JsonGzObject),\n treeFilter.resourceTypeEq(ResourceTypeName.JsonString),\n treeFilter.resourceTypeEq(ResourceTypeName.JsonArray),\n treeFilter.resourceTypeEq(ResourceTypeName.JsonNumber),\n treeFilter.resourceTypeEq(ResourceTypeName.BContextEnd),\n treeFilter.resourceTypeEq(ResourceTypeName.FrontendFromUrl),\n treeFilter.resourceTypeEq(ResourceTypeName.FrontendFromFolder),\n treeFilter.resourceTypeEq(ResourceTypeName.BObjectSpec),\n treeFilter.resourceTypeEq(ResourceTypeName.Blob),\n treeFilter.resourceTypeEq(ResourceTypeName.Null),\n treeFilter.resourceTypeEq(ResourceTypeName.Binary),\n treeFilter.resourceTypeEq(ResourceTypeName.LSProvider),\n treeFilter.resourceTypeEq(ResourceTypeName.WorkingDirectory),\n // BFS default branch: startsWith prefix → return true → no guard needed\n treeFilter.resourceTypeMatch(\"^\" + ResourceTypePrefix.Blob),\n treeFilter.resourceTypeMatch(\"^\" + ResourceTypePrefix.LS),\n treeFilter.resourceTypeMatch(\"^\" + ResourceTypePrefix.WorkingDirectory),\n treeFilter.resourceTypeMatch(\"^\" + ResourceTypePrefix.StorageSpaceAllocation),\n // BFS default branch: readyAndHasAllOutputsFilled → readyOrDuplicateOrError() + outputsLocked(true) + allOutputsFinal(true)\n treeFilter.and(\n treeFilter.resourceTypeMatch(\"^\" + ResourceTypePrefix.BlobUpload),\n treeFilter.readyOrDuplicateOrError(),\n treeFilter.outputsLocked(true),\n treeFilter.allOutputsFinal(true),\n ),\n treeFilter.and(\n treeFilter.resourceTypeMatch(\"^\" + ResourceTypePrefix.BlobIndex),\n treeFilter.readyOrDuplicateOrError(),\n treeFilter.outputsLocked(true),\n treeFilter.allOutputsFinal(true),\n ),\n // BFS default branch: readyOrDuplicateOrError\n treeFilter.and(\n treeFilter.resourceTypeMatch(\"^\" + ResourceTypePrefix.PColumnData),\n treeFilter.readyOrDuplicateOrError(),\n ),\n treeFilter.and(\n treeFilter.resourceTypeMatch(\"^\" + ResourceTypePrefix.StreamWorkdir),\n treeFilter.readyOrDuplicateOrError(),\n ),\n );\n}\n\n/** Returns true if sdk version of the block is old and we need to convert\n * ErrorLike errors to strings like it was.\n * We need it for keeping old blocks and new UI compatibility. */\nfunction shouldStillUseStringErrors(sdkVersion: string): boolean {\n return !isVersionGreater(sdkVersion, \"1.26.0\");\n}\n\n/** Checks if sdk version is greater that a target version. */\nfunction isVersionGreater(sdkVersion: string, targetVersion: string): boolean {\n const version = sdkVersion.split(\".\").map(Number);\n const target = targetVersion.split(\".\").map(Number);\n\n return (\n version[0] > target[0] ||\n (version[0] === target[0] && version[1] > target[1]) ||\n (version[0] === target[0] && version[1] === target[1] && version[2] > target[2])\n );\n}\n\n/** Converts ErrorLike errors to strings in the outputs like it was in old ML versions. */\nfunction convertErrorsToStrings(\n outputs: Record<string, ComputableValueOrErrors<unknown>>,\n): Record<string, ComputableValueOrErrors<unknown>> {\n const result: Record<string, ComputableValueOrErrors<unknown>> = {};\n for (const [key, val] of Object.entries(outputs)) {\n if (val.ok) {\n result[key] = val;\n continue;\n }\n\n result[key] = {\n ok: false,\n errors: val.errors.map((e) => {\n if (typeof e === \"string\") {\n return e;\n } else if (e.type == \"PlError\" && e.fullMessage !== undefined) {\n return e.fullMessage;\n }\n return e.message;\n }),\n moreErrors: val.moreErrors,\n };\n }\n\n return result;\n}\n\n/** Throws when the connected backend doesn't advertise every capability the\n * block-pack requires (as declared in `meta.requiredCapabilities`).\n *\n * The matching set is the desktop's install gate moved server-side so both\n * the UI (`AddBlockModal`) and direct middle-layer callers (the MCP server's\n * `add_block` tool, programmatic block installs, tests) reject incompatible\n * blocks consistently. */\nexport function throwIfMissingServerCapabilities(\n pl: PlClient,\n requiredCapabilities: readonly string[] | undefined,\n): void {\n if (!requiredCapabilities || requiredCapabilities.length === 0) return;\n const advertised = (pl.serverInfo.capabilities ?? []) as readonly string[];\n const filterFn = (c: string) => !advertised.includes(c);\n if (!requiredCapabilities.some(filterFn)) return;\n const missing = requiredCapabilities.filter(filterFn);\n throw new Error(\n `Block cannot be added: connected backend does not advertise capabilities ` +\n `${JSON.stringify(missing)}. ` +\n `Backend advertises ${JSON.stringify(advertised)}. ` +\n `Upgrade the backend or remove the requirement from the block manifest.`,\n );\n}\n"],"mappings":"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"}
@@ -1,5 +1,6 @@
1
1
  import { ProjectId as ProjectId$1 } from "../model/project_model.js";
2
2
  import { BlockPackSpecAny } from "../model/block_pack_spec.js";
3
+ import "../model/index.js";
3
4
  import { FrontendData } from "../model/frontend.js";
4
5
  import { MiddleLayerEnvironment } from "./middle_layer.js";
5
6
  import { AuthorMarker, BlockSettings, BlockStateInternalV3, ProjectOverview } from "@milaboratories/pl-model-middle-layer";
@@ -8,10 +9,9 @@ import { NavigationState } from "@milaboratories/pl-model-common";
8
9
  import { PlClient, SignedResourceId } from "@milaboratories/pl-client";
9
10
  import { ExtendedResourceData, SynchronizedTreeState } from "@milaboratories/pl-tree";
10
11
  import { Computable, ComputableStableDefined } from "@milaboratories/computable";
11
-
12
12
  //#region src/middle_layer/project.d.ts
13
13
  /** Data access object, to manipulate and read single opened (!) project data. */
14
- declare class Project {
14
+ export declare class Project {
15
15
  private readonly env;
16
16
  readonly id: ProjectId$1;
17
17
  readonly rid: SignedResourceId;
@@ -25,9 +25,59 @@ declare class Project {
25
25
  private readonly activeConfigs;
26
26
  private readonly refreshLoopResult;
27
27
  private readonly abortController;
28
+ /** Tree change generation as of the snapshot currently on disk, or -1 when this session has
29
+ * not written one. Compared against the tree's current generation to skip writing a mirror
30
+ * that has not moved, which is what makes a project left open and idle go quiet. */
31
+ private snapshotGeneration;
32
+ /** When a snapshot was last attempted, for the periodic write's wall-clock gate.
33
+ *
34
+ * Zero, not the construction time, so the first write lands on the first maintenance pass
35
+ * after the tree has settled rather than a full interval later. Sessions shorter than one
36
+ * interval are the common case for a desktop app that is quit with a project still open, and
37
+ * seeding this to now would leave every one of them with nothing on disk. Set on every
38
+ * attempt, successful or not, so a persistently failing write retries at the interval rather
39
+ * than on every pass of the loop. */
40
+ private lastSnapshotAt;
28
41
  private get destroyed();
29
- constructor(env: MiddleLayerEnvironment, id: ProjectId$1, rid: SignedResourceId, projectTree: SynchronizedTreeState);
42
+ constructor(env: MiddleLayerEnvironment, id: ProjectId$1, rid: SignedResourceId, projectTree: SynchronizedTreeState,
43
+ /** Whether this tree was seeded from a snapshot. When it was, the file on disk already
44
+ * holds generation 0, so an idle warm reopen writes nothing at all. */
45
+ restoredFromSnapshot?: boolean);
30
46
  get projectLockId(): string;
47
+ /**
48
+ * Periodic snapshot write, carried on the maintenance loop rather than a timer of its own.
49
+ *
50
+ * Gated on the tree having changed since the last snapshot, so a project left open and idle
51
+ * writes once and then goes quiet, and on wall clock, so a project changing continuously
52
+ * writes at most once per interval.
53
+ */
54
+ private maybeWriteSnapshot;
55
+ /**
56
+ * Starts the close-boundary snapshot and returns without waiting for the write.
57
+ *
58
+ * On top of the periodic write, since closing is a natural point to persist. Change-gated but
59
+ * not interval-gated: rewriting a mirror that has not moved is pure waste, but a mirror that
60
+ * has moved is worth keeping however recently the last write happened.
61
+ *
62
+ * The **capture is synchronous and happens here**, before the caller destroys the tree,
63
+ * because destroying it invalidates it and a later capture would be refused. Only the encode
64
+ * and the write are deferred: they are up to ten megabytes of work, and project switching
65
+ * should not wait for them. Deferring is safe only because a capture is a copy rather than a
66
+ * view of the tree.
67
+ *
68
+ * The returned promise never rejects. The caller is expected to keep it so it can be drained
69
+ * at shutdown, not to await it here.
70
+ */
71
+ snapshotOnClose(): Promise<void>;
72
+ /** In-flight snapshot write, if any. Both triggers can fire close together (the close write
73
+ * lands while the loop is mid-write), and encoding ten megabytes twice for the same mirror
74
+ * is worth avoiding. */
75
+ private snapshotInFlight;
76
+ /** Serializes writes, and skips one that the in-flight write has already made redundant. */
77
+ private writeSnapshot;
78
+ /** Captures and writes, never throwing: a snapshot is an optimisation and must not fail
79
+ * whatever triggered it. */
80
+ private captureAndWrite;
31
81
  private refreshLoop;
32
82
  /**
33
83
  * Adds new block to the project.
@@ -103,9 +153,9 @@ declare class Project {
103
153
  * transactionally associated with the block, to facilitate conflict resolution
104
154
  * in collaborative editing scenario.
105
155
  * */
106
- setBlockArgsAndUiState(blockId: string, args: unknown, // keep for v1/v2 compatibility
107
- uiState: unknown, // keep for v1/v2 compatibility
108
- author?: AuthorMarker): Promise<void>;
156
+ setBlockArgsAndUiState(blockId: string, args: unknown // keep for v1/v2 compatibility
157
+ , uiState: unknown // keep for v1/v2 compatibility
158
+ , author?: AuthorMarker): Promise<void>;
109
159
  /**
110
160
  * Sets navigation state.
111
161
  * */
@@ -155,5 +205,4 @@ declare class Project {
155
205
  static init(env: MiddleLayerEnvironment, id: ProjectId$1, rid: SignedResourceId): Promise<Project>;
156
206
  }
157
207
  //#endregion
158
- export { Project };
159
208
  //# sourceMappingURL=project.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"project.d.ts","names":[],"sources":["../../src/middle_layer/project.ts"],"mappings":";;;;;;;;;;;;;cAyFa,OAAA;EAAA,iBAoBQ,GAAA;EAAA,SACD,EAAA,EAAI,WAAA;EAAA,SACX,GAAA,EAAK,gBAAA;EAAA,iBACG,WAAA;EArB+B;EAAA,SAAlC,QAAA,EAAU,uBAAA,CAAwB,eAAA;EAAA,iBACjC,aAAA;EAAA,iBAEA,gBAAA;EAAA,iBAEA,gBAAA;EAAA,iBAEA,cAAA;EAAA,iBACA,aAAA;EAAA,iBACA,iBAAA;EAAA,iBAEA,eAAA;EAAA,YAEL,SAAA;cAKO,GAAA,EAAK,sBAAA,EACN,EAAA,EAAI,WAAA,EACX,GAAA,EAAK,gBAAA,EACG,WAAA,EAAa,qBAAA;EAAA,IAe5B,aAAA;EAAA,QAIU,WAAA;EAoLX;;;;;;;;;;;EApGU,QAAA,CACX,UAAA,UACA,aAAA,EAAe,gBAAA,EACf,MAAA,WACA,MAAA,GAAQ,YAAA,cACR,OAAA,YACC,OAAA;EA2QoB;;;;;;;;;;;;EAzMV,cAAA,CACX,eAAA,UACA,MAAA,WACA,MAAA,GAAQ,YAAA,cACR,UAAA,YACC,OAAA;EAuXuC;;;;EArW7B,eAAA,CACX,OAAA,UACA,aAAA,EAAe,gBAAA,EACf,SAAA,YACA,MAAA,GAAS,YAAA,GACR,OAAA;EAyZG;EAxXO,WAAA,CAAY,OAAA,UAAiB,MAAA,GAAS,YAAA,GAAe,OAAA;EA0XvD;;;;;;EAvWE,aAAA,CAAc,MAAA,YAAkB,MAAA,GAAS,YAAA,GAAe,OAAA;EA5P1D;;;;;EAmSE,QAAA,CAAS,OAAA,WAAkB,OAAA;EAtTvB;;;;;EAsUJ,SAAA,CAAU,OAAA,WAAkB,OAAA;EA5TxB;;;;;;;EA8UJ,YAAA,CAAa,OAAA,UAAiB,IAAA,WAAe,MAAA,GAAS,YAAA,GAAY,OAAA;EArUpE;;;;;;;EA2VE,UAAA,CAAW,OAAA,UAAiB,OAAA,WAAkB,MAAA,GAAS,YAAA,GAAY,OAAA;EArP9E;;;;;;;EA2QW,sBAAA,CACX,OAAA,UACA,IAAA;EACA,OAAA;EACA,MAAA,GAAS,YAAA,GAAY,OAAA;EAtMrB;;;EA2NW,kBAAA,CAAmB,OAAA,UAAiB,KAAA,EAAO,eAAA,GAAkB,OAAA;EAtMxE;;;;;;;;;;EAoNW,kBAAA,CACX,OAAA,UACA,OAAA;IAAW,SAAA;IAAmB,KAAA;EAAA,GAC9B,MAAA,GAAS,YAAA,GAAY,OAAA;EA/J+B;EA6KzC,gBAAA,CAAiB,OAAA,UAAiB,QAAA,EAAU,aAAA,GAAa,OAAA;EA7KD;;;;;;;EAkMxD,kBAAA,CAAmB,OAAA,UAAiB,cAAA,WAAyB,OAAA;EAzHhD;EAwIb,wBAAA,CAAyB,OAAA,UAAiB,MAAA,GAAS,YAAA,GAAe,OAAA;EAAA,QAkCvE,mBAAA;EA1KkD;;;;EA2NnD,aAAA,CAAc,OAAA,WAAkB,UAAA,CAAW,oBAAA;EArMkB;;;;EA6M7D,gBAAA,CAAiB,OAAA,WAAkB,uBAAA,CAAwB,YAAA;EArLhE;EAoMW,OAAA,IAAW,OAAA;EAlMb;EAkOE,0BAAA,IAA8B,OAAA;EAIpC,SAAA,IAAa,oBAAA;EAAA,OAIA,IAAA,CAClB,GAAA,EAAK,sBAAA,EACL,EAAA,EAAI,WAAA,EACJ,GAAA,EAAK,gBAAA,GACJ,OAAA,CAAQ,OAAA;AAAA"}
1
+ {"version":3,"file":"project.d.ts","names":[],"sources":["../../src/middle_layer/project.ts"],"mappings":";;;;;;;;;;;;;qBAiGa;mBAmCQ;WACD,IAAI;WACX,KAAK;mBACG;;WApCH,UAAU,wBAAwB;mBACjC;mBAEA;mBAEA;mBAEA;mBACA;mBACA;mBAEA;;;;UAKT;;;;;;;;;UAUA;cAEI;EAIZ,YACmB,KAAK,wBACN,IAAI,aACX,KAAK,kBACG,aAAa,uBAG9B;;;EAAA;MAgBE;;;;;;;;UAWU;;;;;;;;;;;;;;;;;EA2BP,mBAAmB;;;;UAoClB;;UAGM;;;UAkBA;UAmBA;;;;;;;;;;;;EAkFD,SACX,oBACA,eAAe,kBACf,iBACA,SAAQ,0BACR,mBACC;;;;;;;;;;;;;EAkEU,eACX,yBACA,iBACA,SAAQ,0BACR,sBACC;;;;;EAkBU,gBACX,iBACA,eAAe,kBACf,qBACA,SAAS,eACR;;EAiCU,YAAY,iBAAiB,SAAS,eAAe;;;;;;;EAmBrD,cAAc,kBAAkB,SAAS,eAAe;;;;;;EAuCxD,SAAS,kBAAkB;;;;;;EAgB3B,UAAU,kBAAkB;;;;;;;;EAkB5B,aAAa,iBAAiB,eAAe,SAAS,eAAY;;;;;;;;EAsBlE,WAAW,iBAAiB,kBAAkB,SAAS,eAAY;;;;;;;;EAsBnE,uBACX,iBACA;IACA;IACA,SAAS,eAAY;;;;EAqBV,mBAAmB,iBAAiB,OAAO,kBAAkB;;;;;;;;;;;EAc7D,mBACX,iBACA;IAAW;IAAmB;KAC9B,SAAS,eAAY;;EAcV,iBAAiB,iBAAiB,UAAU,gBAAa;;;;;;;;EAqBzD,mBAAmB,iBAAiB,yBAAyB;;EAe7D,yBAAyB,iBAAiB,SAAS,eAAe;UAkCvE;;;;;EAiDD,cAAc,kBAAkB,WAAW;;;;;EAQ3C,iBAAiB,kBAAkB,wBAAwB;;EAerD,WAAW;;EAgCX,8BAA8B;EAIpC,aAAa;SAIA,KAClB,KAAK,wBACL,IAAI,aACJ,KAAK,mBACJ,QAAQ"}