@milaboratories/pl-middle-layer 1.74.11 → 1.74.12

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 (320) hide show
  1. package/dist/_virtual/{_@oxc-project_runtime@0.137.0 → _@oxc-project_runtime@0.155.0}/helpers/esm/usingCtx.cjs +1 -2
  2. package/dist/_virtual/{_@oxc-project_runtime@0.137.0 → _@oxc-project_runtime@0.155.0}/helpers/esm/usingCtx.js +1 -2
  3. package/dist/_virtual/_rolldown/runtime.cjs +2 -3
  4. package/dist/block_registry/location_provider.cjs +1 -2
  5. package/dist/block_registry/location_provider.cjs.map +1 -1
  6. package/dist/block_registry/location_provider.js +1 -2
  7. package/dist/block_registry/registry-v2-provider.cjs +1 -2
  8. package/dist/block_registry/registry-v2-provider.cjs.map +1 -1
  9. package/dist/block_registry/registry-v2-provider.d.ts +0 -2
  10. package/dist/block_registry/registry-v2-provider.d.ts.map +1 -1
  11. package/dist/block_registry/registry-v2-provider.js +1 -2
  12. package/dist/block_registry/registry.cjs +3 -3
  13. package/dist/block_registry/registry.cjs.map +1 -1
  14. package/dist/block_registry/registry.d.ts +0 -2
  15. package/dist/block_registry/registry.d.ts.map +1 -1
  16. package/dist/block_registry/registry.js +3 -3
  17. package/dist/block_registry/registry.js.map +1 -1
  18. package/dist/block_registry/template_provider.cjs +1 -2
  19. package/dist/block_registry/template_provider.cjs.map +1 -1
  20. package/dist/block_registry/template_provider.d.ts +0 -2
  21. package/dist/block_registry/template_provider.d.ts.map +1 -1
  22. package/dist/block_registry/template_provider.js +1 -2
  23. package/dist/block_registry/watcher.cjs +15 -14
  24. package/dist/block_registry/watcher.cjs.map +1 -1
  25. package/dist/block_registry/watcher.d.ts +0 -2
  26. package/dist/block_registry/watcher.d.ts.map +1 -1
  27. package/dist/block_registry/watcher.js +15 -14
  28. package/dist/block_registry/watcher.js.map +1 -1
  29. package/dist/block_registry/well_known_registries.cjs +1 -2
  30. package/dist/block_registry/well_known_registries.d.ts +0 -2
  31. package/dist/block_registry/well_known_registries.d.ts.map +1 -1
  32. package/dist/block_registry/well_known_registries.js +1 -2
  33. package/dist/cfg_render/executor.cjs +1 -2
  34. package/dist/cfg_render/executor.cjs.map +1 -1
  35. package/dist/cfg_render/executor.js +1 -2
  36. package/dist/cfg_render/renderer.cjs +1 -2
  37. package/dist/cfg_render/renderer.cjs.map +1 -1
  38. package/dist/cfg_render/renderer.js +1 -2
  39. package/dist/cfg_render/traverse.cjs +1 -2
  40. package/dist/cfg_render/traverse.js +1 -2
  41. package/dist/cfg_render/util.cjs +1 -2
  42. package/dist/cfg_render/util.js +1 -2
  43. package/dist/debug/index.cjs +1 -2
  44. package/dist/debug/index.js +1 -2
  45. package/dist/dev_env/index.cjs +1 -2
  46. package/dist/dev_env/index.cjs.map +1 -1
  47. package/dist/dev_env/index.js +1 -2
  48. package/dist/dev_env/util.cjs +1 -2
  49. package/dist/dev_env/util.js +1 -2
  50. package/dist/js_render/column_registry.cjs +1 -2
  51. package/dist/js_render/column_registry.cjs.map +1 -1
  52. package/dist/js_render/column_registry.js +1 -2
  53. package/dist/js_render/computable_context.cjs +4 -4
  54. package/dist/js_render/computable_context.cjs.map +1 -1
  55. package/dist/js_render/computable_context.js +4 -4
  56. package/dist/js_render/computable_context.js.map +1 -1
  57. package/dist/js_render/context.cjs +1 -2
  58. package/dist/js_render/context.cjs.map +1 -1
  59. package/dist/js_render/context.js +1 -2
  60. package/dist/js_render/index.cjs +12 -9
  61. package/dist/js_render/index.cjs.map +1 -1
  62. package/dist/js_render/index.js +12 -9
  63. package/dist/js_render/index.js.map +1 -1
  64. package/dist/js_render/service_injectors.cjs +2 -3
  65. package/dist/js_render/service_injectors.js +2 -3
  66. package/dist/js_render/spec_override_collapse.cjs +1 -2
  67. package/dist/js_render/spec_override_collapse.cjs.map +1 -1
  68. package/dist/js_render/spec_override_collapse.js +1 -2
  69. package/dist/middle_layer/active_cfg.cjs +1 -2
  70. package/dist/middle_layer/active_cfg.cjs.map +1 -1
  71. package/dist/middle_layer/active_cfg.js +1 -2
  72. package/dist/middle_layer/block.cjs +1 -2
  73. package/dist/middle_layer/block.cjs.map +1 -1
  74. package/dist/middle_layer/block.js +1 -2
  75. package/dist/middle_layer/block_ctx.cjs +3 -3
  76. package/dist/middle_layer/block_ctx.cjs.map +1 -1
  77. package/dist/middle_layer/block_ctx.js +3 -3
  78. package/dist/middle_layer/block_ctx.js.map +1 -1
  79. package/dist/middle_layer/block_ctx_unsafe.cjs +1 -2
  80. package/dist/middle_layer/block_ctx_unsafe.js +1 -2
  81. package/dist/middle_layer/build_stamp.cjs +2 -3
  82. package/dist/middle_layer/build_stamp.js +2 -3
  83. package/dist/middle_layer/driver_kit.cjs +1 -2
  84. package/dist/middle_layer/driver_kit.cjs.map +1 -1
  85. package/dist/middle_layer/driver_kit.d.ts +0 -2
  86. package/dist/middle_layer/driver_kit.d.ts.map +1 -1
  87. package/dist/middle_layer/driver_kit.js +1 -2
  88. package/dist/middle_layer/finality_stop_rules.cjs +1 -2
  89. package/dist/middle_layer/finality_stop_rules.js +1 -2
  90. package/dist/middle_layer/folders.cjs +12 -8
  91. package/dist/middle_layer/folders.cjs.map +1 -1
  92. package/dist/middle_layer/folders.d.ts +0 -2
  93. package/dist/middle_layer/folders.d.ts.map +1 -1
  94. package/dist/middle_layer/folders.js +12 -8
  95. package/dist/middle_layer/folders.js.map +1 -1
  96. package/dist/middle_layer/frontend_path.cjs +1 -2
  97. package/dist/middle_layer/frontend_path.cjs.map +1 -1
  98. package/dist/middle_layer/frontend_path.js +1 -2
  99. package/dist/middle_layer/middle_layer.cjs +7 -6
  100. package/dist/middle_layer/middle_layer.cjs.map +1 -1
  101. package/dist/middle_layer/middle_layer.d.ts +0 -2
  102. package/dist/middle_layer/middle_layer.d.ts.map +1 -1
  103. package/dist/middle_layer/middle_layer.js +7 -6
  104. package/dist/middle_layer/middle_layer.js.map +1 -1
  105. package/dist/middle_layer/navigation_states.cjs +1 -2
  106. package/dist/middle_layer/navigation_states.js +1 -2
  107. package/dist/middle_layer/ops.cjs +10 -11
  108. package/dist/middle_layer/ops.cjs.map +1 -1
  109. package/dist/middle_layer/ops.d.ts +0 -2
  110. package/dist/middle_layer/ops.d.ts.map +1 -1
  111. package/dist/middle_layer/ops.js +10 -11
  112. package/dist/middle_layer/ops.js.map +1 -1
  113. package/dist/middle_layer/project.cjs +3 -3
  114. package/dist/middle_layer/project.cjs.map +1 -1
  115. package/dist/middle_layer/project.d.ts +3 -5
  116. package/dist/middle_layer/project.d.ts.map +1 -1
  117. package/dist/middle_layer/project.js +3 -3
  118. package/dist/middle_layer/project.js.map +1 -1
  119. package/dist/middle_layer/project_list.cjs +1 -2
  120. package/dist/middle_layer/project_list.cjs.map +1 -1
  121. package/dist/middle_layer/project_list.d.ts +0 -2
  122. package/dist/middle_layer/project_list.d.ts.map +1 -1
  123. package/dist/middle_layer/project_list.js +1 -2
  124. package/dist/middle_layer/project_overview.cjs +8 -5
  125. package/dist/middle_layer/project_overview.cjs.map +1 -1
  126. package/dist/middle_layer/project_overview.js +8 -5
  127. package/dist/middle_layer/project_overview.js.map +1 -1
  128. package/dist/middle_layer/project_overview_light.cjs +4 -3
  129. package/dist/middle_layer/project_overview_light.cjs.map +1 -1
  130. package/dist/middle_layer/project_overview_light.js +4 -3
  131. package/dist/middle_layer/project_overview_light.js.map +1 -1
  132. package/dist/middle_layer/render.cjs +1 -2
  133. package/dist/middle_layer/render.cjs.map +1 -1
  134. package/dist/middle_layer/render.js +1 -2
  135. package/dist/middle_layer/sharing_list.cjs +1 -2
  136. package/dist/middle_layer/sharing_list.cjs.map +1 -1
  137. package/dist/middle_layer/sharing_list.d.ts +0 -2
  138. package/dist/middle_layer/sharing_list.d.ts.map +1 -1
  139. package/dist/middle_layer/sharing_list.js +1 -2
  140. package/dist/middle_layer/sharing_list.js.map +1 -1
  141. package/dist/middle_layer/template_list.cjs +1 -2
  142. package/dist/middle_layer/template_list.cjs.map +1 -1
  143. package/dist/middle_layer/template_list.d.ts +0 -2
  144. package/dist/middle_layer/template_list.d.ts.map +1 -1
  145. package/dist/middle_layer/template_list.js +1 -2
  146. package/dist/middle_layer/tree_snapshot_store.cjs +3 -3
  147. package/dist/middle_layer/tree_snapshot_store.cjs.map +1 -1
  148. package/dist/middle_layer/tree_snapshot_store.d.ts +0 -2
  149. package/dist/middle_layer/tree_snapshot_store.d.ts.map +1 -1
  150. package/dist/middle_layer/tree_snapshot_store.js +3 -3
  151. package/dist/middle_layer/tree_snapshot_store.js.map +1 -1
  152. package/dist/middle_layer/types.d.ts +0 -2
  153. package/dist/middle_layer/types.d.ts.map +1 -1
  154. package/dist/middle_layer/util.cjs +1 -2
  155. package/dist/middle_layer/util.cjs.map +1 -1
  156. package/dist/middle_layer/util.js +1 -2
  157. package/dist/model/args.cjs +1 -2
  158. package/dist/model/args.cjs.map +1 -1
  159. package/dist/model/args.js +1 -2
  160. package/dist/model/block_pack_spec.cjs +1 -2
  161. package/dist/model/block_pack_spec.d.ts +0 -2
  162. package/dist/model/block_pack_spec.d.ts.map +1 -1
  163. package/dist/model/block_pack_spec.js +1 -2
  164. package/dist/model/frontend.d.ts +0 -2
  165. package/dist/model/frontend.d.ts.map +1 -1
  166. package/dist/model/project_helper.cjs +1 -2
  167. package/dist/model/project_helper.cjs.map +1 -1
  168. package/dist/model/project_helper.d.ts +0 -2
  169. package/dist/model/project_helper.d.ts.map +1 -1
  170. package/dist/model/project_helper.js +1 -2
  171. package/dist/model/project_model.cjs +1 -2
  172. package/dist/model/project_model.d.ts +0 -2
  173. package/dist/model/project_model.d.ts.map +1 -1
  174. package/dist/model/project_model.js +1 -2
  175. package/dist/model/project_model_util.cjs +1 -2
  176. package/dist/model/project_model_util.js +1 -2
  177. package/dist/model/project_model_v1.cjs +1 -2
  178. package/dist/model/project_model_v1.js +1 -2
  179. package/dist/model/sharing_model.cjs +1 -2
  180. package/dist/model/sharing_model.cjs.map +1 -1
  181. package/dist/model/sharing_model.d.ts +0 -2
  182. package/dist/model/sharing_model.d.ts.map +1 -1
  183. package/dist/model/sharing_model.js +1 -2
  184. package/dist/model/template_apply.cjs +1 -2
  185. package/dist/model/template_apply.cjs.map +1 -1
  186. package/dist/model/template_apply.d.ts +0 -2
  187. package/dist/model/template_apply.d.ts.map +1 -1
  188. package/dist/model/template_apply.js +1 -2
  189. package/dist/model/template_export.cjs +1 -2
  190. package/dist/model/template_export.d.ts +0 -2
  191. package/dist/model/template_export.d.ts.map +1 -1
  192. package/dist/model/template_export.js +1 -2
  193. package/dist/model/template_parser.cjs +1 -2
  194. package/dist/model/template_parser.cjs.map +1 -1
  195. package/dist/model/template_parser.d.ts +0 -2
  196. package/dist/model/template_parser.d.ts.map +1 -1
  197. package/dist/model/template_parser.js +1 -2
  198. package/dist/model/template_resolve.cjs +1 -2
  199. package/dist/model/template_resolve.cjs.map +1 -1
  200. package/dist/model/template_resolve.d.ts +0 -2
  201. package/dist/model/template_resolve.d.ts.map +1 -1
  202. package/dist/model/template_resolve.js +1 -2
  203. package/dist/model/template_serializer.cjs +1 -2
  204. package/dist/model/template_serializer.cjs.map +1 -1
  205. package/dist/model/template_serializer.d.ts +0 -2
  206. package/dist/model/template_serializer.d.ts.map +1 -1
  207. package/dist/model/template_serializer.js +1 -2
  208. package/dist/model/template_spec.d.ts +0 -2
  209. package/dist/model/template_spec.d.ts.map +1 -1
  210. package/dist/mutator/block-pack/block_pack.cjs +7 -6
  211. package/dist/mutator/block-pack/block_pack.cjs.map +1 -1
  212. package/dist/mutator/block-pack/block_pack.d.ts +0 -2
  213. package/dist/mutator/block-pack/block_pack.d.ts.map +1 -1
  214. package/dist/mutator/block-pack/block_pack.js +7 -6
  215. package/dist/mutator/block-pack/block_pack.js.map +1 -1
  216. package/dist/mutator/block-pack/frontend.cjs +1 -2
  217. package/dist/mutator/block-pack/frontend.cjs.map +1 -1
  218. package/dist/mutator/block-pack/frontend.js +1 -2
  219. package/dist/mutator/block-pack/required_capabilities.cjs +1 -2
  220. package/dist/mutator/block-pack/required_capabilities.cjs.map +1 -1
  221. package/dist/mutator/block-pack/required_capabilities.js +1 -2
  222. package/dist/mutator/context_export.cjs +1 -2
  223. package/dist/mutator/context_export.cjs.map +1 -1
  224. package/dist/mutator/context_export.js +1 -2
  225. package/dist/mutator/list.cjs +1 -2
  226. package/dist/mutator/list.cjs.map +1 -1
  227. package/dist/mutator/list.js +1 -2
  228. package/dist/mutator/migration.cjs +1 -2
  229. package/dist/mutator/migration.cjs.map +1 -1
  230. package/dist/mutator/migration.js +1 -2
  231. package/dist/mutator/project.cjs +30 -22
  232. package/dist/mutator/project.cjs.map +1 -1
  233. package/dist/mutator/project.d.ts +0 -2
  234. package/dist/mutator/project.d.ts.map +1 -1
  235. package/dist/mutator/project.js +30 -22
  236. package/dist/mutator/project.js.map +1 -1
  237. package/dist/mutator/sharing.cjs +1 -2
  238. package/dist/mutator/sharing.cjs.map +1 -1
  239. package/dist/mutator/sharing.js +1 -2
  240. package/dist/mutator/template/direct_template_loader.cjs +1 -2
  241. package/dist/mutator/template/direct_template_loader.cjs.map +1 -1
  242. package/dist/mutator/template/direct_template_loader.js +1 -2
  243. package/dist/mutator/template/direct_template_loader_v3.cjs +1 -2
  244. package/dist/mutator/template/direct_template_loader_v3.cjs.map +1 -1
  245. package/dist/mutator/template/direct_template_loader_v3.js +1 -2
  246. package/dist/mutator/template/render_block.cjs +1 -2
  247. package/dist/mutator/template/render_block.cjs.map +1 -1
  248. package/dist/mutator/template/render_block.js +1 -2
  249. package/dist/mutator/template/render_template.cjs +1 -2
  250. package/dist/mutator/template/render_template.cjs.map +1 -1
  251. package/dist/mutator/template/render_template.d.ts +0 -2
  252. package/dist/mutator/template/render_template.d.ts.map +1 -1
  253. package/dist/mutator/template/render_template.js +1 -2
  254. package/dist/mutator/template/template_cache.cjs +6 -5
  255. package/dist/mutator/template/template_cache.cjs.map +1 -1
  256. package/dist/mutator/template/template_cache.d.ts +1 -2
  257. package/dist/mutator/template/template_cache.d.ts.map +1 -1
  258. package/dist/mutator/template/template_cache.js +6 -5
  259. package/dist/mutator/template/template_cache.js.map +1 -1
  260. package/dist/mutator/template/template_loading.cjs +1 -2
  261. package/dist/mutator/template/template_loading.cjs.map +1 -1
  262. package/dist/mutator/template/template_loading.d.ts +0 -2
  263. package/dist/mutator/template/template_loading.d.ts.map +1 -1
  264. package/dist/mutator/template/template_loading.js +1 -2
  265. package/dist/mutator/template.cjs +1 -2
  266. package/dist/mutator/template.cjs.map +1 -1
  267. package/dist/mutator/template.js +1 -2
  268. package/dist/mutator/template_construct.cjs +1 -2
  269. package/dist/mutator/template_construct.cjs.map +1 -1
  270. package/dist/mutator/template_construct.js +1 -2
  271. package/dist/network_check/network_check.cjs +2 -3
  272. package/dist/network_check/network_check.cjs.map +1 -1
  273. package/dist/network_check/network_check.d.ts +0 -2
  274. package/dist/network_check/network_check.d.ts.map +1 -1
  275. package/dist/network_check/network_check.js +2 -3
  276. package/dist/network_check/network_check.js.map +1 -1
  277. package/dist/network_check/pings.cjs +1 -2
  278. package/dist/network_check/pings.cjs.map +1 -1
  279. package/dist/network_check/pings.js +1 -2
  280. package/dist/network_check/template.cjs +5 -4
  281. package/dist/network_check/template.cjs.map +1 -1
  282. package/dist/network_check/template.js +5 -4
  283. package/dist/network_check/template.js.map +1 -1
  284. package/dist/pool/data.cjs +1 -2
  285. package/dist/pool/data.cjs.map +1 -1
  286. package/dist/pool/data.d.ts +0 -2
  287. package/dist/pool/data.d.ts.map +1 -1
  288. package/dist/pool/data.js +1 -2
  289. package/dist/pool/driver.cjs +5 -4
  290. package/dist/pool/driver.cjs.map +1 -1
  291. package/dist/pool/driver.d.ts +0 -2
  292. package/dist/pool/driver.d.ts.map +1 -1
  293. package/dist/pool/driver.js +5 -4
  294. package/dist/pool/driver.js.map +1 -1
  295. package/dist/pool/p_object_collection.cjs +9 -8
  296. package/dist/pool/p_object_collection.cjs.map +1 -1
  297. package/dist/pool/p_object_collection.d.ts +0 -2
  298. package/dist/pool/p_object_collection.d.ts.map +1 -1
  299. package/dist/pool/p_object_collection.js +9 -8
  300. package/dist/pool/p_object_collection.js.map +1 -1
  301. package/dist/pool/result_pool.cjs +8 -7
  302. package/dist/pool/result_pool.cjs.map +1 -1
  303. package/dist/pool/result_pool.js +8 -7
  304. package/dist/pool/result_pool.js.map +1 -1
  305. package/dist/pool/upstream_block_ctx.cjs +1 -2
  306. package/dist/pool/upstream_block_ctx.cjs.map +1 -1
  307. package/dist/pool/upstream_block_ctx.js +1 -2
  308. package/dist/service_factories.cjs +1 -2
  309. package/dist/service_factories.js +1 -2
  310. package/dist/worker/WorkerManager.cjs +1 -2
  311. package/dist/worker/WorkerManager.js +1 -2
  312. package/dist/worker/WorkerManager.js.map +1 -1
  313. package/dist/worker/worker.cjs +1 -2
  314. package/dist/worker/worker.js +1 -2
  315. package/dist/worker/workerApi.cjs +1 -2
  316. package/dist/worker/workerApi.cjs.map +1 -1
  317. package/dist/worker/workerApi.js +1 -2
  318. package/package.json +33 -33
  319. package/src/middle_layer/middle_layer.ts +4 -6
  320. package/src/middle_layer/tree_snapshot_store.test.ts +4 -1
@@ -1 +1 @@
1
- {"version":3,"file":"project_helper.cjs","names":["LRUCache","ConsoleLoggerAdapter","BLOCK_STORAGE_FACADE_VERSION","executeSingleLambda","BlockStorageFacadeCallbacks","getDebugFlags"],"sources":["../../src/model/project_helper.ts"],"sourcesContent":["import type { ResultOrError, BlockConfig, BlockStorage, PlRef } from \"@platforma-sdk/model\";\nimport type { StringifiedJson } from \"@milaboratories/pl-model-common\";\nimport {\n extractCodeWithInfo,\n ensureError,\n BlockStorageFacadeCallbacks,\n BLOCK_STORAGE_FACADE_VERSION,\n} from \"@platforma-sdk/model\";\nimport { LRUCache } from \"lru-cache\";\nimport type { QuickJSWASMModule } from \"quickjs-emscripten\";\nimport { executeSingleLambda } from \"../js_render\";\nimport type { SignedResourceId } from \"@milaboratories/pl-client\";\nimport { ConsoleLoggerAdapter, type MiLogger } from \"@milaboratories/ts-helpers\";\nimport { getDebugFlags } from \"../debug\";\n\ntype EnrichmentTargetsRequest = {\n blockConfig: () => BlockConfig;\n args: () => unknown;\n};\n\ntype EnrichmentTargetsValue = {\n value: PlRef[] | undefined;\n};\n\n/**\n * Result of VM-based storage migration.\n * Returned by migrateStorageInVM().\n *\n * - Error result: { error: string } - serious failure (no context, etc.)\n * - Success result: { newStorageJson: StringifiedJson<BlockStorage>, info: string } - migration succeeded\n */\nexport type MigrationResult =\n | { error: string }\n | { error?: undefined; newStorageJson: StringifiedJson<BlockStorage>; info: string };\n\n/**\n * Result of args derivation from storage.\n * Returned by __pl_args_derive and __pl_prerunArgs_derive VM callbacks.\n */\ntype ArgsDeriveResult = { error: string } | { error?: undefined; value: unknown };\n\n/**\n * Result of building initial storage from params.\n * Returned by the __pl_storage_initialFromParams VM callback.\n */\ntype ParamsStorageResult =\n | { error: string }\n | { error?: undefined; storageJson: StringifiedJson<BlockStorage> };\n\n/**\n * Result of checking params against their kind.\n * Returned by the __pl_initializationParams_validate VM callback.\n */\ntype InitializationParamsValidateResult = { error: string } | { error?: undefined };\n\nexport class ProjectHelper {\n private readonly enrichmentTargetsCache = new LRUCache<\n string,\n EnrichmentTargetsValue,\n EnrichmentTargetsRequest\n >({\n max: 256,\n memoMethod: (_key, _value, { context }) => {\n return { value: this.calculateEnrichmentTargets(context) };\n },\n });\n\n constructor(\n private readonly quickJs: QuickJSWASMModule,\n public readonly logger: MiLogger = new ConsoleLoggerAdapter(),\n ) {}\n\n // =============================================================================\n // Args Derivation from Storage (V3+)\n // =============================================================================\n\n /**\n * Derives args directly from storage JSON using VM callback.\n * The VM extracts data from storage and calls the block's args() function.\n *\n * This allows the middle layer to work only with storage JSON,\n * without needing to know the underlying data structure.\n *\n * @param blockConfig The block configuration (provides the model code)\n * @param storageJson Storage as JSON string\n * @returns The derived args object, or error if derivation fails\n */\n public deriveArgsFromStorage(\n blockConfig: BlockConfig,\n storageJson: string,\n ): ResultOrError<unknown> {\n if (blockConfig.modelAPIVersion !== BLOCK_STORAGE_FACADE_VERSION) {\n return {\n error: new Error(\"deriveArgsFromStorage is only supported for model API version 2\"),\n };\n }\n\n try {\n const result = executeSingleLambda(\n this.quickJs,\n blockConfig.blockLifecycleCallbacks[BlockStorageFacadeCallbacks.ArgsDerive],\n extractCodeWithInfo(blockConfig),\n storageJson,\n ) as ArgsDeriveResult;\n\n if (result.error !== undefined) {\n return { error: new Error(result.error) };\n }\n return { value: result.value };\n } catch (e) {\n return { error: new Error(\"Args derivation from storage failed\", { cause: ensureError(e) }) };\n }\n }\n\n /**\n * Derives prerunArgs directly from storage JSON using VM callback.\n * Falls back to args() if prerunArgs is not defined in the block model.\n *\n * @param blockConfig The block configuration (provides the model code)\n * @param storageJson Storage as JSON string\n * @returns The derived prerunArgs, or undefined if derivation fails\n */\n public derivePrerunArgsFromStorage(blockConfig: BlockConfig, storageJson: string): unknown {\n if (blockConfig.modelAPIVersion !== BLOCK_STORAGE_FACADE_VERSION) {\n throw new Error(\"derivePrerunArgsFromStorage is only supported for model API version 2\");\n }\n\n try {\n const result = executeSingleLambda(\n this.quickJs,\n blockConfig.blockLifecycleCallbacks[BlockStorageFacadeCallbacks.PrerunArgsDerive],\n extractCodeWithInfo(blockConfig),\n storageJson,\n ) as ArgsDeriveResult;\n\n if (result.error !== undefined) {\n // Return undefined if derivation fails (skip block in staging)\n return undefined;\n }\n return result.value;\n } catch {\n // Return undefined if derivation fails (skip block in staging)\n return undefined;\n }\n }\n\n /**\n * Derives this block's template-export params from storage JSON using the VM\n * callback (`__pl_initializationParams_derive`).\n *\n * The template-export counterpart of {@link deriveArgsFromStorage}: instead of\n * the args a workflow runs on, it returns the params that would recreate the\n * block — the inverse of the data model's `init`. Params come back exactly as the block\n * projected them, references included: nothing marks or rewrites them on the way out, so\n * nothing here has to know a kind's params shape or how a reference is spelled.\n *\n * A `{ value: undefined }` result means the block declares no `templateParams`, which only\n * a block built against an older SDK can do. It does not reach a document: the export walk\n * requires a mapping and reports anything else as that block's problem, so an entry always\n * carries params.\n *\n * Unlike {@link derivePrerunArgsFromStorage}, a failure here is surfaced rather\n * than swallowed — a prerun that cannot derive args just skips a block in\n * staging, whereas an export that silently drops a block produces a template\n * that does not describe the project.\n *\n * @param blockConfig The block configuration (provides the model code)\n * @param storageJson Storage as JSON string\n * @returns The derived params with identifiers wrapped, `undefined` if the block declares\n * no lambda, or an error if derivation failed\n */\n public deriveTemplateParamsFromStorage(\n blockConfig: BlockConfig,\n storageJson: string,\n ): ResultOrError<unknown> {\n if (blockConfig.modelAPIVersion !== BLOCK_STORAGE_FACADE_VERSION) {\n return {\n error: new Error(\n \"deriveTemplateParamsFromStorage is only supported for model API version 2\",\n ),\n };\n }\n\n const callback =\n blockConfig.blockLifecycleCallbacks[BlockStorageFacadeCallbacks.InitializationParamsDerive];\n\n // A model built before this callback existed simply has no entry for it. That is\n // NOT the same as a block declaring no `templateParams`: the block may well have\n // params, we just have no way to ask for them. Reporting it as `undefined` params\n // would export the block stripped of its configuration and quietly rebuild a\n // differently-configured project, so it has to be an error.\n // The message names the one action available to whoever pressed Export. It\n // deliberately says nothing about SDKs or callbacks: the person reading it did\n // not build this block and cannot change how it was built.\n if (callback === undefined) {\n return {\n error: new Error(\n \"This version of the block cannot be written to a template. Update the block \" +\n \"to a newer version and export again.\",\n ),\n };\n }\n\n try {\n const result = executeSingleLambda(\n this.quickJs,\n callback,\n extractCodeWithInfo(blockConfig),\n storageJson,\n ) as ArgsDeriveResult;\n\n if (result.error !== undefined) {\n return { error: new Error(result.error) };\n }\n return { value: result.value };\n } catch (e) {\n const cause = ensureError(e);\n // The reason goes in the message, not only in `cause`: this error is rendered\n // into a per-block export problem and shown to whoever triggered the export,\n // and every layer between here and there carries only `message`.\n return {\n error: new Error(`Template params derivation from storage failed: ${cause.message}`, {\n cause,\n }),\n };\n }\n }\n\n private calculateEnrichmentTargets(req: EnrichmentTargetsRequest): PlRef[] | undefined {\n const blockConfig = req.blockConfig();\n if (blockConfig.enrichmentTargets === undefined) return undefined;\n const args = req.args();\n const result = executeSingleLambda(\n this.quickJs,\n blockConfig.enrichmentTargets,\n extractCodeWithInfo(blockConfig),\n args,\n ) as PlRef[];\n return result;\n }\n\n public getEnrichmentTargets(\n blockConfig: () => BlockConfig,\n args: () => unknown,\n key?: { argsRid: SignedResourceId; blockPackRid: SignedResourceId },\n ): PlRef[] | undefined {\n const req = { blockConfig, args };\n if (key === undefined) return this.calculateEnrichmentTargets(req);\n const cacheKey = `${key.argsRid}:${key.blockPackRid}`;\n return this.enrichmentTargetsCache.memo(cacheKey, { context: req }).value;\n }\n\n // =============================================================================\n // VM-based Storage Operations\n // =============================================================================\n\n /**\n * Creates initial BlockStorage for a new block using VM-based transformation.\n * This calls the '__pl_storage_initial' callback registered by DataModel which:\n * - Gets initial data from DataModel.getDefaultData()\n * - Creates BlockStorage with correct version\n *\n * @param blockConfig The block configuration (provides the model code)\n * @returns Initial storage as JSON string\n * @throws Error if storage creation fails\n */\n public getInitialStorageInVM(blockConfig: BlockConfig): string {\n if (blockConfig.modelAPIVersion !== BLOCK_STORAGE_FACADE_VERSION) {\n throw new Error(\"getInitialStorageInVM is only supported for model API version 2\");\n }\n\n try {\n const result = executeSingleLambda(\n this.quickJs,\n blockConfig.blockLifecycleCallbacks[BlockStorageFacadeCallbacks.StorageInitial],\n extractCodeWithInfo(blockConfig),\n ) as string;\n return result;\n } catch (e) {\n this.logger.error(\n new Error(\"[ProjectHelper.getInitialStorageInVM] Initial storage creation failed\", {\n cause: e,\n }),\n );\n throw new Error(`Block initial storage creation failed: ${e}`);\n }\n }\n\n /**\n * Checks a template entry's params against the block's kind, creating nothing.\n *\n * The pre-flight half of {@link getInitialStorageFromParamsInVM}: run once per entry\n * before a template is applied, so params a kind rejects are reported against the\n * entry that carries them while there is still no project. Skipping it is safe —\n * initialization runs the same check — but then the report arrives after earlier\n * entries have already been created.\n *\n * Every kind declares a parser, so a pass here means the params were checked against\n * the contract — not merely that they were JSON.\n *\n * A block whose model predates the callback passes unchecked rather than failing.\n * Unlike initialization, this method creates nothing, so there is nothing to get wrong\n * by proceeding, and such a block is refused outright at the point it is applied.\n *\n * @param blockConfig The block configuration (provides the model code)\n * @param params The entry's params. Reference ids may be placeholders: what is being\n * checked is the shape of the params, not what they point at\n * @returns Nothing, or why the params were rejected\n */\n public validateTemplateParamsInVM(\n blockConfig: BlockConfig,\n params: unknown,\n ): ResultOrError<undefined> {\n if (blockConfig.modelAPIVersion !== BLOCK_STORAGE_FACADE_VERSION) {\n return {\n error: new Error(\"validateTemplateParamsInVM is only supported for model API version 2\"),\n };\n }\n\n const callback =\n blockConfig.blockLifecycleCallbacks[BlockStorageFacadeCallbacks.InitializationParamsValidate];\n if (callback === undefined) return { value: undefined };\n\n try {\n const result = executeSingleLambda(\n this.quickJs,\n callback,\n extractCodeWithInfo(blockConfig),\n JSON.stringify(params ?? {}),\n ) as InitializationParamsValidateResult;\n\n if (result.error !== undefined) return { error: new Error(result.error) };\n return { value: undefined };\n } catch (e) {\n const cause = ensureError(e);\n return { error: new Error(`Params check failed to run: ${cause.message}`, { cause }) };\n }\n }\n\n /**\n * Creates initial BlockStorage for a block being created from template params.\n *\n * The inverse of {@link deriveTemplateParamsFromStorage}, and the reason a block\n * can be created by anything other than the UI: it hands the params to the\n * block's own init factory inside the model VM, so the resulting storage is\n * whatever that block considers a correctly-initialized state.\n *\n * **Pointing the entry's references at this project happens in the same call**, before the\n * factory sees them — inside the block's bundle, because recognizing a reference means\n * knowing the reference system and a template engine deliberately does not. Params reach\n * here exactly as the file held them.\n *\n * One call and not two: every VM call builds a fresh runtime and re-evaluates the whole\n * model bundle, so asking the block to relocate and then asking it to initialize would parse\n * it twice per entry, for an intermediate value nothing else reads.\n *\n * `blockIds` holds the entries created so far, so an id it does not name is left as it is —\n * a reference to an entry further down the file keeps pointing at nothing, and the applied\n * block reports itself as missing references rather than being wired to a block below it.\n *\n * @param blockConfig The block configuration (provides the model code)\n * @param params The entry's params, as the document held them\n * @param blockIds template-local entry id → the block id that entry was given\n * @returns The initial storage as JSON string, or why the params yield none\n */\n public getInitialStorageFromParamsInVM(\n blockConfig: BlockConfig,\n params: unknown,\n blockIds: ReadonlyMap<string, string>,\n ): ResultOrError<string> {\n if (blockConfig.modelAPIVersion !== BLOCK_STORAGE_FACADE_VERSION) {\n return {\n error: new Error(\n \"getInitialStorageFromParamsInVM is only supported for model API version 2\",\n ),\n };\n }\n\n const callback =\n blockConfig.blockLifecycleCallbacks[BlockStorageFacadeCallbacks.StorageInitialFromParams];\n\n // A model built before this callback existed has no entry for it. Falling back to the\n // params-less initializer is not an option: it would produce a default-configured block\n // that looks like a successful apply, so the block the user gets would silently differ\n // from the one the template describes. Nor could its params be used as written — they name\n // the blocks of the project the template came from, and only this callback knows which of\n // the values in there are references at all.\n //\n // The message offers the two actions available to whoever applied the file. The\n // second one is the reason this branch is reachable at all: kind resolution only\n // ever returns a block that declares a kind, and such a block is new enough to\n // support this — but an entry may pin an exact block version instead, bypassing\n // resolution, and that pin can name anything ever published.\n if (callback === undefined) {\n return {\n error: new Error(\n \"This version of the block cannot be created from a template. Use a newer \" +\n \"version of the block, or remove the pinned block version from the template \" +\n \"entry so a supported one is chosen automatically.\",\n ),\n };\n }\n\n try {\n const result = executeSingleLambda(\n this.quickJs,\n callback,\n extractCodeWithInfo(blockConfig),\n // Params cross the VM boundary as text, like storage does. `undefined` would\n // stringify to nothing at all, and an entry with no params must go through\n // the params-less initializer rather than reaching this method.\n JSON.stringify(params ?? {}),\n JSON.stringify(Object.fromEntries(blockIds)),\n ) as ParamsStorageResult;\n\n if (result.error !== undefined) return { error: new Error(result.error) };\n return { value: result.storageJson };\n } catch (e) {\n const cause = ensureError(e);\n // The reason goes in the message, not only in `cause`: this error becomes a\n // per-entry apply problem shown to whoever triggered the import, and every\n // layer in between carries only `message`.\n return {\n error: new Error(`Initial storage creation from params failed: ${cause.message}`, {\n cause,\n }),\n };\n }\n }\n\n /**\n * Applies a state update using VM-based transformation.\n * This calls the model's `__pl_storage_applyUpdate` callback which:\n * - Normalizes current storage\n * - Updates state while preserving other fields (version, plugins)\n * - Returns the updated storage as JSON string\n *\n * @param blockConfig The block configuration (provides the model code)\n * @param currentStorageJson Current storage as JSON string (must be defined)\n * @param newState New state from developer\n * @returns Updated storage as JSON string\n * @throws Error if storage update fails\n */\n public applyStorageUpdateInVM(\n blockConfig: BlockConfig,\n currentStorageJson: string,\n payload: { operation: string; value: unknown },\n ): string {\n if (blockConfig.modelAPIVersion !== BLOCK_STORAGE_FACADE_VERSION) {\n throw new Error(\"applyStorageUpdateInVM is only supported for model API version 2\");\n }\n\n if (getDebugFlags().logJsExecStat) {\n this.logger.info(\n `[ProjectHelper.applyStorageUpdateInVM] currentStorageJson=${currentStorageJson.length}B, payload=${JSON.stringify(payload).length}B, operation=${payload.operation}`,\n );\n }\n try {\n const result = executeSingleLambda(\n this.quickJs,\n blockConfig.blockLifecycleCallbacks[BlockStorageFacadeCallbacks.StorageApplyUpdate],\n extractCodeWithInfo(blockConfig),\n currentStorageJson,\n payload,\n ) as string;\n return result;\n } catch (e) {\n const payloadJson = JSON.stringify(payload);\n this.logger.error(\n new Error(\n `[ProjectHelper.applyStorageUpdateInVM] Storage update failed (currentStorageJson=${currentStorageJson.length}B, payload=${payloadJson.length}B, operation=${payload.operation})`,\n { cause: e },\n ),\n );\n throw new Error(`Block storage update failed: ${e}`);\n }\n }\n\n // =============================================================================\n // Block State Migrations\n // =============================================================================\n\n /**\n * Runs block state migrations via VM-based transformation.\n * This calls the model's `__pl_storage_migrate` callback which:\n * - Normalizes current storage to get state and version\n * - Applies DataModel upgrade to reach target version key\n * - Runs all necessary migrations sequentially\n * - Returns new storage with updated state and version\n *\n * The middle layer doesn't need to know about dataVersion or storage internals.\n * All migration logic is encapsulated in the model.\n *\n * @param blockConfig The NEW block configuration (provides the model code with migrations)\n * @param currentStorageJson Current storage as JSON string (or undefined)\n * @returns MigrationResult with new storage or skip/error info\n */\n public migrateStorageInVM(\n blockConfig: BlockConfig,\n currentStorageJson: string | undefined,\n ): MigrationResult {\n if (blockConfig.modelAPIVersion !== BLOCK_STORAGE_FACADE_VERSION) {\n return { error: \"migrateStorageInVM is only supported for model API version 2\" };\n }\n\n try {\n const result = executeSingleLambda(\n this.quickJs,\n blockConfig.blockLifecycleCallbacks[BlockStorageFacadeCallbacks.StorageMigrate],\n extractCodeWithInfo(blockConfig),\n currentStorageJson,\n ) as MigrationResult;\n return result;\n } catch (e) {\n this.logger.error(\n new Error(\"[ProjectHelper.migrateStorageInVM] Migration failed\", { cause: e }),\n );\n return { error: `VM execution failed: ${e}` };\n }\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"project_helper.cjs","names":["LRUCache","ConsoleLoggerAdapter","BLOCK_STORAGE_FACADE_VERSION","executeSingleLambda","BlockStorageFacadeCallbacks","extractCodeWithInfo","ensureError","getDebugFlags"],"sources":["../../src/model/project_helper.ts"],"sourcesContent":["import type { ResultOrError, BlockConfig, BlockStorage, PlRef } from \"@platforma-sdk/model\";\nimport type { StringifiedJson } from \"@milaboratories/pl-model-common\";\nimport {\n extractCodeWithInfo,\n ensureError,\n BlockStorageFacadeCallbacks,\n BLOCK_STORAGE_FACADE_VERSION,\n} from \"@platforma-sdk/model\";\nimport { LRUCache } from \"lru-cache\";\nimport type { QuickJSWASMModule } from \"quickjs-emscripten\";\nimport { executeSingleLambda } from \"../js_render\";\nimport type { SignedResourceId } from \"@milaboratories/pl-client\";\nimport { ConsoleLoggerAdapter, type MiLogger } from \"@milaboratories/ts-helpers\";\nimport { getDebugFlags } from \"../debug\";\n\ntype EnrichmentTargetsRequest = {\n blockConfig: () => BlockConfig;\n args: () => unknown;\n};\n\ntype EnrichmentTargetsValue = {\n value: PlRef[] | undefined;\n};\n\n/**\n * Result of VM-based storage migration.\n * Returned by migrateStorageInVM().\n *\n * - Error result: { error: string } - serious failure (no context, etc.)\n * - Success result: { newStorageJson: StringifiedJson<BlockStorage>, info: string } - migration succeeded\n */\nexport type MigrationResult =\n | { error: string }\n | { error?: undefined; newStorageJson: StringifiedJson<BlockStorage>; info: string };\n\n/**\n * Result of args derivation from storage.\n * Returned by __pl_args_derive and __pl_prerunArgs_derive VM callbacks.\n */\ntype ArgsDeriveResult = { error: string } | { error?: undefined; value: unknown };\n\n/**\n * Result of building initial storage from params.\n * Returned by the __pl_storage_initialFromParams VM callback.\n */\ntype ParamsStorageResult =\n | { error: string }\n | { error?: undefined; storageJson: StringifiedJson<BlockStorage> };\n\n/**\n * Result of checking params against their kind.\n * Returned by the __pl_initializationParams_validate VM callback.\n */\ntype InitializationParamsValidateResult = { error: string } | { error?: undefined };\n\nexport class ProjectHelper {\n private readonly enrichmentTargetsCache = new LRUCache<\n string,\n EnrichmentTargetsValue,\n EnrichmentTargetsRequest\n >({\n max: 256,\n memoMethod: (_key, _value, { context }) => {\n return { value: this.calculateEnrichmentTargets(context) };\n },\n });\n\n constructor(\n private readonly quickJs: QuickJSWASMModule,\n public readonly logger: MiLogger = new ConsoleLoggerAdapter(),\n ) {}\n\n // =============================================================================\n // Args Derivation from Storage (V3+)\n // =============================================================================\n\n /**\n * Derives args directly from storage JSON using VM callback.\n * The VM extracts data from storage and calls the block's args() function.\n *\n * This allows the middle layer to work only with storage JSON,\n * without needing to know the underlying data structure.\n *\n * @param blockConfig The block configuration (provides the model code)\n * @param storageJson Storage as JSON string\n * @returns The derived args object, or error if derivation fails\n */\n public deriveArgsFromStorage(\n blockConfig: BlockConfig,\n storageJson: string,\n ): ResultOrError<unknown> {\n if (blockConfig.modelAPIVersion !== BLOCK_STORAGE_FACADE_VERSION) {\n return {\n error: new Error(\"deriveArgsFromStorage is only supported for model API version 2\"),\n };\n }\n\n try {\n const result = executeSingleLambda(\n this.quickJs,\n blockConfig.blockLifecycleCallbacks[BlockStorageFacadeCallbacks.ArgsDerive],\n extractCodeWithInfo(blockConfig),\n storageJson,\n ) as ArgsDeriveResult;\n\n if (result.error !== undefined) {\n return { error: new Error(result.error) };\n }\n return { value: result.value };\n } catch (e) {\n return { error: new Error(\"Args derivation from storage failed\", { cause: ensureError(e) }) };\n }\n }\n\n /**\n * Derives prerunArgs directly from storage JSON using VM callback.\n * Falls back to args() if prerunArgs is not defined in the block model.\n *\n * @param blockConfig The block configuration (provides the model code)\n * @param storageJson Storage as JSON string\n * @returns The derived prerunArgs, or undefined if derivation fails\n */\n public derivePrerunArgsFromStorage(blockConfig: BlockConfig, storageJson: string): unknown {\n if (blockConfig.modelAPIVersion !== BLOCK_STORAGE_FACADE_VERSION) {\n throw new Error(\"derivePrerunArgsFromStorage is only supported for model API version 2\");\n }\n\n try {\n const result = executeSingleLambda(\n this.quickJs,\n blockConfig.blockLifecycleCallbacks[BlockStorageFacadeCallbacks.PrerunArgsDerive],\n extractCodeWithInfo(blockConfig),\n storageJson,\n ) as ArgsDeriveResult;\n\n if (result.error !== undefined) {\n // Return undefined if derivation fails (skip block in staging)\n return undefined;\n }\n return result.value;\n } catch {\n // Return undefined if derivation fails (skip block in staging)\n return undefined;\n }\n }\n\n /**\n * Derives this block's template-export params from storage JSON using the VM\n * callback (`__pl_initializationParams_derive`).\n *\n * The template-export counterpart of {@link deriveArgsFromStorage}: instead of\n * the args a workflow runs on, it returns the params that would recreate the\n * block — the inverse of the data model's `init`. Params come back exactly as the block\n * projected them, references included: nothing marks or rewrites them on the way out, so\n * nothing here has to know a kind's params shape or how a reference is spelled.\n *\n * A `{ value: undefined }` result means the block declares no `templateParams`, which only\n * a block built against an older SDK can do. It does not reach a document: the export walk\n * requires a mapping and reports anything else as that block's problem, so an entry always\n * carries params.\n *\n * Unlike {@link derivePrerunArgsFromStorage}, a failure here is surfaced rather\n * than swallowed — a prerun that cannot derive args just skips a block in\n * staging, whereas an export that silently drops a block produces a template\n * that does not describe the project.\n *\n * @param blockConfig The block configuration (provides the model code)\n * @param storageJson Storage as JSON string\n * @returns The derived params with identifiers wrapped, `undefined` if the block declares\n * no lambda, or an error if derivation failed\n */\n public deriveTemplateParamsFromStorage(\n blockConfig: BlockConfig,\n storageJson: string,\n ): ResultOrError<unknown> {\n if (blockConfig.modelAPIVersion !== BLOCK_STORAGE_FACADE_VERSION) {\n return {\n error: new Error(\n \"deriveTemplateParamsFromStorage is only supported for model API version 2\",\n ),\n };\n }\n\n const callback =\n blockConfig.blockLifecycleCallbacks[BlockStorageFacadeCallbacks.InitializationParamsDerive];\n\n // A model built before this callback existed simply has no entry for it. That is\n // NOT the same as a block declaring no `templateParams`: the block may well have\n // params, we just have no way to ask for them. Reporting it as `undefined` params\n // would export the block stripped of its configuration and quietly rebuild a\n // differently-configured project, so it has to be an error.\n // The message names the one action available to whoever pressed Export. It\n // deliberately says nothing about SDKs or callbacks: the person reading it did\n // not build this block and cannot change how it was built.\n if (callback === undefined) {\n return {\n error: new Error(\n \"This version of the block cannot be written to a template. Update the block \" +\n \"to a newer version and export again.\",\n ),\n };\n }\n\n try {\n const result = executeSingleLambda(\n this.quickJs,\n callback,\n extractCodeWithInfo(blockConfig),\n storageJson,\n ) as ArgsDeriveResult;\n\n if (result.error !== undefined) {\n return { error: new Error(result.error) };\n }\n return { value: result.value };\n } catch (e) {\n const cause = ensureError(e);\n // The reason goes in the message, not only in `cause`: this error is rendered\n // into a per-block export problem and shown to whoever triggered the export,\n // and every layer between here and there carries only `message`.\n return {\n error: new Error(`Template params derivation from storage failed: ${cause.message}`, {\n cause,\n }),\n };\n }\n }\n\n private calculateEnrichmentTargets(req: EnrichmentTargetsRequest): PlRef[] | undefined {\n const blockConfig = req.blockConfig();\n if (blockConfig.enrichmentTargets === undefined) return undefined;\n const args = req.args();\n const result = executeSingleLambda(\n this.quickJs,\n blockConfig.enrichmentTargets,\n extractCodeWithInfo(blockConfig),\n args,\n ) as PlRef[];\n return result;\n }\n\n public getEnrichmentTargets(\n blockConfig: () => BlockConfig,\n args: () => unknown,\n key?: { argsRid: SignedResourceId; blockPackRid: SignedResourceId },\n ): PlRef[] | undefined {\n const req = { blockConfig, args };\n if (key === undefined) return this.calculateEnrichmentTargets(req);\n const cacheKey = `${key.argsRid}:${key.blockPackRid}`;\n return this.enrichmentTargetsCache.memo(cacheKey, { context: req }).value;\n }\n\n // =============================================================================\n // VM-based Storage Operations\n // =============================================================================\n\n /**\n * Creates initial BlockStorage for a new block using VM-based transformation.\n * This calls the '__pl_storage_initial' callback registered by DataModel which:\n * - Gets initial data from DataModel.getDefaultData()\n * - Creates BlockStorage with correct version\n *\n * @param blockConfig The block configuration (provides the model code)\n * @returns Initial storage as JSON string\n * @throws Error if storage creation fails\n */\n public getInitialStorageInVM(blockConfig: BlockConfig): string {\n if (blockConfig.modelAPIVersion !== BLOCK_STORAGE_FACADE_VERSION) {\n throw new Error(\"getInitialStorageInVM is only supported for model API version 2\");\n }\n\n try {\n const result = executeSingleLambda(\n this.quickJs,\n blockConfig.blockLifecycleCallbacks[BlockStorageFacadeCallbacks.StorageInitial],\n extractCodeWithInfo(blockConfig),\n ) as string;\n return result;\n } catch (e) {\n this.logger.error(\n new Error(\"[ProjectHelper.getInitialStorageInVM] Initial storage creation failed\", {\n cause: e,\n }),\n );\n throw new Error(`Block initial storage creation failed: ${e}`);\n }\n }\n\n /**\n * Checks a template entry's params against the block's kind, creating nothing.\n *\n * The pre-flight half of {@link getInitialStorageFromParamsInVM}: run once per entry\n * before a template is applied, so params a kind rejects are reported against the\n * entry that carries them while there is still no project. Skipping it is safe —\n * initialization runs the same check — but then the report arrives after earlier\n * entries have already been created.\n *\n * Every kind declares a parser, so a pass here means the params were checked against\n * the contract — not merely that they were JSON.\n *\n * A block whose model predates the callback passes unchecked rather than failing.\n * Unlike initialization, this method creates nothing, so there is nothing to get wrong\n * by proceeding, and such a block is refused outright at the point it is applied.\n *\n * @param blockConfig The block configuration (provides the model code)\n * @param params The entry's params. Reference ids may be placeholders: what is being\n * checked is the shape of the params, not what they point at\n * @returns Nothing, or why the params were rejected\n */\n public validateTemplateParamsInVM(\n blockConfig: BlockConfig,\n params: unknown,\n ): ResultOrError<undefined> {\n if (blockConfig.modelAPIVersion !== BLOCK_STORAGE_FACADE_VERSION) {\n return {\n error: new Error(\"validateTemplateParamsInVM is only supported for model API version 2\"),\n };\n }\n\n const callback =\n blockConfig.blockLifecycleCallbacks[BlockStorageFacadeCallbacks.InitializationParamsValidate];\n if (callback === undefined) return { value: undefined };\n\n try {\n const result = executeSingleLambda(\n this.quickJs,\n callback,\n extractCodeWithInfo(blockConfig),\n JSON.stringify(params ?? {}),\n ) as InitializationParamsValidateResult;\n\n if (result.error !== undefined) return { error: new Error(result.error) };\n return { value: undefined };\n } catch (e) {\n const cause = ensureError(e);\n return { error: new Error(`Params check failed to run: ${cause.message}`, { cause }) };\n }\n }\n\n /**\n * Creates initial BlockStorage for a block being created from template params.\n *\n * The inverse of {@link deriveTemplateParamsFromStorage}, and the reason a block\n * can be created by anything other than the UI: it hands the params to the\n * block's own init factory inside the model VM, so the resulting storage is\n * whatever that block considers a correctly-initialized state.\n *\n * **Pointing the entry's references at this project happens in the same call**, before the\n * factory sees them — inside the block's bundle, because recognizing a reference means\n * knowing the reference system and a template engine deliberately does not. Params reach\n * here exactly as the file held them.\n *\n * One call and not two: every VM call builds a fresh runtime and re-evaluates the whole\n * model bundle, so asking the block to relocate and then asking it to initialize would parse\n * it twice per entry, for an intermediate value nothing else reads.\n *\n * `blockIds` holds the entries created so far, so an id it does not name is left as it is —\n * a reference to an entry further down the file keeps pointing at nothing, and the applied\n * block reports itself as missing references rather than being wired to a block below it.\n *\n * @param blockConfig The block configuration (provides the model code)\n * @param params The entry's params, as the document held them\n * @param blockIds template-local entry id → the block id that entry was given\n * @returns The initial storage as JSON string, or why the params yield none\n */\n public getInitialStorageFromParamsInVM(\n blockConfig: BlockConfig,\n params: unknown,\n blockIds: ReadonlyMap<string, string>,\n ): ResultOrError<string> {\n if (blockConfig.modelAPIVersion !== BLOCK_STORAGE_FACADE_VERSION) {\n return {\n error: new Error(\n \"getInitialStorageFromParamsInVM is only supported for model API version 2\",\n ),\n };\n }\n\n const callback =\n blockConfig.blockLifecycleCallbacks[BlockStorageFacadeCallbacks.StorageInitialFromParams];\n\n // A model built before this callback existed has no entry for it. Falling back to the\n // params-less initializer is not an option: it would produce a default-configured block\n // that looks like a successful apply, so the block the user gets would silently differ\n // from the one the template describes. Nor could its params be used as written — they name\n // the blocks of the project the template came from, and only this callback knows which of\n // the values in there are references at all.\n //\n // The message offers the two actions available to whoever applied the file. The\n // second one is the reason this branch is reachable at all: kind resolution only\n // ever returns a block that declares a kind, and such a block is new enough to\n // support this — but an entry may pin an exact block version instead, bypassing\n // resolution, and that pin can name anything ever published.\n if (callback === undefined) {\n return {\n error: new Error(\n \"This version of the block cannot be created from a template. Use a newer \" +\n \"version of the block, or remove the pinned block version from the template \" +\n \"entry so a supported one is chosen automatically.\",\n ),\n };\n }\n\n try {\n const result = executeSingleLambda(\n this.quickJs,\n callback,\n extractCodeWithInfo(blockConfig),\n // Params cross the VM boundary as text, like storage does. `undefined` would\n // stringify to nothing at all, and an entry with no params must go through\n // the params-less initializer rather than reaching this method.\n JSON.stringify(params ?? {}),\n JSON.stringify(Object.fromEntries(blockIds)),\n ) as ParamsStorageResult;\n\n if (result.error !== undefined) return { error: new Error(result.error) };\n return { value: result.storageJson };\n } catch (e) {\n const cause = ensureError(e);\n // The reason goes in the message, not only in `cause`: this error becomes a\n // per-entry apply problem shown to whoever triggered the import, and every\n // layer in between carries only `message`.\n return {\n error: new Error(`Initial storage creation from params failed: ${cause.message}`, {\n cause,\n }),\n };\n }\n }\n\n /**\n * Applies a state update using VM-based transformation.\n * This calls the model's `__pl_storage_applyUpdate` callback which:\n * - Normalizes current storage\n * - Updates state while preserving other fields (version, plugins)\n * - Returns the updated storage as JSON string\n *\n * @param blockConfig The block configuration (provides the model code)\n * @param currentStorageJson Current storage as JSON string (must be defined)\n * @param newState New state from developer\n * @returns Updated storage as JSON string\n * @throws Error if storage update fails\n */\n public applyStorageUpdateInVM(\n blockConfig: BlockConfig,\n currentStorageJson: string,\n payload: { operation: string; value: unknown },\n ): string {\n if (blockConfig.modelAPIVersion !== BLOCK_STORAGE_FACADE_VERSION) {\n throw new Error(\"applyStorageUpdateInVM is only supported for model API version 2\");\n }\n\n if (getDebugFlags().logJsExecStat) {\n this.logger.info(\n `[ProjectHelper.applyStorageUpdateInVM] currentStorageJson=${currentStorageJson.length}B, payload=${JSON.stringify(payload).length}B, operation=${payload.operation}`,\n );\n }\n try {\n const result = executeSingleLambda(\n this.quickJs,\n blockConfig.blockLifecycleCallbacks[BlockStorageFacadeCallbacks.StorageApplyUpdate],\n extractCodeWithInfo(blockConfig),\n currentStorageJson,\n payload,\n ) as string;\n return result;\n } catch (e) {\n const payloadJson = JSON.stringify(payload);\n this.logger.error(\n new Error(\n `[ProjectHelper.applyStorageUpdateInVM] Storage update failed (currentStorageJson=${currentStorageJson.length}B, payload=${payloadJson.length}B, operation=${payload.operation})`,\n { cause: e },\n ),\n );\n throw new Error(`Block storage update failed: ${e}`);\n }\n }\n\n // =============================================================================\n // Block State Migrations\n // =============================================================================\n\n /**\n * Runs block state migrations via VM-based transformation.\n * This calls the model's `__pl_storage_migrate` callback which:\n * - Normalizes current storage to get state and version\n * - Applies DataModel upgrade to reach target version key\n * - Runs all necessary migrations sequentially\n * - Returns new storage with updated state and version\n *\n * The middle layer doesn't need to know about dataVersion or storage internals.\n * All migration logic is encapsulated in the model.\n *\n * @param blockConfig The NEW block configuration (provides the model code with migrations)\n * @param currentStorageJson Current storage as JSON string (or undefined)\n * @returns MigrationResult with new storage or skip/error info\n */\n public migrateStorageInVM(\n blockConfig: BlockConfig,\n currentStorageJson: string | undefined,\n ): MigrationResult {\n if (blockConfig.modelAPIVersion !== BLOCK_STORAGE_FACADE_VERSION) {\n return { error: \"migrateStorageInVM is only supported for model API version 2\" };\n }\n\n try {\n const result = executeSingleLambda(\n this.quickJs,\n blockConfig.blockLifecycleCallbacks[BlockStorageFacadeCallbacks.StorageMigrate],\n extractCodeWithInfo(blockConfig),\n currentStorageJson,\n ) as MigrationResult;\n return result;\n } catch (e) {\n this.logger.error(\n new Error(\"[ProjectHelper.migrateStorageInVM] Migration failed\", { cause: e }),\n );\n return { error: `VM execution failed: ${e}` };\n }\n }\n}\n"],"mappings":"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"}
@@ -3,7 +3,6 @@ import { MiLogger } from "@milaboratories/ts-helpers";
3
3
  import { StringifiedJson } from "@milaboratories/pl-model-common";
4
4
  import { SignedResourceId } from "@milaboratories/pl-client";
5
5
  import { QuickJSWASMModule } from "quickjs-emscripten";
6
- //#region src/model/project_helper.d.ts
7
6
  /**
8
7
  * Result of VM-based storage migration.
9
8
  * Returned by migrateStorageInVM().
@@ -169,5 +168,4 @@ export declare class ProjectHelper {
169
168
  */
170
169
  migrateStorageInVM(blockConfig: BlockConfig, currentStorageJson: string | undefined): MigrationResult;
171
170
  }
172
- //#endregion
173
171
  //# sourceMappingURL=project_helper.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"project_helper.d.ts","names":[],"sources":["../../src/model/project_helper.ts"],"mappings":";;;;;;;;;;;;;YA+BY;EACN;;EACA;EAAmB,gBAAgB,gBAAgB;EAAe;;qBAsB3D;mBAaQ;WACD,QAAQ;mBAbT;EAWjB,YACmB,SAAS,mBACV,SAAQ;;;;;;;;;;;;EAkBnB,sBACL,aAAa,aACb,sBACC;;;;;;;;;EAgCI,4BAA4B,aAAa,aAAa;;;;;;;;;;;;;;;;;;;;;;;;;;EAiDtD,gCACL,aAAa,aACb,sBACC;UAsDK;EAaD,qBACL,mBAAmB,aACnB,qBACA;IAAQ,SAAS;IAAkB,cAAc;MAChD;;;;;;;;;;;EAqBI,sBAAsB,aAAa;;;;;;;;;;;;;;;;;;;;;;EA2CnC,2BACL,aAAa,aACb,kBACC;;;;;;;;;;;;;;;;;;;;;;;;;;;EAqDI,gCACL,aAAa,aACb,iBACA,UAAU,8BACT;;;;;;;;;;;;;;EA0EI,uBACL,aAAa,aACb,4BACA;IAAW;IAAmB;;;;;;;;;;;;;;;;;EAmDzB,mBACL,aAAa,aACb,yCACC"}
1
+ {"version":3,"file":"project_helper.d.ts","names":[],"sources":["../../src/model/project_helper.ts"],"mappings":";;;;;;;;;;;;YA+BY;EACN;;EACA;EAAmB,gBAAgB,gBAAgB;EAAe;;qBAsB3D;mBAaQ;WACD,QAAQ;mBAbT;EAWjB,YACmB,SAAS,mBACV,SAAQ;;;;;;;;;;;;EAkBnB,sBACL,aAAa,aACb,sBACC;;;;;;;;;EAgCI,4BAA4B,aAAa,aAAa;;;;;;;;;;;;;;;;;;;;;;;;;;EAiDtD,gCACL,aAAa,aACb,sBACC;UAsDK;EAaD,qBACL,mBAAmB,aACnB,qBACA;IAAQ,SAAS;IAAkB,cAAc;MAChD;;;;;;;;;;;EAqBI,sBAAsB,aAAa;;;;;;;;;;;;;;;;;;;;;;EA2CnC,2BACL,aAAa,aACb,kBACC;;;;;;;;;;;;;;;;;;;;;;;;;;;EAqDI,gCACL,aAAa,aACb,iBACA,UAAU,8BACT;;;;;;;;;;;;;;EA0EI,uBACL,aAAa,aACb,4BACA;IAAW;IAAmB;;;;;;;;;;;;;;;;;EAmDzB,mBACL,aAAa,aACb,yCACC"}
@@ -3,7 +3,7 @@ import { executeSingleLambda } from "../js_render/index.js";
3
3
  import { BLOCK_STORAGE_FACADE_VERSION, BlockStorageFacadeCallbacks, ensureError, extractCodeWithInfo } from "@platforma-sdk/model";
4
4
  import { ConsoleLoggerAdapter } from "@milaboratories/ts-helpers";
5
5
  import { LRUCache } from "lru-cache";
6
- //#region src/model/project_helper.ts
6
+ // src/model/project_helper.ts
7
7
  var ProjectHelper = class {
8
8
  quickJs;
9
9
  logger;
@@ -250,7 +250,6 @@ var ProjectHelper = class {
250
250
  }
251
251
  }
252
252
  };
253
- //#endregion
254
253
  export { ProjectHelper };
255
254
 
256
255
  //# sourceMappingURL=project_helper.js.map
@@ -1,4 +1,4 @@
1
- //#region src/model/project_model.ts
1
+ // src/model/project_model.ts
2
2
  const InitialBlockStructure = { groups: [{
3
3
  id: "default",
4
4
  label: "Default",
@@ -53,7 +53,6 @@ function parseProjectField(name) {
53
53
  fieldName
54
54
  };
55
55
  }
56
- //#endregion
57
56
  exports.BlockArgsAuthorKeyPrefix = BlockArgsAuthorKeyPrefix;
58
57
  exports.BlockRenderingStateKey = BlockRenderingStateKey;
59
58
  exports.FieldsToDuplicate = FieldsToDuplicate;
@@ -2,7 +2,6 @@ import "@platforma-sdk/model";
2
2
  import { ProjectListEntry, ProjectMeta } from "@milaboratories/pl-model-middle-layer";
3
3
  import { ProjectId as ProjectId$1 } from "@milaboratories/pl-model-common";
4
4
  import { ResourceType } from "@milaboratories/pl-client";
5
- //#region src/model/project_model.d.ts
6
5
  interface ProjectListEntry$1 extends Omit<ProjectListEntry, "id"> {
7
6
  /** Unique project identifier in middle layer. Use to operate with given project. */
8
7
  id: ProjectId$1;
@@ -20,6 +19,5 @@ export interface ProjectField {
20
19
  blockId: string;
21
20
  fieldName: "blockPack" | "blockSettings" | "blockStorage" | "prodArgs" | "currentArgs" | "currentPrerunArgs" | "prodChainCtx" | "prodCtx" | "prodUiCtx" | "prodOutput" | "prodCtxPrevious" | "prodUiCtxPrevious" | "prodOutputPrevious" | "stagingCtx" | "stagingUiCtx" | "stagingOutput" | "stagingCtxPrevious" | "stagingUiCtxPrevious" | "stagingOutputPrevious";
22
21
  }
23
- //#endregion
24
22
  export { type ProjectId$1 as ProjectId, ProjectListEntry$1 as ProjectListEntry };
25
23
  //# sourceMappingURL=project_model.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"project_model.d.ts","names":[],"sources":["../../src/model/project_model.ts"],"mappings":";;;;;UAUiB,2BAAyB,KAAK;;EAE7C,IAAI;;qBA+DO,qBAAqB;qBAErB;qBAGA;qBAEA;qBACA;qBACA;qBACA;qBAGA;qBAOA;iBAQI;EACf;EACA"}
1
+ {"version":3,"file":"project_model.d.ts","names":["ProjectListEntry","ProjectListEntryFromModel","ProjectId"],"sources":["../../src/model/project_model.ts"],"mappings":";;;;UAUiBA,2BAAyB,KAAKC;;EAE7C,IAAIC;;qBA+DO,qBAAqB;qBAErB;qBAGA;qBAEA;qBACA;qBACA;qBACA;qBAGA;qBAOA;iBAQI;EACf;EACA"}
@@ -1,4 +1,4 @@
1
- //#region src/model/project_model.ts
1
+ // src/model/project_model.ts
2
2
  const InitialBlockStructure = { groups: [{
3
3
  id: "default",
4
4
  label: "Default",
@@ -53,7 +53,6 @@ function parseProjectField(name) {
53
53
  fieldName
54
54
  };
55
55
  }
56
- //#endregion
57
56
  export { BlockArgsAuthorKeyPrefix, BlockRenderingStateKey, FieldsToDuplicate, InitialBlockMeta, InitialBlockStructure, InitialProjectRenderingState, ProjectCreatedTimestamp, ProjectLastModifiedTimestamp, ProjectMetaKey, ProjectResourceType, ProjectStructureAuthorKey, ProjectStructureKey, SchemaVersionCurrent, SchemaVersionKey, ServiceTemplateCacheFieldPrefix, blockArgsAuthorKey, getServiceTemplateField, parseProjectField, projectFieldName };
58
57
 
59
58
  //# sourceMappingURL=project_model.js.map
@@ -1,5 +1,5 @@
1
1
  const require_args = require("./args.cjs");
2
- //#region src/model/project_model_util.ts
2
+ // src/model/project_model_util.ts
3
3
  function allBlocks(structure) {
4
4
  return { *[Symbol.iterator]() {
5
5
  for (const g of structure.groups) for (const b of g.blocks) yield b;
@@ -127,7 +127,6 @@ function graphDiff(a, b) {
127
127
  different
128
128
  };
129
129
  }
130
- //#endregion
131
130
  exports.BlockGraph = BlockGraph;
132
131
  exports.allBlocks = allBlocks;
133
132
  exports.graphDiff = graphDiff;
@@ -1,5 +1,5 @@
1
1
  import { inferAllReferencedBlocks } from "./args.js";
2
- //#region src/model/project_model_util.ts
2
+ // src/model/project_model_util.ts
3
3
  function allBlocks(structure) {
4
4
  return { *[Symbol.iterator]() {
5
5
  for (const g of structure.groups) for (const b of g.blocks) yield b;
@@ -127,7 +127,6 @@ function graphDiff(a, b) {
127
127
  different
128
128
  };
129
129
  }
130
- //#endregion
131
130
  export { BlockGraph, allBlocks, graphDiff, productionGraph, stagingGraph };
132
131
 
133
132
  //# sourceMappingURL=project_model_util.js.map
@@ -1,6 +1,5 @@
1
- //#region src/model/project_model_v1.ts
1
+ // src/model/project_model_v1.ts
2
2
  const BlockFrontendStateKeyPrefixV1 = "BlockFrontendState/";
3
- //#endregion
4
3
  exports.BlockFrontendStateKeyPrefixV1 = BlockFrontendStateKeyPrefixV1;
5
4
 
6
5
  //# sourceMappingURL=project_model_v1.cjs.map
@@ -1,6 +1,5 @@
1
- //#region src/model/project_model_v1.ts
1
+ // src/model/project_model_v1.ts
2
2
  const BlockFrontendStateKeyPrefixV1 = "BlockFrontendState/";
3
- //#endregion
4
3
  export { BlockFrontendStateKeyPrefixV1 };
5
4
 
6
5
  //# sourceMappingURL=project_model_v1.js.map
@@ -1,6 +1,6 @@
1
1
  let _milaboratories_pl_client = require("@milaboratories/pl-client");
2
2
  let node_crypto = require("node:crypto");
3
- //#region src/model/sharing_model.ts
3
+ // src/model/sharing_model.ts
4
4
  /** Mints a fresh {@link ShareId}. The single place a share's logical identity is created. */
5
5
  function newShareId() {
6
6
  return (0, node_crypto.randomUUID)();
@@ -155,7 +155,6 @@ const ReadableSchemaVersions = {
155
155
  1: true,
156
156
  2: true
157
157
  };
158
- //#endregion
159
158
  exports.EnvelopeSchemaVersionCurrent = EnvelopeSchemaVersionCurrent;
160
159
  exports.HiddenFieldPrefix = HiddenFieldPrefix;
161
160
  exports.SharedEnvelopeResourceType = SharedEnvelopeResourceType;
@@ -1 +1 @@
1
- {"version":3,"file":"sharing_model.cjs","names":["RoleEnum"],"sources":["../../src/model/sharing_model.ts"],"sourcesContent":["import type { ResourceType, Role } from \"@milaboratories/pl-client\";\nimport { Role as RoleEnum } from \"@milaboratories/pl-client\";\nimport type {\n Branded,\n ProjectId,\n ProjectTemplateV1,\n TemplateId,\n} from \"@milaboratories/pl-model-common\";\nimport type { FolderId } from \"@milaboratories/pl-model-middle-layer\";\nimport { randomUUID } from \"node:crypto\";\n\n/**\n * Identity of one share. A donor-generated UUID string,\n * branded so it cannot be silently confused with a project id, a login, or a raw field\n * name. Minted once with {@link newShareId}; every other site receives it (from decoded\n * {@link EnvelopeData} or by parsing a `decision/{shareId}` field name) and threads it\n * through unchanged.\n */\nexport type ShareId = Branded<string, \"ShareId\">;\n\n/** Mints a fresh {@link ShareId}. The single place a share's logical identity is created. */\nexport function newShareId(): ShareId {\n return randomUUID() as ShareId;\n}\n\n/** Brands a string already known to be a share id (e.g. parsed from a `decision/{shareId}`\n * field name) as a {@link ShareId}, without minting a new one. */\nexport function asShareId(id: string): ShareId {\n return id as ShareId;\n}\n\n//\n// Pl Model — Project Sharing\n//\n// All sharing structures are defined and managed by the middle layer; the\n// backend knows nothing about envelopes.\n//\n\n/** Field on the donor's clientRoot holding the {@link SharingOutboxResourceType} resource. */\nexport const SharingOutboxField = \"sharingOutbox\";\n/** Field on the recipient's clientRoot holding the {@link SharingStateResourceType} resource. */\nexport const SharingStateField = \"sharingState\";\n\nexport const SharingOutboxResourceType: ResourceType = { name: \"SharingOutbox\", version: \"1\" };\nexport const SharedEnvelopeResourceType: ResourceType = { name: \"SharedEnvelope\", version: \"1\" };\nexport const SharingStateResourceType: ResourceType = { name: \"SharingState\", version: \"1\" };\n\nexport type EnvelopeMode = \"copy\" | \"read-only\" | \"collaboration\";\n\n/** Key of the per-project envelope maps: a uuid minted per snapshot to name the `project/{uuid}`\n * field. Distinct from {@link ProjectId} — re-snapshotting one source yields a new uuid each time. */\nexport type ProjectFieldUuid = Branded<string, \"ProjectFieldUuid\">;\n\n/** Mints a fresh {@link ProjectFieldUuid} for one snapshot. */\nexport function newProjectFieldUuid(): ProjectFieldUuid {\n return randomUUID() as ProjectFieldUuid;\n}\n\n/**\n * Whether a role may make a resource public (grant to everyone): true for controller,\n * admin; false for workflow and unspecified. The middle layer carries no policy\n * of its own here — a crafted call still hits the backend's role + permission-ceiling gate.\n * `null` (no-auth mode) returns false.\n */\nexport function canGrantToEveryone(role: Role | null): boolean {\n switch (role) {\n case RoleEnum.CONTROLLER:\n case RoleEnum.ADMIN:\n return true;\n default:\n return false;\n }\n}\n\n/**\n * Whether a role may impersonate another user: open/create another user's root and list\n * the resources that user can access. Mirrors the backend's authorization rule\n * `util/misecurity/role.go` `CanImpersonate` — true for controller and admin only. This is\n * the admin gate for the \"open another user's root\" feature and is intentionally stricter\n * than {@link canGrantToEveryone}, which also returns true for a regular user (a normal user\n * may share their own projects, but must never be offered impersonation). `null` (no-auth\n * mode) returns false.\n */\nexport function canImpersonate(role: Role | null): boolean {\n switch (role) {\n case RoleEnum.CONTROLLER:\n case RoleEnum.ADMIN:\n return true;\n default:\n return false;\n }\n}\n\n/** One project's snapshot inside an envelope, keyed by {@link ProjectFieldUuid} in a\n * `projects` {@link EnvelopePayload}. */\nexport interface EnvelopeProject {\n label: string; // carried so the share lists render without traversing into the project\n source: ProjectId; // donor's source projectId; what a prior share of the same project is matched on\n updatedAt: number; // ms epoch of the last (re)snapshot\n /** What the project said about itself when it was snapshotted, carried for the same reason as\n * `label`. Absent when it had none, and on envelopes written before it was carried. */\n description?: string;\n}\n\n/**\n * Identifier of a folder inside one envelope.\n *\n * Local to the envelope, because the recipient's own folder document mints its own ids and the\n * donor's mean nothing there. What travels is the shape of the subtree, not its identity.\n */\nexport type EnvelopeFolderId = Branded<string, \"EnvelopeFolderId\">;\n\n/** Mints a fresh {@link EnvelopeFolderId} for one folder of the envelope being built. */\nexport function newEnvelopeFolderId(): EnvelopeFolderId {\n return randomUUID() as EnvelopeFolderId;\n}\n\n/** One folder of a shared subtree. */\nexport interface EnvelopeFolder {\n name: string;\n /** Absent for the subtree's root — the folder that was shared. */\n parent?: EnvelopeFolderId;\n /** What the donor wrote about the folder. Absent when there is none. */\n description?: string;\n}\n\n/** A project of a shared subtree: an {@link EnvelopeProject} placed in the subtree. */\nexport interface EnvelopeFolderProject extends EnvelopeProject {\n folder: EnvelopeFolderId;\n}\n\n/** A template of a shared subtree. The document rides here whole, exactly as a `template`\n * payload carries it — a template is never snapshotted. */\nexport interface EnvelopeFolderTemplate {\n document: ProjectTemplateV1;\n /** Label to give the template among the recipient's templates. */\n label: string;\n /** What the template says about itself. Absent when the donor described it with nothing. */\n description?: string;\n folder: EnvelopeFolderId;\n}\n\n/**\n * What a share carries. The discriminant is what a reader checks before anything else: a\n * client that does not know a kind hides the share instead of offering something it cannot\n * act on.\n *\n * `projects` snapshots ride as `project/{uuid}` fields on the envelope and this map only\n * describes them; a `template` payload has no fields at all — the document is right here.\n */\nexport type EnvelopePayload =\n | { kind: \"projects\"; projects: Record<ProjectFieldUuid, EnvelopeProject> }\n | {\n kind: \"template\";\n document: ProjectTemplateV1;\n /** Donor's own id of the shared template; what a prior share of the same template is\n * matched on. It names nothing in the recipient's tree, and envelopes written before it\n * existed carry none — those match no later share of anything. */\n source?: TemplateId;\n /** Label to give the template among the recipient's templates. */\n label: string;\n /** What the template says about itself, carried to the recipient's copy. Absent when the\n * donor described it with nothing. */\n description?: string;\n /** Donor login, kept on each copy of the template as its provenance. */\n from: string;\n }\n | {\n kind: \"folder\";\n /** Donor's own id of the shared folder; what a prior share of the same folder is matched\n * on. It names nothing in the recipient's tree. */\n source: FolderId;\n /** The shared subtree. Exactly one folder has no parent, and that one is its root. */\n folders: Record<EnvelopeFolderId, EnvelopeFolder>;\n /** Project snapshots, each tagged with the folder of the subtree holding it. Their\n * `project/{uuid}` fields are the same ones a `projects` payload describes. */\n projects: Record<ProjectFieldUuid, EnvelopeFolderProject>;\n /** Templates of the subtree, documents and all. Nothing of a template is snapshotted. */\n templates: EnvelopeFolderTemplate[];\n /** Donor login, kept on each copied template as its provenance. */\n from: string;\n };\n\nexport type EnvelopePayloadKind = EnvelopePayload[\"kind\"];\n\n/** Every envelope schema version this build can read. Adding a version here is what makes\n * {@link normalizeEnvelopeData} accept it; bumping {@link EnvelopeSchemaVersionCurrent} to a\n * version missing from this union is a compile error. */\nexport type EnvelopeSchemaVersion = 1 | 2;\n\n/** Version written into every new envelope. Bumped from 1 when the payload became discriminated. */\nexport const EnvelopeSchemaVersionCurrent = 2 satisfies EnvelopeSchemaVersion;\n\n/**\n * Immutable `data` on a SharedEnvelope, set at createEphemeral, never mutated.\n *\n * Always the current version in memory: a v1 envelope (project map at the top level, no\n * `payload` field) is upcast on read by {@link normalizeEnvelopeData}, so no reader past the\n * decode has to know that two shapes ever existed.\n */\nexport interface EnvelopeData {\n schemaVersion: typeof EnvelopeSchemaVersionCurrent;\n shareId: ShareId; // donor-generated UUID; identity of this share alone\n sharedAt: number; // ms epoch; when the share was created\n expiresAt: number | null; // ms epoch; sharedAt + ttl (default 14 days) for a targeted share; null for share-with-everybody (never expires)\n mode: EnvelopeMode; // what the recipient's app should do with the contents\n sender: string; // donor login (informational; backend granted_by is authoritative)\n title: string; // display name shown to recipients; defaults to the first project's name\n payload: EnvelopePayload; // what the share carries\n}\n\n/** The project map of a projects-payload envelope, or `{}` for any other payload — the one\n * place a project-shaped reader turns a payload into the map it expects. */\nexport function envelopeProjectMap(data: EnvelopeData): Record<ProjectFieldUuid, EnvelopeProject> {\n return data.payload.kind === \"projects\" ? data.payload.projects : {};\n}\n\n/**\n * The shared folder itself: the one folder of the subtree that has no parent.\n *\n * Derived rather than stored, so it cannot disagree with the folders beside it. `undefined` for\n * a subtree with no root or more than one, which is an envelope nothing can be reconstructed\n * from — the copy reports it rather than guessing which folder was meant.\n */\nexport function envelopeFolderRoot(\n folders: Record<EnvelopeFolderId, EnvelopeFolder>,\n): EnvelopeFolderId | undefined {\n const roots = (Object.keys(folders) as EnvelopeFolderId[]).filter(\n (id) => folders[id].parent === undefined,\n );\n return roots.length === 1 ? roots[0] : undefined;\n}\n\n/**\n * Dynamic field on SharingState, one per share this user has hidden, keyed by shareId.\n *\n * Hiding is private to the recipient and reversible: the field is written to put a share out of\n * sight and removed to bring it back. It says nothing to the donor and nothing about whether\n * anything was ever copied out of the share — a share can be copied from any number of times,\n * before or after being hidden.\n *\n * The field name keeps its original `decision/` prefix. Records written before hiding replaced\n * accept/reject carry a different value under the same key, and every reader treats the presence\n * of the field as the whole answer: someone who accepted or rejected a share back then does not\n * want to see it, which is exactly what hidden means.\n */\nexport const HiddenFieldPrefix = \"decision/\";\nexport const hiddenField = (shareId: ShareId) => `${HiddenFieldPrefix}${shareId}`;\nexport const isHiddenField = (name: string) => name.startsWith(HiddenFieldPrefix);\nexport const hiddenFieldShareId = (name: string): ShareId =>\n asShareId(name.slice(HiddenFieldPrefix.length));\n\nexport interface ShareHidden {\n hidden: true;\n timestamp: number; // ms epoch — when the recipient hid it\n}\n\n/**\n * Single owner of the raw-data → {@link EnvelopeData} decode. The envelope's immutable `data`\n * blob is UTF-8 JSON set once at createEphemeral; every site that reads it from a raw resource\n * `data` byte buffer (the basic-resource read path) goes through here. The reactive tree-node\n * path decodes the same JSON with `getDataAsJson` and normalizes it with\n * {@link normalizeEnvelopeData} — both paths must, so neither sees the raw v1 shape.\n *\n * `undefined` for an envelope this build cannot act on; see {@link normalizeEnvelopeData}.\n */\nexport function decodeEnvelopeData(data: Uint8Array): EnvelopeData | undefined {\n return normalizeEnvelopeData(JSON.parse(Buffer.from(data).toString(\"utf-8\")));\n}\n\n/**\n * Brings a decoded envelope blob to the current shape, or reports that this build cannot act\n * on it by returning `undefined` — an unknown `schemaVersion` or an unknown payload kind. A\n * caller hides such a share rather than offering the recipient something it cannot handle.\n *\n * A v1 envelope carried its project map at the top level and had no `payload` field; it reads\n * here as a `projects` payload, so envelopes written before the discriminant existed keep\n * working unchanged.\n */\nexport function normalizeEnvelopeData(raw: unknown): EnvelopeData | undefined {\n if (typeof raw !== \"object\" || raw === null) return undefined;\n const e = raw as RawEnvelopeData;\n if (!Object.hasOwn(ReadableSchemaVersions, e.schemaVersion)) return undefined;\n\n const payload =\n e.payload ??\n (e.projects !== undefined ? ({ kind: \"projects\", projects: e.projects } as const) : undefined);\n if (payload === undefined) return undefined;\n if (!Object.hasOwn(KnownPayloadKinds, payload.kind)) return undefined;\n\n return {\n schemaVersion: EnvelopeSchemaVersionCurrent,\n shareId: e.shareId,\n sharedAt: e.sharedAt,\n expiresAt: e.expiresAt,\n mode: e.mode,\n sender: e.sender,\n title: e.title,\n payload,\n };\n}\n\n/**\n * Who a share is granted to: named recipients XOR everyone — two clean variants, not one struct\n * with mutually exclusive optional fields.\n *\n * The everyone variant issues a single make-public grant, and the envelope's `expiresAt` is `null`,\n * so it never expires. The recipients variant grants each named login, and the envelope expires\n * after the default TTL.\n */\nexport type ShareAudience =\n | { recipients: string[] } // recipient logins\n | { everyone: true }; // every user on the server\n\n/**\n * Options every share takes: the audience, the title recipients see it under, and the prior\n * shares it replaces.\n */\nexport type ShareOptions = ShareAudience & {\n title: string;\n replace?: ShareReplaceOption;\n};\n\n/**\n * Prior shares the new one supersedes: each is deleted in the same transaction that creates the\n * replacement, so the outbox never holds both.\n *\n * The set is the caller's, never inferred here. The author is shown the shares that will go and\n * agrees to that list, so what was shown has to be what is deleted — an overlap rule computed on\n * this side would diverge from it. Ids that no longer resolve are skipped: a share revoked between\n * the dialog opening and the confirm is nothing to undo.\n *\n * The replacement is a new {@link ShareId}: a recipient who had hidden the old share sees the new\n * one, and copies already taken from the old share are untouched.\n */\nexport type ShareReplaceOption = ShareId[];\n\n/** Options for {@link MiddleLayer.shareProjects}: the common ones, plus what the recipient's app\n * does with the projects. */\nexport type ShareProjectsOptions = ShareOptions & { mode: EnvelopeMode };\n\n/** Options for {@link MiddleLayer.shareTemplate}. */\nexport type ShareTemplateOptions = ShareOptions;\n\n/** Options for {@link MiddleLayer.shareFolder}. */\nexport type ShareFolderOptions = ShareOptions;\n\n/** What creating a share hands back: the id of the share just created. */\nexport type ShareOutcome = { readonly shareId: ShareId };\n\n//\n// Internals\n//\n\n/** Every payload kind this build can act on; anything else is hidden rather than offered.\n * Keyed by {@link EnvelopePayloadKind}, so adding a kind to {@link EnvelopePayload} without\n * teaching the decoder about it is a compile error, not a share that silently disappears. */\nconst KnownPayloadKinds: Record<EnvelopePayloadKind, true> = {\n projects: true,\n template: true,\n folder: true,\n};\n\n/** Every schema version {@link normalizeEnvelopeData} accepts. Keyed by\n * {@link EnvelopeSchemaVersion}, so widening that union without deciding how the new shape\n * is upcast is a compile error. */\nconst ReadableSchemaVersions: Record<EnvelopeSchemaVersion, true> = {\n 1: true,\n 2: true,\n};\n\n/**\n * The envelope blob as it comes off the wire, before {@link normalizeEnvelopeData} decides\n * whether this build can act on it: the version is any number, the payload may be missing,\n * and `projects` is the v1 top-level project map.\n */\ntype RawEnvelopeData = Omit<EnvelopeData, \"schemaVersion\" | \"payload\"> & {\n schemaVersion: number;\n payload?: EnvelopePayload;\n projects?: Record<ProjectFieldUuid, EnvelopeProject>;\n};\n"],"mappings":";;;;AAqBA,SAAgB,aAAsB;CACpC,QAAA,GAAA,YAAA,WAAA,CAAkB;AACpB;;;AAIA,SAAgB,UAAU,IAAqB;CAC7C,OAAO;AACT;;AAUA,MAAa,qBAAqB;;AAElC,MAAa,oBAAoB;AAEjC,MAAa,4BAA0C;CAAE,MAAM;CAAiB,SAAS;AAAI;AAC7F,MAAa,6BAA2C;CAAE,MAAM;CAAkB,SAAS;AAAI;AAC/F,MAAa,2BAAyC;CAAE,MAAM;CAAgB,SAAS;AAAI;;AAS3F,SAAgB,sBAAwC;CACtD,QAAA,GAAA,YAAA,WAAA,CAAkB;AACpB;;;;;;;AAQA,SAAgB,mBAAmB,MAA4B;CAC7D,QAAQ,MAAR;EACE,KAAKA,0BAAAA,KAAS;EACd,KAAKA,0BAAAA,KAAS,OACZ,OAAO;EACT,SACE,OAAO;CACX;AACF;;;;;;;;;;AAWA,SAAgB,eAAe,MAA4B;CACzD,QAAQ,MAAR;EACE,KAAKA,0BAAAA,KAAS;EACd,KAAKA,0BAAAA,KAAS,OACZ,OAAO;EACT,SACE,OAAO;CACX;AACF;;AAsBA,SAAgB,sBAAwC;CACtD,QAAA,GAAA,YAAA,WAAA,CAAkB;AACpB;;AA4EA,MAAa,+BAA+B;;;AAsB5C,SAAgB,mBAAmB,MAA+D;CAChG,OAAO,KAAK,QAAQ,SAAS,aAAa,KAAK,QAAQ,WAAW,CAAC;AACrE;;;;;;;;AASA,SAAgB,mBACd,SAC8B;CAC9B,MAAM,QAAS,OAAO,KAAK,OAAO,CAAC,CAAwB,QACxD,OAAO,QAAQ,GAAG,CAAC,WAAW,KAAA,CACjC;CACA,OAAO,MAAM,WAAW,IAAI,MAAM,KAAK,KAAA;AACzC;;;;;;;;;;;;;;AAeA,MAAa,oBAAoB;AACjC,MAAa,eAAe,YAAqB,GAAG,oBAAoB;AACxE,MAAa,iBAAiB,SAAiB,KAAK,WAAW,iBAAiB;AAChF,MAAa,sBAAsB,SACjC,UAAU,KAAK,MAAM,CAAwB,CAAC;;;;;;;;;;AAgBhD,SAAgB,mBAAmB,MAA4C;CAC7E,OAAO,sBAAsB,KAAK,MAAM,OAAO,KAAK,IAAI,CAAC,CAAC,SAAS,OAAO,CAAC,CAAC;AAC9E;;;;;;;;;;AAWA,SAAgB,sBAAsB,KAAwC;CAC5E,IAAI,OAAO,QAAQ,YAAY,QAAQ,MAAM,OAAO,KAAA;CACpD,MAAM,IAAI;CACV,IAAI,CAAC,OAAO,OAAO,wBAAwB,EAAE,aAAa,GAAG,OAAO,KAAA;CAEpE,MAAM,UACJ,EAAE,YACD,EAAE,aAAa,KAAA,IAAa;EAAE,MAAM;EAAY,UAAU,EAAE;CAAS,IAAc,KAAA;CACtF,IAAI,YAAY,KAAA,GAAW,OAAO,KAAA;CAClC,IAAI,CAAC,OAAO,OAAO,mBAAmB,QAAQ,IAAI,GAAG,OAAO,KAAA;CAE5D,OAAO;EACL,eAAA;EACA,SAAS,EAAE;EACX,UAAU,EAAE;EACZ,WAAW,EAAE;EACb,MAAM,EAAE;EACR,QAAQ,EAAE;EACV,OAAO,EAAE;EACT;CACF;AACF;;;;AAyDA,MAAM,oBAAuD;CAC3D,UAAU;CACV,UAAU;CACV,QAAQ;AACV;;;;AAKA,MAAM,yBAA8D;CAClE,GAAG;CACH,GAAG;AACL"}
1
+ {"version":3,"file":"sharing_model.cjs","names":["randomUUID","RoleEnum"],"sources":["../../src/model/sharing_model.ts"],"sourcesContent":["import type { ResourceType, Role } from \"@milaboratories/pl-client\";\nimport { Role as RoleEnum } from \"@milaboratories/pl-client\";\nimport type {\n Branded,\n ProjectId,\n ProjectTemplateV1,\n TemplateId,\n} from \"@milaboratories/pl-model-common\";\nimport type { FolderId } from \"@milaboratories/pl-model-middle-layer\";\nimport { randomUUID } from \"node:crypto\";\n\n/**\n * Identity of one share. A donor-generated UUID string,\n * branded so it cannot be silently confused with a project id, a login, or a raw field\n * name. Minted once with {@link newShareId}; every other site receives it (from decoded\n * {@link EnvelopeData} or by parsing a `decision/{shareId}` field name) and threads it\n * through unchanged.\n */\nexport type ShareId = Branded<string, \"ShareId\">;\n\n/** Mints a fresh {@link ShareId}. The single place a share's logical identity is created. */\nexport function newShareId(): ShareId {\n return randomUUID() as ShareId;\n}\n\n/** Brands a string already known to be a share id (e.g. parsed from a `decision/{shareId}`\n * field name) as a {@link ShareId}, without minting a new one. */\nexport function asShareId(id: string): ShareId {\n return id as ShareId;\n}\n\n//\n// Pl Model — Project Sharing\n//\n// All sharing structures are defined and managed by the middle layer; the\n// backend knows nothing about envelopes.\n//\n\n/** Field on the donor's clientRoot holding the {@link SharingOutboxResourceType} resource. */\nexport const SharingOutboxField = \"sharingOutbox\";\n/** Field on the recipient's clientRoot holding the {@link SharingStateResourceType} resource. */\nexport const SharingStateField = \"sharingState\";\n\nexport const SharingOutboxResourceType: ResourceType = { name: \"SharingOutbox\", version: \"1\" };\nexport const SharedEnvelopeResourceType: ResourceType = { name: \"SharedEnvelope\", version: \"1\" };\nexport const SharingStateResourceType: ResourceType = { name: \"SharingState\", version: \"1\" };\n\nexport type EnvelopeMode = \"copy\" | \"read-only\" | \"collaboration\";\n\n/** Key of the per-project envelope maps: a uuid minted per snapshot to name the `project/{uuid}`\n * field. Distinct from {@link ProjectId} — re-snapshotting one source yields a new uuid each time. */\nexport type ProjectFieldUuid = Branded<string, \"ProjectFieldUuid\">;\n\n/** Mints a fresh {@link ProjectFieldUuid} for one snapshot. */\nexport function newProjectFieldUuid(): ProjectFieldUuid {\n return randomUUID() as ProjectFieldUuid;\n}\n\n/**\n * Whether a role may make a resource public (grant to everyone): true for controller,\n * admin; false for workflow and unspecified. The middle layer carries no policy\n * of its own here — a crafted call still hits the backend's role + permission-ceiling gate.\n * `null` (no-auth mode) returns false.\n */\nexport function canGrantToEveryone(role: Role | null): boolean {\n switch (role) {\n case RoleEnum.CONTROLLER:\n case RoleEnum.ADMIN:\n return true;\n default:\n return false;\n }\n}\n\n/**\n * Whether a role may impersonate another user: open/create another user's root and list\n * the resources that user can access. Mirrors the backend's authorization rule\n * `util/misecurity/role.go` `CanImpersonate` — true for controller and admin only. This is\n * the admin gate for the \"open another user's root\" feature and is intentionally stricter\n * than {@link canGrantToEveryone}, which also returns true for a regular user (a normal user\n * may share their own projects, but must never be offered impersonation). `null` (no-auth\n * mode) returns false.\n */\nexport function canImpersonate(role: Role | null): boolean {\n switch (role) {\n case RoleEnum.CONTROLLER:\n case RoleEnum.ADMIN:\n return true;\n default:\n return false;\n }\n}\n\n/** One project's snapshot inside an envelope, keyed by {@link ProjectFieldUuid} in a\n * `projects` {@link EnvelopePayload}. */\nexport interface EnvelopeProject {\n label: string; // carried so the share lists render without traversing into the project\n source: ProjectId; // donor's source projectId; what a prior share of the same project is matched on\n updatedAt: number; // ms epoch of the last (re)snapshot\n /** What the project said about itself when it was snapshotted, carried for the same reason as\n * `label`. Absent when it had none, and on envelopes written before it was carried. */\n description?: string;\n}\n\n/**\n * Identifier of a folder inside one envelope.\n *\n * Local to the envelope, because the recipient's own folder document mints its own ids and the\n * donor's mean nothing there. What travels is the shape of the subtree, not its identity.\n */\nexport type EnvelopeFolderId = Branded<string, \"EnvelopeFolderId\">;\n\n/** Mints a fresh {@link EnvelopeFolderId} for one folder of the envelope being built. */\nexport function newEnvelopeFolderId(): EnvelopeFolderId {\n return randomUUID() as EnvelopeFolderId;\n}\n\n/** One folder of a shared subtree. */\nexport interface EnvelopeFolder {\n name: string;\n /** Absent for the subtree's root — the folder that was shared. */\n parent?: EnvelopeFolderId;\n /** What the donor wrote about the folder. Absent when there is none. */\n description?: string;\n}\n\n/** A project of a shared subtree: an {@link EnvelopeProject} placed in the subtree. */\nexport interface EnvelopeFolderProject extends EnvelopeProject {\n folder: EnvelopeFolderId;\n}\n\n/** A template of a shared subtree. The document rides here whole, exactly as a `template`\n * payload carries it — a template is never snapshotted. */\nexport interface EnvelopeFolderTemplate {\n document: ProjectTemplateV1;\n /** Label to give the template among the recipient's templates. */\n label: string;\n /** What the template says about itself. Absent when the donor described it with nothing. */\n description?: string;\n folder: EnvelopeFolderId;\n}\n\n/**\n * What a share carries. The discriminant is what a reader checks before anything else: a\n * client that does not know a kind hides the share instead of offering something it cannot\n * act on.\n *\n * `projects` snapshots ride as `project/{uuid}` fields on the envelope and this map only\n * describes them; a `template` payload has no fields at all — the document is right here.\n */\nexport type EnvelopePayload =\n | { kind: \"projects\"; projects: Record<ProjectFieldUuid, EnvelopeProject> }\n | {\n kind: \"template\";\n document: ProjectTemplateV1;\n /** Donor's own id of the shared template; what a prior share of the same template is\n * matched on. It names nothing in the recipient's tree, and envelopes written before it\n * existed carry none — those match no later share of anything. */\n source?: TemplateId;\n /** Label to give the template among the recipient's templates. */\n label: string;\n /** What the template says about itself, carried to the recipient's copy. Absent when the\n * donor described it with nothing. */\n description?: string;\n /** Donor login, kept on each copy of the template as its provenance. */\n from: string;\n }\n | {\n kind: \"folder\";\n /** Donor's own id of the shared folder; what a prior share of the same folder is matched\n * on. It names nothing in the recipient's tree. */\n source: FolderId;\n /** The shared subtree. Exactly one folder has no parent, and that one is its root. */\n folders: Record<EnvelopeFolderId, EnvelopeFolder>;\n /** Project snapshots, each tagged with the folder of the subtree holding it. Their\n * `project/{uuid}` fields are the same ones a `projects` payload describes. */\n projects: Record<ProjectFieldUuid, EnvelopeFolderProject>;\n /** Templates of the subtree, documents and all. Nothing of a template is snapshotted. */\n templates: EnvelopeFolderTemplate[];\n /** Donor login, kept on each copied template as its provenance. */\n from: string;\n };\n\nexport type EnvelopePayloadKind = EnvelopePayload[\"kind\"];\n\n/** Every envelope schema version this build can read. Adding a version here is what makes\n * {@link normalizeEnvelopeData} accept it; bumping {@link EnvelopeSchemaVersionCurrent} to a\n * version missing from this union is a compile error. */\nexport type EnvelopeSchemaVersion = 1 | 2;\n\n/** Version written into every new envelope. Bumped from 1 when the payload became discriminated. */\nexport const EnvelopeSchemaVersionCurrent = 2 satisfies EnvelopeSchemaVersion;\n\n/**\n * Immutable `data` on a SharedEnvelope, set at createEphemeral, never mutated.\n *\n * Always the current version in memory: a v1 envelope (project map at the top level, no\n * `payload` field) is upcast on read by {@link normalizeEnvelopeData}, so no reader past the\n * decode has to know that two shapes ever existed.\n */\nexport interface EnvelopeData {\n schemaVersion: typeof EnvelopeSchemaVersionCurrent;\n shareId: ShareId; // donor-generated UUID; identity of this share alone\n sharedAt: number; // ms epoch; when the share was created\n expiresAt: number | null; // ms epoch; sharedAt + ttl (default 14 days) for a targeted share; null for share-with-everybody (never expires)\n mode: EnvelopeMode; // what the recipient's app should do with the contents\n sender: string; // donor login (informational; backend granted_by is authoritative)\n title: string; // display name shown to recipients; defaults to the first project's name\n payload: EnvelopePayload; // what the share carries\n}\n\n/** The project map of a projects-payload envelope, or `{}` for any other payload — the one\n * place a project-shaped reader turns a payload into the map it expects. */\nexport function envelopeProjectMap(data: EnvelopeData): Record<ProjectFieldUuid, EnvelopeProject> {\n return data.payload.kind === \"projects\" ? data.payload.projects : {};\n}\n\n/**\n * The shared folder itself: the one folder of the subtree that has no parent.\n *\n * Derived rather than stored, so it cannot disagree with the folders beside it. `undefined` for\n * a subtree with no root or more than one, which is an envelope nothing can be reconstructed\n * from — the copy reports it rather than guessing which folder was meant.\n */\nexport function envelopeFolderRoot(\n folders: Record<EnvelopeFolderId, EnvelopeFolder>,\n): EnvelopeFolderId | undefined {\n const roots = (Object.keys(folders) as EnvelopeFolderId[]).filter(\n (id) => folders[id].parent === undefined,\n );\n return roots.length === 1 ? roots[0] : undefined;\n}\n\n/**\n * Dynamic field on SharingState, one per share this user has hidden, keyed by shareId.\n *\n * Hiding is private to the recipient and reversible: the field is written to put a share out of\n * sight and removed to bring it back. It says nothing to the donor and nothing about whether\n * anything was ever copied out of the share — a share can be copied from any number of times,\n * before or after being hidden.\n *\n * The field name keeps its original `decision/` prefix. Records written before hiding replaced\n * accept/reject carry a different value under the same key, and every reader treats the presence\n * of the field as the whole answer: someone who accepted or rejected a share back then does not\n * want to see it, which is exactly what hidden means.\n */\nexport const HiddenFieldPrefix = \"decision/\";\nexport const hiddenField = (shareId: ShareId) => `${HiddenFieldPrefix}${shareId}`;\nexport const isHiddenField = (name: string) => name.startsWith(HiddenFieldPrefix);\nexport const hiddenFieldShareId = (name: string): ShareId =>\n asShareId(name.slice(HiddenFieldPrefix.length));\n\nexport interface ShareHidden {\n hidden: true;\n timestamp: number; // ms epoch — when the recipient hid it\n}\n\n/**\n * Single owner of the raw-data → {@link EnvelopeData} decode. The envelope's immutable `data`\n * blob is UTF-8 JSON set once at createEphemeral; every site that reads it from a raw resource\n * `data` byte buffer (the basic-resource read path) goes through here. The reactive tree-node\n * path decodes the same JSON with `getDataAsJson` and normalizes it with\n * {@link normalizeEnvelopeData} — both paths must, so neither sees the raw v1 shape.\n *\n * `undefined` for an envelope this build cannot act on; see {@link normalizeEnvelopeData}.\n */\nexport function decodeEnvelopeData(data: Uint8Array): EnvelopeData | undefined {\n return normalizeEnvelopeData(JSON.parse(Buffer.from(data).toString(\"utf-8\")));\n}\n\n/**\n * Brings a decoded envelope blob to the current shape, or reports that this build cannot act\n * on it by returning `undefined` — an unknown `schemaVersion` or an unknown payload kind. A\n * caller hides such a share rather than offering the recipient something it cannot handle.\n *\n * A v1 envelope carried its project map at the top level and had no `payload` field; it reads\n * here as a `projects` payload, so envelopes written before the discriminant existed keep\n * working unchanged.\n */\nexport function normalizeEnvelopeData(raw: unknown): EnvelopeData | undefined {\n if (typeof raw !== \"object\" || raw === null) return undefined;\n const e = raw as RawEnvelopeData;\n if (!Object.hasOwn(ReadableSchemaVersions, e.schemaVersion)) return undefined;\n\n const payload =\n e.payload ??\n (e.projects !== undefined ? ({ kind: \"projects\", projects: e.projects } as const) : undefined);\n if (payload === undefined) return undefined;\n if (!Object.hasOwn(KnownPayloadKinds, payload.kind)) return undefined;\n\n return {\n schemaVersion: EnvelopeSchemaVersionCurrent,\n shareId: e.shareId,\n sharedAt: e.sharedAt,\n expiresAt: e.expiresAt,\n mode: e.mode,\n sender: e.sender,\n title: e.title,\n payload,\n };\n}\n\n/**\n * Who a share is granted to: named recipients XOR everyone — two clean variants, not one struct\n * with mutually exclusive optional fields.\n *\n * The everyone variant issues a single make-public grant, and the envelope's `expiresAt` is `null`,\n * so it never expires. The recipients variant grants each named login, and the envelope expires\n * after the default TTL.\n */\nexport type ShareAudience =\n | { recipients: string[] } // recipient logins\n | { everyone: true }; // every user on the server\n\n/**\n * Options every share takes: the audience, the title recipients see it under, and the prior\n * shares it replaces.\n */\nexport type ShareOptions = ShareAudience & {\n title: string;\n replace?: ShareReplaceOption;\n};\n\n/**\n * Prior shares the new one supersedes: each is deleted in the same transaction that creates the\n * replacement, so the outbox never holds both.\n *\n * The set is the caller's, never inferred here. The author is shown the shares that will go and\n * agrees to that list, so what was shown has to be what is deleted — an overlap rule computed on\n * this side would diverge from it. Ids that no longer resolve are skipped: a share revoked between\n * the dialog opening and the confirm is nothing to undo.\n *\n * The replacement is a new {@link ShareId}: a recipient who had hidden the old share sees the new\n * one, and copies already taken from the old share are untouched.\n */\nexport type ShareReplaceOption = ShareId[];\n\n/** Options for {@link MiddleLayer.shareProjects}: the common ones, plus what the recipient's app\n * does with the projects. */\nexport type ShareProjectsOptions = ShareOptions & { mode: EnvelopeMode };\n\n/** Options for {@link MiddleLayer.shareTemplate}. */\nexport type ShareTemplateOptions = ShareOptions;\n\n/** Options for {@link MiddleLayer.shareFolder}. */\nexport type ShareFolderOptions = ShareOptions;\n\n/** What creating a share hands back: the id of the share just created. */\nexport type ShareOutcome = { readonly shareId: ShareId };\n\n//\n// Internals\n//\n\n/** Every payload kind this build can act on; anything else is hidden rather than offered.\n * Keyed by {@link EnvelopePayloadKind}, so adding a kind to {@link EnvelopePayload} without\n * teaching the decoder about it is a compile error, not a share that silently disappears. */\nconst KnownPayloadKinds: Record<EnvelopePayloadKind, true> = {\n projects: true,\n template: true,\n folder: true,\n};\n\n/** Every schema version {@link normalizeEnvelopeData} accepts. Keyed by\n * {@link EnvelopeSchemaVersion}, so widening that union without deciding how the new shape\n * is upcast is a compile error. */\nconst ReadableSchemaVersions: Record<EnvelopeSchemaVersion, true> = {\n 1: true,\n 2: true,\n};\n\n/**\n * The envelope blob as it comes off the wire, before {@link normalizeEnvelopeData} decides\n * whether this build can act on it: the version is any number, the payload may be missing,\n * and `projects` is the v1 top-level project map.\n */\ntype RawEnvelopeData = Omit<EnvelopeData, \"schemaVersion\" | \"payload\"> & {\n schemaVersion: number;\n payload?: EnvelopePayload;\n projects?: Record<ProjectFieldUuid, EnvelopeProject>;\n};\n"],"mappings":";;;;AAqBA,SAAgB,aAAsB;CACpC,QAAA,GAAOA,YAAAA,WAAAA,CAAW;AACpB;;;AAIA,SAAgB,UAAU,IAAqB;CAC7C,OAAO;AACT;;AAUA,MAAa,qBAAqB;;AAElC,MAAa,oBAAoB;AAEjC,MAAa,4BAA0C;CAAE,MAAM;CAAiB,SAAS;AAAI;AAC7F,MAAa,6BAA2C;CAAE,MAAM;CAAkB,SAAS;AAAI;AAC/F,MAAa,2BAAyC;CAAE,MAAM;CAAgB,SAAS;AAAI;;AAS3F,SAAgB,sBAAwC;CACtD,QAAA,GAAOA,YAAAA,WAAAA,CAAW;AACpB;;;;;;;AAQA,SAAgB,mBAAmB,MAA4B;CAC7D,QAAQ,MAAR;EACE,KAAKC,0BAAAA,KAAS;EACd,KAAKA,0BAAAA,KAAS,OACZ,OAAO;EACT,SACE,OAAO;CACX;AACF;;;;;;;;;;AAWA,SAAgB,eAAe,MAA4B;CACzD,QAAQ,MAAR;EACE,KAAKA,0BAAAA,KAAS;EACd,KAAKA,0BAAAA,KAAS,OACZ,OAAO;EACT,SACE,OAAO;CACX;AACF;;AAsBA,SAAgB,sBAAwC;CACtD,QAAA,GAAOD,YAAAA,WAAAA,CAAW;AACpB;;AA4EA,MAAa,+BAA+B;;;AAsB5C,SAAgB,mBAAmB,MAA+D;CAChG,OAAO,KAAK,QAAQ,SAAS,aAAa,KAAK,QAAQ,WAAW,CAAC;AACrE;;;;;;;;AASA,SAAgB,mBACd,SAC8B;CAC9B,MAAM,QAAS,OAAO,KAAK,OAAO,CAAC,CAAwB,QACxD,OAAO,QAAQ,GAAG,CAAC,WAAW,KAAA,CACjC;CACA,OAAO,MAAM,WAAW,IAAI,MAAM,KAAK,KAAA;AACzC;;;;;;;;;;;;;;AAeA,MAAa,oBAAoB;AACjC,MAAa,eAAe,YAAqB,GAAG,oBAAoB;AACxE,MAAa,iBAAiB,SAAiB,KAAK,WAAW,iBAAiB;AAChF,MAAa,sBAAsB,SACjC,UAAU,KAAK,MAAM,CAAwB,CAAC;;;;;;;;;;AAgBhD,SAAgB,mBAAmB,MAA4C;CAC7E,OAAO,sBAAsB,KAAK,MAAM,OAAO,KAAK,IAAI,CAAC,CAAC,SAAS,OAAO,CAAC,CAAC;AAC9E;;;;;;;;;;AAWA,SAAgB,sBAAsB,KAAwC;CAC5E,IAAI,OAAO,QAAQ,YAAY,QAAQ,MAAM,OAAO,KAAA;CACpD,MAAM,IAAI;CACV,IAAI,CAAC,OAAO,OAAO,wBAAwB,EAAE,aAAa,GAAG,OAAO,KAAA;CAEpE,MAAM,UACJ,EAAE,YACD,EAAE,aAAa,KAAA,IAAa;EAAE,MAAM;EAAY,UAAU,EAAE;CAAS,IAAc,KAAA;CACtF,IAAI,YAAY,KAAA,GAAW,OAAO,KAAA;CAClC,IAAI,CAAC,OAAO,OAAO,mBAAmB,QAAQ,IAAI,GAAG,OAAO,KAAA;CAE5D,OAAO;EACL,eAAA;EACA,SAAS,EAAE;EACX,UAAU,EAAE;EACZ,WAAW,EAAE;EACb,MAAM,EAAE;EACR,QAAQ,EAAE;EACV,OAAO,EAAE;EACT;CACF;AACF;;;;AAyDA,MAAM,oBAAuD;CAC3D,UAAU;CACV,UAAU;CACV,QAAQ;AACV;;;;AAKA,MAAM,yBAA8D;CAClE,GAAG;CACH,GAAG;AACL"}
@@ -1,7 +1,6 @@
1
1
  import { FolderId } from "@milaboratories/pl-model-middle-layer";
2
2
  import { Branded, ProjectId, ProjectTemplateV1, TemplateId } from "@milaboratories/pl-model-common";
3
3
  import { ResourceType, Role } from "@milaboratories/pl-client";
4
- //#region src/model/sharing_model.d.ts
5
4
  /**
6
5
  * Identity of one share. A donor-generated UUID string,
7
6
  * branded so it cannot be silently confused with a project id, a login, or a raw field
@@ -249,5 +248,4 @@ export type ShareFolderOptions = ShareOptions;
249
248
  export type ShareOutcome = {
250
249
  readonly shareId: ShareId;
251
250
  };
252
- //#endregion
253
251
  //# sourceMappingURL=sharing_model.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"sharing_model.d.ts","names":[],"sources":["../../src/model/sharing_model.ts"],"mappings":";;;;;;;;;;;YAkBY,UAAU;;wBAGN,cAAc;;;wBAMd,UAAU,aAAa;;qBAY1B;;qBAEA;qBAEA,2BAA2B;qBAC3B,4BAA4B;qBAC5B,0BAA0B;YAE3B;;;YAIA,mBAAmB;;wBAGf,uBAAuB;;;;;;;wBAUvB,mBAAmB,MAAM;;;;;;;;;;wBAmBzB,eAAe,MAAM;;;iBAYpB;EACf;EACA,QAAQ;EACR;;;EAGA;;;;;;;;YASU,mBAAmB;;wBAGf,uBAAuB;;iBAKtB;EACf;;EAEA,SAAS;;EAET;;;iBAIe,8BAA8B;EAC7C,QAAQ;;;;iBAKO;EACf,UAAU;;EAEV;;EAEA;EACA,QAAQ;;;;;;;;;;YAWE;EACN;EAAkB,UAAU,OAAO,kBAAkB;;EAErD;EACA,UAAU;;;;EAIV,SAAS;;EAET;;;EAGA;;EAEA;;EAGA;;;EAGA,QAAQ;;EAER,SAAS,OAAO,kBAAkB;;;EAGlC,UAAU,OAAO,kBAAkB;;EAEnC,WAAW;;EAEX;;YAGM,sBAAsB;;;;YAKtB;;qBAGC;;;;;;;;iBASI;EACf,sBAAsB;EACtB,SAAS;EACT;EACA;EACA,MAAM;EACN;EACA;EACA,SAAS;;;;wBAKK,mBAAmB,MAAM,eAAe,OAAO,kBAAkB;;;;;;;;wBAWjE,mBACd,SAAS,OAAO,kBAAkB,kBACjC;;;;;;;;;;;;;;qBAoBU;qBACA,cAAW,SAAa;qBACxB,gBAAa;qBACb,qBAAkB,iBAAmB;iBAGjC;EACf;EACA;;;;;;;;;;;wBAYc,mBAAmB,MAAM,aAAa;;;;;;;;;;wBAatC,sBAAsB,eAAe;;;;;;;;;YA+BzC;EACN;;EACA;;;;;;YAMM,eAAe;EACzB;EACA,UAAU;;;;;;;;;;;;;;YAeA,qBAAqB;;;YAIrB,uBAAuB;EAAiB,MAAM;;;YAG9C,uBAAuB;;YAGvB,qBAAqB;;YAGrB;WAA0B,SAAS"}
1
+ {"version":3,"file":"sharing_model.d.ts","names":[],"sources":["../../src/model/sharing_model.ts"],"mappings":";;;;;;;;;;YAkBY,UAAU;;wBAGN,cAAc;;;wBAMd,UAAU,aAAa;;qBAY1B;;qBAEA;qBAEA,2BAA2B;qBAC3B,4BAA4B;qBAC5B,0BAA0B;YAE3B;;;YAIA,mBAAmB;;wBAGf,uBAAuB;;;;;;;wBAUvB,mBAAmB,MAAM;;;;;;;;;;wBAmBzB,eAAe,MAAM;;;iBAYpB;EACf;EACA,QAAQ;EACR;;;EAGA;;;;;;;;YASU,mBAAmB;;wBAGf,uBAAuB;;iBAKtB;EACf;;EAEA,SAAS;;EAET;;;iBAIe,8BAA8B;EAC7C,QAAQ;;;;iBAKO;EACf,UAAU;;EAEV;;EAEA;EACA,QAAQ;;;;;;;;;;YAWE;EACN;EAAkB,UAAU,OAAO,kBAAkB;;EAErD;EACA,UAAU;;;;EAIV,SAAS;;EAET;;;EAGA;;EAEA;;EAGA;;;EAGA,QAAQ;;EAER,SAAS,OAAO,kBAAkB;;;EAGlC,UAAU,OAAO,kBAAkB;;EAEnC,WAAW;;EAEX;;YAGM,sBAAsB;;;;YAKtB;;qBAGC;;;;;;;;iBASI;EACf,sBAAsB;EACtB,SAAS;EACT;EACA;EACA,MAAM;EACN;EACA;EACA,SAAS;;;;wBAKK,mBAAmB,MAAM,eAAe,OAAO,kBAAkB;;;;;;;;wBAWjE,mBACd,SAAS,OAAO,kBAAkB,kBACjC;;;;;;;;;;;;;;qBAoBU;qBACA,cAAW,SAAa;qBACxB,gBAAa;qBACb,qBAAkB,iBAAmB;iBAGjC;EACf;EACA;;;;;;;;;;;wBAYc,mBAAmB,MAAM,aAAa;;;;;;;;;;wBAatC,sBAAsB,eAAe;;;;;;;;;YA+BzC;EACN;;EACA;;;;;;YAMM,eAAe;EACzB;EACA,UAAU;;;;;;;;;;;;;;YAeA,qBAAqB;;;YAIrB,uBAAuB;EAAiB,MAAM;;;YAG9C,uBAAuB;;YAGvB,qBAAqB;;YAGrB;WAA0B,SAAS"}
@@ -1,6 +1,6 @@
1
1
  import { Role } from "@milaboratories/pl-client";
2
2
  import { randomUUID } from "node:crypto";
3
- //#region src/model/sharing_model.ts
3
+ // src/model/sharing_model.ts
4
4
  /** Mints a fresh {@link ShareId}. The single place a share's logical identity is created. */
5
5
  function newShareId() {
6
6
  return randomUUID();
@@ -155,7 +155,6 @@ const ReadableSchemaVersions = {
155
155
  1: true,
156
156
  2: true
157
157
  };
158
- //#endregion
159
158
  export { EnvelopeSchemaVersionCurrent, HiddenFieldPrefix, SharedEnvelopeResourceType, SharingOutboxField, SharingOutboxResourceType, SharingStateField, SharingStateResourceType, asShareId, canGrantToEveryone, canImpersonate, decodeEnvelopeData, envelopeFolderRoot, envelopeProjectMap, hiddenField, hiddenFieldShareId, isHiddenField, newEnvelopeFolderId, newProjectFieldUuid, newShareId, normalizeEnvelopeData };
160
159
 
161
160
  //# sourceMappingURL=sharing_model.js.map
@@ -4,7 +4,7 @@ let _platforma_sdk_block_tools = require("@platforma-sdk/block-tools");
4
4
  let _milaboratories_pl_model_common = require("@milaboratories/pl-model-common");
5
5
  let semver = require("semver");
6
6
  semver = require_runtime.__toESM(semver, 1);
7
- //#region src/model/template_apply.ts
7
+ // src/model/template_apply.ts
8
8
  /**
9
9
  * One entry the file describes in a way this project cannot honour.
10
10
  *
@@ -60,7 +60,6 @@ function kindMismatch(asked, declared) {
60
60
  if (wanted.name !== has.name) return `This entry asks for kind '${wanted.name}', but the block resolved for it implements '${has.name}'`;
61
61
  if (!semver.satisfies(has.version, (0, _platforma_sdk_block_tools.selectorToRange)(wanted.selector))) return `This entry asks for '${asked}', but the block resolved for it implements version ${has.version} of that kind`;
62
62
  }
63
- //#endregion
64
63
  exports.TemplateEntryRejected = TemplateEntryRejected;
65
64
  exports.kindMismatch = kindMismatch;
66
65
 
@@ -1 +1 @@
1
- {"version":3,"file":"template_apply.cjs","names":[],"sources":["../../src/model/template_apply.ts"],"sourcesContent":["import type {\n BlockKindReference,\n BlockKindSelectorReference,\n} from \"@milaboratories/pl-model-common\";\nimport { parseKindRef, parseKindSelectorReference } from \"@milaboratories/pl-model-common\";\nimport { selectorToRange } from \"@platforma-sdk/block-tools\";\nimport { ensureError } from \"@platforma-sdk/model\";\nimport * as semver from \"semver\";\n\n/**\n * One entry the file describes in a way this project cannot honour.\n *\n * Thrown, not returned, and that is the whole failure policy: an apply either creates every\n * entry or creates none. It travels out through the open transaction, which is therefore\n * never committed, so a rejected file leaves the project exactly as it was. The caller turns\n * it into a {@link TemplateApplyProblem}; anything else reaching that caller is an outage\n * rather than a statement about the file, and keeps propagating.\n */\nexport class TemplateEntryRejected extends Error {\n constructor(\n readonly entryId: string,\n message: string,\n ) {\n super(message);\n this.name = \"TemplateEntryRejected\";\n }\n}\n\n/**\n * Something that stopped one entry from being applied.\n *\n * Every stage of an apply reports in this shape — resolution, validation,\n * construction — so a caller assembles one list and the reader sees which entry in\n * their file each problem belongs to. `error` is a finished sentence for the person\n * who applied the file, not a code.\n */\nexport type TemplateApplyProblem = {\n /** The template-local id of the entry the problem belongs to. */\n readonly entryId: string;\n readonly error: string;\n};\n\n/** One entry that made it into the project. */\nexport type AppliedEntry = {\n /** The entry's id in the file. */\n readonly templateLocalId: string;\n /** The project-local id the block was given. */\n readonly blockId: string;\n};\n\n/**\n * What a whole apply — reading, checking, resolving, placing — left behind.\n *\n * One shape for every stage's findings, because the reader does not care which stage\n * objected. `problems` empty means the project holds exactly what the document described;\n * otherwise `added` is empty, because no stage creates anything until every entry has passed.\n *\n * A stage that checks reports every problem it found, so a file with three mistakes takes one\n * pass to fix. Placement stops at the first one — hence at most one problem from there.\n */\nexport type TemplateApplyReport = {\n readonly added: readonly AppliedEntry[];\n readonly problems: readonly TemplateApplyProblem[];\n};\n\n/**\n * Why the block prepared for an entry cannot serve it, or `undefined` when it can.\n *\n * An entry's `kind` is the contract its params are written against, so the block that ends up\n * installed has to implement it. Only one of the three routes to a block gives that for free:\n * kind resolution, where the kind's own projection picks the block. The two overrides do not —\n * a location's folder can change without the file changing, and a pinned version names a\n * package with no reference to a kind at all.\n *\n * So this belongs here, with the apply's other per-entry checks, and not in resolution: it is\n * asked once, of the block that was actually prepared, whichever route found it. Resolution\n * could answer it for a location — `byLocation` reads the block's config anyway — and doing so\n * there would have been a second place stating the same invariant, with the pinned-version\n * route still uncovered. One caller is the point.\n *\n * It is also the check that makes the params check meaningful, so it is asked first: params are\n * checked by the INSTALLED block's kind parser, which against a block of the wrong kind would\n * hold params written for one contract against another.\n *\n * Version comparison goes through the same selector-to-range translation the registry resolver\n * uses, so \"this resolves locally\" and \"this would resolve once published\" cannot disagree\n * about the version math.\n *\n * Messages name no route, so a caller adds whichever locator the entry carried.\n */\nexport function kindMismatch(\n asked: BlockKindSelectorReference,\n declared: BlockKindReference | undefined,\n): string | undefined {\n if (declared === undefined) {\n return (\n \"The block resolved for this entry declares no kind, so it cannot be the \" +\n \"implementation it asks for\"\n );\n }\n\n let wanted: { name: string; selector: { op: \"exact\" | \"patch\" | \"minor\"; version: string } };\n let has: { name: string; version: string };\n try {\n wanted = parseKindSelectorReference(asked);\n has = parseKindRef(declared);\n } catch (e) {\n // The entry's own selector was checked when the document was parsed, so this is the\n // block's stored reference being unreadable.\n return `The block resolved for this entry declares an unreadable kind: ${ensureError(e).message}`;\n }\n\n if (wanted.name !== has.name) {\n return (\n `This entry asks for kind '${wanted.name}', but the block resolved for it ` +\n `implements '${has.name}'`\n );\n }\n\n if (!semver.satisfies(has.version, selectorToRange(wanted.selector))) {\n return (\n `This entry asks for '${asked}', but the block resolved for it implements ` +\n `version ${has.version} of that kind`\n );\n }\n\n return undefined;\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAkBA,IAAa,wBAAb,cAA2C,MAAM;CAEpC;CADX,YACE,SACA,SACA;EACA,MAAM,OAAO;EAHJ,KAAA,UAAA;EAIT,KAAK,OAAO;CACd;AACF;;;;;;;;;;;;;;;;;;;;;;;;;;AAgEA,SAAgB,aACd,OACA,UACoB;CACpB,IAAI,aAAa,KAAA,GACf,OACE;CAKJ,IAAI;CACJ,IAAI;CACJ,IAAI;EACF,UAAA,GAAA,gCAAA,2BAAA,CAAoC,KAAK;EACzC,OAAA,GAAA,gCAAA,aAAA,CAAmB,QAAQ;CAC7B,SAAS,GAAG;EAGV,OAAO,mEAAA,GAAA,qBAAA,YAAA,CAA8E,CAAC,CAAC,CAAC;CAC1F;CAEA,IAAI,OAAO,SAAS,IAAI,MACtB,OACE,6BAA6B,OAAO,KAAK,+CAC1B,IAAI,KAAK;CAI5B,IAAI,CAAC,OAAO,UAAU,IAAI,UAAA,GAAA,2BAAA,gBAAA,CAAyB,OAAO,QAAQ,CAAC,GACjE,OACE,wBAAwB,MAAM,sDACnB,IAAI,QAAQ;AAK7B"}
1
+ {"version":3,"file":"template_apply.cjs","names":["parseKindSelectorReference","parseKindRef","ensureError","selectorToRange"],"sources":["../../src/model/template_apply.ts"],"sourcesContent":["import type {\n BlockKindReference,\n BlockKindSelectorReference,\n} from \"@milaboratories/pl-model-common\";\nimport { parseKindRef, parseKindSelectorReference } from \"@milaboratories/pl-model-common\";\nimport { selectorToRange } from \"@platforma-sdk/block-tools\";\nimport { ensureError } from \"@platforma-sdk/model\";\nimport * as semver from \"semver\";\n\n/**\n * One entry the file describes in a way this project cannot honour.\n *\n * Thrown, not returned, and that is the whole failure policy: an apply either creates every\n * entry or creates none. It travels out through the open transaction, which is therefore\n * never committed, so a rejected file leaves the project exactly as it was. The caller turns\n * it into a {@link TemplateApplyProblem}; anything else reaching that caller is an outage\n * rather than a statement about the file, and keeps propagating.\n */\nexport class TemplateEntryRejected extends Error {\n constructor(\n readonly entryId: string,\n message: string,\n ) {\n super(message);\n this.name = \"TemplateEntryRejected\";\n }\n}\n\n/**\n * Something that stopped one entry from being applied.\n *\n * Every stage of an apply reports in this shape — resolution, validation,\n * construction — so a caller assembles one list and the reader sees which entry in\n * their file each problem belongs to. `error` is a finished sentence for the person\n * who applied the file, not a code.\n */\nexport type TemplateApplyProblem = {\n /** The template-local id of the entry the problem belongs to. */\n readonly entryId: string;\n readonly error: string;\n};\n\n/** One entry that made it into the project. */\nexport type AppliedEntry = {\n /** The entry's id in the file. */\n readonly templateLocalId: string;\n /** The project-local id the block was given. */\n readonly blockId: string;\n};\n\n/**\n * What a whole apply — reading, checking, resolving, placing — left behind.\n *\n * One shape for every stage's findings, because the reader does not care which stage\n * objected. `problems` empty means the project holds exactly what the document described;\n * otherwise `added` is empty, because no stage creates anything until every entry has passed.\n *\n * A stage that checks reports every problem it found, so a file with three mistakes takes one\n * pass to fix. Placement stops at the first one — hence at most one problem from there.\n */\nexport type TemplateApplyReport = {\n readonly added: readonly AppliedEntry[];\n readonly problems: readonly TemplateApplyProblem[];\n};\n\n/**\n * Why the block prepared for an entry cannot serve it, or `undefined` when it can.\n *\n * An entry's `kind` is the contract its params are written against, so the block that ends up\n * installed has to implement it. Only one of the three routes to a block gives that for free:\n * kind resolution, where the kind's own projection picks the block. The two overrides do not —\n * a location's folder can change without the file changing, and a pinned version names a\n * package with no reference to a kind at all.\n *\n * So this belongs here, with the apply's other per-entry checks, and not in resolution: it is\n * asked once, of the block that was actually prepared, whichever route found it. Resolution\n * could answer it for a location — `byLocation` reads the block's config anyway — and doing so\n * there would have been a second place stating the same invariant, with the pinned-version\n * route still uncovered. One caller is the point.\n *\n * It is also the check that makes the params check meaningful, so it is asked first: params are\n * checked by the INSTALLED block's kind parser, which against a block of the wrong kind would\n * hold params written for one contract against another.\n *\n * Version comparison goes through the same selector-to-range translation the registry resolver\n * uses, so \"this resolves locally\" and \"this would resolve once published\" cannot disagree\n * about the version math.\n *\n * Messages name no route, so a caller adds whichever locator the entry carried.\n */\nexport function kindMismatch(\n asked: BlockKindSelectorReference,\n declared: BlockKindReference | undefined,\n): string | undefined {\n if (declared === undefined) {\n return (\n \"The block resolved for this entry declares no kind, so it cannot be the \" +\n \"implementation it asks for\"\n );\n }\n\n let wanted: { name: string; selector: { op: \"exact\" | \"patch\" | \"minor\"; version: string } };\n let has: { name: string; version: string };\n try {\n wanted = parseKindSelectorReference(asked);\n has = parseKindRef(declared);\n } catch (e) {\n // The entry's own selector was checked when the document was parsed, so this is the\n // block's stored reference being unreadable.\n return `The block resolved for this entry declares an unreadable kind: ${ensureError(e).message}`;\n }\n\n if (wanted.name !== has.name) {\n return (\n `This entry asks for kind '${wanted.name}', but the block resolved for it ` +\n `implements '${has.name}'`\n );\n }\n\n if (!semver.satisfies(has.version, selectorToRange(wanted.selector))) {\n return (\n `This entry asks for '${asked}', but the block resolved for it implements ` +\n `version ${has.version} of that kind`\n );\n }\n\n return undefined;\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAkBA,IAAa,wBAAb,cAA2C,MAAM;CAEpC;CADX,YACE,SACA,SACA;EACA,MAAM,OAAO;EAHJ,KAAA,UAAA;EAIT,KAAK,OAAO;CACd;AACF;;;;;;;;;;;;;;;;;;;;;;;;;;AAgEA,SAAgB,aACd,OACA,UACoB;CACpB,IAAI,aAAa,KAAA,GACf,OACE;CAKJ,IAAI;CACJ,IAAI;CACJ,IAAI;EACF,UAAA,GAASA,gCAAAA,2BAAAA,CAA2B,KAAK;EACzC,OAAA,GAAMC,gCAAAA,aAAAA,CAAa,QAAQ;CAC7B,SAAS,GAAG;EAGV,OAAO,mEAAA,GAAkEC,qBAAAA,YAAAA,CAAY,CAAC,CAAC,CAAC;CAC1F;CAEA,IAAI,OAAO,SAAS,IAAI,MACtB,OACE,6BAA6B,OAAO,KAAK,+CAC1B,IAAI,KAAK;CAI5B,IAAI,CAAC,OAAO,UAAU,IAAI,UAAA,GAASC,2BAAAA,gBAAAA,CAAgB,OAAO,QAAQ,CAAC,GACjE,OACE,wBAAwB,MAAM,sDACnB,IAAI,QAAQ;AAK7B"}
@@ -1,5 +1,4 @@
1
1
  import { BlockKindReference, BlockKindSelectorReference } from "@milaboratories/pl-model-common";
2
- //#region src/model/template_apply.d.ts
3
2
  /**
4
3
  * One entry the file describes in a way this project cannot honour.
5
4
  *
@@ -47,5 +46,4 @@ export type TemplateApplyReport = {
47
46
  readonly added: readonly AppliedEntry[];
48
47
  readonly problems: readonly TemplateApplyProblem[];
49
48
  };
50
- //#endregion
51
49
  //# sourceMappingURL=template_apply.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"template_apply.d.ts","names":[],"sources":["../../src/model/template_apply.ts"],"mappings":";;;;;;;;;;;qBAkBa,8BAA8B;WAE9B;EADX,YACW,iBACT;;;;;;;;;;YAeQ;;WAED;WACA;;;YAIC;;WAED;;WAEA;;;;;;;;;;;;YAaC;WACD,gBAAgB;WAChB,mBAAmB"}
1
+ {"version":3,"file":"template_apply.d.ts","names":[],"sources":["../../src/model/template_apply.ts"],"mappings":";;;;;;;;;;qBAkBa,8BAA8B;WAE9B;EADX,YACW,iBACT;;;;;;;;;;YAeQ;;WAED;WACA;;;YAIC;;WAED;;WAEA;;;;;;;;;;;;YAaC;WACD,gBAAgB;WAChB,mBAAmB"}
@@ -2,7 +2,7 @@ import { ensureError } from "@platforma-sdk/model";
2
2
  import { selectorToRange } from "@platforma-sdk/block-tools";
3
3
  import { parseKindRef, parseKindSelectorReference } from "@milaboratories/pl-model-common";
4
4
  import * as semver from "semver";
5
- //#region src/model/template_apply.ts
5
+ // src/model/template_apply.ts
6
6
  /**
7
7
  * One entry the file describes in a way this project cannot honour.
8
8
  *
@@ -58,7 +58,6 @@ function kindMismatch(asked, declared) {
58
58
  if (wanted.name !== has.name) return `This entry asks for kind '${wanted.name}', but the block resolved for it implements '${has.name}'`;
59
59
  if (!semver.satisfies(has.version, selectorToRange(wanted.selector))) return `This entry asks for '${asked}', but the block resolved for it implements version ${has.version} of that kind`;
60
60
  }
61
- //#endregion
62
61
  export { TemplateEntryRejected, kindMismatch };
63
62
 
64
63
  //# sourceMappingURL=template_apply.js.map
@@ -1,5 +1,5 @@
1
1
  const require_project_model_util = require("./project_model_util.cjs");
2
- //#region src/model/template_export.ts
2
+ // src/model/template_export.ts
3
3
  /**
4
4
  * Walk a project's blocks in dependency order, collecting each one's
5
5
  * template-descriptor output.
@@ -80,7 +80,6 @@ function typeName(value) {
80
80
  if (Array.isArray(value)) return "an array";
81
81
  return `a ${typeof value}`;
82
82
  }
83
- //#endregion
84
83
  exports.walkProjectForTemplateExport = walkProjectForTemplateExport;
85
84
 
86
85
  //# sourceMappingURL=template_export.cjs.map
@@ -1,5 +1,4 @@
1
1
  import "./project_model.js";
2
- //#region src/model/template_export.d.ts
3
2
  /** Why one block could not be exported. */
4
3
  export type TemplateExportProblem = {
5
4
  readonly blockId: string;
@@ -8,5 +7,4 @@ export type TemplateExportProblem = {
8
7
  readonly blockLabel: string;
9
8
  readonly error: string;
10
9
  };
11
- //#endregion
12
10
  //# sourceMappingURL=template_export.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"template_export.d.ts","names":[],"sources":["../../src/model/template_export.ts"],"mappings":";;;YAoCY;WACD;;;WAGA;WACA"}
1
+ {"version":3,"file":"template_export.d.ts","names":[],"sources":["../../src/model/template_export.ts"],"mappings":";;YAoCY;WACD;;;WAGA;WACA"}
@@ -1,5 +1,5 @@
1
1
  import { allBlocks } from "./project_model_util.js";
2
- //#region src/model/template_export.ts
2
+ // src/model/template_export.ts
3
3
  /**
4
4
  * Walk a project's blocks in dependency order, collecting each one's
5
5
  * template-descriptor output.
@@ -80,7 +80,6 @@ function typeName(value) {
80
80
  if (Array.isArray(value)) return "an array";
81
81
  return `a ${typeof value}`;
82
82
  }
83
- //#endregion
84
83
  export { walkProjectForTemplateExport };
85
84
 
86
85
  //# sourceMappingURL=template_export.js.map
@@ -2,7 +2,7 @@ const require_runtime = require("../_virtual/_rolldown/runtime.cjs");
2
2
  let yaml = require("yaml");
3
3
  yaml = require_runtime.__toESM(yaml, 1);
4
4
  let _milaboratories_pl_model_common = require("@milaboratories/pl-model-common");
5
- //#region src/model/template_parser.ts
5
+ // src/model/template_parser.ts
6
6
  /**
7
7
  * Read `template-v1` YAML text into a document.
8
8
  *
@@ -68,7 +68,6 @@ function describeIssues(issues) {
68
68
  const lines = issues.map((issue) => `- ${(0, _milaboratories_pl_model_common.formatTemplateParseIssue)(issue)}`);
69
69
  return [lines.length === 1 ? "The template file has a problem:" : `The template file has ${lines.length} problems:`, ...lines].join("\n");
70
70
  }
71
- //#endregion
72
71
  exports.parseProjectTemplateV1Yaml = parseProjectTemplateV1Yaml;
73
72
 
74
73
  //# sourceMappingURL=template_parser.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"template_parser.cjs","names":["YAML","PROJECT_TEMPLATE_SCHEMA_V1"],"sources":["../../src/model/template_parser.ts"],"sourcesContent":["import YAML from \"yaml\";\nimport type { ProjectTemplateV1, TemplateParseIssue } from \"@milaboratories/pl-model-common\";\nimport {\n PROJECT_TEMPLATE_SCHEMA_V1,\n formatTemplateParseIssue,\n readProjectTemplateV1,\n} from \"@milaboratories/pl-model-common\";\n\n/**\n * A template file read, or why it could not be.\n *\n * A single message rather than a list of per-entry problems: until the document\n * parses there are no entries to attach anything to, and a file that does not parse\n * has one problem — it is not a template. Per-entry reporting starts at the stage\n * after this one. The message may span several lines when the file has several\n * fixable issues, so that fixing it takes one pass.\n */\nexport type TemplateParseOutcome =\n | { readonly ok: true; readonly document: ProjectTemplateV1 }\n | { readonly ok: false; readonly error: string };\n\n/**\n * Read `template-v1` YAML text into a document.\n *\n * The text half of the import direction, mirroring `stringifyProjectTemplateV1` on the\n * export side — and, like it, living here rather than in `pl-model-common`, which ships\n * in every block-model and UI bundle and takes no `yaml` dependency. The document half\n * is `parseProjectTemplateV1`, shared with export so that what export writes is by\n * construction what import reads.\n *\n * JSON is accepted for free: every JSON document is also YAML.\n *\n * **Read as YAML 1.2**, while the emitter quotes as if for 1.1. That asymmetry is\n * deliberate on both ends: quoting against the stricter ruleset makes a file we write\n * mean the same thing to any reader, and reading with the looser one means a bare\n * `yes` or `1:30` in a hand-written file stays the string it looks like instead of\n * silently becoming `true` or `90`.\n *\n * Nothing here checks that references point anywhere or that a kind can be resolved —\n * those are later stages, and both need more than the file to answer.\n */\nexport function parseProjectTemplateV1Yaml(text: string): TemplateParseOutcome {\n let value: unknown;\n try {\n value = YAML.parse(text);\n } catch (e) {\n // The library's message already carries \"at line L, column C\"; what follows it is\n // a code frame of the offending lines, dropped here because whoever is fixing the\n // file has it open and the position is what they need.\n const first = e instanceof Error ? e.message.split(\"\\n\")[0] : String(e);\n return { ok: false, error: `The file is not valid YAML: ${first}` };\n }\n\n // Empty input, blank lines and a file of nothing but comments all parse to null.\n // Left to the schema, this reads as \"expected object, received null\", which says\n // nothing about the actual mistake.\n if (value === null || value === undefined) {\n return { ok: false, error: \"The file is empty.\" };\n }\n\n if (typeof value !== \"object\" || Array.isArray(value)) {\n return {\n ok: false,\n error:\n \"The file does not describe a template: expected a mapping with 'schema' and \" +\n \"'blocks' at the top level.\",\n };\n }\n\n // Checked ahead of the document reader because it is the likeliest mistake by far — the\n // wrong file was picked — and deserves a sentence about that rather than one about a field\n // whose value is not what was expected.\n const marker = (value as { schema?: unknown }).schema;\n if (marker !== PROJECT_TEMPLATE_SCHEMA_V1) {\n return {\n ok: false,\n error:\n marker === undefined\n ? `This file has no 'schema' field, so it is not a ${PROJECT_TEMPLATE_SCHEMA_V1} template.`\n : `This file says it is '${String(marker)}', not ${PROJECT_TEMPLATE_SCHEMA_V1}.`,\n };\n }\n\n const outcome = readProjectTemplateV1(value);\n return outcome.ok\n ? { ok: true, document: outcome.document }\n : { ok: false, error: describeIssues(outcome.issues) };\n}\n\n/**\n * Turn the reader's issues into something a person can act on, all of them at once.\n *\n * The per-issue line comes from `formatTemplateParseIssue`, shared with the error the reader\n * throws, so a problem reads the same whether it reached a person through this outcome or\n * through a log. What is added here is the headline, which is the one part that belongs to\n * this stage: it says the FILE is at fault, which a caller that has one can say and the\n * document reader cannot.\n */\nfunction describeIssues(issues: readonly TemplateParseIssue[]): string {\n const lines = issues.map((issue) => `- ${formatTemplateParseIssue(issue)}`);\n\n const headline =\n lines.length === 1\n ? \"The template file has a problem:\"\n : `The template file has ${lines.length} problems:`;\n\n return [headline, ...lines].join(\"\\n\");\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;AAyCA,SAAgB,2BAA2B,MAAoC;CAC7E,IAAI;CACJ,IAAI;EACF,QAAQA,KAAAA,QAAK,MAAM,IAAI;CACzB,SAAS,GAAG;EAKV,OAAO;GAAE,IAAI;GAAO,OAAO,+BADb,aAAa,QAAQ,EAAE,QAAQ,MAAM,IAAI,CAAC,CAAC,KAAK,OAAO,CAAC;EACJ;CACpE;CAKA,IAAI,UAAU,QAAQ,UAAU,KAAA,GAC9B,OAAO;EAAE,IAAI;EAAO,OAAO;CAAqB;CAGlD,IAAI,OAAO,UAAU,YAAY,MAAM,QAAQ,KAAK,GAClD,OAAO;EACL,IAAI;EACJ,OACE;CAEJ;CAMF,MAAM,SAAU,MAA+B;CAC/C,IAAI,WAAWC,gCAAAA,4BACb,OAAO;EACL,IAAI;EACJ,OACE,WAAW,KAAA,IACP,mDAAmDA,gCAAAA,2BAA2B,cAC9E,yBAAyB,OAAO,MAAM,EAAE,SAASA,gCAAAA,2BAA2B;CACpF;CAGF,MAAM,WAAA,GAAA,gCAAA,sBAAA,CAAgC,KAAK;CAC3C,OAAO,QAAQ,KACX;EAAE,IAAI;EAAM,UAAU,QAAQ;CAAS,IACvC;EAAE,IAAI;EAAO,OAAO,eAAe,QAAQ,MAAM;CAAE;AACzD;;;;;;;;;;AAWA,SAAS,eAAe,QAA+C;CACrE,MAAM,QAAQ,OAAO,KAAK,UAAU,MAAA,GAAA,gCAAA,yBAAA,CAA8B,KAAK,GAAG;CAO1E,OAAO,CAJL,MAAM,WAAW,IACb,qCACA,yBAAyB,MAAM,OAAO,aAE1B,GAAG,KAAK,CAAC,CAAC,KAAK,IAAI;AACvC"}
1
+ {"version":3,"file":"template_parser.cjs","names":["YAML","PROJECT_TEMPLATE_SCHEMA_V1","readProjectTemplateV1","formatTemplateParseIssue"],"sources":["../../src/model/template_parser.ts"],"sourcesContent":["import YAML from \"yaml\";\nimport type { ProjectTemplateV1, TemplateParseIssue } from \"@milaboratories/pl-model-common\";\nimport {\n PROJECT_TEMPLATE_SCHEMA_V1,\n formatTemplateParseIssue,\n readProjectTemplateV1,\n} from \"@milaboratories/pl-model-common\";\n\n/**\n * A template file read, or why it could not be.\n *\n * A single message rather than a list of per-entry problems: until the document\n * parses there are no entries to attach anything to, and a file that does not parse\n * has one problem — it is not a template. Per-entry reporting starts at the stage\n * after this one. The message may span several lines when the file has several\n * fixable issues, so that fixing it takes one pass.\n */\nexport type TemplateParseOutcome =\n | { readonly ok: true; readonly document: ProjectTemplateV1 }\n | { readonly ok: false; readonly error: string };\n\n/**\n * Read `template-v1` YAML text into a document.\n *\n * The text half of the import direction, mirroring `stringifyProjectTemplateV1` on the\n * export side — and, like it, living here rather than in `pl-model-common`, which ships\n * in every block-model and UI bundle and takes no `yaml` dependency. The document half\n * is `parseProjectTemplateV1`, shared with export so that what export writes is by\n * construction what import reads.\n *\n * JSON is accepted for free: every JSON document is also YAML.\n *\n * **Read as YAML 1.2**, while the emitter quotes as if for 1.1. That asymmetry is\n * deliberate on both ends: quoting against the stricter ruleset makes a file we write\n * mean the same thing to any reader, and reading with the looser one means a bare\n * `yes` or `1:30` in a hand-written file stays the string it looks like instead of\n * silently becoming `true` or `90`.\n *\n * Nothing here checks that references point anywhere or that a kind can be resolved —\n * those are later stages, and both need more than the file to answer.\n */\nexport function parseProjectTemplateV1Yaml(text: string): TemplateParseOutcome {\n let value: unknown;\n try {\n value = YAML.parse(text);\n } catch (e) {\n // The library's message already carries \"at line L, column C\"; what follows it is\n // a code frame of the offending lines, dropped here because whoever is fixing the\n // file has it open and the position is what they need.\n const first = e instanceof Error ? e.message.split(\"\\n\")[0] : String(e);\n return { ok: false, error: `The file is not valid YAML: ${first}` };\n }\n\n // Empty input, blank lines and a file of nothing but comments all parse to null.\n // Left to the schema, this reads as \"expected object, received null\", which says\n // nothing about the actual mistake.\n if (value === null || value === undefined) {\n return { ok: false, error: \"The file is empty.\" };\n }\n\n if (typeof value !== \"object\" || Array.isArray(value)) {\n return {\n ok: false,\n error:\n \"The file does not describe a template: expected a mapping with 'schema' and \" +\n \"'blocks' at the top level.\",\n };\n }\n\n // Checked ahead of the document reader because it is the likeliest mistake by far — the\n // wrong file was picked — and deserves a sentence about that rather than one about a field\n // whose value is not what was expected.\n const marker = (value as { schema?: unknown }).schema;\n if (marker !== PROJECT_TEMPLATE_SCHEMA_V1) {\n return {\n ok: false,\n error:\n marker === undefined\n ? `This file has no 'schema' field, so it is not a ${PROJECT_TEMPLATE_SCHEMA_V1} template.`\n : `This file says it is '${String(marker)}', not ${PROJECT_TEMPLATE_SCHEMA_V1}.`,\n };\n }\n\n const outcome = readProjectTemplateV1(value);\n return outcome.ok\n ? { ok: true, document: outcome.document }\n : { ok: false, error: describeIssues(outcome.issues) };\n}\n\n/**\n * Turn the reader's issues into something a person can act on, all of them at once.\n *\n * The per-issue line comes from `formatTemplateParseIssue`, shared with the error the reader\n * throws, so a problem reads the same whether it reached a person through this outcome or\n * through a log. What is added here is the headline, which is the one part that belongs to\n * this stage: it says the FILE is at fault, which a caller that has one can say and the\n * document reader cannot.\n */\nfunction describeIssues(issues: readonly TemplateParseIssue[]): string {\n const lines = issues.map((issue) => `- ${formatTemplateParseIssue(issue)}`);\n\n const headline =\n lines.length === 1\n ? \"The template file has a problem:\"\n : `The template file has ${lines.length} problems:`;\n\n return [headline, ...lines].join(\"\\n\");\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;AAyCA,SAAgB,2BAA2B,MAAoC;CAC7E,IAAI;CACJ,IAAI;EACF,QAAQA,KAAAA,QAAK,MAAM,IAAI;CACzB,SAAS,GAAG;EAKV,OAAO;GAAE,IAAI;GAAO,OAAO,+BADb,aAAa,QAAQ,EAAE,QAAQ,MAAM,IAAI,CAAC,CAAC,KAAK,OAAO,CAAC;EACJ;CACpE;CAKA,IAAI,UAAU,QAAQ,UAAU,KAAA,GAC9B,OAAO;EAAE,IAAI;EAAO,OAAO;CAAqB;CAGlD,IAAI,OAAO,UAAU,YAAY,MAAM,QAAQ,KAAK,GAClD,OAAO;EACL,IAAI;EACJ,OACE;CAEJ;CAMF,MAAM,SAAU,MAA+B;CAC/C,IAAI,WAAWC,gCAAAA,4BACb,OAAO;EACL,IAAI;EACJ,OACE,WAAW,KAAA,IACP,mDAAmDA,gCAAAA,2BAA2B,cAC9E,yBAAyB,OAAO,MAAM,EAAE,SAASA,gCAAAA,2BAA2B;CACpF;CAGF,MAAM,WAAA,GAAUC,gCAAAA,sBAAAA,CAAsB,KAAK;CAC3C,OAAO,QAAQ,KACX;EAAE,IAAI;EAAM,UAAU,QAAQ;CAAS,IACvC;EAAE,IAAI;EAAO,OAAO,eAAe,QAAQ,MAAM;CAAE;AACzD;;;;;;;;;;AAWA,SAAS,eAAe,QAA+C;CACrE,MAAM,QAAQ,OAAO,KAAK,UAAU,MAAA,GAAKC,gCAAAA,yBAAAA,CAAyB,KAAK,GAAG;CAO1E,OAAO,CAJL,MAAM,WAAW,IACb,qCACA,yBAAyB,MAAM,OAAO,aAE1B,GAAG,KAAK,CAAC,CAAC,KAAK,IAAI;AACvC"}