@milaboratories/pl-middle-layer 1.74.10 → 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 (322) 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 +6 -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 +7 -3
  88. package/dist/middle_layer/driver_kit.js.map +1 -1
  89. package/dist/middle_layer/finality_stop_rules.cjs +1 -2
  90. package/dist/middle_layer/finality_stop_rules.js +1 -2
  91. package/dist/middle_layer/folders.cjs +12 -8
  92. package/dist/middle_layer/folders.cjs.map +1 -1
  93. package/dist/middle_layer/folders.d.ts +0 -2
  94. package/dist/middle_layer/folders.d.ts.map +1 -1
  95. package/dist/middle_layer/folders.js +12 -8
  96. package/dist/middle_layer/folders.js.map +1 -1
  97. package/dist/middle_layer/frontend_path.cjs +1 -2
  98. package/dist/middle_layer/frontend_path.cjs.map +1 -1
  99. package/dist/middle_layer/frontend_path.js +1 -2
  100. package/dist/middle_layer/middle_layer.cjs +7 -6
  101. package/dist/middle_layer/middle_layer.cjs.map +1 -1
  102. package/dist/middle_layer/middle_layer.d.ts +0 -2
  103. package/dist/middle_layer/middle_layer.d.ts.map +1 -1
  104. package/dist/middle_layer/middle_layer.js +7 -6
  105. package/dist/middle_layer/middle_layer.js.map +1 -1
  106. package/dist/middle_layer/navigation_states.cjs +1 -2
  107. package/dist/middle_layer/navigation_states.js +1 -2
  108. package/dist/middle_layer/ops.cjs +10 -11
  109. package/dist/middle_layer/ops.cjs.map +1 -1
  110. package/dist/middle_layer/ops.d.ts +0 -2
  111. package/dist/middle_layer/ops.d.ts.map +1 -1
  112. package/dist/middle_layer/ops.js +10 -11
  113. package/dist/middle_layer/ops.js.map +1 -1
  114. package/dist/middle_layer/project.cjs +3 -3
  115. package/dist/middle_layer/project.cjs.map +1 -1
  116. package/dist/middle_layer/project.d.ts +3 -5
  117. package/dist/middle_layer/project.d.ts.map +1 -1
  118. package/dist/middle_layer/project.js +3 -3
  119. package/dist/middle_layer/project.js.map +1 -1
  120. package/dist/middle_layer/project_list.cjs +1 -2
  121. package/dist/middle_layer/project_list.cjs.map +1 -1
  122. package/dist/middle_layer/project_list.d.ts +0 -2
  123. package/dist/middle_layer/project_list.d.ts.map +1 -1
  124. package/dist/middle_layer/project_list.js +1 -2
  125. package/dist/middle_layer/project_overview.cjs +8 -5
  126. package/dist/middle_layer/project_overview.cjs.map +1 -1
  127. package/dist/middle_layer/project_overview.js +8 -5
  128. package/dist/middle_layer/project_overview.js.map +1 -1
  129. package/dist/middle_layer/project_overview_light.cjs +4 -3
  130. package/dist/middle_layer/project_overview_light.cjs.map +1 -1
  131. package/dist/middle_layer/project_overview_light.js +4 -3
  132. package/dist/middle_layer/project_overview_light.js.map +1 -1
  133. package/dist/middle_layer/render.cjs +1 -2
  134. package/dist/middle_layer/render.cjs.map +1 -1
  135. package/dist/middle_layer/render.js +1 -2
  136. package/dist/middle_layer/sharing_list.cjs +1 -2
  137. package/dist/middle_layer/sharing_list.cjs.map +1 -1
  138. package/dist/middle_layer/sharing_list.d.ts +0 -2
  139. package/dist/middle_layer/sharing_list.d.ts.map +1 -1
  140. package/dist/middle_layer/sharing_list.js +1 -2
  141. package/dist/middle_layer/sharing_list.js.map +1 -1
  142. package/dist/middle_layer/template_list.cjs +1 -2
  143. package/dist/middle_layer/template_list.cjs.map +1 -1
  144. package/dist/middle_layer/template_list.d.ts +0 -2
  145. package/dist/middle_layer/template_list.d.ts.map +1 -1
  146. package/dist/middle_layer/template_list.js +1 -2
  147. package/dist/middle_layer/tree_snapshot_store.cjs +3 -3
  148. package/dist/middle_layer/tree_snapshot_store.cjs.map +1 -1
  149. package/dist/middle_layer/tree_snapshot_store.d.ts +0 -2
  150. package/dist/middle_layer/tree_snapshot_store.d.ts.map +1 -1
  151. package/dist/middle_layer/tree_snapshot_store.js +3 -3
  152. package/dist/middle_layer/tree_snapshot_store.js.map +1 -1
  153. package/dist/middle_layer/types.d.ts +0 -2
  154. package/dist/middle_layer/types.d.ts.map +1 -1
  155. package/dist/middle_layer/util.cjs +1 -2
  156. package/dist/middle_layer/util.cjs.map +1 -1
  157. package/dist/middle_layer/util.js +1 -2
  158. package/dist/model/args.cjs +1 -2
  159. package/dist/model/args.cjs.map +1 -1
  160. package/dist/model/args.js +1 -2
  161. package/dist/model/block_pack_spec.cjs +1 -2
  162. package/dist/model/block_pack_spec.d.ts +0 -2
  163. package/dist/model/block_pack_spec.d.ts.map +1 -1
  164. package/dist/model/block_pack_spec.js +1 -2
  165. package/dist/model/frontend.d.ts +0 -2
  166. package/dist/model/frontend.d.ts.map +1 -1
  167. package/dist/model/project_helper.cjs +1 -2
  168. package/dist/model/project_helper.cjs.map +1 -1
  169. package/dist/model/project_helper.d.ts +0 -2
  170. package/dist/model/project_helper.d.ts.map +1 -1
  171. package/dist/model/project_helper.js +1 -2
  172. package/dist/model/project_model.cjs +1 -2
  173. package/dist/model/project_model.d.ts +0 -2
  174. package/dist/model/project_model.d.ts.map +1 -1
  175. package/dist/model/project_model.js +1 -2
  176. package/dist/model/project_model_util.cjs +1 -2
  177. package/dist/model/project_model_util.js +1 -2
  178. package/dist/model/project_model_v1.cjs +1 -2
  179. package/dist/model/project_model_v1.js +1 -2
  180. package/dist/model/sharing_model.cjs +1 -2
  181. package/dist/model/sharing_model.cjs.map +1 -1
  182. package/dist/model/sharing_model.d.ts +0 -2
  183. package/dist/model/sharing_model.d.ts.map +1 -1
  184. package/dist/model/sharing_model.js +1 -2
  185. package/dist/model/template_apply.cjs +1 -2
  186. package/dist/model/template_apply.cjs.map +1 -1
  187. package/dist/model/template_apply.d.ts +0 -2
  188. package/dist/model/template_apply.d.ts.map +1 -1
  189. package/dist/model/template_apply.js +1 -2
  190. package/dist/model/template_export.cjs +1 -2
  191. package/dist/model/template_export.d.ts +0 -2
  192. package/dist/model/template_export.d.ts.map +1 -1
  193. package/dist/model/template_export.js +1 -2
  194. package/dist/model/template_parser.cjs +1 -2
  195. package/dist/model/template_parser.cjs.map +1 -1
  196. package/dist/model/template_parser.d.ts +0 -2
  197. package/dist/model/template_parser.d.ts.map +1 -1
  198. package/dist/model/template_parser.js +1 -2
  199. package/dist/model/template_resolve.cjs +1 -2
  200. package/dist/model/template_resolve.cjs.map +1 -1
  201. package/dist/model/template_resolve.d.ts +0 -2
  202. package/dist/model/template_resolve.d.ts.map +1 -1
  203. package/dist/model/template_resolve.js +1 -2
  204. package/dist/model/template_serializer.cjs +1 -2
  205. package/dist/model/template_serializer.cjs.map +1 -1
  206. package/dist/model/template_serializer.d.ts +0 -2
  207. package/dist/model/template_serializer.d.ts.map +1 -1
  208. package/dist/model/template_serializer.js +1 -2
  209. package/dist/model/template_spec.d.ts +0 -2
  210. package/dist/model/template_spec.d.ts.map +1 -1
  211. package/dist/mutator/block-pack/block_pack.cjs +7 -6
  212. package/dist/mutator/block-pack/block_pack.cjs.map +1 -1
  213. package/dist/mutator/block-pack/block_pack.d.ts +0 -2
  214. package/dist/mutator/block-pack/block_pack.d.ts.map +1 -1
  215. package/dist/mutator/block-pack/block_pack.js +7 -6
  216. package/dist/mutator/block-pack/block_pack.js.map +1 -1
  217. package/dist/mutator/block-pack/frontend.cjs +1 -2
  218. package/dist/mutator/block-pack/frontend.cjs.map +1 -1
  219. package/dist/mutator/block-pack/frontend.js +1 -2
  220. package/dist/mutator/block-pack/required_capabilities.cjs +1 -2
  221. package/dist/mutator/block-pack/required_capabilities.cjs.map +1 -1
  222. package/dist/mutator/block-pack/required_capabilities.js +1 -2
  223. package/dist/mutator/context_export.cjs +1 -2
  224. package/dist/mutator/context_export.cjs.map +1 -1
  225. package/dist/mutator/context_export.js +1 -2
  226. package/dist/mutator/list.cjs +1 -2
  227. package/dist/mutator/list.cjs.map +1 -1
  228. package/dist/mutator/list.js +1 -2
  229. package/dist/mutator/migration.cjs +1 -2
  230. package/dist/mutator/migration.cjs.map +1 -1
  231. package/dist/mutator/migration.js +1 -2
  232. package/dist/mutator/project.cjs +30 -22
  233. package/dist/mutator/project.cjs.map +1 -1
  234. package/dist/mutator/project.d.ts +0 -2
  235. package/dist/mutator/project.d.ts.map +1 -1
  236. package/dist/mutator/project.js +30 -22
  237. package/dist/mutator/project.js.map +1 -1
  238. package/dist/mutator/sharing.cjs +1 -2
  239. package/dist/mutator/sharing.cjs.map +1 -1
  240. package/dist/mutator/sharing.js +1 -2
  241. package/dist/mutator/template/direct_template_loader.cjs +1 -2
  242. package/dist/mutator/template/direct_template_loader.cjs.map +1 -1
  243. package/dist/mutator/template/direct_template_loader.js +1 -2
  244. package/dist/mutator/template/direct_template_loader_v3.cjs +1 -2
  245. package/dist/mutator/template/direct_template_loader_v3.cjs.map +1 -1
  246. package/dist/mutator/template/direct_template_loader_v3.js +1 -2
  247. package/dist/mutator/template/render_block.cjs +1 -2
  248. package/dist/mutator/template/render_block.cjs.map +1 -1
  249. package/dist/mutator/template/render_block.js +1 -2
  250. package/dist/mutator/template/render_template.cjs +1 -2
  251. package/dist/mutator/template/render_template.cjs.map +1 -1
  252. package/dist/mutator/template/render_template.d.ts +0 -2
  253. package/dist/mutator/template/render_template.d.ts.map +1 -1
  254. package/dist/mutator/template/render_template.js +1 -2
  255. package/dist/mutator/template/template_cache.cjs +6 -5
  256. package/dist/mutator/template/template_cache.cjs.map +1 -1
  257. package/dist/mutator/template/template_cache.d.ts +1 -2
  258. package/dist/mutator/template/template_cache.d.ts.map +1 -1
  259. package/dist/mutator/template/template_cache.js +6 -5
  260. package/dist/mutator/template/template_cache.js.map +1 -1
  261. package/dist/mutator/template/template_loading.cjs +1 -2
  262. package/dist/mutator/template/template_loading.cjs.map +1 -1
  263. package/dist/mutator/template/template_loading.d.ts +0 -2
  264. package/dist/mutator/template/template_loading.d.ts.map +1 -1
  265. package/dist/mutator/template/template_loading.js +1 -2
  266. package/dist/mutator/template.cjs +1 -2
  267. package/dist/mutator/template.cjs.map +1 -1
  268. package/dist/mutator/template.js +1 -2
  269. package/dist/mutator/template_construct.cjs +1 -2
  270. package/dist/mutator/template_construct.cjs.map +1 -1
  271. package/dist/mutator/template_construct.js +1 -2
  272. package/dist/network_check/network_check.cjs +2 -3
  273. package/dist/network_check/network_check.cjs.map +1 -1
  274. package/dist/network_check/network_check.d.ts +0 -2
  275. package/dist/network_check/network_check.d.ts.map +1 -1
  276. package/dist/network_check/network_check.js +2 -3
  277. package/dist/network_check/network_check.js.map +1 -1
  278. package/dist/network_check/pings.cjs +1 -2
  279. package/dist/network_check/pings.cjs.map +1 -1
  280. package/dist/network_check/pings.js +1 -2
  281. package/dist/network_check/template.cjs +5 -4
  282. package/dist/network_check/template.cjs.map +1 -1
  283. package/dist/network_check/template.js +5 -4
  284. package/dist/network_check/template.js.map +1 -1
  285. package/dist/pool/data.cjs +1 -2
  286. package/dist/pool/data.cjs.map +1 -1
  287. package/dist/pool/data.d.ts +0 -2
  288. package/dist/pool/data.d.ts.map +1 -1
  289. package/dist/pool/data.js +1 -2
  290. package/dist/pool/driver.cjs +5 -4
  291. package/dist/pool/driver.cjs.map +1 -1
  292. package/dist/pool/driver.d.ts +0 -2
  293. package/dist/pool/driver.d.ts.map +1 -1
  294. package/dist/pool/driver.js +5 -4
  295. package/dist/pool/driver.js.map +1 -1
  296. package/dist/pool/p_object_collection.cjs +9 -8
  297. package/dist/pool/p_object_collection.cjs.map +1 -1
  298. package/dist/pool/p_object_collection.d.ts +0 -2
  299. package/dist/pool/p_object_collection.d.ts.map +1 -1
  300. package/dist/pool/p_object_collection.js +9 -8
  301. package/dist/pool/p_object_collection.js.map +1 -1
  302. package/dist/pool/result_pool.cjs +8 -7
  303. package/dist/pool/result_pool.cjs.map +1 -1
  304. package/dist/pool/result_pool.js +8 -7
  305. package/dist/pool/result_pool.js.map +1 -1
  306. package/dist/pool/upstream_block_ctx.cjs +1 -2
  307. package/dist/pool/upstream_block_ctx.cjs.map +1 -1
  308. package/dist/pool/upstream_block_ctx.js +1 -2
  309. package/dist/service_factories.cjs +1 -2
  310. package/dist/service_factories.js +1 -2
  311. package/dist/worker/WorkerManager.cjs +1 -2
  312. package/dist/worker/WorkerManager.js +1 -2
  313. package/dist/worker/WorkerManager.js.map +1 -1
  314. package/dist/worker/worker.cjs +1 -2
  315. package/dist/worker/worker.js +1 -2
  316. package/dist/worker/workerApi.cjs +1 -2
  317. package/dist/worker/workerApi.cjs.map +1 -1
  318. package/dist/worker/workerApi.js +1 -2
  319. package/package.json +33 -33
  320. package/src/middle_layer/driver_kit.ts +16 -0
  321. package/src/middle_layer/middle_layer.ts +4 -6
  322. package/src/middle_layer/tree_snapshot_store.test.ts +4 -1
@@ -10,11 +10,13 @@ import { notEmpty } from "@milaboratories/ts-helpers";
10
10
  import { resourceIdToString } from "@milaboratories/pl-client";
11
11
  import { Computable } from "@milaboratories/computable";
12
12
  import { isEqual, omitBy } from "es-toolkit";
13
- //#region src/middle_layer/project_overview.ts
13
+ // src/middle_layer/project_overview.ts
14
14
  function argsEquals(a, b) {
15
15
  if (a === b) return true;
16
16
  if (a === void 0 || b === void 0) return false;
17
- return isEqual(omitBy(a, (_, key) => key.startsWith("__")), omitBy(b, (_, key) => key.startsWith("__")));
17
+ const cleanA = omitBy(a, (_, key) => key.startsWith("__"));
18
+ const cleanB = omitBy(b, (_, key) => key.startsWith("__"));
19
+ return isEqual(cleanA, cleanB);
18
20
  }
19
21
  /** Returns derived general project state form the project resource */
20
22
  function projectOverview(prjEntry, navigationStates, env) {
@@ -83,8 +85,10 @@ function projectOverview(prjEntry, navigationStates, env) {
83
85
  const info = notEmpty(infos.get(id));
84
86
  const gNode = notEmpty(currentGraph.nodes.get(id));
85
87
  let calculationStatus = "NotCalculated";
86
- if (info.prod !== void 0) if (limbo.has(id)) calculationStatus = "Limbo";
87
- else calculationStatus = info.prod.finished ? "Done" : "Running";
88
+ if (info.prod !== void 0) {
89
+ if (limbo.has(id)) calculationStatus = "Limbo";
90
+ else calculationStatus = info.prod.finished ? "Done" : "Running";
91
+ }
88
92
  const bp = getBlockPackInfo(prj, id);
89
93
  const { sections, title, subtitle, tags, inputsValid, sdkVersion, featureFlags, isIncompatibleWithRuntime } = ifNotUndef(bp, ({ bpId, cfg, info: blockPackInfo }) => {
90
94
  if (!env.runtimeCapabilities.checkCompatibility(cfg.featureFlags)) return {
@@ -198,7 +202,6 @@ function projectOverview(prjEntry, navigationStates, env) {
198
202
  } : void 0
199
203
  }).withStableType();
200
204
  }
201
- //#endregion
202
205
  export { projectOverview };
203
206
 
204
207
  //# sourceMappingURL=project_overview.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"project_overview.js","names":[],"sources":["../../src/middle_layer/project_overview.ts"],"sourcesContent":["import type { PlTreeEntry } from \"@milaboratories/pl-tree\";\nimport type { ComputableStableDefined } from \"@milaboratories/computable\";\nimport { Computable } from \"@milaboratories/computable\";\nimport type { ProjectRenderingState, ProjectStructure } from \"../model/project_model\";\nimport {\n BlockRenderingStateKey,\n ProjectCreatedTimestamp,\n projectFieldName,\n ProjectLastModifiedTimestamp,\n ProjectMetaKey,\n ProjectStructureAuthorKey,\n ProjectStructureKey,\n} from \"../model/project_model\";\nimport { notEmpty } from \"@milaboratories/ts-helpers\";\nimport { allBlocks, productionGraph } from \"../model/project_model_util\";\nimport type { MiddleLayerEnvironment } from \"./middle_layer\";\nimport type {\n AuthorMarker,\n BlockCalculationStatus,\n BlockSettings,\n ProjectMeta,\n ProjectOverview,\n} from \"@milaboratories/pl-model-middle-layer\";\nimport { constructBlockContext, constructBlockContextArgsOnly } from \"./block_ctx\";\nimport { ifNotUndef } from \"../cfg_render/util\";\nimport { type BlockSection, BLOCK_STORAGE_FACADE_VERSION } from \"@platforma-sdk/model\";\nimport { extractCodeWithInfo, wrapCallback } from \"@platforma-sdk/model\";\nimport { computableFromCfgOrRF } from \"./render\";\nimport type { NavigationStates } from \"./navigation_states\";\nimport { getBlockPackInfo } from \"./util\";\nimport { resourceIdToString, type SignedResourceId } from \"@milaboratories/pl-client\";\nimport { omitBy, isEqual } from \"es-toolkit\";\nimport { getDebugFlags } from \"../debug\";\n\ntype BlockInfo = {\n argsRid?: SignedResourceId;\n currentArguments: unknown;\n prod?: ProdState;\n};\n\ntype ProdState = {\n finished: boolean;\n\n outputError: boolean;\n\n outputsError?: string;\n\n exportsError?: string;\n\n stale: boolean;\n\n /** Arguments current production was rendered with. */\n arguments: Record<string, unknown>;\n};\n\nfunction argsEquals(\n a: Record<string, unknown> | undefined,\n b: Record<string, unknown> | undefined,\n): boolean {\n if (a === b) return true;\n if (a === undefined || b === undefined) return false;\n const cleanA = omitBy(a, (_, key) => key.startsWith(\"__\"));\n const cleanB = omitBy(b, (_, key) => key.startsWith(\"__\"));\n return isEqual(cleanA, cleanB);\n}\n\n/** Returns derived general project state form the project resource */\nexport function projectOverview(\n prjEntry: PlTreeEntry,\n navigationStates: NavigationStates,\n env: MiddleLayerEnvironment,\n): ComputableStableDefined<ProjectOverview> {\n return Computable.make(\n (ctx) => {\n const prj = ctx.accessor(prjEntry).node();\n\n const created = notEmpty(prj.getKeyValueAsJson<number>(ProjectCreatedTimestamp));\n const lastModified = notEmpty(prj.getKeyValueAsJson<number>(ProjectLastModifiedTimestamp));\n\n const meta = notEmpty(prj.getKeyValueAsJson<ProjectMeta>(ProjectMetaKey));\n const structure = notEmpty(prj.getKeyValueAsJson<ProjectStructure>(ProjectStructureKey));\n const renderingState = notEmpty(\n prj.getKeyValueAsJson<ProjectRenderingState>(BlockRenderingStateKey),\n );\n\n const infos = new Map<string, BlockInfo>();\n for (const { id } of allBlocks(structure)) {\n const cInputs = prj.traverse({\n field: projectFieldName(id, \"currentArgs\"),\n assertFieldType: \"Dynamic\",\n stableIfNotFound: true,\n });\n const currentArguments = cInputs?.getDataAsJson<Record<string, unknown>>();\n\n let prod: ProdState | undefined = undefined;\n\n const rInputs = prj.traverse({\n field: projectFieldName(id, \"prodArgs\"),\n assertFieldType: \"Dynamic\",\n stableIfNotFound: true,\n });\n if (rInputs !== undefined) {\n const prodArgs = rInputs.getDataAsJson() as Record<string, unknown>;\n const result = prj.getField({\n field: projectFieldName(id, \"prodOutput\"),\n assertFieldType: \"Dynamic\",\n errorIfFieldNotFound: true,\n });\n const ctx = prj.getField({\n field: projectFieldName(id, \"prodUiCtx\"),\n assertFieldType: \"Dynamic\",\n errorIfFieldNotFound: true,\n });\n prod = {\n arguments: prodArgs,\n stale: !argsEquals(currentArguments, prodArgs),\n outputError:\n result.error !== undefined ||\n ctx.error !== undefined ||\n result.value?.getError() !== undefined ||\n ctx.value?.getError() !== undefined,\n outputsError:\n result.error?.getDataAsString() ?? result.value?.getError()?.getDataAsString(),\n exportsError: ctx.error?.getDataAsString() ?? ctx.value?.getError()?.getDataAsString(),\n finished:\n ((result.value !== undefined && result.value.getIsReadyOrError()) ||\n (result.error !== undefined && result.error.getIsReadyOrError())) &&\n ((ctx.value !== undefined && ctx.value.getIsReadyOrError()) ||\n (ctx.error !== undefined && ctx.error.getIsReadyOrError())),\n };\n }\n\n infos.set(id, { currentArguments, prod, argsRid: cInputs?.resourceInfo.id });\n }\n\n const currentGraph = productionGraph(structure, (id) => {\n const bpInfo = getBlockPackInfo(prj, id)!;\n const bInfo = infos.get(id)!;\n const args = bInfo.currentArguments;\n return {\n args,\n enrichmentTargets: bInfo.argsRid\n ? env.projectHelper.getEnrichmentTargets(\n () => bpInfo.cfg,\n () => args,\n { argsRid: bInfo.argsRid, blockPackRid: bpInfo.bpResourceId },\n )\n : undefined,\n };\n });\n\n const limbo = new Set(renderingState.blocksInLimbo);\n\n const blocks = [...allBlocks(structure)].map(({ id, label: defaultLabel, renderingMode }) => {\n const info = notEmpty(infos.get(id));\n const gNode = notEmpty(currentGraph.nodes.get(id));\n let calculationStatus: BlockCalculationStatus = \"NotCalculated\";\n if (info.prod !== undefined) {\n if (limbo.has(id)) calculationStatus = \"Limbo\";\n else calculationStatus = info.prod.finished ? \"Done\" : \"Running\";\n }\n\n const bp = getBlockPackInfo(prj, id);\n\n const {\n sections,\n title,\n subtitle,\n tags,\n inputsValid,\n sdkVersion,\n featureFlags,\n isIncompatibleWithRuntime,\n } =\n ifNotUndef(bp, ({ bpId, cfg, info: blockPackInfo }) => {\n if (!env.runtimeCapabilities.checkCompatibility(cfg.featureFlags)) {\n return {\n isIncompatibleWithRuntime: true,\n featureFlags: cfg.featureFlags,\n };\n }\n const blockCtx = constructBlockContext(prjEntry, id);\n const blockCtxArgsOnly = constructBlockContextArgsOnly(prjEntry, id);\n const codeWithInfoOrError = wrapCallback(() => extractCodeWithInfo(cfg));\n if (codeWithInfoOrError.error) {\n return {\n title: codeWithInfoOrError.error.message,\n isIncompatibleWithRuntime: true,\n featureFlags: cfg.featureFlags,\n };\n }\n const codeWithInfo = codeWithInfoOrError.value;\n return {\n sections: computableFromCfgOrRF(\n env,\n blockCtx,\n cfg.sections,\n codeWithInfo,\n bpId,\n {},\n blockPackInfo.source,\n ).wrap({\n recover: (cause) => {\n env.logger.error(new Error(\"Error in block model sections\", { cause }));\n return [];\n },\n }) as ComputableStableDefined<BlockSection[]>,\n title: ifNotUndef(\n cfg.title,\n (title) =>\n computableFromCfgOrRF(\n env,\n blockCtxArgsOnly,\n title,\n codeWithInfo,\n bpId,\n {},\n blockPackInfo.source,\n ).wrap({\n recover: (cause) => {\n env.logger.error(new Error(\"Error in block model title\", { cause }));\n return \"Invalid title\";\n },\n }) as ComputableStableDefined<string>,\n ),\n subtitle: ifNotUndef(\n cfg.subtitle,\n (subtitle) =>\n computableFromCfgOrRF(\n env,\n blockCtxArgsOnly,\n subtitle,\n codeWithInfo,\n bpId,\n {},\n blockPackInfo.source,\n ).wrap({\n recover: (cause) => {\n env.logger.error(new Error(\"Error in block model subtitle\", { cause }));\n return \"Invalid subtitle\";\n },\n }) as ComputableStableDefined<string>,\n ),\n tags: ifNotUndef(\n cfg.tags,\n (tags) =>\n computableFromCfgOrRF(\n env,\n blockCtx,\n tags,\n codeWithInfo,\n bpId,\n {},\n blockPackInfo.source,\n ).wrap({\n recover: (cause) => {\n env.logger.error(new Error(\"Error in block model tags\", { cause }));\n return [];\n },\n }) as ComputableStableDefined<string[]>,\n ),\n // inputsValid: for modelAPIVersion 2, it's true if currentArgs exists (args derivation succeeded)\n // For older blocks, use the inputsValid callback from config\n inputsValid:\n cfg.modelAPIVersion === BLOCK_STORAGE_FACADE_VERSION\n ? info.currentArguments !== undefined\n : cfg.inputsValid\n ? (computableFromCfgOrRF(\n env,\n blockCtxArgsOnly,\n cfg.inputsValid,\n codeWithInfo,\n bpId,\n ).wrap({\n recover: (cause) => {\n env.logger.error(\n new Error(\"Error in block model inputsValid\", { cause }),\n );\n return false;\n },\n }) as ComputableStableDefined<boolean>)\n : undefined,\n sdkVersion: codeWithInfo?.sdkVersion,\n featureFlags: codeWithInfo?.featureFlags ?? {},\n isIncompatibleWithRuntime: false,\n };\n }) || {};\n\n const settings = prj\n .traverse({\n field: projectFieldName(id, \"blockSettings\"),\n assertFieldType: \"Dynamic\",\n errorIfFieldNotSet: true,\n })\n .getDataAsJson() as BlockSettings;\n\n const updates = ifNotUndef(bp, ({ info }) =>\n env.blockUpdateWatcher.get({ currentSpec: info.source, settings }),\n );\n\n return {\n projectResourceId: resourceIdToString(prjEntry.rid),\n id,\n label: title ?? defaultLabel,\n title: title ?? defaultLabel,\n subtitle,\n tags,\n renderingMode,\n stale: info.prod?.stale !== false || calculationStatus === \"Limbo\",\n missingReference: gNode.missingReferences,\n upstreams: [...currentGraph.traverseIdsExcludingRoots(\"upstream\", id)],\n downstreams: [...currentGraph.traverseIdsExcludingRoots(\"downstream\", id)],\n calculationStatus,\n outputErrors: info.prod?.outputError === true,\n outputsError: info.prod?.outputsError,\n exportsError: info.prod?.exportsError,\n settings,\n sections,\n inputsValid,\n updateInfo: {},\n currentBlockPack: bp?.info?.source,\n updates,\n sdkVersion,\n featureFlags,\n isIncompatibleWithRuntime,\n navigationState: navigationStates.getState(id),\n };\n });\n\n return {\n meta,\n created: new Date(created),\n lastModified: new Date(lastModified),\n authorMarker: prj.getKeyValueAsJson<AuthorMarker>(ProjectStructureAuthorKey),\n blocks,\n };\n },\n {\n postprocessValue: (value) => {\n const cantRun = new Set<string>();\n const staleBlocks = new Set<string>();\n return {\n ...value,\n blocks: value.blocks.map((b) => {\n if (!b.inputsValid) cantRun.add(b.id);\n if (b.stale) staleBlocks.add(b.id);\n const stale = b.stale || b.upstreams.findIndex((u) => staleBlocks.has(u)) !== -1;\n const canRun =\n (stale || b.outputErrors) &&\n Boolean(b.inputsValid) &&\n !b.missingReference &&\n b.upstreams.findIndex((u) => cantRun.has(u)) === -1;\n const bb = {\n ...b,\n canRun,\n stale,\n updateSuggestions: b.updates?.suggestions ?? [],\n updatedBlockPack: b.updates?.mainSuggestion,\n };\n delete bb[\"updates\"];\n return bb;\n }),\n };\n },\n onRecalculation: getDebugFlags().logProjectOverviewStat\n ? (stats) => {\n console.log(`[projectOverview] ${JSON.stringify(stats)}`);\n }\n : undefined,\n },\n ).withStableType();\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"project_overview.js","names":[],"sources":["../../src/middle_layer/project_overview.ts"],"sourcesContent":["import type { PlTreeEntry } from \"@milaboratories/pl-tree\";\nimport type { ComputableStableDefined } from \"@milaboratories/computable\";\nimport { Computable } from \"@milaboratories/computable\";\nimport type { ProjectRenderingState, ProjectStructure } from \"../model/project_model\";\nimport {\n BlockRenderingStateKey,\n ProjectCreatedTimestamp,\n projectFieldName,\n ProjectLastModifiedTimestamp,\n ProjectMetaKey,\n ProjectStructureAuthorKey,\n ProjectStructureKey,\n} from \"../model/project_model\";\nimport { notEmpty } from \"@milaboratories/ts-helpers\";\nimport { allBlocks, productionGraph } from \"../model/project_model_util\";\nimport type { MiddleLayerEnvironment } from \"./middle_layer\";\nimport type {\n AuthorMarker,\n BlockCalculationStatus,\n BlockSettings,\n ProjectMeta,\n ProjectOverview,\n} from \"@milaboratories/pl-model-middle-layer\";\nimport { constructBlockContext, constructBlockContextArgsOnly } from \"./block_ctx\";\nimport { ifNotUndef } from \"../cfg_render/util\";\nimport { type BlockSection, BLOCK_STORAGE_FACADE_VERSION } from \"@platforma-sdk/model\";\nimport { extractCodeWithInfo, wrapCallback } from \"@platforma-sdk/model\";\nimport { computableFromCfgOrRF } from \"./render\";\nimport type { NavigationStates } from \"./navigation_states\";\nimport { getBlockPackInfo } from \"./util\";\nimport { resourceIdToString, type SignedResourceId } from \"@milaboratories/pl-client\";\nimport { omitBy, isEqual } from \"es-toolkit\";\nimport { getDebugFlags } from \"../debug\";\n\ntype BlockInfo = {\n argsRid?: SignedResourceId;\n currentArguments: unknown;\n prod?: ProdState;\n};\n\ntype ProdState = {\n finished: boolean;\n\n outputError: boolean;\n\n outputsError?: string;\n\n exportsError?: string;\n\n stale: boolean;\n\n /** Arguments current production was rendered with. */\n arguments: Record<string, unknown>;\n};\n\nfunction argsEquals(\n a: Record<string, unknown> | undefined,\n b: Record<string, unknown> | undefined,\n): boolean {\n if (a === b) return true;\n if (a === undefined || b === undefined) return false;\n const cleanA = omitBy(a, (_, key) => key.startsWith(\"__\"));\n const cleanB = omitBy(b, (_, key) => key.startsWith(\"__\"));\n return isEqual(cleanA, cleanB);\n}\n\n/** Returns derived general project state form the project resource */\nexport function projectOverview(\n prjEntry: PlTreeEntry,\n navigationStates: NavigationStates,\n env: MiddleLayerEnvironment,\n): ComputableStableDefined<ProjectOverview> {\n return Computable.make(\n (ctx) => {\n const prj = ctx.accessor(prjEntry).node();\n\n const created = notEmpty(prj.getKeyValueAsJson<number>(ProjectCreatedTimestamp));\n const lastModified = notEmpty(prj.getKeyValueAsJson<number>(ProjectLastModifiedTimestamp));\n\n const meta = notEmpty(prj.getKeyValueAsJson<ProjectMeta>(ProjectMetaKey));\n const structure = notEmpty(prj.getKeyValueAsJson<ProjectStructure>(ProjectStructureKey));\n const renderingState = notEmpty(\n prj.getKeyValueAsJson<ProjectRenderingState>(BlockRenderingStateKey),\n );\n\n const infos = new Map<string, BlockInfo>();\n for (const { id } of allBlocks(structure)) {\n const cInputs = prj.traverse({\n field: projectFieldName(id, \"currentArgs\"),\n assertFieldType: \"Dynamic\",\n stableIfNotFound: true,\n });\n const currentArguments = cInputs?.getDataAsJson<Record<string, unknown>>();\n\n let prod: ProdState | undefined = undefined;\n\n const rInputs = prj.traverse({\n field: projectFieldName(id, \"prodArgs\"),\n assertFieldType: \"Dynamic\",\n stableIfNotFound: true,\n });\n if (rInputs !== undefined) {\n const prodArgs = rInputs.getDataAsJson() as Record<string, unknown>;\n const result = prj.getField({\n field: projectFieldName(id, \"prodOutput\"),\n assertFieldType: \"Dynamic\",\n errorIfFieldNotFound: true,\n });\n const ctx = prj.getField({\n field: projectFieldName(id, \"prodUiCtx\"),\n assertFieldType: \"Dynamic\",\n errorIfFieldNotFound: true,\n });\n prod = {\n arguments: prodArgs,\n stale: !argsEquals(currentArguments, prodArgs),\n outputError:\n result.error !== undefined ||\n ctx.error !== undefined ||\n result.value?.getError() !== undefined ||\n ctx.value?.getError() !== undefined,\n outputsError:\n result.error?.getDataAsString() ?? result.value?.getError()?.getDataAsString(),\n exportsError: ctx.error?.getDataAsString() ?? ctx.value?.getError()?.getDataAsString(),\n finished:\n ((result.value !== undefined && result.value.getIsReadyOrError()) ||\n (result.error !== undefined && result.error.getIsReadyOrError())) &&\n ((ctx.value !== undefined && ctx.value.getIsReadyOrError()) ||\n (ctx.error !== undefined && ctx.error.getIsReadyOrError())),\n };\n }\n\n infos.set(id, { currentArguments, prod, argsRid: cInputs?.resourceInfo.id });\n }\n\n const currentGraph = productionGraph(structure, (id) => {\n const bpInfo = getBlockPackInfo(prj, id)!;\n const bInfo = infos.get(id)!;\n const args = bInfo.currentArguments;\n return {\n args,\n enrichmentTargets: bInfo.argsRid\n ? env.projectHelper.getEnrichmentTargets(\n () => bpInfo.cfg,\n () => args,\n { argsRid: bInfo.argsRid, blockPackRid: bpInfo.bpResourceId },\n )\n : undefined,\n };\n });\n\n const limbo = new Set(renderingState.blocksInLimbo);\n\n const blocks = [...allBlocks(structure)].map(({ id, label: defaultLabel, renderingMode }) => {\n const info = notEmpty(infos.get(id));\n const gNode = notEmpty(currentGraph.nodes.get(id));\n let calculationStatus: BlockCalculationStatus = \"NotCalculated\";\n if (info.prod !== undefined) {\n if (limbo.has(id)) calculationStatus = \"Limbo\";\n else calculationStatus = info.prod.finished ? \"Done\" : \"Running\";\n }\n\n const bp = getBlockPackInfo(prj, id);\n\n const {\n sections,\n title,\n subtitle,\n tags,\n inputsValid,\n sdkVersion,\n featureFlags,\n isIncompatibleWithRuntime,\n } =\n ifNotUndef(bp, ({ bpId, cfg, info: blockPackInfo }) => {\n if (!env.runtimeCapabilities.checkCompatibility(cfg.featureFlags)) {\n return {\n isIncompatibleWithRuntime: true,\n featureFlags: cfg.featureFlags,\n };\n }\n const blockCtx = constructBlockContext(prjEntry, id);\n const blockCtxArgsOnly = constructBlockContextArgsOnly(prjEntry, id);\n const codeWithInfoOrError = wrapCallback(() => extractCodeWithInfo(cfg));\n if (codeWithInfoOrError.error) {\n return {\n title: codeWithInfoOrError.error.message,\n isIncompatibleWithRuntime: true,\n featureFlags: cfg.featureFlags,\n };\n }\n const codeWithInfo = codeWithInfoOrError.value;\n return {\n sections: computableFromCfgOrRF(\n env,\n blockCtx,\n cfg.sections,\n codeWithInfo,\n bpId,\n {},\n blockPackInfo.source,\n ).wrap({\n recover: (cause) => {\n env.logger.error(new Error(\"Error in block model sections\", { cause }));\n return [];\n },\n }) as ComputableStableDefined<BlockSection[]>,\n title: ifNotUndef(\n cfg.title,\n (title) =>\n computableFromCfgOrRF(\n env,\n blockCtxArgsOnly,\n title,\n codeWithInfo,\n bpId,\n {},\n blockPackInfo.source,\n ).wrap({\n recover: (cause) => {\n env.logger.error(new Error(\"Error in block model title\", { cause }));\n return \"Invalid title\";\n },\n }) as ComputableStableDefined<string>,\n ),\n subtitle: ifNotUndef(\n cfg.subtitle,\n (subtitle) =>\n computableFromCfgOrRF(\n env,\n blockCtxArgsOnly,\n subtitle,\n codeWithInfo,\n bpId,\n {},\n blockPackInfo.source,\n ).wrap({\n recover: (cause) => {\n env.logger.error(new Error(\"Error in block model subtitle\", { cause }));\n return \"Invalid subtitle\";\n },\n }) as ComputableStableDefined<string>,\n ),\n tags: ifNotUndef(\n cfg.tags,\n (tags) =>\n computableFromCfgOrRF(\n env,\n blockCtx,\n tags,\n codeWithInfo,\n bpId,\n {},\n blockPackInfo.source,\n ).wrap({\n recover: (cause) => {\n env.logger.error(new Error(\"Error in block model tags\", { cause }));\n return [];\n },\n }) as ComputableStableDefined<string[]>,\n ),\n // inputsValid: for modelAPIVersion 2, it's true if currentArgs exists (args derivation succeeded)\n // For older blocks, use the inputsValid callback from config\n inputsValid:\n cfg.modelAPIVersion === BLOCK_STORAGE_FACADE_VERSION\n ? info.currentArguments !== undefined\n : cfg.inputsValid\n ? (computableFromCfgOrRF(\n env,\n blockCtxArgsOnly,\n cfg.inputsValid,\n codeWithInfo,\n bpId,\n ).wrap({\n recover: (cause) => {\n env.logger.error(\n new Error(\"Error in block model inputsValid\", { cause }),\n );\n return false;\n },\n }) as ComputableStableDefined<boolean>)\n : undefined,\n sdkVersion: codeWithInfo?.sdkVersion,\n featureFlags: codeWithInfo?.featureFlags ?? {},\n isIncompatibleWithRuntime: false,\n };\n }) || {};\n\n const settings = prj\n .traverse({\n field: projectFieldName(id, \"blockSettings\"),\n assertFieldType: \"Dynamic\",\n errorIfFieldNotSet: true,\n })\n .getDataAsJson() as BlockSettings;\n\n const updates = ifNotUndef(bp, ({ info }) =>\n env.blockUpdateWatcher.get({ currentSpec: info.source, settings }),\n );\n\n return {\n projectResourceId: resourceIdToString(prjEntry.rid),\n id,\n label: title ?? defaultLabel,\n title: title ?? defaultLabel,\n subtitle,\n tags,\n renderingMode,\n stale: info.prod?.stale !== false || calculationStatus === \"Limbo\",\n missingReference: gNode.missingReferences,\n upstreams: [...currentGraph.traverseIdsExcludingRoots(\"upstream\", id)],\n downstreams: [...currentGraph.traverseIdsExcludingRoots(\"downstream\", id)],\n calculationStatus,\n outputErrors: info.prod?.outputError === true,\n outputsError: info.prod?.outputsError,\n exportsError: info.prod?.exportsError,\n settings,\n sections,\n inputsValid,\n updateInfo: {},\n currentBlockPack: bp?.info?.source,\n updates,\n sdkVersion,\n featureFlags,\n isIncompatibleWithRuntime,\n navigationState: navigationStates.getState(id),\n };\n });\n\n return {\n meta,\n created: new Date(created),\n lastModified: new Date(lastModified),\n authorMarker: prj.getKeyValueAsJson<AuthorMarker>(ProjectStructureAuthorKey),\n blocks,\n };\n },\n {\n postprocessValue: (value) => {\n const cantRun = new Set<string>();\n const staleBlocks = new Set<string>();\n return {\n ...value,\n blocks: value.blocks.map((b) => {\n if (!b.inputsValid) cantRun.add(b.id);\n if (b.stale) staleBlocks.add(b.id);\n const stale = b.stale || b.upstreams.findIndex((u) => staleBlocks.has(u)) !== -1;\n const canRun =\n (stale || b.outputErrors) &&\n Boolean(b.inputsValid) &&\n !b.missingReference &&\n b.upstreams.findIndex((u) => cantRun.has(u)) === -1;\n const bb = {\n ...b,\n canRun,\n stale,\n updateSuggestions: b.updates?.suggestions ?? [],\n updatedBlockPack: b.updates?.mainSuggestion,\n };\n delete bb[\"updates\"];\n return bb;\n }),\n };\n },\n onRecalculation: getDebugFlags().logProjectOverviewStat\n ? (stats) => {\n console.log(`[projectOverview] ${JSON.stringify(stats)}`);\n }\n : undefined,\n },\n ).withStableType();\n}\n"],"mappings":"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"}
@@ -2,14 +2,15 @@ const require_project_model = require("../model/project_model.cjs");
2
2
  const require_project_model_util = require("../model/project_model_util.cjs");
3
3
  let _milaboratories_ts_helpers = require("@milaboratories/ts-helpers");
4
4
  let _milaboratories_computable = require("@milaboratories/computable");
5
- //#region src/middle_layer/project_overview_light.ts
5
+ // src/middle_layer/project_overview_light.ts
6
6
  /** Returns derived general project state form the project resource */
7
7
  function projectOverviewLight(prjEntry) {
8
8
  return _milaboratories_computable.Computable.make((ctx) => {
9
- return { listOfBlocks: [...require_project_model_util.allBlocks((0, _milaboratories_ts_helpers.notEmpty)(ctx.accessor(prjEntry).node().getKeyValueAsJson(require_project_model.ProjectStructureKey)))].map((b) => b.id) };
9
+ const prj = ctx.accessor(prjEntry).node();
10
+ const structure = (0, _milaboratories_ts_helpers.notEmpty)(prj.getKeyValueAsJson(require_project_model.ProjectStructureKey));
11
+ return { listOfBlocks: [...require_project_model_util.allBlocks(structure)].map((b) => b.id) };
10
12
  });
11
13
  }
12
- //#endregion
13
14
  exports.projectOverviewLight = projectOverviewLight;
14
15
 
15
16
  //# sourceMappingURL=project_overview_light.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"project_overview_light.cjs","names":["Computable","allBlocks","ProjectStructureKey"],"sources":["../../src/middle_layer/project_overview_light.ts"],"sourcesContent":["import { notEmpty } from \"@milaboratories/ts-helpers\";\nimport type { PlTreeEntry } from \"@milaboratories/pl-tree\";\nimport { Computable } from \"@milaboratories/computable\";\nimport type { ProjectStructure } from \"../model/project_model\";\nimport { ProjectStructureKey } from \"../model/project_model\";\nimport { allBlocks } from \"../model/project_model_util\";\n\nexport type ProjectOverviewLight = {\n readonly listOfBlocks: string[];\n};\n\n/** Returns derived general project state form the project resource */\nexport function projectOverviewLight(prjEntry: PlTreeEntry): Computable<ProjectOverviewLight> {\n return Computable.make((ctx) => {\n const prj = ctx.accessor(prjEntry).node();\n\n const structure = notEmpty(prj.getKeyValueAsJson<ProjectStructure>(ProjectStructureKey));\n\n return {\n listOfBlocks: [...allBlocks(structure)].map((b) => b.id),\n };\n });\n}\n"],"mappings":";;;;;;AAYA,SAAgB,qBAAqB,UAAyD;CAC5F,OAAOA,2BAAAA,WAAW,MAAM,QAAQ;EAK9B,OAAO,EACL,cAAc,CAAC,GAAGC,2BAAAA,WAAAA,GAAAA,2BAAAA,SAAAA,CALR,IAAI,SAAS,QAAQ,CAAC,CAAC,KAEN,CAAC,CAAC,kBAAoCC,sBAAAA,mBAAmB,CAGhD,CAAC,CAAC,CAAC,CAAC,KAAK,MAAM,EAAE,EAAE,EACzD;CACF,CAAC;AACH"}
1
+ {"version":3,"file":"project_overview_light.cjs","names":["Computable","notEmpty","ProjectStructureKey","allBlocks"],"sources":["../../src/middle_layer/project_overview_light.ts"],"sourcesContent":["import { notEmpty } from \"@milaboratories/ts-helpers\";\nimport type { PlTreeEntry } from \"@milaboratories/pl-tree\";\nimport { Computable } from \"@milaboratories/computable\";\nimport type { ProjectStructure } from \"../model/project_model\";\nimport { ProjectStructureKey } from \"../model/project_model\";\nimport { allBlocks } from \"../model/project_model_util\";\n\nexport type ProjectOverviewLight = {\n readonly listOfBlocks: string[];\n};\n\n/** Returns derived general project state form the project resource */\nexport function projectOverviewLight(prjEntry: PlTreeEntry): Computable<ProjectOverviewLight> {\n return Computable.make((ctx) => {\n const prj = ctx.accessor(prjEntry).node();\n\n const structure = notEmpty(prj.getKeyValueAsJson<ProjectStructure>(ProjectStructureKey));\n\n return {\n listOfBlocks: [...allBlocks(structure)].map((b) => b.id),\n };\n });\n}\n"],"mappings":";;;;;;AAYA,SAAgB,qBAAqB,UAAyD;CAC5F,OAAOA,2BAAAA,WAAW,MAAM,QAAQ;EAC9B,MAAM,MAAM,IAAI,SAAS,QAAQ,CAAC,CAAC,KAAK;EAExC,MAAM,aAAA,GAAYC,2BAAAA,SAAAA,CAAS,IAAI,kBAAoCC,sBAAAA,mBAAmB,CAAC;EAEvF,OAAO,EACL,cAAc,CAAC,GAAGC,2BAAAA,UAAU,SAAS,CAAC,CAAC,CAAC,KAAK,MAAM,EAAE,EAAE,EACzD;CACF,CAAC;AACH"}
@@ -2,14 +2,15 @@ import { ProjectStructureKey } from "../model/project_model.js";
2
2
  import { allBlocks } from "../model/project_model_util.js";
3
3
  import { notEmpty } from "@milaboratories/ts-helpers";
4
4
  import { Computable } from "@milaboratories/computable";
5
- //#region src/middle_layer/project_overview_light.ts
5
+ // src/middle_layer/project_overview_light.ts
6
6
  /** Returns derived general project state form the project resource */
7
7
  function projectOverviewLight(prjEntry) {
8
8
  return Computable.make((ctx) => {
9
- return { listOfBlocks: [...allBlocks(notEmpty(ctx.accessor(prjEntry).node().getKeyValueAsJson(ProjectStructureKey)))].map((b) => b.id) };
9
+ const prj = ctx.accessor(prjEntry).node();
10
+ const structure = notEmpty(prj.getKeyValueAsJson(ProjectStructureKey));
11
+ return { listOfBlocks: [...allBlocks(structure)].map((b) => b.id) };
10
12
  });
11
13
  }
12
- //#endregion
13
14
  export { projectOverviewLight };
14
15
 
15
16
  //# sourceMappingURL=project_overview_light.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"project_overview_light.js","names":[],"sources":["../../src/middle_layer/project_overview_light.ts"],"sourcesContent":["import { notEmpty } from \"@milaboratories/ts-helpers\";\nimport type { PlTreeEntry } from \"@milaboratories/pl-tree\";\nimport { Computable } from \"@milaboratories/computable\";\nimport type { ProjectStructure } from \"../model/project_model\";\nimport { ProjectStructureKey } from \"../model/project_model\";\nimport { allBlocks } from \"../model/project_model_util\";\n\nexport type ProjectOverviewLight = {\n readonly listOfBlocks: string[];\n};\n\n/** Returns derived general project state form the project resource */\nexport function projectOverviewLight(prjEntry: PlTreeEntry): Computable<ProjectOverviewLight> {\n return Computable.make((ctx) => {\n const prj = ctx.accessor(prjEntry).node();\n\n const structure = notEmpty(prj.getKeyValueAsJson<ProjectStructure>(ProjectStructureKey));\n\n return {\n listOfBlocks: [...allBlocks(structure)].map((b) => b.id),\n };\n });\n}\n"],"mappings":";;;;;;AAYA,SAAgB,qBAAqB,UAAyD;CAC5F,OAAO,WAAW,MAAM,QAAQ;EAK9B,OAAO,EACL,cAAc,CAAC,GAAG,UAHF,SAFN,IAAI,SAAS,QAAQ,CAAC,CAAC,KAEN,CAAC,CAAC,kBAAoC,mBAAmB,CAGhD,CAAC,CAAC,CAAC,CAAC,KAAK,MAAM,EAAE,EAAE,EACzD;CACF,CAAC;AACH"}
1
+ {"version":3,"file":"project_overview_light.js","names":[],"sources":["../../src/middle_layer/project_overview_light.ts"],"sourcesContent":["import { notEmpty } from \"@milaboratories/ts-helpers\";\nimport type { PlTreeEntry } from \"@milaboratories/pl-tree\";\nimport { Computable } from \"@milaboratories/computable\";\nimport type { ProjectStructure } from \"../model/project_model\";\nimport { ProjectStructureKey } from \"../model/project_model\";\nimport { allBlocks } from \"../model/project_model_util\";\n\nexport type ProjectOverviewLight = {\n readonly listOfBlocks: string[];\n};\n\n/** Returns derived general project state form the project resource */\nexport function projectOverviewLight(prjEntry: PlTreeEntry): Computable<ProjectOverviewLight> {\n return Computable.make((ctx) => {\n const prj = ctx.accessor(prjEntry).node();\n\n const structure = notEmpty(prj.getKeyValueAsJson<ProjectStructure>(ProjectStructureKey));\n\n return {\n listOfBlocks: [...allBlocks(structure)].map((b) => b.id),\n };\n });\n}\n"],"mappings":";;;;;;AAYA,SAAgB,qBAAqB,UAAyD;CAC5F,OAAO,WAAW,MAAM,QAAQ;EAC9B,MAAM,MAAM,IAAI,SAAS,QAAQ,CAAC,CAAC,KAAK;EAExC,MAAM,YAAY,SAAS,IAAI,kBAAoC,mBAAmB,CAAC;EAEvF,OAAO,EACL,cAAc,CAAC,GAAG,UAAU,SAAS,CAAC,CAAC,CAAC,KAAK,MAAM,EAAE,EAAE,EACzD;CACF,CAAC;AACH"}
@@ -2,7 +2,7 @@ const require_util = require("../cfg_render/util.cjs");
2
2
  const require_executor = require("../cfg_render/executor.cjs");
3
3
  const require_index = require("../js_render/index.cjs");
4
4
  let _platforma_sdk_model = require("@platforma-sdk/model");
5
- //#region src/middle_layer/render.ts
5
+ // src/middle_layer/render.ts
6
6
  function isActive(cfg) {
7
7
  if ((0, _platforma_sdk_model.isConfigLambda)(cfg)) return cfg.isActive === true;
8
8
  else return require_util.hasActiveCfgComponents(cfg);
@@ -13,7 +13,6 @@ function computableFromCfgOrRF(env, ctx, cfgOrFh, codeWithInfo, configKey, ops =
13
13
  return require_index.computableFromRF(env, ctx, cfgOrFh, codeWithInfo, configKey, ops, blockPack);
14
14
  } else return require_executor.computableFromCfg(env.driverKit, ctx, cfgOrFh, ops);
15
15
  }
16
- //#endregion
17
16
  exports.computableFromCfgOrRF = computableFromCfgOrRF;
18
17
  exports.isActive = isActive;
19
18
 
@@ -1 +1 @@
1
- {"version":3,"file":"render.cjs","names":["hasActiveCfgComponents","computableFromRF","computableFromCfg"],"sources":["../../src/middle_layer/render.ts"],"sourcesContent":["import type { BlockCodeWithInfo, TypedConfigOrConfigLambda } from \"@platforma-sdk/model\";\nimport { isConfigLambda } from \"@platforma-sdk/model\";\nimport type { Computable, ComputableRenderingOps } from \"@milaboratories/computable\";\nimport { computableFromCfg } from \"../cfg_render/executor\";\nimport type { MiddleLayerEnvironment } from \"./middle_layer\";\nimport { computableFromRF } from \"../js_render\";\nimport type { BlockContextAny } from \"./block_ctx\";\nimport type { BlockPackSpec } from \"@milaboratories/pl-model-middle-layer\";\nimport { hasActiveCfgComponents } from \"../cfg_render/util\";\n\nexport function isActive(cfg: TypedConfigOrConfigLambda): boolean {\n if (isConfigLambda(cfg)) return cfg.isActive === true;\n else return hasActiveCfgComponents(cfg);\n}\n\nexport function computableFromCfgOrRF(\n env: MiddleLayerEnvironment,\n ctx: BlockContextAny,\n cfgOrFh: TypedConfigOrConfigLambda,\n codeWithInfo: BlockCodeWithInfo | undefined,\n configKey: string,\n ops: Partial<ComputableRenderingOps> = {},\n blockPack?: BlockPackSpec,\n): Computable<unknown> {\n if (isConfigLambda(cfgOrFh)) {\n if (codeWithInfo === undefined) throw new Error(\"computableFromCfgOrRF: No code bundle.\");\n return computableFromRF(env, ctx, cfgOrFh, codeWithInfo, configKey, ops, blockPack);\n } else return computableFromCfg(env.driverKit, ctx, cfgOrFh, ops);\n}\n"],"mappings":";;;;;AAUA,SAAgB,SAAS,KAAyC;CAChE,KAAA,GAAA,qBAAA,eAAA,CAAmB,GAAG,GAAG,OAAO,IAAI,aAAa;MAC5C,OAAOA,aAAAA,uBAAuB,GAAG;AACxC;AAEA,SAAgB,sBACd,KACA,KACA,SACA,cACA,WACA,MAAuC,CAAC,GACxC,WACqB;CACrB,KAAA,GAAA,qBAAA,eAAA,CAAmB,OAAO,GAAG;EAC3B,IAAI,iBAAiB,KAAA,GAAW,MAAM,IAAI,MAAM,wCAAwC;EACxF,OAAOC,cAAAA,iBAAiB,KAAK,KAAK,SAAS,cAAc,WAAW,KAAK,SAAS;CACpF,OAAO,OAAOC,iBAAAA,kBAAkB,IAAI,WAAW,KAAK,SAAS,GAAG;AAClE"}
1
+ {"version":3,"file":"render.cjs","names":["isConfigLambda","hasActiveCfgComponents","computableFromRF","computableFromCfg"],"sources":["../../src/middle_layer/render.ts"],"sourcesContent":["import type { BlockCodeWithInfo, TypedConfigOrConfigLambda } from \"@platforma-sdk/model\";\nimport { isConfigLambda } from \"@platforma-sdk/model\";\nimport type { Computable, ComputableRenderingOps } from \"@milaboratories/computable\";\nimport { computableFromCfg } from \"../cfg_render/executor\";\nimport type { MiddleLayerEnvironment } from \"./middle_layer\";\nimport { computableFromRF } from \"../js_render\";\nimport type { BlockContextAny } from \"./block_ctx\";\nimport type { BlockPackSpec } from \"@milaboratories/pl-model-middle-layer\";\nimport { hasActiveCfgComponents } from \"../cfg_render/util\";\n\nexport function isActive(cfg: TypedConfigOrConfigLambda): boolean {\n if (isConfigLambda(cfg)) return cfg.isActive === true;\n else return hasActiveCfgComponents(cfg);\n}\n\nexport function computableFromCfgOrRF(\n env: MiddleLayerEnvironment,\n ctx: BlockContextAny,\n cfgOrFh: TypedConfigOrConfigLambda,\n codeWithInfo: BlockCodeWithInfo | undefined,\n configKey: string,\n ops: Partial<ComputableRenderingOps> = {},\n blockPack?: BlockPackSpec,\n): Computable<unknown> {\n if (isConfigLambda(cfgOrFh)) {\n if (codeWithInfo === undefined) throw new Error(\"computableFromCfgOrRF: No code bundle.\");\n return computableFromRF(env, ctx, cfgOrFh, codeWithInfo, configKey, ops, blockPack);\n } else return computableFromCfg(env.driverKit, ctx, cfgOrFh, ops);\n}\n"],"mappings":";;;;;AAUA,SAAgB,SAAS,KAAyC;CAChE,KAAA,GAAIA,qBAAAA,eAAAA,CAAe,GAAG,GAAG,OAAO,IAAI,aAAa;MAC5C,OAAOC,aAAAA,uBAAuB,GAAG;AACxC;AAEA,SAAgB,sBACd,KACA,KACA,SACA,cACA,WACA,MAAuC,CAAC,GACxC,WACqB;CACrB,KAAA,GAAID,qBAAAA,eAAAA,CAAe,OAAO,GAAG;EAC3B,IAAI,iBAAiB,KAAA,GAAW,MAAM,IAAI,MAAM,wCAAwC;EACxF,OAAOE,cAAAA,iBAAiB,KAAK,KAAK,SAAS,cAAc,WAAW,KAAK,SAAS;CACpF,OAAO,OAAOC,iBAAAA,kBAAkB,IAAI,WAAW,KAAK,SAAS,GAAG;AAClE"}
@@ -2,7 +2,7 @@ import { hasActiveCfgComponents } from "../cfg_render/util.js";
2
2
  import { computableFromCfg } from "../cfg_render/executor.js";
3
3
  import { computableFromRF } from "../js_render/index.js";
4
4
  import { isConfigLambda } from "@platforma-sdk/model";
5
- //#region src/middle_layer/render.ts
5
+ // src/middle_layer/render.ts
6
6
  function isActive(cfg) {
7
7
  if (isConfigLambda(cfg)) return cfg.isActive === true;
8
8
  else return hasActiveCfgComponents(cfg);
@@ -13,7 +13,6 @@ function computableFromCfgOrRF(env, ctx, cfgOrFh, codeWithInfo, configKey, ops =
13
13
  return computableFromRF(env, ctx, cfgOrFh, codeWithInfo, configKey, ops, blockPack);
14
14
  } else return computableFromCfg(env.driverKit, ctx, cfgOrFh, ops);
15
15
  }
16
- //#endregion
17
16
  export { computableFromCfgOrRF, isActive };
18
17
 
19
18
  //# sourceMappingURL=render.js.map
@@ -2,7 +2,7 @@ const require_sharing_model = require("../model/sharing_model.cjs");
2
2
  let _milaboratories_pl_client = require("@milaboratories/pl-client");
3
3
  let _milaboratories_pl_tree = require("@milaboratories/pl-tree");
4
4
  let _milaboratories_computable = require("@milaboratories/computable");
5
- //#region src/middle_layer/sharing_list.ts
5
+ // src/middle_layer/sharing_list.ts
6
6
  /**
7
7
  * Reactive view of the donor's own outbox. Reads each live envelope's immutable
8
8
  * {@link EnvelopeData} from the tree, then enriches each share's full recipient list via
@@ -230,7 +230,6 @@ function envelopeDescription(data) {
230
230
  }
231
231
  }
232
232
  }
233
- //#endregion
234
233
  exports.createAvailableSharesComputable = createAvailableSharesComputable;
235
234
  exports.createAvailableSharesTree = createAvailableSharesTree;
236
235
  exports.createLiveEnvelopesComputable = createLiveEnvelopesComputable;
@@ -1 +1 @@
1
- {"version":3,"file":"sharing_list.cjs","names":["Computable","SharedEnvelopeResourceType","normalizeEnvelopeData","SynchronizedTreeState","isHiddenField","hiddenFieldShareId","SharingOutboxResourceType","treeFilter","SharingStateResourceType","envelopeProjectMap","envelopeFolderRoot"],"sources":["../../src/middle_layer/sharing_list.ts"],"sourcesContent":["import type { PlTreeNodeAccessor, PruningFunction } from \"@milaboratories/pl-tree\";\nimport { SynchronizedTreeState } from \"@milaboratories/pl-tree\";\nimport type { Filter, PlClient, SignedResourceId } from \"@milaboratories/pl-client\";\nimport {\n isEveryoneUserLogin,\n resourceType,\n resourceTypesEqual,\n treeFilter,\n} from \"@milaboratories/pl-client\";\nimport { Computable } from \"@milaboratories/computable\";\nimport type { MiddleLayerEnvironment } from \"./middle_layer\";\nimport type { ProjectId, TemplateId } from \"@milaboratories/pl-model-common\";\nimport type { FolderId } from \"@milaboratories/pl-model-middle-layer\";\nimport type {\n EnvelopeData,\n EnvelopeMode,\n EnvelopePayloadKind,\n ShareId,\n} from \"../model/sharing_model\";\nimport {\n hiddenFieldShareId,\n isHiddenField,\n envelopeFolderRoot,\n envelopeProjectMap,\n normalizeEnvelopeData,\n SharedEnvelopeResourceType,\n SharingOutboxResourceType,\n SharingStateResourceType,\n} from \"../model/sharing_model\";\n\n/** What a folder share carries, as both share lists show it. */\nexport interface EnvelopeFolderSummary {\n label: string;\n /** Donor's own id of the shared folder. */\n source: FolderId;\n folderCount: number;\n projectCount: number;\n templateCount: number;\n}\n\n/** Donor-facing view of one outgoing share. */\nexport interface OutgoingShare {\n shareId: ShareId; // identity of the share; a share that replaces it gets its own\n sharedAt: number; // this instance's creation time (ms epoch)\n expiresAt?: number; // EnvelopeData.expiresAt; null maps to undefined = never expires\n mode: EnvelopeMode;\n title: string; // display name shown to recipients; defaults to the first project's name\n /** What the share carries — a pack of projects, one template document, or a folder subtree. */\n payloadKind: EnvelopePayloadKind;\n /** One entry per project in the pack. `projectId` is the donor's source project id, which is\n * what the share dialog matches a project's prior shares on; `updatedAt` is when this\n * project's snapshot was taken. Empty for any share that is not a pack of projects. */\n projects: { projectId: ProjectId; label: string; updatedAt: number }[];\n /** The shared template, for a template share; absent otherwise. `source` is the donor's own\n * template id, which is what the share dialog matches a template's prior shares on; a share\n * made before it was carried has none and matches nothing. */\n template?: { label: string; blockCount: number; source?: TemplateId };\n /** The shared folder, for a folder share; absent otherwise. `label` is the root folder's own\n * name, `source` the donor's own id for it — what a prior share of the same folder is matched\n * on — and the counts are of the whole subtree, the root folder itself excluded. */\n folder?: EnvelopeFolderSummary;\n /** What the shared thing says about itself: a template's, a folder's, or the one project's of\n * a single-project share. Absent for a pack of several, which has no one thing to describe. */\n description?: string;\n /** Full recipient logins, from `ListGrants` on the envelope; `[\"*\"]` for everyone-shares. */\n recipients: string[];\n}\n\n/**\n * Recipient-facing view of one share that is open to this user.\n *\n * A share is a shelf, not an invitation: it stays listed for as long as the envelope lives, and\n * the recipient may copy from it any number of times. {@link hidden} is that recipient's own\n * private choice to stop seeing it, and it can be undone.\n */\nexport interface AvailableShare {\n shareId: ShareId;\n sender: string; // EnvelopeData.sender, display only\n title: string; // display name shown to recipients; defaults to the first project's name\n mode: EnvelopeMode;\n /** What the share carries — projects to copy, a template to add to the recipient's templates,\n * or a folder subtree to rebuild in the recipient's tree. */\n payloadKind: EnvelopePayloadKind;\n grantedAt: number;\n /** What the shared thing says about itself. See {@link OutgoingShare.description}. */\n description?: string;\n /** The shared folder, for a folder share; absent otherwise. See {@link OutgoingShare.folder}. */\n folder?: EnvelopeFolderSummary;\n /** Whether this recipient has put it out of sight. Hidden shares are listed, not dropped: the\n * view that shows them is what \"show hidden\" turns on. */\n hidden: boolean;\n}\n\n/** A live envelope discovered in the recipient's shared-resource tree: its signed resource id and\n * decoded {@link EnvelopeData}. A copy out of a share finds it by `data.shareId`. */\nexport type LiveEnvelope = { rid: SignedResourceId; data: EnvelopeData };\n\n/**\n * Reactive view of the donor's own outbox. Reads each live envelope's immutable\n * {@link EnvelopeData} from the tree, then enriches each share's full recipient list via\n * `ListGrants` on the envelope (`[\"*\"]` for an everyone-share). `ListGrants` is gated backend-side\n * to the envelope owner (the donor), which is exactly who reads this view.\n */\nexport function createOutgoingSharesComputable(\n pl: PlClient,\n tree: SynchronizedTreeState,\n): Computable<OutgoingShare[] | undefined> {\n return Computable.make(\n (ctx) => {\n const node = ctx.accessor(tree.entry()).node();\n if (node === undefined) return undefined;\n\n const drafts: OutgoingShareDraft[] = [];\n // Outbox fields are keyed by shareId; each value is a SharedEnvelope.\n for (const fieldName of node.listDynamicFields()) {\n const envelope = node.traverse(fieldName);\n if (envelope === undefined) continue;\n if (!resourceTypesEqual(envelope.resourceType, SharedEnvelopeResourceType)) continue;\n\n const data = normalizeEnvelopeData(envelope.getDataAsJson<unknown>());\n if (data === undefined) continue; // unknown version or payload kind — not ours to show\n\n const folder = envelopeFolderSummary(data);\n const description = envelopeDescription(data);\n drafts.push({\n shareId: data.shareId,\n sharedAt: data.sharedAt,\n ...(data.expiresAt !== null ? { expiresAt: data.expiresAt } : {}),\n mode: data.mode,\n title: data.title,\n payloadKind: data.payload.kind,\n projects: envelopeProjects(data),\n ...(data.payload.kind === \"template\"\n ? {\n template: {\n label: data.payload.label,\n blockCount: data.payload.document.blocks.length,\n ...(data.payload.source === undefined ? {} : { source: data.payload.source }),\n },\n }\n : {}),\n ...(folder === undefined ? {} : { folder }),\n ...(description === undefined ? {} : { description }),\n envelopeRid: envelope.id,\n });\n }\n drafts.sort((a, b) => b.sharedAt - a.sharedAt);\n return drafts;\n },\n {\n // Resolve each share's recipients via listGrants. An everyone-grant maps to \"*\"; the donor's\n // own grant is dropped. One tx per envelope so a just-revoked rid faults only its own read,\n // which allSettled degrades to []. Recipients aren't cached — a live share's recipient set can\n // change. Transactional listGrants when available, else the standalone gRPC-only RPC.\n postprocessValue: async (\n drafts: OutgoingShareDraft[] | undefined,\n ): Promise<OutgoingShare[] | undefined> => {\n if (drafts === undefined) return undefined;\n const self = pl.userResources.authUser;\n const toRecipients = (grants: { user: string }[]): string[] =>\n grants.some((g) => isEveryoneUserLogin(g.user))\n ? [\"*\"]\n : grants.map((g) => g.user).filter((u) => u !== self);\n\n const txGrants = pl.hasCapability(\"txListGrants:v1\");\n const settled = await Promise.allSettled(\n drafts.map((d) =>\n txGrants\n ? pl.withReadTx(\"ListShareGrant\", (tx) => tx.listGrants(d.envelopeRid))\n : pl.userResources.listGrants(d.envelopeRid),\n ),\n );\n\n return drafts.map(({ envelopeRid: _envelopeRid, ...share }, i): OutgoingShare => {\n const r = settled[i];\n return { ...share, recipients: r.status === \"fulfilled\" ? toRecipients(r.value) : [] };\n });\n },\n },\n );\n}\n\n/**\n * Creates the donor's outbox synchronized tree (single explicit root) plus the\n * {@link OutgoingShare} computable over it.\n */\nexport async function createOutgoingShares(\n pl: PlClient,\n outboxRid: SignedResourceId,\n env: MiddleLayerEnvironment,\n): Promise<{ tree: SynchronizedTreeState; computable: Computable<OutgoingShare[] | undefined> }> {\n const tree = await SynchronizedTreeState.init(\n pl,\n outboxRid,\n {\n ...env.ops.defaultTreeOptions,\n pruning: SharingOutboxPruningFunction,\n fieldFilter: SharingOutboxFieldFilter,\n },\n env.logger,\n );\n return { computable: createOutgoingSharesComputable(pl, tree), tree };\n}\n\n/**\n * Creates the recipient's shared-resource discovery tree: a `{kind:'shared'}` seed over\n * {@link SharedEnvelopeResourceType}. {@link createAvailableSharesComputable} and\n * {@link createLiveEnvelopesComputable} both read it.\n */\nexport async function createAvailableSharesTree(\n pl: PlClient,\n env: MiddleLayerEnvironment,\n): Promise<SynchronizedTreeState> {\n return await SynchronizedTreeState.init(\n pl,\n {\n kind: \"shared\",\n resourceType: resourceType(\n SharedEnvelopeResourceType.name,\n SharedEnvelopeResourceType.version,\n ),\n },\n {\n ...env.ops.defaultTreeOptions,\n pruning: SharedEnvelopePruningFunction,\n fieldFilter: AvailableSharesFieldFilter,\n },\n env.logger,\n );\n}\n\n/**\n * Builds a Computable yielding the recipient's currently-live envelopes, read from the\n * shared-resource discovery tree the ML already maintains — the single discovery mechanism.\n * A copy out of a share `.getValue()`s this instead of re-streaming `ListUserResources`, so there\n * is no second discovery path. The envelope's signed `rid` (from the tree node) is what the write\n * tx needs; `copyEnvelopeProjectsIntoList` reads the project snapshots itself inside the tx.\n *\n * Yields a flat list; the caller dedups by `shareId` — at most one live envelope per shareId is\n * expected (the donor keeps one), and a replace tears the old one down.\n */\nexport function createLiveEnvelopesComputable(\n sharedTree: SynchronizedTreeState,\n): Computable<LiveEnvelope[] | undefined> {\n return Computable.make((ctx) => decodedEnvelopes(ctx.accessor(sharedTree.rootsEntry()).nodes()));\n}\n\n/**\n * Builds the {@link AvailableShare} computable over the shared-resource discovery tree, marking\n * each entry with whether this user has hidden it (a hiddenField in their own SharingState).\n * Both trees feed one Computable so it recomputes when either changes.\n *\n * `currentUserLogin` (when known) suppresses the user's own shares: a share-with-everybody grants\n * the everyone-user, so the donor discovers their own envelope here. A donor already owns what\n * they shared, so their own envelopes are dropped from this view.\n */\nexport function createAvailableSharesComputable(\n sharedTree: SynchronizedTreeState,\n sharingStateTree: SynchronizedTreeState,\n currentUserLogin: string | null,\n): Computable<AvailableShare[] | undefined> {\n return Computable.make((ctx) => {\n // Shares this user has put out of sight, keyed on the share. A share replaced by a newer one\n // is a new share, so its replacement arrives unhidden.\n const stateNode = ctx.accessor(sharingStateTree.entry()).node();\n const hidden = new Set<ShareId>();\n if (stateNode !== undefined)\n for (const f of stateNode.listDynamicFields())\n if (isHiddenField(f)) hidden.add(hiddenFieldShareId(f));\n\n const result: AvailableShare[] = [];\n for (const { data } of decodedEnvelopes(ctx.accessor(sharedTree.rootsEntry()).nodes())) {\n if (currentUserLogin !== null && data.sender === currentUserLogin) continue; // own share\n if (data.expiresAt !== null && data.expiresAt <= Date.now()) continue;\n\n const folder = envelopeFolderSummary(data);\n const description = envelopeDescription(data);\n result.push({\n shareId: data.shareId,\n sender: data.sender,\n title: data.title,\n mode: data.mode,\n payloadKind: data.payload.kind,\n grantedAt: data.sharedAt,\n ...(description === undefined ? {} : { description }),\n ...(folder === undefined ? {} : { folder }),\n hidden: hidden.has(data.shareId),\n });\n }\n result.sort((a, b) => b.grantedAt - a.grantedAt);\n return result;\n });\n}\n\n/** Creates the recipient's SharingState synchronized tree (single explicit root). */\nexport async function createSharingStateTree(\n pl: PlClient,\n stateRid: SignedResourceId,\n env: MiddleLayerEnvironment,\n): Promise<SynchronizedTreeState> {\n return await SynchronizedTreeState.init(\n pl,\n stateRid,\n {\n ...env.ops.defaultTreeOptions,\n pruning: SharingStatePruningFunction,\n fieldFilter: SharingStateFieldFilter,\n },\n env.logger,\n );\n}\n\n//\n// Internals\n//\n\nconst SharingOutboxPruningFunction: PruningFunction = (resource) => {\n if (\n !resourceTypesEqual(resource.type, SharingOutboxResourceType) &&\n !resourceTypesEqual(resource.type, SharedEnvelopeResourceType)\n )\n return [];\n return resource.fields;\n};\n\n// Server-side traversal scope (modern resourceTree path). Pruning is client-side ONLY and does\n// NOT stop the backend walk — without a fieldFilter the backend descends through the envelope's\n// project/{uuid} snapshots into the whole project graph (StreamManager etc.), which the tree would\n// then hold, with its fields pruned to [], and re-poll for nothing. Following fields only FROM the outbox\n// and the envelope stops the walk at the project snapshots (UserProject), which we never traverse.\nconst SharingOutboxFieldFilter: Filter = treeFilter.or(\n treeFilter.resourceTypeEq(SharingOutboxResourceType.name),\n treeFilter.resourceTypeEq(SharedEnvelopeResourceType.name),\n);\n\nconst SharedEnvelopePruningFunction: PruningFunction = (resource) => {\n if (!resourceTypesEqual(resource.type, SharedEnvelopeResourceType)) return [];\n return resource.fields;\n};\n\n// Discovery only needs each envelope's immutable EnvelopeData (basic resource data); it must NOT\n// descend into the project snapshots. Following fields only FROM the envelope stops the walk at\n// the UserProject snapshots (their fields are never followed).\nconst AvailableSharesFieldFilter: Filter = treeFilter.resourceTypeEq(\n SharedEnvelopeResourceType.name,\n);\n\nconst SharingStatePruningFunction: PruningFunction = (resource) => {\n if (!resourceTypesEqual(resource.type, SharingStateResourceType)) return [];\n return resource.fields;\n};\n\n// decision/{shareId} values are leaf JSON resources; follow fields only from SharingState.\nconst SharingStateFieldFilter: Filter = treeFilter.resourceTypeEq(SharingStateResourceType.name);\n\n/** Intermediate of an outgoing share before its full recipient list is fetched: everything the\n * tree carries synchronously, plus the envelope's signed id for the async `ListGrants` enrich. */\ntype OutgoingShareDraft = Omit<OutgoingShare, \"recipients\"> & { envelopeRid: SignedResourceId };\n\n/**\n * Every envelope among the discovery tree's roots that this build can read, decoded. A root that\n * is not a {@link SharedEnvelopeResourceType}, or whose schemaVersion or payload kind this build\n * does not know, is left out rather than offered: there is nothing useful to do with a share that\n * cannot be read.\n */\nfunction decodedEnvelopes(roots: readonly (PlTreeNodeAccessor | undefined)[]): LiveEnvelope[] {\n const result: LiveEnvelope[] = [];\n for (const envelope of roots) {\n if (envelope === undefined) continue;\n if (!resourceTypesEqual(envelope.resourceType, SharedEnvelopeResourceType)) continue;\n const data = normalizeEnvelopeData(envelope.getDataAsJson<unknown>());\n if (data === undefined) continue;\n result.push({ rid: envelope.id, data });\n }\n return result;\n}\n\n/** Per-project view for the donor, from the envelope's `projects` payload; empty for a payload\n * that carries no project. */\nfunction envelopeProjects(data: EnvelopeData): OutgoingShare[\"projects\"] {\n return Object.values(envelopeProjectMap(data)).map((p) => ({\n projectId: p.source,\n label: p.label,\n updatedAt: p.updatedAt,\n }));\n}\n\n/**\n * What a folder share is, in the words both lists show it in: the shared folder's name and how\n * much is inside. `undefined` for any other payload.\n *\n * The root folder is excluded from `folderCount` — it is the thing being described, not something\n * inside it. A folder envelope with no single root is one nothing can be rebuilt from, and it is\n * described as nothing rather than guessed at.\n */\nfunction envelopeFolderSummary(data: EnvelopeData): EnvelopeFolderSummary | undefined {\n if (data.payload.kind !== \"folder\") return undefined;\n const { folders, projects, templates } = data.payload;\n const root = envelopeFolderRoot(folders);\n if (root === undefined) return undefined;\n return {\n label: folders[root].name,\n source: data.payload.source,\n folderCount: Object.keys(folders).length - 1,\n projectCount: Object.keys(projects).length,\n templateCount: templates.length,\n };\n}\n\n/**\n * What the shared thing says about itself: the template's description, the root folder's, or the\n * one project's of a single-project share. `undefined` when it has none, for a pack of several\n * projects, which describes no single thing, and for a folder envelope with no single root.\n */\nfunction envelopeDescription(data: EnvelopeData): string | undefined {\n const payload = data.payload;\n switch (payload.kind) {\n case \"template\":\n return payload.description;\n case \"folder\": {\n const root = envelopeFolderRoot(payload.folders);\n return root === undefined ? undefined : payload.folders[root].description;\n }\n case \"projects\": {\n const projects = Object.values(payload.projects);\n return projects.length === 1 ? projects[0]?.description : undefined;\n }\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"sharing_list.cjs","names":["Computable","resourceTypesEqual","SharedEnvelopeResourceType","normalizeEnvelopeData","isEveryoneUserLogin","SynchronizedTreeState","resourceType","isHiddenField","hiddenFieldShareId","SharingOutboxResourceType","treeFilter","SharingStateResourceType","envelopeProjectMap","envelopeFolderRoot"],"sources":["../../src/middle_layer/sharing_list.ts"],"sourcesContent":["import type { PlTreeNodeAccessor, PruningFunction } from \"@milaboratories/pl-tree\";\nimport { SynchronizedTreeState } from \"@milaboratories/pl-tree\";\nimport type { Filter, PlClient, SignedResourceId } from \"@milaboratories/pl-client\";\nimport {\n isEveryoneUserLogin,\n resourceType,\n resourceTypesEqual,\n treeFilter,\n} from \"@milaboratories/pl-client\";\nimport { Computable } from \"@milaboratories/computable\";\nimport type { MiddleLayerEnvironment } from \"./middle_layer\";\nimport type { ProjectId, TemplateId } from \"@milaboratories/pl-model-common\";\nimport type { FolderId } from \"@milaboratories/pl-model-middle-layer\";\nimport type {\n EnvelopeData,\n EnvelopeMode,\n EnvelopePayloadKind,\n ShareId,\n} from \"../model/sharing_model\";\nimport {\n hiddenFieldShareId,\n isHiddenField,\n envelopeFolderRoot,\n envelopeProjectMap,\n normalizeEnvelopeData,\n SharedEnvelopeResourceType,\n SharingOutboxResourceType,\n SharingStateResourceType,\n} from \"../model/sharing_model\";\n\n/** What a folder share carries, as both share lists show it. */\nexport interface EnvelopeFolderSummary {\n label: string;\n /** Donor's own id of the shared folder. */\n source: FolderId;\n folderCount: number;\n projectCount: number;\n templateCount: number;\n}\n\n/** Donor-facing view of one outgoing share. */\nexport interface OutgoingShare {\n shareId: ShareId; // identity of the share; a share that replaces it gets its own\n sharedAt: number; // this instance's creation time (ms epoch)\n expiresAt?: number; // EnvelopeData.expiresAt; null maps to undefined = never expires\n mode: EnvelopeMode;\n title: string; // display name shown to recipients; defaults to the first project's name\n /** What the share carries — a pack of projects, one template document, or a folder subtree. */\n payloadKind: EnvelopePayloadKind;\n /** One entry per project in the pack. `projectId` is the donor's source project id, which is\n * what the share dialog matches a project's prior shares on; `updatedAt` is when this\n * project's snapshot was taken. Empty for any share that is not a pack of projects. */\n projects: { projectId: ProjectId; label: string; updatedAt: number }[];\n /** The shared template, for a template share; absent otherwise. `source` is the donor's own\n * template id, which is what the share dialog matches a template's prior shares on; a share\n * made before it was carried has none and matches nothing. */\n template?: { label: string; blockCount: number; source?: TemplateId };\n /** The shared folder, for a folder share; absent otherwise. `label` is the root folder's own\n * name, `source` the donor's own id for it — what a prior share of the same folder is matched\n * on — and the counts are of the whole subtree, the root folder itself excluded. */\n folder?: EnvelopeFolderSummary;\n /** What the shared thing says about itself: a template's, a folder's, or the one project's of\n * a single-project share. Absent for a pack of several, which has no one thing to describe. */\n description?: string;\n /** Full recipient logins, from `ListGrants` on the envelope; `[\"*\"]` for everyone-shares. */\n recipients: string[];\n}\n\n/**\n * Recipient-facing view of one share that is open to this user.\n *\n * A share is a shelf, not an invitation: it stays listed for as long as the envelope lives, and\n * the recipient may copy from it any number of times. {@link hidden} is that recipient's own\n * private choice to stop seeing it, and it can be undone.\n */\nexport interface AvailableShare {\n shareId: ShareId;\n sender: string; // EnvelopeData.sender, display only\n title: string; // display name shown to recipients; defaults to the first project's name\n mode: EnvelopeMode;\n /** What the share carries — projects to copy, a template to add to the recipient's templates,\n * or a folder subtree to rebuild in the recipient's tree. */\n payloadKind: EnvelopePayloadKind;\n grantedAt: number;\n /** What the shared thing says about itself. See {@link OutgoingShare.description}. */\n description?: string;\n /** The shared folder, for a folder share; absent otherwise. See {@link OutgoingShare.folder}. */\n folder?: EnvelopeFolderSummary;\n /** Whether this recipient has put it out of sight. Hidden shares are listed, not dropped: the\n * view that shows them is what \"show hidden\" turns on. */\n hidden: boolean;\n}\n\n/** A live envelope discovered in the recipient's shared-resource tree: its signed resource id and\n * decoded {@link EnvelopeData}. A copy out of a share finds it by `data.shareId`. */\nexport type LiveEnvelope = { rid: SignedResourceId; data: EnvelopeData };\n\n/**\n * Reactive view of the donor's own outbox. Reads each live envelope's immutable\n * {@link EnvelopeData} from the tree, then enriches each share's full recipient list via\n * `ListGrants` on the envelope (`[\"*\"]` for an everyone-share). `ListGrants` is gated backend-side\n * to the envelope owner (the donor), which is exactly who reads this view.\n */\nexport function createOutgoingSharesComputable(\n pl: PlClient,\n tree: SynchronizedTreeState,\n): Computable<OutgoingShare[] | undefined> {\n return Computable.make(\n (ctx) => {\n const node = ctx.accessor(tree.entry()).node();\n if (node === undefined) return undefined;\n\n const drafts: OutgoingShareDraft[] = [];\n // Outbox fields are keyed by shareId; each value is a SharedEnvelope.\n for (const fieldName of node.listDynamicFields()) {\n const envelope = node.traverse(fieldName);\n if (envelope === undefined) continue;\n if (!resourceTypesEqual(envelope.resourceType, SharedEnvelopeResourceType)) continue;\n\n const data = normalizeEnvelopeData(envelope.getDataAsJson<unknown>());\n if (data === undefined) continue; // unknown version or payload kind — not ours to show\n\n const folder = envelopeFolderSummary(data);\n const description = envelopeDescription(data);\n drafts.push({\n shareId: data.shareId,\n sharedAt: data.sharedAt,\n ...(data.expiresAt !== null ? { expiresAt: data.expiresAt } : {}),\n mode: data.mode,\n title: data.title,\n payloadKind: data.payload.kind,\n projects: envelopeProjects(data),\n ...(data.payload.kind === \"template\"\n ? {\n template: {\n label: data.payload.label,\n blockCount: data.payload.document.blocks.length,\n ...(data.payload.source === undefined ? {} : { source: data.payload.source }),\n },\n }\n : {}),\n ...(folder === undefined ? {} : { folder }),\n ...(description === undefined ? {} : { description }),\n envelopeRid: envelope.id,\n });\n }\n drafts.sort((a, b) => b.sharedAt - a.sharedAt);\n return drafts;\n },\n {\n // Resolve each share's recipients via listGrants. An everyone-grant maps to \"*\"; the donor's\n // own grant is dropped. One tx per envelope so a just-revoked rid faults only its own read,\n // which allSettled degrades to []. Recipients aren't cached — a live share's recipient set can\n // change. Transactional listGrants when available, else the standalone gRPC-only RPC.\n postprocessValue: async (\n drafts: OutgoingShareDraft[] | undefined,\n ): Promise<OutgoingShare[] | undefined> => {\n if (drafts === undefined) return undefined;\n const self = pl.userResources.authUser;\n const toRecipients = (grants: { user: string }[]): string[] =>\n grants.some((g) => isEveryoneUserLogin(g.user))\n ? [\"*\"]\n : grants.map((g) => g.user).filter((u) => u !== self);\n\n const txGrants = pl.hasCapability(\"txListGrants:v1\");\n const settled = await Promise.allSettled(\n drafts.map((d) =>\n txGrants\n ? pl.withReadTx(\"ListShareGrant\", (tx) => tx.listGrants(d.envelopeRid))\n : pl.userResources.listGrants(d.envelopeRid),\n ),\n );\n\n return drafts.map(({ envelopeRid: _envelopeRid, ...share }, i): OutgoingShare => {\n const r = settled[i];\n return { ...share, recipients: r.status === \"fulfilled\" ? toRecipients(r.value) : [] };\n });\n },\n },\n );\n}\n\n/**\n * Creates the donor's outbox synchronized tree (single explicit root) plus the\n * {@link OutgoingShare} computable over it.\n */\nexport async function createOutgoingShares(\n pl: PlClient,\n outboxRid: SignedResourceId,\n env: MiddleLayerEnvironment,\n): Promise<{ tree: SynchronizedTreeState; computable: Computable<OutgoingShare[] | undefined> }> {\n const tree = await SynchronizedTreeState.init(\n pl,\n outboxRid,\n {\n ...env.ops.defaultTreeOptions,\n pruning: SharingOutboxPruningFunction,\n fieldFilter: SharingOutboxFieldFilter,\n },\n env.logger,\n );\n return { computable: createOutgoingSharesComputable(pl, tree), tree };\n}\n\n/**\n * Creates the recipient's shared-resource discovery tree: a `{kind:'shared'}` seed over\n * {@link SharedEnvelopeResourceType}. {@link createAvailableSharesComputable} and\n * {@link createLiveEnvelopesComputable} both read it.\n */\nexport async function createAvailableSharesTree(\n pl: PlClient,\n env: MiddleLayerEnvironment,\n): Promise<SynchronizedTreeState> {\n return await SynchronizedTreeState.init(\n pl,\n {\n kind: \"shared\",\n resourceType: resourceType(\n SharedEnvelopeResourceType.name,\n SharedEnvelopeResourceType.version,\n ),\n },\n {\n ...env.ops.defaultTreeOptions,\n pruning: SharedEnvelopePruningFunction,\n fieldFilter: AvailableSharesFieldFilter,\n },\n env.logger,\n );\n}\n\n/**\n * Builds a Computable yielding the recipient's currently-live envelopes, read from the\n * shared-resource discovery tree the ML already maintains — the single discovery mechanism.\n * A copy out of a share `.getValue()`s this instead of re-streaming `ListUserResources`, so there\n * is no second discovery path. The envelope's signed `rid` (from the tree node) is what the write\n * tx needs; `copyEnvelopeProjectsIntoList` reads the project snapshots itself inside the tx.\n *\n * Yields a flat list; the caller dedups by `shareId` — at most one live envelope per shareId is\n * expected (the donor keeps one), and a replace tears the old one down.\n */\nexport function createLiveEnvelopesComputable(\n sharedTree: SynchronizedTreeState,\n): Computable<LiveEnvelope[] | undefined> {\n return Computable.make((ctx) => decodedEnvelopes(ctx.accessor(sharedTree.rootsEntry()).nodes()));\n}\n\n/**\n * Builds the {@link AvailableShare} computable over the shared-resource discovery tree, marking\n * each entry with whether this user has hidden it (a hiddenField in their own SharingState).\n * Both trees feed one Computable so it recomputes when either changes.\n *\n * `currentUserLogin` (when known) suppresses the user's own shares: a share-with-everybody grants\n * the everyone-user, so the donor discovers their own envelope here. A donor already owns what\n * they shared, so their own envelopes are dropped from this view.\n */\nexport function createAvailableSharesComputable(\n sharedTree: SynchronizedTreeState,\n sharingStateTree: SynchronizedTreeState,\n currentUserLogin: string | null,\n): Computable<AvailableShare[] | undefined> {\n return Computable.make((ctx) => {\n // Shares this user has put out of sight, keyed on the share. A share replaced by a newer one\n // is a new share, so its replacement arrives unhidden.\n const stateNode = ctx.accessor(sharingStateTree.entry()).node();\n const hidden = new Set<ShareId>();\n if (stateNode !== undefined)\n for (const f of stateNode.listDynamicFields())\n if (isHiddenField(f)) hidden.add(hiddenFieldShareId(f));\n\n const result: AvailableShare[] = [];\n for (const { data } of decodedEnvelopes(ctx.accessor(sharedTree.rootsEntry()).nodes())) {\n if (currentUserLogin !== null && data.sender === currentUserLogin) continue; // own share\n if (data.expiresAt !== null && data.expiresAt <= Date.now()) continue;\n\n const folder = envelopeFolderSummary(data);\n const description = envelopeDescription(data);\n result.push({\n shareId: data.shareId,\n sender: data.sender,\n title: data.title,\n mode: data.mode,\n payloadKind: data.payload.kind,\n grantedAt: data.sharedAt,\n ...(description === undefined ? {} : { description }),\n ...(folder === undefined ? {} : { folder }),\n hidden: hidden.has(data.shareId),\n });\n }\n result.sort((a, b) => b.grantedAt - a.grantedAt);\n return result;\n });\n}\n\n/** Creates the recipient's SharingState synchronized tree (single explicit root). */\nexport async function createSharingStateTree(\n pl: PlClient,\n stateRid: SignedResourceId,\n env: MiddleLayerEnvironment,\n): Promise<SynchronizedTreeState> {\n return await SynchronizedTreeState.init(\n pl,\n stateRid,\n {\n ...env.ops.defaultTreeOptions,\n pruning: SharingStatePruningFunction,\n fieldFilter: SharingStateFieldFilter,\n },\n env.logger,\n );\n}\n\n//\n// Internals\n//\n\nconst SharingOutboxPruningFunction: PruningFunction = (resource) => {\n if (\n !resourceTypesEqual(resource.type, SharingOutboxResourceType) &&\n !resourceTypesEqual(resource.type, SharedEnvelopeResourceType)\n )\n return [];\n return resource.fields;\n};\n\n// Server-side traversal scope (modern resourceTree path). Pruning is client-side ONLY and does\n// NOT stop the backend walk — without a fieldFilter the backend descends through the envelope's\n// project/{uuid} snapshots into the whole project graph (StreamManager etc.), which the tree would\n// then hold, with its fields pruned to [], and re-poll for nothing. Following fields only FROM the outbox\n// and the envelope stops the walk at the project snapshots (UserProject), which we never traverse.\nconst SharingOutboxFieldFilter: Filter = treeFilter.or(\n treeFilter.resourceTypeEq(SharingOutboxResourceType.name),\n treeFilter.resourceTypeEq(SharedEnvelopeResourceType.name),\n);\n\nconst SharedEnvelopePruningFunction: PruningFunction = (resource) => {\n if (!resourceTypesEqual(resource.type, SharedEnvelopeResourceType)) return [];\n return resource.fields;\n};\n\n// Discovery only needs each envelope's immutable EnvelopeData (basic resource data); it must NOT\n// descend into the project snapshots. Following fields only FROM the envelope stops the walk at\n// the UserProject snapshots (their fields are never followed).\nconst AvailableSharesFieldFilter: Filter = treeFilter.resourceTypeEq(\n SharedEnvelopeResourceType.name,\n);\n\nconst SharingStatePruningFunction: PruningFunction = (resource) => {\n if (!resourceTypesEqual(resource.type, SharingStateResourceType)) return [];\n return resource.fields;\n};\n\n// decision/{shareId} values are leaf JSON resources; follow fields only from SharingState.\nconst SharingStateFieldFilter: Filter = treeFilter.resourceTypeEq(SharingStateResourceType.name);\n\n/** Intermediate of an outgoing share before its full recipient list is fetched: everything the\n * tree carries synchronously, plus the envelope's signed id for the async `ListGrants` enrich. */\ntype OutgoingShareDraft = Omit<OutgoingShare, \"recipients\"> & { envelopeRid: SignedResourceId };\n\n/**\n * Every envelope among the discovery tree's roots that this build can read, decoded. A root that\n * is not a {@link SharedEnvelopeResourceType}, or whose schemaVersion or payload kind this build\n * does not know, is left out rather than offered: there is nothing useful to do with a share that\n * cannot be read.\n */\nfunction decodedEnvelopes(roots: readonly (PlTreeNodeAccessor | undefined)[]): LiveEnvelope[] {\n const result: LiveEnvelope[] = [];\n for (const envelope of roots) {\n if (envelope === undefined) continue;\n if (!resourceTypesEqual(envelope.resourceType, SharedEnvelopeResourceType)) continue;\n const data = normalizeEnvelopeData(envelope.getDataAsJson<unknown>());\n if (data === undefined) continue;\n result.push({ rid: envelope.id, data });\n }\n return result;\n}\n\n/** Per-project view for the donor, from the envelope's `projects` payload; empty for a payload\n * that carries no project. */\nfunction envelopeProjects(data: EnvelopeData): OutgoingShare[\"projects\"] {\n return Object.values(envelopeProjectMap(data)).map((p) => ({\n projectId: p.source,\n label: p.label,\n updatedAt: p.updatedAt,\n }));\n}\n\n/**\n * What a folder share is, in the words both lists show it in: the shared folder's name and how\n * much is inside. `undefined` for any other payload.\n *\n * The root folder is excluded from `folderCount` — it is the thing being described, not something\n * inside it. A folder envelope with no single root is one nothing can be rebuilt from, and it is\n * described as nothing rather than guessed at.\n */\nfunction envelopeFolderSummary(data: EnvelopeData): EnvelopeFolderSummary | undefined {\n if (data.payload.kind !== \"folder\") return undefined;\n const { folders, projects, templates } = data.payload;\n const root = envelopeFolderRoot(folders);\n if (root === undefined) return undefined;\n return {\n label: folders[root].name,\n source: data.payload.source,\n folderCount: Object.keys(folders).length - 1,\n projectCount: Object.keys(projects).length,\n templateCount: templates.length,\n };\n}\n\n/**\n * What the shared thing says about itself: the template's description, the root folder's, or the\n * one project's of a single-project share. `undefined` when it has none, for a pack of several\n * projects, which describes no single thing, and for a folder envelope with no single root.\n */\nfunction envelopeDescription(data: EnvelopeData): string | undefined {\n const payload = data.payload;\n switch (payload.kind) {\n case \"template\":\n return payload.description;\n case \"folder\": {\n const root = envelopeFolderRoot(payload.folders);\n return root === undefined ? undefined : payload.folders[root].description;\n }\n case \"projects\": {\n const projects = Object.values(payload.projects);\n return projects.length === 1 ? projects[0]?.description : undefined;\n }\n }\n}\n"],"mappings":"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"}
@@ -5,7 +5,6 @@ import { ProjectId, TemplateId } from "@milaboratories/pl-model-common";
5
5
  import { PlClient, SignedResourceId } from "@milaboratories/pl-client";
6
6
  import { SynchronizedTreeState } from "@milaboratories/pl-tree";
7
7
  import { Computable } from "@milaboratories/computable";
8
- //#region src/middle_layer/sharing_list.d.ts
9
8
  /** What a folder share carries, as both share lists show it. */
10
9
  export interface EnvelopeFolderSummary {
11
10
  label: string;
@@ -74,5 +73,4 @@ export interface AvailableShare {
74
73
  * view that shows them is what "show hidden" turns on. */
75
74
  hidden: boolean;
76
75
  }
77
- //#endregion
78
76
  //# sourceMappingURL=sharing_list.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"sharing_list.d.ts","names":[],"sources":["../../src/middle_layer/sharing_list.ts"],"mappings":";;;;;;;;;iBA+BiB;EACf;;EAEA,QAAQ;EACR;EACA;EACA;;;iBAIe;EACf,SAAS;EACT;EACA;EACA,MAAM;EACN;;EAEA,aAAa;;;;EAIb;IAAY,WAAW;IAAW;IAAe;;;;;EAIjD;IAAa;IAAe;IAAoB,SAAS;;;;;EAIzD,SAAS;;;EAGT;;EAEA;;;;;;;;;iBAUe;EACf,SAAS;EACT;EACA;EACA,MAAM;;;EAGN,aAAa;EACb;;EAEA;;EAEA,SAAS;;;EAGT"}
1
+ {"version":3,"file":"sharing_list.d.ts","names":[],"sources":["../../src/middle_layer/sharing_list.ts"],"mappings":";;;;;;;;iBA+BiB;EACf;;EAEA,QAAQ;EACR;EACA;EACA;;;iBAIe;EACf,SAAS;EACT;EACA;EACA,MAAM;EACN;;EAEA,aAAa;;;;EAIb;IAAY,WAAW;IAAW;IAAe;;;;;EAIjD;IAAa;IAAe;IAAoB,SAAS;;;;;EAIzD,SAAS;;;EAGT;;EAEA;;;;;;;;;iBAUe;EACf,SAAS;EACT;EACA;EACA,MAAM;;;EAGN,aAAa;EACb;;EAEA;;EAEA,SAAS;;;EAGT"}
@@ -2,7 +2,7 @@ import { SharedEnvelopeResourceType, SharingOutboxResourceType, SharingStateReso
2
2
  import { isEveryoneUserLogin, resourceType, resourceTypesEqual, treeFilter } from "@milaboratories/pl-client";
3
3
  import { SynchronizedTreeState } from "@milaboratories/pl-tree";
4
4
  import { Computable } from "@milaboratories/computable";
5
- //#region src/middle_layer/sharing_list.ts
5
+ // src/middle_layer/sharing_list.ts
6
6
  /**
7
7
  * Reactive view of the donor's own outbox. Reads each live envelope's immutable
8
8
  * {@link EnvelopeData} from the tree, then enriches each share's full recipient list via
@@ -230,7 +230,6 @@ function envelopeDescription(data) {
230
230
  }
231
231
  }
232
232
  }
233
- //#endregion
234
233
  export { createAvailableSharesComputable, createAvailableSharesTree, createLiveEnvelopesComputable, createOutgoingShares, createOutgoingSharesComputable, createSharingStateTree };
235
234
 
236
235
  //# sourceMappingURL=sharing_list.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"sharing_list.js","names":[],"sources":["../../src/middle_layer/sharing_list.ts"],"sourcesContent":["import type { PlTreeNodeAccessor, PruningFunction } from \"@milaboratories/pl-tree\";\nimport { SynchronizedTreeState } from \"@milaboratories/pl-tree\";\nimport type { Filter, PlClient, SignedResourceId } from \"@milaboratories/pl-client\";\nimport {\n isEveryoneUserLogin,\n resourceType,\n resourceTypesEqual,\n treeFilter,\n} from \"@milaboratories/pl-client\";\nimport { Computable } from \"@milaboratories/computable\";\nimport type { MiddleLayerEnvironment } from \"./middle_layer\";\nimport type { ProjectId, TemplateId } from \"@milaboratories/pl-model-common\";\nimport type { FolderId } from \"@milaboratories/pl-model-middle-layer\";\nimport type {\n EnvelopeData,\n EnvelopeMode,\n EnvelopePayloadKind,\n ShareId,\n} from \"../model/sharing_model\";\nimport {\n hiddenFieldShareId,\n isHiddenField,\n envelopeFolderRoot,\n envelopeProjectMap,\n normalizeEnvelopeData,\n SharedEnvelopeResourceType,\n SharingOutboxResourceType,\n SharingStateResourceType,\n} from \"../model/sharing_model\";\n\n/** What a folder share carries, as both share lists show it. */\nexport interface EnvelopeFolderSummary {\n label: string;\n /** Donor's own id of the shared folder. */\n source: FolderId;\n folderCount: number;\n projectCount: number;\n templateCount: number;\n}\n\n/** Donor-facing view of one outgoing share. */\nexport interface OutgoingShare {\n shareId: ShareId; // identity of the share; a share that replaces it gets its own\n sharedAt: number; // this instance's creation time (ms epoch)\n expiresAt?: number; // EnvelopeData.expiresAt; null maps to undefined = never expires\n mode: EnvelopeMode;\n title: string; // display name shown to recipients; defaults to the first project's name\n /** What the share carries — a pack of projects, one template document, or a folder subtree. */\n payloadKind: EnvelopePayloadKind;\n /** One entry per project in the pack. `projectId` is the donor's source project id, which is\n * what the share dialog matches a project's prior shares on; `updatedAt` is when this\n * project's snapshot was taken. Empty for any share that is not a pack of projects. */\n projects: { projectId: ProjectId; label: string; updatedAt: number }[];\n /** The shared template, for a template share; absent otherwise. `source` is the donor's own\n * template id, which is what the share dialog matches a template's prior shares on; a share\n * made before it was carried has none and matches nothing. */\n template?: { label: string; blockCount: number; source?: TemplateId };\n /** The shared folder, for a folder share; absent otherwise. `label` is the root folder's own\n * name, `source` the donor's own id for it — what a prior share of the same folder is matched\n * on — and the counts are of the whole subtree, the root folder itself excluded. */\n folder?: EnvelopeFolderSummary;\n /** What the shared thing says about itself: a template's, a folder's, or the one project's of\n * a single-project share. Absent for a pack of several, which has no one thing to describe. */\n description?: string;\n /** Full recipient logins, from `ListGrants` on the envelope; `[\"*\"]` for everyone-shares. */\n recipients: string[];\n}\n\n/**\n * Recipient-facing view of one share that is open to this user.\n *\n * A share is a shelf, not an invitation: it stays listed for as long as the envelope lives, and\n * the recipient may copy from it any number of times. {@link hidden} is that recipient's own\n * private choice to stop seeing it, and it can be undone.\n */\nexport interface AvailableShare {\n shareId: ShareId;\n sender: string; // EnvelopeData.sender, display only\n title: string; // display name shown to recipients; defaults to the first project's name\n mode: EnvelopeMode;\n /** What the share carries — projects to copy, a template to add to the recipient's templates,\n * or a folder subtree to rebuild in the recipient's tree. */\n payloadKind: EnvelopePayloadKind;\n grantedAt: number;\n /** What the shared thing says about itself. See {@link OutgoingShare.description}. */\n description?: string;\n /** The shared folder, for a folder share; absent otherwise. See {@link OutgoingShare.folder}. */\n folder?: EnvelopeFolderSummary;\n /** Whether this recipient has put it out of sight. Hidden shares are listed, not dropped: the\n * view that shows them is what \"show hidden\" turns on. */\n hidden: boolean;\n}\n\n/** A live envelope discovered in the recipient's shared-resource tree: its signed resource id and\n * decoded {@link EnvelopeData}. A copy out of a share finds it by `data.shareId`. */\nexport type LiveEnvelope = { rid: SignedResourceId; data: EnvelopeData };\n\n/**\n * Reactive view of the donor's own outbox. Reads each live envelope's immutable\n * {@link EnvelopeData} from the tree, then enriches each share's full recipient list via\n * `ListGrants` on the envelope (`[\"*\"]` for an everyone-share). `ListGrants` is gated backend-side\n * to the envelope owner (the donor), which is exactly who reads this view.\n */\nexport function createOutgoingSharesComputable(\n pl: PlClient,\n tree: SynchronizedTreeState,\n): Computable<OutgoingShare[] | undefined> {\n return Computable.make(\n (ctx) => {\n const node = ctx.accessor(tree.entry()).node();\n if (node === undefined) return undefined;\n\n const drafts: OutgoingShareDraft[] = [];\n // Outbox fields are keyed by shareId; each value is a SharedEnvelope.\n for (const fieldName of node.listDynamicFields()) {\n const envelope = node.traverse(fieldName);\n if (envelope === undefined) continue;\n if (!resourceTypesEqual(envelope.resourceType, SharedEnvelopeResourceType)) continue;\n\n const data = normalizeEnvelopeData(envelope.getDataAsJson<unknown>());\n if (data === undefined) continue; // unknown version or payload kind — not ours to show\n\n const folder = envelopeFolderSummary(data);\n const description = envelopeDescription(data);\n drafts.push({\n shareId: data.shareId,\n sharedAt: data.sharedAt,\n ...(data.expiresAt !== null ? { expiresAt: data.expiresAt } : {}),\n mode: data.mode,\n title: data.title,\n payloadKind: data.payload.kind,\n projects: envelopeProjects(data),\n ...(data.payload.kind === \"template\"\n ? {\n template: {\n label: data.payload.label,\n blockCount: data.payload.document.blocks.length,\n ...(data.payload.source === undefined ? {} : { source: data.payload.source }),\n },\n }\n : {}),\n ...(folder === undefined ? {} : { folder }),\n ...(description === undefined ? {} : { description }),\n envelopeRid: envelope.id,\n });\n }\n drafts.sort((a, b) => b.sharedAt - a.sharedAt);\n return drafts;\n },\n {\n // Resolve each share's recipients via listGrants. An everyone-grant maps to \"*\"; the donor's\n // own grant is dropped. One tx per envelope so a just-revoked rid faults only its own read,\n // which allSettled degrades to []. Recipients aren't cached — a live share's recipient set can\n // change. Transactional listGrants when available, else the standalone gRPC-only RPC.\n postprocessValue: async (\n drafts: OutgoingShareDraft[] | undefined,\n ): Promise<OutgoingShare[] | undefined> => {\n if (drafts === undefined) return undefined;\n const self = pl.userResources.authUser;\n const toRecipients = (grants: { user: string }[]): string[] =>\n grants.some((g) => isEveryoneUserLogin(g.user))\n ? [\"*\"]\n : grants.map((g) => g.user).filter((u) => u !== self);\n\n const txGrants = pl.hasCapability(\"txListGrants:v1\");\n const settled = await Promise.allSettled(\n drafts.map((d) =>\n txGrants\n ? pl.withReadTx(\"ListShareGrant\", (tx) => tx.listGrants(d.envelopeRid))\n : pl.userResources.listGrants(d.envelopeRid),\n ),\n );\n\n return drafts.map(({ envelopeRid: _envelopeRid, ...share }, i): OutgoingShare => {\n const r = settled[i];\n return { ...share, recipients: r.status === \"fulfilled\" ? toRecipients(r.value) : [] };\n });\n },\n },\n );\n}\n\n/**\n * Creates the donor's outbox synchronized tree (single explicit root) plus the\n * {@link OutgoingShare} computable over it.\n */\nexport async function createOutgoingShares(\n pl: PlClient,\n outboxRid: SignedResourceId,\n env: MiddleLayerEnvironment,\n): Promise<{ tree: SynchronizedTreeState; computable: Computable<OutgoingShare[] | undefined> }> {\n const tree = await SynchronizedTreeState.init(\n pl,\n outboxRid,\n {\n ...env.ops.defaultTreeOptions,\n pruning: SharingOutboxPruningFunction,\n fieldFilter: SharingOutboxFieldFilter,\n },\n env.logger,\n );\n return { computable: createOutgoingSharesComputable(pl, tree), tree };\n}\n\n/**\n * Creates the recipient's shared-resource discovery tree: a `{kind:'shared'}` seed over\n * {@link SharedEnvelopeResourceType}. {@link createAvailableSharesComputable} and\n * {@link createLiveEnvelopesComputable} both read it.\n */\nexport async function createAvailableSharesTree(\n pl: PlClient,\n env: MiddleLayerEnvironment,\n): Promise<SynchronizedTreeState> {\n return await SynchronizedTreeState.init(\n pl,\n {\n kind: \"shared\",\n resourceType: resourceType(\n SharedEnvelopeResourceType.name,\n SharedEnvelopeResourceType.version,\n ),\n },\n {\n ...env.ops.defaultTreeOptions,\n pruning: SharedEnvelopePruningFunction,\n fieldFilter: AvailableSharesFieldFilter,\n },\n env.logger,\n );\n}\n\n/**\n * Builds a Computable yielding the recipient's currently-live envelopes, read from the\n * shared-resource discovery tree the ML already maintains — the single discovery mechanism.\n * A copy out of a share `.getValue()`s this instead of re-streaming `ListUserResources`, so there\n * is no second discovery path. The envelope's signed `rid` (from the tree node) is what the write\n * tx needs; `copyEnvelopeProjectsIntoList` reads the project snapshots itself inside the tx.\n *\n * Yields a flat list; the caller dedups by `shareId` — at most one live envelope per shareId is\n * expected (the donor keeps one), and a replace tears the old one down.\n */\nexport function createLiveEnvelopesComputable(\n sharedTree: SynchronizedTreeState,\n): Computable<LiveEnvelope[] | undefined> {\n return Computable.make((ctx) => decodedEnvelopes(ctx.accessor(sharedTree.rootsEntry()).nodes()));\n}\n\n/**\n * Builds the {@link AvailableShare} computable over the shared-resource discovery tree, marking\n * each entry with whether this user has hidden it (a hiddenField in their own SharingState).\n * Both trees feed one Computable so it recomputes when either changes.\n *\n * `currentUserLogin` (when known) suppresses the user's own shares: a share-with-everybody grants\n * the everyone-user, so the donor discovers their own envelope here. A donor already owns what\n * they shared, so their own envelopes are dropped from this view.\n */\nexport function createAvailableSharesComputable(\n sharedTree: SynchronizedTreeState,\n sharingStateTree: SynchronizedTreeState,\n currentUserLogin: string | null,\n): Computable<AvailableShare[] | undefined> {\n return Computable.make((ctx) => {\n // Shares this user has put out of sight, keyed on the share. A share replaced by a newer one\n // is a new share, so its replacement arrives unhidden.\n const stateNode = ctx.accessor(sharingStateTree.entry()).node();\n const hidden = new Set<ShareId>();\n if (stateNode !== undefined)\n for (const f of stateNode.listDynamicFields())\n if (isHiddenField(f)) hidden.add(hiddenFieldShareId(f));\n\n const result: AvailableShare[] = [];\n for (const { data } of decodedEnvelopes(ctx.accessor(sharedTree.rootsEntry()).nodes())) {\n if (currentUserLogin !== null && data.sender === currentUserLogin) continue; // own share\n if (data.expiresAt !== null && data.expiresAt <= Date.now()) continue;\n\n const folder = envelopeFolderSummary(data);\n const description = envelopeDescription(data);\n result.push({\n shareId: data.shareId,\n sender: data.sender,\n title: data.title,\n mode: data.mode,\n payloadKind: data.payload.kind,\n grantedAt: data.sharedAt,\n ...(description === undefined ? {} : { description }),\n ...(folder === undefined ? {} : { folder }),\n hidden: hidden.has(data.shareId),\n });\n }\n result.sort((a, b) => b.grantedAt - a.grantedAt);\n return result;\n });\n}\n\n/** Creates the recipient's SharingState synchronized tree (single explicit root). */\nexport async function createSharingStateTree(\n pl: PlClient,\n stateRid: SignedResourceId,\n env: MiddleLayerEnvironment,\n): Promise<SynchronizedTreeState> {\n return await SynchronizedTreeState.init(\n pl,\n stateRid,\n {\n ...env.ops.defaultTreeOptions,\n pruning: SharingStatePruningFunction,\n fieldFilter: SharingStateFieldFilter,\n },\n env.logger,\n );\n}\n\n//\n// Internals\n//\n\nconst SharingOutboxPruningFunction: PruningFunction = (resource) => {\n if (\n !resourceTypesEqual(resource.type, SharingOutboxResourceType) &&\n !resourceTypesEqual(resource.type, SharedEnvelopeResourceType)\n )\n return [];\n return resource.fields;\n};\n\n// Server-side traversal scope (modern resourceTree path). Pruning is client-side ONLY and does\n// NOT stop the backend walk — without a fieldFilter the backend descends through the envelope's\n// project/{uuid} snapshots into the whole project graph (StreamManager etc.), which the tree would\n// then hold, with its fields pruned to [], and re-poll for nothing. Following fields only FROM the outbox\n// and the envelope stops the walk at the project snapshots (UserProject), which we never traverse.\nconst SharingOutboxFieldFilter: Filter = treeFilter.or(\n treeFilter.resourceTypeEq(SharingOutboxResourceType.name),\n treeFilter.resourceTypeEq(SharedEnvelopeResourceType.name),\n);\n\nconst SharedEnvelopePruningFunction: PruningFunction = (resource) => {\n if (!resourceTypesEqual(resource.type, SharedEnvelopeResourceType)) return [];\n return resource.fields;\n};\n\n// Discovery only needs each envelope's immutable EnvelopeData (basic resource data); it must NOT\n// descend into the project snapshots. Following fields only FROM the envelope stops the walk at\n// the UserProject snapshots (their fields are never followed).\nconst AvailableSharesFieldFilter: Filter = treeFilter.resourceTypeEq(\n SharedEnvelopeResourceType.name,\n);\n\nconst SharingStatePruningFunction: PruningFunction = (resource) => {\n if (!resourceTypesEqual(resource.type, SharingStateResourceType)) return [];\n return resource.fields;\n};\n\n// decision/{shareId} values are leaf JSON resources; follow fields only from SharingState.\nconst SharingStateFieldFilter: Filter = treeFilter.resourceTypeEq(SharingStateResourceType.name);\n\n/** Intermediate of an outgoing share before its full recipient list is fetched: everything the\n * tree carries synchronously, plus the envelope's signed id for the async `ListGrants` enrich. */\ntype OutgoingShareDraft = Omit<OutgoingShare, \"recipients\"> & { envelopeRid: SignedResourceId };\n\n/**\n * Every envelope among the discovery tree's roots that this build can read, decoded. A root that\n * is not a {@link SharedEnvelopeResourceType}, or whose schemaVersion or payload kind this build\n * does not know, is left out rather than offered: there is nothing useful to do with a share that\n * cannot be read.\n */\nfunction decodedEnvelopes(roots: readonly (PlTreeNodeAccessor | undefined)[]): LiveEnvelope[] {\n const result: LiveEnvelope[] = [];\n for (const envelope of roots) {\n if (envelope === undefined) continue;\n if (!resourceTypesEqual(envelope.resourceType, SharedEnvelopeResourceType)) continue;\n const data = normalizeEnvelopeData(envelope.getDataAsJson<unknown>());\n if (data === undefined) continue;\n result.push({ rid: envelope.id, data });\n }\n return result;\n}\n\n/** Per-project view for the donor, from the envelope's `projects` payload; empty for a payload\n * that carries no project. */\nfunction envelopeProjects(data: EnvelopeData): OutgoingShare[\"projects\"] {\n return Object.values(envelopeProjectMap(data)).map((p) => ({\n projectId: p.source,\n label: p.label,\n updatedAt: p.updatedAt,\n }));\n}\n\n/**\n * What a folder share is, in the words both lists show it in: the shared folder's name and how\n * much is inside. `undefined` for any other payload.\n *\n * The root folder is excluded from `folderCount` — it is the thing being described, not something\n * inside it. A folder envelope with no single root is one nothing can be rebuilt from, and it is\n * described as nothing rather than guessed at.\n */\nfunction envelopeFolderSummary(data: EnvelopeData): EnvelopeFolderSummary | undefined {\n if (data.payload.kind !== \"folder\") return undefined;\n const { folders, projects, templates } = data.payload;\n const root = envelopeFolderRoot(folders);\n if (root === undefined) return undefined;\n return {\n label: folders[root].name,\n source: data.payload.source,\n folderCount: Object.keys(folders).length - 1,\n projectCount: Object.keys(projects).length,\n templateCount: templates.length,\n };\n}\n\n/**\n * What the shared thing says about itself: the template's description, the root folder's, or the\n * one project's of a single-project share. `undefined` when it has none, for a pack of several\n * projects, which describes no single thing, and for a folder envelope with no single root.\n */\nfunction envelopeDescription(data: EnvelopeData): string | undefined {\n const payload = data.payload;\n switch (payload.kind) {\n case \"template\":\n return payload.description;\n case \"folder\": {\n const root = envelopeFolderRoot(payload.folders);\n return root === undefined ? undefined : payload.folders[root].description;\n }\n case \"projects\": {\n const projects = Object.values(payload.projects);\n return projects.length === 1 ? projects[0]?.description : undefined;\n }\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"sharing_list.js","names":[],"sources":["../../src/middle_layer/sharing_list.ts"],"sourcesContent":["import type { PlTreeNodeAccessor, PruningFunction } from \"@milaboratories/pl-tree\";\nimport { SynchronizedTreeState } from \"@milaboratories/pl-tree\";\nimport type { Filter, PlClient, SignedResourceId } from \"@milaboratories/pl-client\";\nimport {\n isEveryoneUserLogin,\n resourceType,\n resourceTypesEqual,\n treeFilter,\n} from \"@milaboratories/pl-client\";\nimport { Computable } from \"@milaboratories/computable\";\nimport type { MiddleLayerEnvironment } from \"./middle_layer\";\nimport type { ProjectId, TemplateId } from \"@milaboratories/pl-model-common\";\nimport type { FolderId } from \"@milaboratories/pl-model-middle-layer\";\nimport type {\n EnvelopeData,\n EnvelopeMode,\n EnvelopePayloadKind,\n ShareId,\n} from \"../model/sharing_model\";\nimport {\n hiddenFieldShareId,\n isHiddenField,\n envelopeFolderRoot,\n envelopeProjectMap,\n normalizeEnvelopeData,\n SharedEnvelopeResourceType,\n SharingOutboxResourceType,\n SharingStateResourceType,\n} from \"../model/sharing_model\";\n\n/** What a folder share carries, as both share lists show it. */\nexport interface EnvelopeFolderSummary {\n label: string;\n /** Donor's own id of the shared folder. */\n source: FolderId;\n folderCount: number;\n projectCount: number;\n templateCount: number;\n}\n\n/** Donor-facing view of one outgoing share. */\nexport interface OutgoingShare {\n shareId: ShareId; // identity of the share; a share that replaces it gets its own\n sharedAt: number; // this instance's creation time (ms epoch)\n expiresAt?: number; // EnvelopeData.expiresAt; null maps to undefined = never expires\n mode: EnvelopeMode;\n title: string; // display name shown to recipients; defaults to the first project's name\n /** What the share carries — a pack of projects, one template document, or a folder subtree. */\n payloadKind: EnvelopePayloadKind;\n /** One entry per project in the pack. `projectId` is the donor's source project id, which is\n * what the share dialog matches a project's prior shares on; `updatedAt` is when this\n * project's snapshot was taken. Empty for any share that is not a pack of projects. */\n projects: { projectId: ProjectId; label: string; updatedAt: number }[];\n /** The shared template, for a template share; absent otherwise. `source` is the donor's own\n * template id, which is what the share dialog matches a template's prior shares on; a share\n * made before it was carried has none and matches nothing. */\n template?: { label: string; blockCount: number; source?: TemplateId };\n /** The shared folder, for a folder share; absent otherwise. `label` is the root folder's own\n * name, `source` the donor's own id for it — what a prior share of the same folder is matched\n * on — and the counts are of the whole subtree, the root folder itself excluded. */\n folder?: EnvelopeFolderSummary;\n /** What the shared thing says about itself: a template's, a folder's, or the one project's of\n * a single-project share. Absent for a pack of several, which has no one thing to describe. */\n description?: string;\n /** Full recipient logins, from `ListGrants` on the envelope; `[\"*\"]` for everyone-shares. */\n recipients: string[];\n}\n\n/**\n * Recipient-facing view of one share that is open to this user.\n *\n * A share is a shelf, not an invitation: it stays listed for as long as the envelope lives, and\n * the recipient may copy from it any number of times. {@link hidden} is that recipient's own\n * private choice to stop seeing it, and it can be undone.\n */\nexport interface AvailableShare {\n shareId: ShareId;\n sender: string; // EnvelopeData.sender, display only\n title: string; // display name shown to recipients; defaults to the first project's name\n mode: EnvelopeMode;\n /** What the share carries — projects to copy, a template to add to the recipient's templates,\n * or a folder subtree to rebuild in the recipient's tree. */\n payloadKind: EnvelopePayloadKind;\n grantedAt: number;\n /** What the shared thing says about itself. See {@link OutgoingShare.description}. */\n description?: string;\n /** The shared folder, for a folder share; absent otherwise. See {@link OutgoingShare.folder}. */\n folder?: EnvelopeFolderSummary;\n /** Whether this recipient has put it out of sight. Hidden shares are listed, not dropped: the\n * view that shows them is what \"show hidden\" turns on. */\n hidden: boolean;\n}\n\n/** A live envelope discovered in the recipient's shared-resource tree: its signed resource id and\n * decoded {@link EnvelopeData}. A copy out of a share finds it by `data.shareId`. */\nexport type LiveEnvelope = { rid: SignedResourceId; data: EnvelopeData };\n\n/**\n * Reactive view of the donor's own outbox. Reads each live envelope's immutable\n * {@link EnvelopeData} from the tree, then enriches each share's full recipient list via\n * `ListGrants` on the envelope (`[\"*\"]` for an everyone-share). `ListGrants` is gated backend-side\n * to the envelope owner (the donor), which is exactly who reads this view.\n */\nexport function createOutgoingSharesComputable(\n pl: PlClient,\n tree: SynchronizedTreeState,\n): Computable<OutgoingShare[] | undefined> {\n return Computable.make(\n (ctx) => {\n const node = ctx.accessor(tree.entry()).node();\n if (node === undefined) return undefined;\n\n const drafts: OutgoingShareDraft[] = [];\n // Outbox fields are keyed by shareId; each value is a SharedEnvelope.\n for (const fieldName of node.listDynamicFields()) {\n const envelope = node.traverse(fieldName);\n if (envelope === undefined) continue;\n if (!resourceTypesEqual(envelope.resourceType, SharedEnvelopeResourceType)) continue;\n\n const data = normalizeEnvelopeData(envelope.getDataAsJson<unknown>());\n if (data === undefined) continue; // unknown version or payload kind — not ours to show\n\n const folder = envelopeFolderSummary(data);\n const description = envelopeDescription(data);\n drafts.push({\n shareId: data.shareId,\n sharedAt: data.sharedAt,\n ...(data.expiresAt !== null ? { expiresAt: data.expiresAt } : {}),\n mode: data.mode,\n title: data.title,\n payloadKind: data.payload.kind,\n projects: envelopeProjects(data),\n ...(data.payload.kind === \"template\"\n ? {\n template: {\n label: data.payload.label,\n blockCount: data.payload.document.blocks.length,\n ...(data.payload.source === undefined ? {} : { source: data.payload.source }),\n },\n }\n : {}),\n ...(folder === undefined ? {} : { folder }),\n ...(description === undefined ? {} : { description }),\n envelopeRid: envelope.id,\n });\n }\n drafts.sort((a, b) => b.sharedAt - a.sharedAt);\n return drafts;\n },\n {\n // Resolve each share's recipients via listGrants. An everyone-grant maps to \"*\"; the donor's\n // own grant is dropped. One tx per envelope so a just-revoked rid faults only its own read,\n // which allSettled degrades to []. Recipients aren't cached — a live share's recipient set can\n // change. Transactional listGrants when available, else the standalone gRPC-only RPC.\n postprocessValue: async (\n drafts: OutgoingShareDraft[] | undefined,\n ): Promise<OutgoingShare[] | undefined> => {\n if (drafts === undefined) return undefined;\n const self = pl.userResources.authUser;\n const toRecipients = (grants: { user: string }[]): string[] =>\n grants.some((g) => isEveryoneUserLogin(g.user))\n ? [\"*\"]\n : grants.map((g) => g.user).filter((u) => u !== self);\n\n const txGrants = pl.hasCapability(\"txListGrants:v1\");\n const settled = await Promise.allSettled(\n drafts.map((d) =>\n txGrants\n ? pl.withReadTx(\"ListShareGrant\", (tx) => tx.listGrants(d.envelopeRid))\n : pl.userResources.listGrants(d.envelopeRid),\n ),\n );\n\n return drafts.map(({ envelopeRid: _envelopeRid, ...share }, i): OutgoingShare => {\n const r = settled[i];\n return { ...share, recipients: r.status === \"fulfilled\" ? toRecipients(r.value) : [] };\n });\n },\n },\n );\n}\n\n/**\n * Creates the donor's outbox synchronized tree (single explicit root) plus the\n * {@link OutgoingShare} computable over it.\n */\nexport async function createOutgoingShares(\n pl: PlClient,\n outboxRid: SignedResourceId,\n env: MiddleLayerEnvironment,\n): Promise<{ tree: SynchronizedTreeState; computable: Computable<OutgoingShare[] | undefined> }> {\n const tree = await SynchronizedTreeState.init(\n pl,\n outboxRid,\n {\n ...env.ops.defaultTreeOptions,\n pruning: SharingOutboxPruningFunction,\n fieldFilter: SharingOutboxFieldFilter,\n },\n env.logger,\n );\n return { computable: createOutgoingSharesComputable(pl, tree), tree };\n}\n\n/**\n * Creates the recipient's shared-resource discovery tree: a `{kind:'shared'}` seed over\n * {@link SharedEnvelopeResourceType}. {@link createAvailableSharesComputable} and\n * {@link createLiveEnvelopesComputable} both read it.\n */\nexport async function createAvailableSharesTree(\n pl: PlClient,\n env: MiddleLayerEnvironment,\n): Promise<SynchronizedTreeState> {\n return await SynchronizedTreeState.init(\n pl,\n {\n kind: \"shared\",\n resourceType: resourceType(\n SharedEnvelopeResourceType.name,\n SharedEnvelopeResourceType.version,\n ),\n },\n {\n ...env.ops.defaultTreeOptions,\n pruning: SharedEnvelopePruningFunction,\n fieldFilter: AvailableSharesFieldFilter,\n },\n env.logger,\n );\n}\n\n/**\n * Builds a Computable yielding the recipient's currently-live envelopes, read from the\n * shared-resource discovery tree the ML already maintains — the single discovery mechanism.\n * A copy out of a share `.getValue()`s this instead of re-streaming `ListUserResources`, so there\n * is no second discovery path. The envelope's signed `rid` (from the tree node) is what the write\n * tx needs; `copyEnvelopeProjectsIntoList` reads the project snapshots itself inside the tx.\n *\n * Yields a flat list; the caller dedups by `shareId` — at most one live envelope per shareId is\n * expected (the donor keeps one), and a replace tears the old one down.\n */\nexport function createLiveEnvelopesComputable(\n sharedTree: SynchronizedTreeState,\n): Computable<LiveEnvelope[] | undefined> {\n return Computable.make((ctx) => decodedEnvelopes(ctx.accessor(sharedTree.rootsEntry()).nodes()));\n}\n\n/**\n * Builds the {@link AvailableShare} computable over the shared-resource discovery tree, marking\n * each entry with whether this user has hidden it (a hiddenField in their own SharingState).\n * Both trees feed one Computable so it recomputes when either changes.\n *\n * `currentUserLogin` (when known) suppresses the user's own shares: a share-with-everybody grants\n * the everyone-user, so the donor discovers their own envelope here. A donor already owns what\n * they shared, so their own envelopes are dropped from this view.\n */\nexport function createAvailableSharesComputable(\n sharedTree: SynchronizedTreeState,\n sharingStateTree: SynchronizedTreeState,\n currentUserLogin: string | null,\n): Computable<AvailableShare[] | undefined> {\n return Computable.make((ctx) => {\n // Shares this user has put out of sight, keyed on the share. A share replaced by a newer one\n // is a new share, so its replacement arrives unhidden.\n const stateNode = ctx.accessor(sharingStateTree.entry()).node();\n const hidden = new Set<ShareId>();\n if (stateNode !== undefined)\n for (const f of stateNode.listDynamicFields())\n if (isHiddenField(f)) hidden.add(hiddenFieldShareId(f));\n\n const result: AvailableShare[] = [];\n for (const { data } of decodedEnvelopes(ctx.accessor(sharedTree.rootsEntry()).nodes())) {\n if (currentUserLogin !== null && data.sender === currentUserLogin) continue; // own share\n if (data.expiresAt !== null && data.expiresAt <= Date.now()) continue;\n\n const folder = envelopeFolderSummary(data);\n const description = envelopeDescription(data);\n result.push({\n shareId: data.shareId,\n sender: data.sender,\n title: data.title,\n mode: data.mode,\n payloadKind: data.payload.kind,\n grantedAt: data.sharedAt,\n ...(description === undefined ? {} : { description }),\n ...(folder === undefined ? {} : { folder }),\n hidden: hidden.has(data.shareId),\n });\n }\n result.sort((a, b) => b.grantedAt - a.grantedAt);\n return result;\n });\n}\n\n/** Creates the recipient's SharingState synchronized tree (single explicit root). */\nexport async function createSharingStateTree(\n pl: PlClient,\n stateRid: SignedResourceId,\n env: MiddleLayerEnvironment,\n): Promise<SynchronizedTreeState> {\n return await SynchronizedTreeState.init(\n pl,\n stateRid,\n {\n ...env.ops.defaultTreeOptions,\n pruning: SharingStatePruningFunction,\n fieldFilter: SharingStateFieldFilter,\n },\n env.logger,\n );\n}\n\n//\n// Internals\n//\n\nconst SharingOutboxPruningFunction: PruningFunction = (resource) => {\n if (\n !resourceTypesEqual(resource.type, SharingOutboxResourceType) &&\n !resourceTypesEqual(resource.type, SharedEnvelopeResourceType)\n )\n return [];\n return resource.fields;\n};\n\n// Server-side traversal scope (modern resourceTree path). Pruning is client-side ONLY and does\n// NOT stop the backend walk — without a fieldFilter the backend descends through the envelope's\n// project/{uuid} snapshots into the whole project graph (StreamManager etc.), which the tree would\n// then hold, with its fields pruned to [], and re-poll for nothing. Following fields only FROM the outbox\n// and the envelope stops the walk at the project snapshots (UserProject), which we never traverse.\nconst SharingOutboxFieldFilter: Filter = treeFilter.or(\n treeFilter.resourceTypeEq(SharingOutboxResourceType.name),\n treeFilter.resourceTypeEq(SharedEnvelopeResourceType.name),\n);\n\nconst SharedEnvelopePruningFunction: PruningFunction = (resource) => {\n if (!resourceTypesEqual(resource.type, SharedEnvelopeResourceType)) return [];\n return resource.fields;\n};\n\n// Discovery only needs each envelope's immutable EnvelopeData (basic resource data); it must NOT\n// descend into the project snapshots. Following fields only FROM the envelope stops the walk at\n// the UserProject snapshots (their fields are never followed).\nconst AvailableSharesFieldFilter: Filter = treeFilter.resourceTypeEq(\n SharedEnvelopeResourceType.name,\n);\n\nconst SharingStatePruningFunction: PruningFunction = (resource) => {\n if (!resourceTypesEqual(resource.type, SharingStateResourceType)) return [];\n return resource.fields;\n};\n\n// decision/{shareId} values are leaf JSON resources; follow fields only from SharingState.\nconst SharingStateFieldFilter: Filter = treeFilter.resourceTypeEq(SharingStateResourceType.name);\n\n/** Intermediate of an outgoing share before its full recipient list is fetched: everything the\n * tree carries synchronously, plus the envelope's signed id for the async `ListGrants` enrich. */\ntype OutgoingShareDraft = Omit<OutgoingShare, \"recipients\"> & { envelopeRid: SignedResourceId };\n\n/**\n * Every envelope among the discovery tree's roots that this build can read, decoded. A root that\n * is not a {@link SharedEnvelopeResourceType}, or whose schemaVersion or payload kind this build\n * does not know, is left out rather than offered: there is nothing useful to do with a share that\n * cannot be read.\n */\nfunction decodedEnvelopes(roots: readonly (PlTreeNodeAccessor | undefined)[]): LiveEnvelope[] {\n const result: LiveEnvelope[] = [];\n for (const envelope of roots) {\n if (envelope === undefined) continue;\n if (!resourceTypesEqual(envelope.resourceType, SharedEnvelopeResourceType)) continue;\n const data = normalizeEnvelopeData(envelope.getDataAsJson<unknown>());\n if (data === undefined) continue;\n result.push({ rid: envelope.id, data });\n }\n return result;\n}\n\n/** Per-project view for the donor, from the envelope's `projects` payload; empty for a payload\n * that carries no project. */\nfunction envelopeProjects(data: EnvelopeData): OutgoingShare[\"projects\"] {\n return Object.values(envelopeProjectMap(data)).map((p) => ({\n projectId: p.source,\n label: p.label,\n updatedAt: p.updatedAt,\n }));\n}\n\n/**\n * What a folder share is, in the words both lists show it in: the shared folder's name and how\n * much is inside. `undefined` for any other payload.\n *\n * The root folder is excluded from `folderCount` — it is the thing being described, not something\n * inside it. A folder envelope with no single root is one nothing can be rebuilt from, and it is\n * described as nothing rather than guessed at.\n */\nfunction envelopeFolderSummary(data: EnvelopeData): EnvelopeFolderSummary | undefined {\n if (data.payload.kind !== \"folder\") return undefined;\n const { folders, projects, templates } = data.payload;\n const root = envelopeFolderRoot(folders);\n if (root === undefined) return undefined;\n return {\n label: folders[root].name,\n source: data.payload.source,\n folderCount: Object.keys(folders).length - 1,\n projectCount: Object.keys(projects).length,\n templateCount: templates.length,\n };\n}\n\n/**\n * What the shared thing says about itself: the template's description, the root folder's, or the\n * one project's of a single-project share. `undefined` when it has none, for a pack of several\n * projects, which describes no single thing, and for a folder envelope with no single root.\n */\nfunction envelopeDescription(data: EnvelopeData): string | undefined {\n const payload = data.payload;\n switch (payload.kind) {\n case \"template\":\n return payload.description;\n case \"folder\": {\n const root = envelopeFolderRoot(payload.folders);\n return root === undefined ? undefined : payload.folders[root].description;\n }\n case \"projects\": {\n const projects = Object.values(payload.projects);\n return projects.length === 1 ? projects[0]?.description : undefined;\n }\n }\n}\n"],"mappings":";;;;;;;;;;;AAuGA,SAAgB,+BACd,IACA,MACyC;CACzC,OAAO,WAAW,MACf,QAAQ;EACP,MAAM,OAAO,IAAI,SAAS,KAAK,MAAM,CAAC,CAAC,CAAC,KAAK;EAC7C,IAAI,SAAS,KAAA,GAAW,OAAO,KAAA;EAE/B,MAAM,SAA+B,CAAC;EAEtC,KAAK,MAAM,aAAa,KAAK,kBAAkB,GAAG;GAChD,MAAM,WAAW,KAAK,SAAS,SAAS;GACxC,IAAI,aAAa,KAAA,GAAW;GAC5B,IAAI,CAAC,mBAAmB,SAAS,cAAc,0BAA0B,GAAG;GAE5E,MAAM,OAAO,sBAAsB,SAAS,cAAuB,CAAC;GACpE,IAAI,SAAS,KAAA,GAAW;GAExB,MAAM,SAAS,sBAAsB,IAAI;GACzC,MAAM,cAAc,oBAAoB,IAAI;GAC5C,OAAO,KAAK;IACV,SAAS,KAAK;IACd,UAAU,KAAK;IACf,GAAI,KAAK,cAAc,OAAO,EAAE,WAAW,KAAK,UAAU,IAAI,CAAC;IAC/D,MAAM,KAAK;IACX,OAAO,KAAK;IACZ,aAAa,KAAK,QAAQ;IAC1B,UAAU,iBAAiB,IAAI;IAC/B,GAAI,KAAK,QAAQ,SAAS,aACtB,EACE,UAAU;KACR,OAAO,KAAK,QAAQ;KACpB,YAAY,KAAK,QAAQ,SAAS,OAAO;KACzC,GAAI,KAAK,QAAQ,WAAW,KAAA,IAAY,CAAC,IAAI,EAAE,QAAQ,KAAK,QAAQ,OAAO;IAC7E,EACF,IACA,CAAC;IACL,GAAI,WAAW,KAAA,IAAY,CAAC,IAAI,EAAE,OAAO;IACzC,GAAI,gBAAgB,KAAA,IAAY,CAAC,IAAI,EAAE,YAAY;IACnD,aAAa,SAAS;GACxB,CAAC;EACH;EACA,OAAO,MAAM,GAAG,MAAM,EAAE,WAAW,EAAE,QAAQ;EAC7C,OAAO;CACT,GACA,EAKE,kBAAkB,OAChB,WACyC;EACzC,IAAI,WAAW,KAAA,GAAW,OAAO,KAAA;EACjC,MAAM,OAAO,GAAG,cAAc;EAC9B,MAAM,gBAAgB,WACpB,OAAO,MAAM,MAAM,oBAAoB,EAAE,IAAI,CAAC,IAC1C,CAAC,GAAG,IACJ,OAAO,KAAK,MAAM,EAAE,IAAI,CAAC,CAAC,QAAQ,MAAM,MAAM,IAAI;EAExD,MAAM,WAAW,GAAG,cAAc,iBAAiB;EACnD,MAAM,UAAU,MAAM,QAAQ,WAC5B,OAAO,KAAK,MACV,WACI,GAAG,WAAW,mBAAmB,OAAO,GAAG,WAAW,EAAE,WAAW,CAAC,IACpE,GAAG,cAAc,WAAW,EAAE,WAAW,CAC/C,CACF;EAEA,OAAO,OAAO,KAAK,EAAE,aAAa,cAAc,GAAG,SAAS,MAAqB;GAC/E,MAAM,IAAI,QAAQ;GAClB,OAAO;IAAE,GAAG;IAAO,YAAY,EAAE,WAAW,cAAc,aAAa,EAAE,KAAK,IAAI,CAAC;GAAE;EACvF,CAAC;CACH,EACF,CACF;AACF;;;;;AAMA,eAAsB,qBACpB,IACA,WACA,KAC+F;CAC/F,MAAM,OAAO,MAAM,sBAAsB,KACvC,IACA,WACA;EACE,GAAG,IAAI,IAAI;EACX,SAAS;EACT,aAAa;CACf,GACA,IAAI,MACN;CACA,OAAO;EAAE,YAAY,+BAA+B,IAAI,IAAI;EAAG;CAAK;AACtE;;;;;;AAOA,eAAsB,0BACpB,IACA,KACgC;CAChC,OAAO,MAAM,sBAAsB,KACjC,IACA;EACE,MAAM;EACN,cAAc,aACZ,2BAA2B,MAC3B,2BAA2B,OAC7B;CACF,GACA;EACE,GAAG,IAAI,IAAI;EACX,SAAS;EACT,aAAa;CACf,GACA,IAAI,MACN;AACF;;;;;;;;;;;AAYA,SAAgB,8BACd,YACwC;CACxC,OAAO,WAAW,MAAM,QAAQ,iBAAiB,IAAI,SAAS,WAAW,WAAW,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;AACjG;;;;;;;;;;AAWA,SAAgB,gCACd,YACA,kBACA,kBAC0C;CAC1C,OAAO,WAAW,MAAM,QAAQ;EAG9B,MAAM,YAAY,IAAI,SAAS,iBAAiB,MAAM,CAAC,CAAC,CAAC,KAAK;EAC9D,MAAM,yBAAS,IAAI,IAAa;EAChC,IAAI,cAAc,KAAA,GACX;QAAA,MAAM,KAAK,UAAU,kBAAkB,GAC1C,IAAI,cAAc,CAAC,GAAG,OAAO,IAAI,mBAAmB,CAAC,CAAC;EAAA;EAE1D,MAAM,SAA2B,CAAC;EAClC,KAAK,MAAM,EAAE,UAAU,iBAAiB,IAAI,SAAS,WAAW,WAAW,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG;GACtF,IAAI,qBAAqB,QAAQ,KAAK,WAAW,kBAAkB;GACnE,IAAI,KAAK,cAAc,QAAQ,KAAK,aAAa,KAAK,IAAI,GAAG;GAE7D,MAAM,SAAS,sBAAsB,IAAI;GACzC,MAAM,cAAc,oBAAoB,IAAI;GAC5C,OAAO,KAAK;IACV,SAAS,KAAK;IACd,QAAQ,KAAK;IACb,OAAO,KAAK;IACZ,MAAM,KAAK;IACX,aAAa,KAAK,QAAQ;IAC1B,WAAW,KAAK;IAChB,GAAI,gBAAgB,KAAA,IAAY,CAAC,IAAI,EAAE,YAAY;IACnD,GAAI,WAAW,KAAA,IAAY,CAAC,IAAI,EAAE,OAAO;IACzC,QAAQ,OAAO,IAAI,KAAK,OAAO;GACjC,CAAC;EACH;EACA,OAAO,MAAM,GAAG,MAAM,EAAE,YAAY,EAAE,SAAS;EAC/C,OAAO;CACT,CAAC;AACH;;AAGA,eAAsB,uBACpB,IACA,UACA,KACgC;CAChC,OAAO,MAAM,sBAAsB,KACjC,IACA,UACA;EACE,GAAG,IAAI,IAAI;EACX,SAAS;EACT,aAAa;CACf,GACA,IAAI,MACN;AACF;AAMA,MAAM,gCAAiD,aAAa;CAClE,IACE,CAAC,mBAAmB,SAAS,MAAM,yBAAyB,KAC5D,CAAC,mBAAmB,SAAS,MAAM,0BAA0B,GAE7D,OAAO,CAAC;CACV,OAAO,SAAS;AAClB;AAOA,MAAM,2BAAmC,WAAW,GAClD,WAAW,eAAe,0BAA0B,IAAI,GACxD,WAAW,eAAe,2BAA2B,IAAI,CAC3D;AAEA,MAAM,iCAAkD,aAAa;CACnE,IAAI,CAAC,mBAAmB,SAAS,MAAM,0BAA0B,GAAG,OAAO,CAAC;CAC5E,OAAO,SAAS;AAClB;AAKA,MAAM,6BAAqC,WAAW,eACpD,2BAA2B,IAC7B;AAEA,MAAM,+BAAgD,aAAa;CACjE,IAAI,CAAC,mBAAmB,SAAS,MAAM,wBAAwB,GAAG,OAAO,CAAC;CAC1E,OAAO,SAAS;AAClB;AAGA,MAAM,0BAAkC,WAAW,eAAe,yBAAyB,IAAI;;;;;;;AAY/F,SAAS,iBAAiB,OAAoE;CAC5F,MAAM,SAAyB,CAAC;CAChC,KAAK,MAAM,YAAY,OAAO;EAC5B,IAAI,aAAa,KAAA,GAAW;EAC5B,IAAI,CAAC,mBAAmB,SAAS,cAAc,0BAA0B,GAAG;EAC5E,MAAM,OAAO,sBAAsB,SAAS,cAAuB,CAAC;EACpE,IAAI,SAAS,KAAA,GAAW;EACxB,OAAO,KAAK;GAAE,KAAK,SAAS;GAAI;EAAK,CAAC;CACxC;CACA,OAAO;AACT;;;AAIA,SAAS,iBAAiB,MAA+C;CACvE,OAAO,OAAO,OAAO,mBAAmB,IAAI,CAAC,CAAC,CAAC,KAAK,OAAO;EACzD,WAAW,EAAE;EACb,OAAO,EAAE;EACT,WAAW,EAAE;CACf,EAAE;AACJ;;;;;;;;;AAUA,SAAS,sBAAsB,MAAuD;CACpF,IAAI,KAAK,QAAQ,SAAS,UAAU,OAAO,KAAA;CAC3C,MAAM,EAAE,SAAS,UAAU,cAAc,KAAK;CAC9C,MAAM,OAAO,mBAAmB,OAAO;CACvC,IAAI,SAAS,KAAA,GAAW,OAAO,KAAA;CAC/B,OAAO;EACL,OAAO,QAAQ,KAAK,CAAC;EACrB,QAAQ,KAAK,QAAQ;EACrB,aAAa,OAAO,KAAK,OAAO,CAAC,CAAC,SAAS;EAC3C,cAAc,OAAO,KAAK,QAAQ,CAAC,CAAC;EACpC,eAAe,UAAU;CAC3B;AACF;;;;;;AAOA,SAAS,oBAAoB,MAAwC;CACnE,MAAM,UAAU,KAAK;CACrB,QAAQ,QAAQ,MAAhB;EACE,KAAK,YACH,OAAO,QAAQ;EACjB,KAAK,UAAU;GACb,MAAM,OAAO,mBAAmB,QAAQ,OAAO;GAC/C,OAAO,SAAS,KAAA,IAAY,KAAA,IAAY,QAAQ,QAAQ,KAAK,CAAC;EAChE;EACA,KAAK,YAAY;GACf,MAAM,WAAW,OAAO,OAAO,QAAQ,QAAQ;GAC/C,OAAO,SAAS,WAAW,IAAI,SAAS,EAAE,EAAE,cAAc,KAAA;EAC5D;CACF;AACF"}
@@ -3,7 +3,7 @@ let _milaboratories_pl_model_common = require("@milaboratories/pl-model-common")
3
3
  let _milaboratories_pl_client = require("@milaboratories/pl-client");
4
4
  let _milaboratories_pl_tree = require("@milaboratories/pl-tree");
5
5
  let _milaboratories_computable = require("@milaboratories/computable");
6
- //#region src/middle_layer/template_list.ts
6
+ // src/middle_layer/template_list.ts
7
7
  const TemplatesField = "templates";
8
8
  const TemplatesResourceType = {
9
9
  name: "Templates",
@@ -81,7 +81,6 @@ function templateListEntries(node) {
81
81
  result.sort((a, b) => b.created.valueOf() - a.created.valueOf());
82
82
  return result;
83
83
  }
84
- //#endregion
85
84
  exports.TemplateCreatedTimestamp = TemplateCreatedTimestamp;
86
85
  exports.TemplateDescriptionKey = TemplateDescriptionKey;
87
86
  exports.TemplateLabelKey = TemplateLabelKey;