@elaraai/east-ui 1.0.80 → 1.0.82

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 (353) hide show
  1. package/dist/src/charts/chart/index.d.ts +4 -0
  2. package/dist/src/charts/chart/index.d.ts.map +1 -1
  3. package/dist/src/charts/spec/index.d.ts +8 -0
  4. package/dist/src/charts/spec/index.d.ts.map +1 -1
  5. package/dist/src/collections/deck/index.d.ts +8 -0
  6. package/dist/src/collections/deck/index.d.ts.map +1 -1
  7. package/dist/src/collections/index.d.ts +2 -2
  8. package/dist/src/collections/index.d.ts.map +1 -1
  9. package/dist/src/collections/index.js.map +1 -1
  10. package/dist/src/collections/library/index.d.ts +4 -0
  11. package/dist/src/collections/library/index.d.ts.map +1 -1
  12. package/dist/src/collections/library/types.d.ts +4 -0
  13. package/dist/src/collections/library/types.d.ts.map +1 -1
  14. package/dist/src/collections/matrix/index.d.ts +56 -19
  15. package/dist/src/collections/matrix/index.d.ts.map +1 -1
  16. package/dist/src/collections/matrix/index.js +38 -24
  17. package/dist/src/collections/matrix/index.js.map +1 -1
  18. package/dist/src/collections/plan/assemble.d.ts +655 -2113
  19. package/dist/src/collections/plan/assemble.d.ts.map +1 -1
  20. package/dist/src/collections/plan/assemble.js +159 -136
  21. package/dist/src/collections/plan/assemble.js.map +1 -1
  22. package/dist/src/collections/plan/builders.d.ts +193 -40
  23. package/dist/src/collections/plan/builders.d.ts.map +1 -1
  24. package/dist/src/collections/plan/builders.js +162 -32
  25. package/dist/src/collections/plan/builders.js.map +1 -1
  26. package/dist/src/collections/plan/factories.d.ts +290 -116
  27. package/dist/src/collections/plan/factories.d.ts.map +1 -1
  28. package/dist/src/collections/plan/factories.js +281 -156
  29. package/dist/src/collections/plan/factories.js.map +1 -1
  30. package/dist/src/collections/plan/index.d.ts +111 -58
  31. package/dist/src/collections/plan/index.d.ts.map +1 -1
  32. package/dist/src/collections/plan/index.js +62 -31
  33. package/dist/src/collections/plan/index.js.map +1 -1
  34. package/dist/src/collections/plan/ir.d.ts +759 -1769
  35. package/dist/src/collections/plan/ir.d.ts.map +1 -1
  36. package/dist/src/collections/plan/ir.js +51 -27
  37. package/dist/src/collections/plan/ir.js.map +1 -1
  38. package/dist/src/collections/plan/pick.d.ts +89 -71
  39. package/dist/src/collections/plan/pick.d.ts.map +1 -1
  40. package/dist/src/collections/plan/pick.js +101 -86
  41. package/dist/src/collections/plan/pick.js.map +1 -1
  42. package/dist/src/collections/plan/root.d.ts +164 -77
  43. package/dist/src/collections/plan/root.d.ts.map +1 -1
  44. package/dist/src/collections/plan/root.js +350 -42
  45. package/dist/src/collections/plan/root.js.map +1 -1
  46. package/dist/src/collections/plan/series.d.ts +12524 -10527
  47. package/dist/src/collections/plan/series.d.ts.map +1 -1
  48. package/dist/src/collections/plan/series.js +1596 -298
  49. package/dist/src/collections/plan/series.js.map +1 -1
  50. package/dist/src/collections/plan/types.d.ts +6115 -2802
  51. package/dist/src/collections/plan/types.d.ts.map +1 -1
  52. package/dist/src/collections/plan/types.js +575 -170
  53. package/dist/src/collections/plan/types.js.map +1 -1
  54. package/dist/src/collections/sheet/bridge.d.ts +154 -43
  55. package/dist/src/collections/sheet/bridge.d.ts.map +1 -1
  56. package/dist/src/collections/sheet/bridge.js +383 -240
  57. package/dist/src/collections/sheet/bridge.js.map +1 -1
  58. package/dist/src/collections/sheet/columns.d.ts +66 -16
  59. package/dist/src/collections/sheet/columns.d.ts.map +1 -1
  60. package/dist/src/collections/sheet/columns.js +25 -25
  61. package/dist/src/collections/sheet/columns.js.map +1 -1
  62. package/dist/src/collections/sheet/context-bridge.d.ts +48 -0
  63. package/dist/src/collections/sheet/context-bridge.d.ts.map +1 -0
  64. package/dist/src/collections/sheet/context-bridge.js +216 -0
  65. package/dist/src/collections/sheet/context-bridge.js.map +1 -0
  66. package/dist/src/collections/sheet/draft-bridge.d.ts +37 -0
  67. package/dist/src/collections/sheet/draft-bridge.d.ts.map +1 -0
  68. package/dist/src/collections/sheet/draft-bridge.js +153 -0
  69. package/dist/src/collections/sheet/draft-bridge.js.map +1 -0
  70. package/dist/src/collections/sheet/drafts.d.ts +14 -0
  71. package/dist/src/collections/sheet/drafts.d.ts.map +1 -0
  72. package/dist/src/collections/sheet/drafts.js +14 -0
  73. package/dist/src/collections/sheet/drafts.js.map +1 -0
  74. package/dist/src/collections/sheet/editing-bridge.d.ts +36 -0
  75. package/dist/src/collections/sheet/editing-bridge.d.ts.map +1 -0
  76. package/dist/src/collections/sheet/editing-bridge.js +196 -0
  77. package/dist/src/collections/sheet/editing-bridge.js.map +1 -0
  78. package/dist/src/collections/sheet/editing-types.d.ts +268 -0
  79. package/dist/src/collections/sheet/editing-types.d.ts.map +1 -0
  80. package/dist/src/collections/sheet/editing-types.js +34 -0
  81. package/dist/src/collections/sheet/editing-types.js.map +1 -0
  82. package/dist/src/collections/sheet/edits.d.ts +37 -0
  83. package/dist/src/collections/sheet/edits.d.ts.map +1 -0
  84. package/dist/src/collections/sheet/edits.js +31 -0
  85. package/dist/src/collections/sheet/edits.js.map +1 -0
  86. package/dist/src/collections/sheet/group.d.ts +165 -0
  87. package/dist/src/collections/sheet/group.d.ts.map +1 -0
  88. package/dist/src/collections/sheet/group.js +52 -0
  89. package/dist/src/collections/sheet/group.js.map +1 -0
  90. package/dist/src/collections/sheet/index.d.ts +171 -27
  91. package/dist/src/collections/sheet/index.d.ts.map +1 -1
  92. package/dist/src/collections/sheet/index.js +99 -17
  93. package/dist/src/collections/sheet/index.js.map +1 -1
  94. package/dist/src/collections/sheet/link.d.ts +22 -16
  95. package/dist/src/collections/sheet/link.d.ts.map +1 -1
  96. package/dist/src/collections/sheet/link.js +18 -12
  97. package/dist/src/collections/sheet/link.js.map +1 -1
  98. package/dist/src/collections/sheet/registers.d.ts +152 -5
  99. package/dist/src/collections/sheet/registers.d.ts.map +1 -1
  100. package/dist/src/collections/sheet/registers.js +154 -5
  101. package/dist/src/collections/sheet/registers.js.map +1 -1
  102. package/dist/src/collections/sheet/root.d.ts +175 -26
  103. package/dist/src/collections/sheet/root.d.ts.map +1 -1
  104. package/dist/src/collections/sheet/root.js +150 -26
  105. package/dist/src/collections/sheet/root.js.map +1 -1
  106. package/dist/src/collections/sheet/seed-bridge.d.ts +14 -0
  107. package/dist/src/collections/sheet/seed-bridge.d.ts.map +1 -0
  108. package/dist/src/collections/sheet/seed-bridge.js +51 -0
  109. package/dist/src/collections/sheet/seed-bridge.js.map +1 -0
  110. package/dist/src/collections/sheet/sub-rows.d.ts +249 -0
  111. package/dist/src/collections/sheet/sub-rows.d.ts.map +1 -0
  112. package/dist/src/collections/sheet/sub-rows.js +222 -0
  113. package/dist/src/collections/sheet/sub-rows.js.map +1 -0
  114. package/dist/src/collections/sheet/transactions.d.ts +76 -0
  115. package/dist/src/collections/sheet/transactions.d.ts.map +1 -0
  116. package/dist/src/collections/sheet/transactions.js +40 -0
  117. package/dist/src/collections/sheet/transactions.js.map +1 -0
  118. package/dist/src/collections/sheet/types.d.ts +12034 -3651
  119. package/dist/src/collections/sheet/types.d.ts.map +1 -1
  120. package/dist/src/collections/sheet/types.js +365 -48
  121. package/dist/src/collections/sheet/types.js.map +1 -1
  122. package/dist/src/collections/table/index.d.ts +98 -123
  123. package/dist/src/collections/table/index.d.ts.map +1 -1
  124. package/dist/src/collections/table/index.js +97 -111
  125. package/dist/src/collections/table/index.js.map +1 -1
  126. package/dist/src/collections/table/types.d.ts +87 -31
  127. package/dist/src/collections/table/types.d.ts.map +1 -1
  128. package/dist/src/collections/table/types.js +51 -26
  129. package/dist/src/collections/table/types.js.map +1 -1
  130. package/dist/src/collections/value-tree/flatten.d.ts.map +1 -1
  131. package/dist/src/collections/value-tree/flatten.js +4 -1
  132. package/dist/src/collections/value-tree/flatten.js.map +1 -1
  133. package/dist/src/component.d.ts +5075 -4079
  134. package/dist/src/component.d.ts.map +1 -1
  135. package/dist/src/component.js +46 -46
  136. package/dist/src/component.js.map +1 -1
  137. package/dist/src/contracts/approval.d.ts +10 -8
  138. package/dist/src/contracts/approval.d.ts.map +1 -1
  139. package/dist/src/contracts/approval.js +10 -8
  140. package/dist/src/contracts/approval.js.map +1 -1
  141. package/dist/src/contracts/drag.d.ts +11 -9
  142. package/dist/src/contracts/drag.d.ts.map +1 -1
  143. package/dist/src/contracts/drag.js +28 -21
  144. package/dist/src/contracts/drag.js.map +1 -1
  145. package/dist/src/contracts/editing.d.ts +1283 -0
  146. package/dist/src/contracts/editing.d.ts.map +1 -0
  147. package/dist/src/contracts/editing.js +711 -0
  148. package/dist/src/contracts/editing.js.map +1 -0
  149. package/dist/src/contracts/index.d.ts +2 -1
  150. package/dist/src/contracts/index.d.ts.map +1 -1
  151. package/dist/src/contracts/index.js +2 -1
  152. package/dist/src/contracts/index.js.map +1 -1
  153. package/dist/src/contracts/pick.d.ts +6 -7
  154. package/dist/src/contracts/pick.d.ts.map +1 -1
  155. package/dist/src/contracts/pick.js +6 -7
  156. package/dist/src/contracts/pick.js.map +1 -1
  157. package/dist/src/contracts/review.d.ts +3 -1
  158. package/dist/src/contracts/review.d.ts.map +1 -1
  159. package/dist/src/contracts/review.js +3 -1
  160. package/dist/src/contracts/review.js.map +1 -1
  161. package/dist/src/contracts/source.d.ts +270 -80
  162. package/dist/src/contracts/source.d.ts.map +1 -1
  163. package/dist/src/contracts/source.js +357 -58
  164. package/dist/src/contracts/source.js.map +1 -1
  165. package/dist/src/display/chip-rail/index.d.ts.map +1 -1
  166. package/dist/src/display/chip-rail/index.js +10 -10
  167. package/dist/src/display/chip-rail/index.js.map +1 -1
  168. package/dist/src/extension.d.ts +2 -1
  169. package/dist/src/extension.d.ts.map +1 -1
  170. package/dist/src/extension.js +2 -1
  171. package/dist/src/extension.js.map +1 -1
  172. package/dist/src/format/index.d.ts +1 -154
  173. package/dist/src/format/index.d.ts.map +1 -1
  174. package/dist/src/format/types.d.ts +35 -23
  175. package/dist/src/format/types.d.ts.map +1 -1
  176. package/dist/src/format/types.js +16 -14
  177. package/dist/src/format/types.js.map +1 -1
  178. package/dist/src/forms/field/index.js +4 -4
  179. package/dist/src/forms/field/index.js.map +1 -1
  180. package/dist/src/forms/file-upload/index.js +16 -16
  181. package/dist/src/forms/file-upload/index.js.map +1 -1
  182. package/dist/src/index.d.ts +4 -2
  183. package/dist/src/index.d.ts.map +1 -1
  184. package/dist/src/index.js +12 -5
  185. package/dist/src/index.js.map +1 -1
  186. package/dist/src/internal.d.ts +8 -3
  187. package/dist/src/internal.d.ts.map +1 -1
  188. package/dist/src/internal.js +11 -3
  189. package/dist/src/internal.js.map +1 -1
  190. package/dist/src/layout/box/index.d.ts.map +1 -1
  191. package/dist/src/layout/box/index.js +47 -47
  192. package/dist/src/layout/box/index.js.map +1 -1
  193. package/dist/src/layout/flex/index.d.ts.map +1 -1
  194. package/dist/src/layout/flex/index.js +47 -47
  195. package/dist/src/layout/flex/index.js.map +1 -1
  196. package/dist/src/layout/grid/index.js +11 -11
  197. package/dist/src/layout/grid/index.js.map +1 -1
  198. package/dist/src/layout/scroll-area/index.d.ts.map +1 -1
  199. package/dist/src/layout/scroll-area/index.js +8 -8
  200. package/dist/src/layout/scroll-area/index.js.map +1 -1
  201. package/dist/src/layout/separator/index.d.ts.map +1 -1
  202. package/dist/src/layout/separator/index.js +6 -6
  203. package/dist/src/layout/separator/index.js.map +1 -1
  204. package/dist/src/layout/stack/index.d.ts.map +1 -1
  205. package/dist/src/layout/stack/index.js +46 -46
  206. package/dist/src/layout/stack/index.js.map +1 -1
  207. package/dist/src/layout/sticky/index.d.ts.map +1 -1
  208. package/dist/src/layout/sticky/index.js +8 -8
  209. package/dist/src/layout/sticky/index.js.map +1 -1
  210. package/dist/src/overlays/action-bar/index.d.ts.map +1 -1
  211. package/dist/src/overlays/action-bar/index.js +8 -8
  212. package/dist/src/overlays/action-bar/index.js.map +1 -1
  213. package/dist/src/platform/index.d.ts +1 -1
  214. package/dist/src/platform/index.d.ts.map +1 -1
  215. package/dist/src/platform/index.js +1 -1
  216. package/dist/src/platform/index.js.map +1 -1
  217. package/dist/src/platform/slice/impl.d.ts +62 -51
  218. package/dist/src/platform/slice/impl.d.ts.map +1 -1
  219. package/dist/src/platform/slice/impl.js +155 -72
  220. package/dist/src/platform/slice/impl.js.map +1 -1
  221. package/dist/src/platform/slice/index.d.ts +3744 -2226
  222. package/dist/src/platform/slice/index.d.ts.map +1 -1
  223. package/dist/src/platform/slice/index.js +43 -1
  224. package/dist/src/platform/slice/index.js.map +1 -1
  225. package/dist/src/runtime/collections/deck.d.ts +4 -0
  226. package/dist/src/runtime/collections/deck.d.ts.map +1 -1
  227. package/dist/src/runtime/collections/matrix.d.ts +10 -9
  228. package/dist/src/runtime/collections/matrix.d.ts.map +1 -1
  229. package/dist/src/runtime/collections/matrix.js +11 -6
  230. package/dist/src/runtime/collections/matrix.js.map +1 -1
  231. package/dist/src/runtime/collections/plan.d.ts +148 -65
  232. package/dist/src/runtime/collections/plan.d.ts.map +1 -1
  233. package/dist/src/runtime/collections/plan.js +155 -67
  234. package/dist/src/runtime/collections/plan.js.map +1 -1
  235. package/dist/src/runtime/collections/sheet.d.ts +56 -23
  236. package/dist/src/runtime/collections/sheet.d.ts.map +1 -1
  237. package/dist/src/runtime/collections/sheet.js +30 -22
  238. package/dist/src/runtime/collections/sheet.js.map +1 -1
  239. package/dist/src/runtime/collections/table.d.ts +18 -11
  240. package/dist/src/runtime/collections/table.d.ts.map +1 -1
  241. package/dist/src/runtime/collections/table.js +7 -4
  242. package/dist/src/runtime/collections/table.js.map +1 -1
  243. package/dist/src/shared/reify.d.ts +4 -46
  244. package/dist/src/shared/reify.d.ts.map +1 -1
  245. package/dist/src/shared/reify.js +4 -61
  246. package/dist/src/shared/reify.js.map +1 -1
  247. package/dist/src/shared/tree.d.ts +88 -0
  248. package/dist/src/shared/tree.d.ts.map +1 -0
  249. package/dist/src/shared/tree.js +134 -0
  250. package/dist/src/shared/tree.js.map +1 -0
  251. package/dist/src/slice/breakdown/index.d.ts +4 -0
  252. package/dist/src/slice/breakdown/index.d.ts.map +1 -1
  253. package/dist/src/slice/breakdown/types.d.ts +4 -0
  254. package/dist/src/slice/breakdown/types.d.ts.map +1 -1
  255. package/dist/src/slice/cohort/index.d.ts +24 -4
  256. package/dist/src/slice/cohort/index.d.ts.map +1 -1
  257. package/dist/src/slice/cohort/index.js +8 -4
  258. package/dist/src/slice/cohort/index.js.map +1 -1
  259. package/dist/src/slice/cohort/types.d.ts +11 -0
  260. package/dist/src/slice/cohort/types.d.ts.map +1 -1
  261. package/dist/src/slice/cohort/types.js +7 -0
  262. package/dist/src/slice/cohort/types.js.map +1 -1
  263. package/dist/src/slice/filter/index.d.ts +4 -0
  264. package/dist/src/slice/filter/index.d.ts.map +1 -1
  265. package/dist/src/slice/filter/types.d.ts +4 -0
  266. package/dist/src/slice/filter/types.d.ts.map +1 -1
  267. package/dist/src/slice/index.d.ts +736 -0
  268. package/dist/src/slice/index.d.ts.map +1 -1
  269. package/dist/src/slice/legend/index.d.ts +4 -0
  270. package/dist/src/slice/legend/index.d.ts.map +1 -1
  271. package/dist/src/slice/legend/types.d.ts +4 -0
  272. package/dist/src/slice/legend/types.d.ts.map +1 -1
  273. package/dist/src/slice/rail/index.d.ts +8 -4
  274. package/dist/src/slice/rail/index.d.ts.map +1 -1
  275. package/dist/src/slice/rail/index.js.map +1 -1
  276. package/dist/src/slice/range/index.d.ts +4 -0
  277. package/dist/src/slice/range/index.d.ts.map +1 -1
  278. package/dist/src/slice/range/types.d.ts +4 -0
  279. package/dist/src/slice/range/types.d.ts.map +1 -1
  280. package/dist/src/slice/search/index.d.ts +4 -0
  281. package/dist/src/slice/search/index.d.ts.map +1 -1
  282. package/dist/src/slice/search/types.d.ts +4 -0
  283. package/dist/src/slice/search/types.d.ts.map +1 -1
  284. package/dist/src/slice/summary/index.d.ts +4 -0
  285. package/dist/src/slice/summary/index.d.ts.map +1 -1
  286. package/dist/src/slice/summary/types.d.ts +4 -0
  287. package/dist/src/slice/summary/types.d.ts.map +1 -1
  288. package/dist/src/typography/code/index.js +1 -1
  289. package/dist/src/typography/code/index.js.map +1 -1
  290. package/dist/src/typography/code-block/index.js +7 -7
  291. package/dist/src/typography/code-block/index.js.map +1 -1
  292. package/dist/src/typography/heading/index.js +2 -2
  293. package/dist/src/typography/heading/index.js.map +1 -1
  294. package/dist/src/typography/list/index.js +1 -1
  295. package/dist/src/typography/list/index.js.map +1 -1
  296. package/dist/src/typography/mark/index.js +1 -1
  297. package/dist/src/typography/mark/index.js.map +1 -1
  298. package/dist/src/typography/note/index.js +1 -1
  299. package/dist/src/typography/note/index.js.map +1 -1
  300. package/dist/src/typography/numeric/index.d.ts +3 -308
  301. package/dist/src/typography/numeric/index.d.ts.map +1 -1
  302. package/dist/src/typography/numeric/index.js +4 -4
  303. package/dist/src/typography/numeric/index.js.map +1 -1
  304. package/dist/src/typography/numeric/types.d.ts +1 -154
  305. package/dist/src/typography/numeric/types.d.ts.map +1 -1
  306. package/dist/src/typography/text/index.js +1 -1
  307. package/dist/src/typography/text/index.js.map +1 -1
  308. package/dist/test/collections/matrix.examples.d.ts +7 -3
  309. package/dist/test/collections/matrix.examples.d.ts.map +1 -1
  310. package/dist/test/collections/matrix.examples.js +55 -24
  311. package/dist/test/collections/matrix.examples.js.map +1 -1
  312. package/dist/test/collections/paged-source.examples.d.ts +4 -0
  313. package/dist/test/collections/paged-source.examples.d.ts.map +1 -1
  314. package/dist/test/collections/paged-source.examples.js +98 -13
  315. package/dist/test/collections/paged-source.examples.js.map +1 -1
  316. package/dist/test/collections/plan.examples.d.ts +101 -26
  317. package/dist/test/collections/plan.examples.d.ts.map +1 -1
  318. package/dist/test/collections/plan.examples.js +1481 -755
  319. package/dist/test/collections/plan.examples.js.map +1 -1
  320. package/dist/test/collections/sheet-link.examples.d.ts +7 -0
  321. package/dist/test/collections/sheet-link.examples.d.ts.map +1 -0
  322. package/dist/test/collections/sheet-link.examples.js +41 -0
  323. package/dist/test/collections/sheet-link.examples.js.map +1 -0
  324. package/dist/test/collections/sheet-transactions.examples.d.ts +7 -0
  325. package/dist/test/collections/sheet-transactions.examples.d.ts.map +1 -0
  326. package/dist/test/collections/sheet-transactions.examples.js +58 -0
  327. package/dist/test/collections/sheet-transactions.examples.js.map +1 -0
  328. package/dist/test/collections/sheet.examples.d.ts +52 -5
  329. package/dist/test/collections/sheet.examples.d.ts.map +1 -1
  330. package/dist/test/collections/sheet.examples.js +500 -158
  331. package/dist/test/collections/sheet.examples.js.map +1 -1
  332. package/dist/test/collections/table.examples.d.ts +31 -3
  333. package/dist/test/collections/table.examples.d.ts.map +1 -1
  334. package/dist/test/collections/table.examples.js +188 -28
  335. package/dist/test/collections/table.examples.js.map +1 -1
  336. package/dist/test/contracts/editing.examples.d.ts +7 -0
  337. package/dist/test/contracts/editing.examples.d.ts.map +1 -0
  338. package/dist/test/contracts/editing.examples.js +58 -0
  339. package/dist/test/contracts/editing.examples.js.map +1 -0
  340. package/dist/test/layout/splitter.examples.d.ts.map +1 -1
  341. package/dist/test/layout/splitter.examples.js +3 -1
  342. package/dist/test/layout/splitter.examples.js.map +1 -1
  343. package/dist/test/platform/slice.examples.d.ts.map +1 -1
  344. package/dist/test/platform/slice.examples.js +1 -0
  345. package/dist/test/platform/slice.examples.js.map +1 -1
  346. package/dist/test/slice/slice.examples.d.ts.map +1 -1
  347. package/dist/test/slice/slice.examples.js +5 -2
  348. package/dist/test/slice/slice.examples.js.map +1 -1
  349. package/package.json +4 -3
  350. package/dist/src/collections/plan/data-forms.d.ts +0 -332
  351. package/dist/src/collections/plan/data-forms.d.ts.map +0 -1
  352. package/dist/src/collections/plan/data-forms.js +0 -212
  353. package/dist/src/collections/plan/data-forms.js.map +0 -1
@@ -0,0 +1,711 @@
1
+ /**
2
+ * Copyright (c) 2025 Elara AI Pty Ltd
3
+ * Dual-licensed under AGPL-3.0 and commercial license. See LICENSE for details.
4
+ */
5
+ /**
6
+ * The editing contract (#879) — one transaction session for every editable
7
+ * collection. A gesture edits DRAFTS (every field missing, a value, or text
8
+ * that could not be read); each gesture is one undoable transaction, reported
9
+ * to the host as a {@link EditingPatchEventTypeFor patch event}; and Apply
10
+ * sends one checked, idempotent batch ({@link EditingChangeSetTypeFor}) against
11
+ * the base the drafts began from, which {@link applyEditing} applies to a
12
+ * collection atomically.
13
+ *
14
+ * The Sheet was first to speak it, and keeps its names for it —
15
+ * `Sheet.Types.ChangeSet` is `Editing.Types.ChangeSet`, `Sheet.apply` is
16
+ * `Editing.apply`. What only a sheet has (a new row's destination among a
17
+ * group's children, the `newRow` / `newGroup` contexts) stays the Sheet's.
18
+ *
19
+ * @packageDocumentation
20
+ */
21
+ import { ArrayType, AsyncFunctionType, BlobType, DictType, East, EastTypeType, FunctionType, IntegerType, NullType, OptionType, PatchType, SetType, StringType, StructType, VariantType, isTypeEqual, none, some, variant, } from "@elaraai/east";
22
+ // ============================================================================
23
+ // Placement, readiness, origins, results
24
+ // ============================================================================
25
+ /**
26
+ * A position in an explicitly ordered collection.
27
+ *
28
+ * @property start - First
29
+ * @property end - Last
30
+ * @property before - Just before the entry with this id
31
+ * @property after - Just after the entry with this id
32
+ */
33
+ export const EditingPositionType = VariantType({ start: NullType, end: NullType, before: StringType, after: StringType });
34
+ /**
35
+ * Where an entry stands: a position in an ordered collection, or the key order
36
+ * of a keyed one.
37
+ *
38
+ * @property ordered - A position in an Array source
39
+ * @property keyOrder - A keyed source's own order — its entries sort by key
40
+ */
41
+ export const EditingPlacementType = VariantType({ ordered: EditingPositionType, keyOrder: NullType });
42
+ /**
43
+ * One issue on a field, as an author check reports it.
44
+ *
45
+ * @property field - The field
46
+ * @property message - What is wrong, in the author's words
47
+ */
48
+ export const EditingFieldIssueType = StructType({ field: StringType, message: StringType });
49
+ /**
50
+ * One entry's readiness, after the structural checks and the author's.
51
+ *
52
+ * @property ready - Nothing stands in the way
53
+ * @property incomplete - Fields still missing
54
+ * @property invalid - Fields whose text could not be read, or that a check refused
55
+ */
56
+ export const EditingReadinessType = VariantType({
57
+ ready: NullType, incomplete: ArrayType(EditingFieldIssueType), invalid: ArrayType(EditingFieldIssueType),
58
+ });
59
+ /**
60
+ * An issue addressed to an entry, and optionally to a child row and a field.
61
+ *
62
+ * @property entry - The entry's id
63
+ * @property row - The child row's index in a group's children, when it is one
64
+ * @property field - The field, when the issue has one
65
+ * @property message - What is wrong
66
+ */
67
+ export const EditingIssueType = StructType({
68
+ entry: StringType, row: OptionType(IntegerType), field: OptionType(StringType), message: StringType,
69
+ });
70
+ /**
71
+ * The readiness of a whole batch — every draft's issues together.
72
+ *
73
+ * @property ready - The batch may be applied
74
+ * @property incomplete - Fields still missing
75
+ * @property invalid - Fields whose text could not be read, or that a check refused
76
+ */
77
+ export const EditingBatchReadinessType = VariantType({
78
+ ready: NullType, incomplete: ArrayType(EditingIssueType), invalid: ArrayType(EditingIssueType),
79
+ });
80
+ /**
81
+ * The gesture that made one transaction — how a host tells typing from a
82
+ * paste, a copilot's fill from a planner's drag, and a history step from both.
83
+ *
84
+ * @property typed - Typed into a cell
85
+ * @property pasted - Pasted
86
+ * @property fill - A copilot's fill taken
87
+ * @property row - A copilot's row fill taken
88
+ * @property pattern - A proposed row taken
89
+ * @property insert - An entry inserted
90
+ * @property move - An entry moved
91
+ * @property remove - An entry removed
92
+ * @property resize - An element's extent changed (#879 — a Plan run's start or end)
93
+ * @property drop - Something dropped onto the collection from elsewhere (#879)
94
+ * @property verdict - A review verdict (#879 — Approve, Reject, and their "all" forms)
95
+ * @property undo - Undo
96
+ * @property redo - Redo
97
+ * @property discard - Drafts discarded
98
+ */
99
+ export const EditingOriginType = VariantType({
100
+ typed: NullType, pasted: NullType, fill: NullType, row: NullType, pattern: NullType,
101
+ insert: NullType, move: NullType, remove: NullType, resize: NullType, drop: NullType, verdict: NullType,
102
+ undo: NullType, redo: NullType, discard: NullType,
103
+ });
104
+ /**
105
+ * The source's authoritative answer to one idempotent request.
106
+ *
107
+ * @property applied - Applied; a mutable source names the revision it committed
108
+ * @property rejected - Refused as asked — revise the drafts before applying again
109
+ * @property conflict - The source moved on — review or discard the drafts
110
+ */
111
+ export const EditingApplyResultType = VariantType({
112
+ applied: StructType({ revision: OptionType(StringType) }),
113
+ rejected: ArrayType(EditingIssueType), conflict: ArrayType(EditingIssueType),
114
+ });
115
+ // ============================================================================
116
+ // Drafts
117
+ // ============================================================================
118
+ /**
119
+ * One field of a draft — missing, a value of the field's type, or the text a
120
+ * planner typed that could not be read, kept as typed.
121
+ *
122
+ * @typeParam T - The field's type
123
+ * @param type - The field's type
124
+ * @returns The field's draft variant
125
+ */
126
+ export function EditingDraftFieldType(type) {
127
+ return VariantType({ missing: NullType, value: type, invalid: StringType });
128
+ }
129
+ /**
130
+ * Constructs the field-by-field draft type of a struct, including the fields
131
+ * no column shows.
132
+ *
133
+ * @typeParam R - The domain row type
134
+ * @param rowType - The complete domain struct
135
+ * @returns The draft struct; an optional domain field still starts missing
136
+ */
137
+ export function EditingDraftTypeFor(rowType) {
138
+ return StructType(Object.fromEntries(Object.entries(rowType.fields).map(([k, t]) => [k, EditingDraftFieldType(t)])));
139
+ }
140
+ /** The declared child field of a group-or-row entry type (never inferred from arbitrary row fields). */
141
+ const children = new WeakMap();
142
+ /**
143
+ * Constructs a group's draft type, with drafts in its child array.
144
+ *
145
+ * @typeParam G - The complete group struct
146
+ * @typeParam F - Its Array-of-structs child field
147
+ * @param groupType - The group type
148
+ * @param field - The child array field
149
+ * @returns The group's draft struct
150
+ * @throws {Error} When the named field is not an Array of structs
151
+ */
152
+ export function EditingDraftGroupTypeFor(groupType, field) {
153
+ const t = groupType.fields[field];
154
+ if (t?.type !== "Array" || t.value.type !== "Struct")
155
+ throw new Error(`Editing: "${field}" must hold an Array of row structs`);
156
+ const rowDraft = EditingDraftTypeFor(t.value);
157
+ return StructType(Object.fromEntries(Object.entries(groupType.fields).map(([key, type]) => [key,
158
+ key === field ? ArrayType(rowDraft) : EditingDraftFieldType(type),
159
+ ])));
160
+ }
161
+ /**
162
+ * Constructs the union of groups carrying child rows and ungrouped rows. The
163
+ * child field is recorded with the type, so {@link EditingDraftEntryTypeFor}
164
+ * and {@link EditingPatchEventTypeFor} find it without being told again.
165
+ *
166
+ * @remarks
167
+ * The Sheet names it `Sheet.Types.Entry`; the example below uses that name.
168
+ *
169
+ * @typeParam G - The group struct
170
+ * @typeParam F - Its Array-of-structs child field
171
+ * @param groupType - The group type
172
+ * @param field - The child array field
173
+ * @returns The group-or-row entry type
174
+ * @throws {Error} When the child field is not an Array of structs
175
+ * @example
176
+ * ```ts
177
+ * import { ArrayType, East, OptionType, StringType, StructType, none, some, variant } from "@elaraai/east";
178
+ * import { Sheet } from "@elaraai/east-ui";
179
+ *
180
+ * const reordered = East.function([], ArrayType(StringType), ($) => {
181
+ * const TaskType = StructType({ id: StringType, task: StringType });
182
+ * const PackageType = StructType({ id: StringType, name: StringType, tasks: ArrayType(TaskType) });
183
+ * const Entry = Sheet.Types.Entry(PackageType, "tasks");
184
+ * const before = $.const(variant("group", { id: "p1", name: "P-40 roughing", tasks: [
185
+ * { id: "t1", task: "Machine blanks" }, { id: "t2", task: "Inspect lots" },
186
+ * ] }), Entry);
187
+ * const after = $.const(variant("group", { id: "p1", name: "P-40 roughing", tasks: [
188
+ * { id: "t2", task: "Inspect lots" }, { id: "t1", task: "Machine blanks" },
189
+ * ] }), Entry);
190
+ * const loose = $.const(variant("row", { id: "t9", task: "Pack for shipping" }), Entry);
191
+ * const entries = $.const([before, loose], ArrayType(Entry));
192
+ * const oldEntry = $.const(some(before), OptionType(Entry));
193
+ * const newEntry = $.const(some(after), OptionType(Entry));
194
+ * const batch = $.const({
195
+ * requestId: "reorder-roughing", base: variant("snapshot", entries), label: "Move a task",
196
+ * changes: [{ id: "p1", patch: East.diff(oldEntry, newEntry), place: none }],
197
+ * }, Sheet.Types.ChangeSet(Entry));
198
+ * const apply = $.const(Sheet.apply(Entry, "id"));
199
+ * const applied = $.const(apply(entries, batch, none).unwrap("applied"));
200
+ * return applied.map((_$, entry) => entry.match({
201
+ * group: (_$2, p) => East.str`${p.name}: ${p.tasks.map((_$3, t) => t.task).stringJoin(" → ")}`,
202
+ * row: (_$2, t) => t.task,
203
+ * }));
204
+ * });
205
+ * ```
206
+ */
207
+ export function EditingEntryTypeFor(groupType, field) {
208
+ EditingDraftGroupTypeFor(groupType, field);
209
+ const row = groupType.fields[field].value;
210
+ const entry = VariantType({ group: groupType, row });
211
+ children.set(entry, field);
212
+ return entry;
213
+ }
214
+ /**
215
+ * Constructs the draft equivalent of a source entry.
216
+ *
217
+ * @typeParam E - The entry schema
218
+ * @typeParam F - A groups-only source's child field
219
+ * @param entryType - A flat struct or a group-or-row union
220
+ * @param field - The child field for a groups-only source
221
+ * @returns The draft entry schema
222
+ * @throws {Error} When a group union has no unambiguous child field
223
+ */
224
+ export function EditingDraftEntryTypeFor(entryType, field) {
225
+ if (entryType.type === "Struct") {
226
+ return (field === undefined ? EditingDraftTypeFor(entryType) : EditingDraftGroupTypeFor(entryType, field));
227
+ }
228
+ if (entryType.type === "Variant" && entryType.cases.group?.type === "Struct" && entryType.cases.row?.type === "Struct") {
229
+ const group = entryType.cases.group;
230
+ const row = entryType.cases.row;
231
+ const candidates = Object.entries(group.fields).filter(([, t]) => t.type === "Array" && isTypeEqual(t.value, row));
232
+ const childField = field ?? children.get(entryType) ?? (candidates.length === 1 ? candidates[0][0] : undefined);
233
+ if (childField === undefined)
234
+ throw new Error("Editing: declare the child field with Entry(GroupType, field) — Sheet.Types.Entry / Editing.Types.Entry");
235
+ return VariantType({ group: EditingDraftGroupTypeFor(group, childField), row: EditingDraftTypeFor(row) });
236
+ }
237
+ throw new Error("Editing: entries must be row structs or a group/row variant of structs");
238
+ }
239
+ /**
240
+ * Constructs the checked base of a batch — the revision a mutable source
241
+ * committed, or the whole inline collection the drafts began from.
242
+ *
243
+ * @typeParam E - The source entry type
244
+ * @typeParam K - A keyed source's key type; omitted for an Array
245
+ * @param entryType - The source entry type
246
+ * @param keyType - A keyed source's key type
247
+ * @returns A revision token or the complete collection snapshot
248
+ */
249
+ export function EditingBaseTypeFor(entryType, keyType) {
250
+ const snapshot = keyType === undefined ? ArrayType(entryType) : DictType(keyType, entryType);
251
+ return VariantType({ revision: StringType, snapshot });
252
+ }
253
+ /**
254
+ * Constructs one composed entry patch and its placement.
255
+ *
256
+ * @typeParam E - The source entry type
257
+ * @param entryType - The source entry type
258
+ * @returns An entry-addressed East patch; `none` stands for an absent entry
259
+ */
260
+ export function EditingChangeTypeFor(entryType) {
261
+ return StructType({ id: StringType, patch: PatchType(OptionType(entryType)), place: OptionType(EditingPlacementType) });
262
+ }
263
+ /**
264
+ * Constructs an atomic request against a checked base — what `onApply`
265
+ * receives.
266
+ *
267
+ * @typeParam E - The source entry type
268
+ * @typeParam K - A keyed source's key type; omitted for an Array
269
+ * @param entryType - The source entry type
270
+ * @param keyType - A keyed source's key type
271
+ * @returns The batch type
272
+ */
273
+ export function EditingChangeSetTypeFor(entryType, keyType) {
274
+ return StructType({
275
+ requestId: StringType, base: EditingBaseTypeFor(entryType, keyType), label: StringType,
276
+ changes: ArrayType(EditingChangeTypeFor(entryType)),
277
+ });
278
+ }
279
+ /**
280
+ * Constructs the result of {@link applyEditing}.
281
+ *
282
+ * @typeParam E - The source entry type
283
+ * @typeParam K - A keyed source's key type; omitted for an Array
284
+ * @param entryType - The source entry type
285
+ * @param keyType - A keyed source's key type
286
+ * @returns The complete applied collection, or the conflict's issues
287
+ */
288
+ export function EditingAppliedTypeFor(entryType, keyType) {
289
+ const applied = keyType === undefined ? ArrayType(entryType) : DictType(keyType, entryType);
290
+ return VariantType({ applied, conflict: ArrayType(EditingIssueType) });
291
+ }
292
+ /**
293
+ * Constructs one gesture's typed, draft-aware patch event — what `onPatch`
294
+ * receives, incomplete drafts included.
295
+ *
296
+ * @typeParam E - The source entry type
297
+ * @typeParam F - A groups-only source's child field
298
+ * @param entryType - The domain entry schema
299
+ * @param field - The child field for a groups-only source
300
+ * @returns The event: its gesture, the draft changes, the domain changes once every draft is complete, and the batch's readiness
301
+ */
302
+ export function EditingPatchEventTypeFor(entryType, field) {
303
+ return EditingPatchEventTypeWith(entryType, EditingDraftEntryTypeFor(entryType, field));
304
+ }
305
+ /**
306
+ * Constructs the patch event of a collection whose drafts take another shape
307
+ * than a field-by-field one — the Plan drafts a whole entry at once
308
+ * (`DraftField(E)`, #880), since every gesture on it writes a complete entry.
309
+ * {@link EditingPatchEventTypeFor} is this over the field-by-field draft.
310
+ *
311
+ * @typeParam E - The source entry type
312
+ * @typeParam D - The entry's draft type
313
+ * @param entryType - The domain entry schema
314
+ * @param draftType - The entry's draft schema
315
+ * @returns The event: its gesture, the draft changes, the domain changes once every draft is complete, and the batch's readiness
316
+ */
317
+ export function EditingPatchEventTypeWith(entryType, draftType) {
318
+ return StructType({
319
+ transactionId: StringType, origin: EditingOriginType, label: StringType,
320
+ draftChanges: ArrayType(EditingChangeTypeFor(draftType)),
321
+ domainChanges: OptionType(ArrayType(EditingChangeTypeFor(entryType))),
322
+ readiness: EditingBatchReadinessType,
323
+ });
324
+ }
325
+ /**
326
+ * Constructs an entry-addressed draft patch, placement included.
327
+ *
328
+ * @typeParam E - The source entry schema
329
+ * @typeParam F - A groups-only source's child field
330
+ * @param entryType - The source entry type
331
+ * @param field - The child field for a groups-only source
332
+ * @returns One change to the local draft collection
333
+ */
334
+ export function EditingDraftChangeTypeFor(entryType, field) {
335
+ return EditingChangeTypeFor(EditingDraftEntryTypeFor(entryType, field));
336
+ }
337
+ export function applyEditing(type, idField) {
338
+ if (idField !== undefined)
339
+ return applyOrdered(type, idField);
340
+ if (type.type !== "Dict") {
341
+ throw new Error("Editing.apply: an Array source names its entries' identity field — Editing.apply(E, \"id\"); a keyed source passes its Dict type — Editing.apply(DictType(K, E))");
342
+ }
343
+ return applyKeyed(type);
344
+ }
345
+ /** {@link applyEditing} over an Array, its entries addressed by their identity field. */
346
+ function applyOrdered(entryType, idField) {
347
+ const identity = (type) => {
348
+ if (type.type === "Struct" && type.fields[idField]?.type === "String") {
349
+ return East.function([type], StringType, (_$, row) => row[idField]);
350
+ }
351
+ if (type.type === "Variant") {
352
+ const arms = Object.fromEntries(Object.entries(type.cases).map(([tag, t]) => [tag, identity(t)]));
353
+ return East.function([type], StringType, ($, entry) => {
354
+ const fns = Object.fromEntries(Object.entries(arms).map(([tag, fn]) => [tag, $.const(fn)]));
355
+ return entry.match(Object.fromEntries(Object.entries(fns).map(([tag, fn]) => [tag, (_$, row) => fn(row)])));
356
+ });
357
+ }
358
+ throw new Error(`Editing.apply: "${idField}" must be a String field on every entry — pass the source identity field`);
359
+ };
360
+ const idOf = identity(entryType);
361
+ // The algorithm treats entries opaquely. Erase their TS fields here to
362
+ // avoid expanding recursive PatchTypeOf<EastType>; the runtime East type
363
+ // remains the exact author type, including every nested field and arm.
364
+ const opaqueEntry = entryType;
365
+ const rowsType = ArrayType(opaqueEntry);
366
+ const batchType = EditingChangeSetTypeFor(opaqueEntry);
367
+ const resultType = EditingAppliedTypeFor(opaqueEntry);
368
+ return East.function([rowsType, batchType, OptionType(StringType)], resultType, ($, current, batch, revision) => {
369
+ const id = $.const(idOf);
370
+ const issues = $.let([], ArrayType(EditingIssueType));
371
+ const result = $.let(variant("conflict", issues), resultType);
372
+ const activeId = $.let("");
373
+ $.try(($) => {
374
+ const valid = $.const(batch.base.match({
375
+ snapshot: (_$, snapshot) => East.equal(current, snapshot),
376
+ revision: (_$, expected) => East.equal(revision, some(expected)),
377
+ }));
378
+ $.if(valid.not(), ($) => { $.error("The source changed since this batch began — discard or review against the new source"); });
379
+ const seen = $.let(new Set(), SetType(StringType));
380
+ $.for(current, ($, row) => {
381
+ const key = $.const(id(row));
382
+ $.if(seen.has(key), ($) => { $.error("The source contains duplicate entry identities"); });
383
+ $(seen.insert(key));
384
+ });
385
+ // Detach nested mutable values: even a conflict after an earlier
386
+ // patch leaves the caller's complete collection untouched.
387
+ const next = $.let(East.Blob.encodeBeast(current, "v2").decodeBeast(rowsType, "v2"));
388
+ const changed = $.let(new Set(), SetType(StringType));
389
+ $.for(batch.changes, ($, change) => {
390
+ $.assign(activeId, change.id);
391
+ $.if(changed.has(change.id), ($) => { $.error("Compose each entry into one change before applying a batch"); });
392
+ $(changed.insert(change.id));
393
+ const before = $.const(next.firstMap((_$, row) => id(row).equal(change.id).ifElse(() => some(row), () => none)));
394
+ const after = $.const(East.applyPatch(before, change.patch));
395
+ $.if(after.hasTag("some"), ($) => {
396
+ const row = $.const(after.unwrap("some"));
397
+ $.if(id(row).notEqual(change.id), ($) => { $.error("An entry patch cannot change its identity"); });
398
+ $.if(before.hasTag("none").and(() => change.place.hasTag("none")), ($) => { $.error("A new entry needs an explicit placement"); });
399
+ $.if(before.hasTag("some"), ($) => {
400
+ $.assign(next, next.map((_$, old) => id(old).equal(change.id).ifElse(() => row, () => old)));
401
+ }).else(($) => { $.assign(next, next.concat([row])); });
402
+ }).else(($) => {
403
+ $.if(change.place.hasTag("some"), ($) => { $.error("A removed entry cannot have a placement"); });
404
+ $.assign(next, next.filter((_$, row) => id(row).notEqual(change.id)));
405
+ });
406
+ });
407
+ // All newly created identities exist before resolving anchors.
408
+ $.for(batch.changes, ($, change) => {
409
+ $.assign(activeId, change.id);
410
+ $.if(change.place.hasTag("some"), ($) => {
411
+ const placement = $.const(change.place.unwrap("some"));
412
+ $.if(placement.hasTag("keyOrder"), ($) => { $.error("An inline Array requires an ordered placement; keyOrder belongs to a keyed source"); });
413
+ const position = $.const(placement.unwrap("ordered"));
414
+ const row = $.const(next.firstMap((_$, row) => id(row).equal(change.id).ifElse(() => some(row), () => none)).unwrap("some"));
415
+ const rest = $.const(next.filter((_$, row) => id(row).notEqual(change.id)));
416
+ const anchored = $.const(East.function([StringType], rowsType, ($, anchor) => {
417
+ $.if(anchor.equal(change.id).or(() => rest.filter((_$, r) => id(r).equal(anchor)).size().equal(0n)), ($) => {
418
+ $.error("The placement anchor is missing or names the moved entry");
419
+ });
420
+ return rest.flatMap((_$, other) => id(other).equal(anchor).ifElse(() => position.hasTag("before").ifElse(() => [row, other], () => [other, row]), () => [other]));
421
+ }));
422
+ $.assign(next, position.match({
423
+ start: () => East.value([row], rowsType).concat(rest),
424
+ end: () => rest.concat([row]),
425
+ before: (_$, anchor) => anchored(anchor),
426
+ after: (_$, anchor) => anchored(anchor),
427
+ }));
428
+ });
429
+ });
430
+ $.assign(result, variant("applied", next));
431
+ }).catch(($, message) => {
432
+ $(issues.pushLast({ entry: activeId, row: none, field: none, message }));
433
+ $.assign(result, variant("conflict", issues));
434
+ });
435
+ return result;
436
+ });
437
+ }
438
+ /** {@link applyEditing} over a keyed Dict, its entries addressed by key. */
439
+ function applyKeyed(sourceType) {
440
+ const keyType = sourceType.key;
441
+ // Entries are opaque here, as in the ordered form; the runtime types are exact.
442
+ const opaqueEntry = sourceType.value;
443
+ const entriesType = DictType(keyType, opaqueEntry);
444
+ const batchType = EditingChangeSetTypeFor(opaqueEntry, keyType);
445
+ const resultType = EditingAppliedTypeFor(opaqueEntry, keyType);
446
+ // A change names its entry by the key's text: a String key is its own
447
+ // text, any other key its `.east` printing, read back here.
448
+ const keyOf = keyType.type === "String"
449
+ ? East.function([StringType], StringType, (_$, id) => id)
450
+ : East.function([StringType], keyType, (_$, id) => id.parse(keyType));
451
+ return East.function([entriesType, batchType, OptionType(StringType)], resultType, ($, current, batch, revision) => {
452
+ const keyFrom = $.const(keyOf);
453
+ const issues = $.let([], ArrayType(EditingIssueType));
454
+ const result = $.let(variant("conflict", issues), resultType);
455
+ const activeId = $.let("");
456
+ $.try(($) => {
457
+ const valid = $.const(batch.base.match({
458
+ snapshot: (_$, snapshot) => East.equal(current, snapshot),
459
+ revision: (_$, expected) => East.equal(revision, some(expected)),
460
+ }));
461
+ $.if(valid.not(), ($) => { $.error("The source changed since this batch began — discard or review against the new source"); });
462
+ // Detached, as in the ordered form: a conflict leaves the caller's collection untouched.
463
+ const next = $.let(East.Blob.encodeBeast(current, "v2").decodeBeast(entriesType, "v2"));
464
+ const changed = $.let(new Set(), SetType(StringType));
465
+ $.for(batch.changes, ($, change) => {
466
+ $.assign(activeId, change.id);
467
+ $.if(changed.has(change.id), ($) => { $.error("Compose each entry into one change before applying a batch"); });
468
+ $(changed.insert(change.id));
469
+ const key = $.const(keyFrom(change.id));
470
+ $.if(change.place.hasTag("some").and(() => change.place.unwrap("some").hasTag("ordered")), ($) => {
471
+ $.error("A keyed source orders its entries by key — its placement is keyOrder");
472
+ });
473
+ const before = $.const(next.tryGet(key));
474
+ const after = $.const(East.applyPatch(before, change.patch));
475
+ $.if(after.hasTag("some"), ($) => {
476
+ $.if(before.hasTag("none").and(() => change.place.hasTag("none")), ($) => { $.error("A new entry needs an explicit placement"); });
477
+ $(next.insertOrUpdate(key, after.unwrap("some"), (_$, _old, value) => value));
478
+ }).else(($) => {
479
+ $.if(change.place.hasTag("some"), ($) => { $.error("A removed entry cannot have a placement"); });
480
+ $.if(before.hasTag("some"), ($) => { $(next.delete(key)); });
481
+ });
482
+ });
483
+ $.assign(result, variant("applied", next));
484
+ }).catch(($, message) => {
485
+ $(issues.pushLast({ entry: activeId, row: none, field: none, message }));
486
+ $.assign(result, variant("conflict", issues));
487
+ });
488
+ return result;
489
+ });
490
+ }
491
+ // ============================================================================
492
+ // The wire — what a collection hands the renderer's session
493
+ // ============================================================================
494
+ /**
495
+ * A synchronous or asynchronous authoritative apply callback, over the batch's
496
+ * bytes.
497
+ *
498
+ * @internal
499
+ * @property sync - A function
500
+ * @property async - An async function
501
+ */
502
+ export const EditingWireApplyType = VariantType({
503
+ sync: FunctionType([BlobType], EditingApplyResultType),
504
+ async: AsyncFunctionType([BlobType], EditingApplyResultType),
505
+ });
506
+ /**
507
+ * When a ready batch goes: on Apply, or as soon as it is ready. Both use the
508
+ * same serial checked protocol.
509
+ *
510
+ * @property batch - On Apply
511
+ * @property auto - As soon as the batch is ready
512
+ */
513
+ export const EditingApplyModeType = VariantType({ batch: NullType, auto: NullType });
514
+ /**
515
+ * The fields every source-bound editing session carries to the renderer's
516
+ * shared session — a collection's own editing declaration spreads them beside
517
+ * its own (`SheetEditingType`). Blobs carry values at the exact schemas named,
518
+ * so no hidden domain field is ever lost.
519
+ *
520
+ * @internal
521
+ */
522
+ export const EditingSessionFields = {
523
+ /** The source's identity — one session, and one unresolved request, per source. */
524
+ sourceId: StringType,
525
+ /** The entry schema. */
526
+ entryType: EastTypeType,
527
+ /** An Array source's String identity field. */
528
+ idField: OptionType(StringType),
529
+ /** The entry's draft schema. */
530
+ draftType: EastTypeType,
531
+ /** A group entry's child field. */
532
+ children: OptionType(StringType),
533
+ /**
534
+ * A keyed source's key type — its entries sort by key, a change names its
535
+ * entry by the key's text (a String key as it is, any other key its
536
+ * `.east` text), its batches are `ChangeSet(E, K)` and an inline snapshot
537
+ * is a `Dict` of it; `none` for an Array source.
538
+ */
539
+ keyType: OptionType(EastTypeType),
540
+ /** An inline source's whole collection — the base its batches check. */
541
+ snapshot: OptionType(BlobType),
542
+ /** One entry by id at its source offset, for a paged source's reads. */
543
+ readEntry: FunctionType([StringType, IntegerType], OptionType(BlobType)),
544
+ /** The author's patch observer, over the event's bytes. */
545
+ onPatch: OptionType(FunctionType([BlobType], NullType)),
546
+ /** The authoritative apply. */
547
+ onApply: OptionType(EditingWireApplyType),
548
+ /** When a ready batch goes. */
549
+ mode: EditingApplyModeType,
550
+ };
551
+ /**
552
+ * The shared session's wire declaration — {@link EditingSessionFields} alone.
553
+ *
554
+ * @internal
555
+ */
556
+ export const EditingType = StructType(EditingSessionFields);
557
+ // ============================================================================
558
+ // The inline adapter — idempotent writes through a live handle
559
+ // ============================================================================
560
+ /**
561
+ * The inline adapter's request ledger. Unlike reactive state, it must outlive
562
+ * a collection disappearing from a render; the browser implementation scopes
563
+ * it to the current UI store's lifetime.
564
+ *
565
+ * @internal
566
+ */
567
+ export const EditingRequestStore = {
568
+ read: East.platform("editing_requests_read", [StringType], OptionType(BlobType), { optional: true }),
569
+ write: East.platform("editing_requests_write", [StringType, BlobType], NullType, { optional: true }),
570
+ };
571
+ /** A request retains its payload before writing, and the target of an uncertain write. */
572
+ const RequestType = StructType({
573
+ payload: BlobType,
574
+ result: OptionType(EditingApplyResultType),
575
+ expected: OptionType(BlobType),
576
+ });
577
+ const RequestsType = DictType(StringType, RequestType);
578
+ /**
579
+ * Builds the inline `onUpdate` adapter over a live Array handle.
580
+ *
581
+ * A confirmed request replays before any stale-base check. A throwing write
582
+ * leaves an unresolved request in the store: retries confirm the target by
583
+ * reading it, and never repeat an uncertain mutation. The request table lives
584
+ * in the same browser state store as the binding, surviving remounts. It
585
+ * holds the source's latest request alone — a new one is taken only once
586
+ * every earlier one is resolved, so none of those is retried again — and a
587
+ * confirmed request keeps no copy of the collection it wrote.
588
+ *
589
+ * @internal
590
+ * @param entryType - The exact domain schema
591
+ * @param idField - The entry identity field
592
+ * @param sourceId - Stable identity of the captured binding
593
+ * @param read - Invocation-time collection reader
594
+ * @param write - The author's whole-collection writer
595
+ * @returns A closed Blob transport function for the typed apply callback
596
+ */
597
+ export function buildInlineApply(entryType, idField, sourceId, read, write) {
598
+ const entry = entryType;
599
+ return inlineApply(ArrayType(entry), EditingChangeSetTypeFor(entry), applyEditing(entry, idField), sourceId, read, write);
600
+ }
601
+ /**
602
+ * Builds the inline `onUpdate` adapter over a live keyed handle — the
603
+ * {@link buildInlineApply} protocol over a `Dict`, its batches applied by key
604
+ * (`Editing.apply(DictType(K, E))`, #880).
605
+ *
606
+ * @internal
607
+ * @param sourceType - The source's Dict type
608
+ * @param sourceId - Stable identity of the captured binding
609
+ * @param read - Invocation-time collection reader
610
+ * @param write - The author's whole-collection writer
611
+ * @returns A closed Blob transport function for the typed apply callback
612
+ */
613
+ export function buildKeyedInlineApply(sourceType, sourceId, read, write) {
614
+ const entry = sourceType.value;
615
+ return inlineApply(DictType(sourceType.key, entry), EditingChangeSetTypeFor(entry, sourceType.key), applyEditing(DictType(sourceType.key, entry)), sourceId, read, write);
616
+ }
617
+ /** The inline adapter's protocol over one collection type — see {@link buildInlineApply}. */
618
+ function inlineApply(collectionType, batchType, apply, sourceId, read, write) {
619
+ // The algorithm treats the collection opaquely; its runtime type is exact.
620
+ const _rowsType = collectionType;
621
+ const typedBatch = batchType;
622
+ return East.function([BlobType], EditingApplyResultType, ($, payload) => {
623
+ const reader = $.const(read);
624
+ const writer = $.const(write);
625
+ const transform = $.const(apply);
626
+ const key = $.const(East.str `editing.requests:${sourceId}`);
627
+ const saved = $.const(EditingRequestStore.read(key));
628
+ const requests = $.let(saved.match({ none: ($) => $.const(new Map(), RequestsType), some: (_$, blob) => blob.decodeBeast(RequestsType, "v2") }));
629
+ const batch = $.const(payload.decodeBeast(typedBatch, "v2"));
630
+ const recorded = $.const(requests.tryGet(batch.requestId));
631
+ return recorded.match({
632
+ some: ($, request) => East.equal(request.payload, payload).ifElse((_$) => request.result.match({
633
+ some: (_$, result) => result,
634
+ none: ($) => {
635
+ // An uncertain writer is never invoked twice. Only
636
+ // the exact target establishes successful application.
637
+ const current = $.const(East.Blob.encodeBeast(reader(), "v2"));
638
+ return East.equal(request.expected, some(current)).ifElse(($) => {
639
+ const confirmed = $.const(variant("applied", { revision: none }), EditingApplyResultType);
640
+ // Confirmed: the target it was recovered by is no longer needed.
641
+ $(requests.insertOrUpdate(batch.requestId, { payload, result: some(confirmed), expected: none }, (_$, _old, next) => next));
642
+ $(EditingRequestStore.write(key, East.Blob.encodeBeast(requests, "v2")));
643
+ return confirmed;
644
+ }, ($) => $.error("The previous write has an unknown outcome — retry after its target is confirmed; it cannot be safely issued twice"));
645
+ },
646
+ }), ($) => $.const(variant("conflict", [{ entry: "", row: none, field: none, message: "This request id already names a different batch" }]), EditingApplyResultType)),
647
+ none: ($) => {
648
+ const unresolved = $.const(requests.toArray((_$, request) => request.result.hasTag("none")).filter((_$, pending) => pending).size());
649
+ $.if(unresolved.greater(0n), ($) => {
650
+ $.error("This source already has an unresolved write — recover its original request before submitting another batch");
651
+ });
652
+ // Every earlier request is resolved, so none is retried again:
653
+ // the ledger keeps this one alone.
654
+ const ledger = $.let(new Map(), RequestsType);
655
+ const current = $.const(reader());
656
+ const applied = $.const(transform(current, batch, none));
657
+ return applied.match({
658
+ conflict: ($, issues) => {
659
+ const result = $.const(variant("conflict", issues), EditingApplyResultType);
660
+ $(ledger.insert(batch.requestId, { payload, result: some(result), expected: none }));
661
+ $(EditingRequestStore.write(key, East.Blob.encodeBeast(ledger, "v2")));
662
+ return result;
663
+ },
664
+ applied: ($, rows) => {
665
+ const expected = $.const(some(East.Blob.encodeBeast(rows, "v2")), OptionType(BlobType));
666
+ $(ledger.insert(batch.requestId, { payload, result: none, expected }));
667
+ $(EditingRequestStore.write(key, East.Blob.encodeBeast(ledger, "v2")));
668
+ $(writer(rows));
669
+ const result = $.const(variant("applied", { revision: none }), EditingApplyResultType);
670
+ // Confirmed: the target is kept only while the outcome is unknown.
671
+ $(ledger.insertOrUpdate(batch.requestId, { payload, result: some(result), expected: none }, (_$, _old, next) => next));
672
+ $(EditingRequestStore.write(key, East.Blob.encodeBeast(ledger, "v2")));
673
+ return result;
674
+ },
675
+ });
676
+ },
677
+ });
678
+ });
679
+ }
680
+ /**
681
+ * The editing contract (#879) — the one transaction session every editable
682
+ * collection speaks: drafts, one undoable transaction per gesture reported as a
683
+ * `PatchEvent`, and Apply as one checked, idempotent `ChangeSet` applied with
684
+ * `Editing.apply`. The Sheet keeps its names for it (`Sheet.Types.ChangeSet`,
685
+ * `Sheet.apply`, …) — the same values.
686
+ */
687
+ export const Editing = {
688
+ apply: applyEditing,
689
+ Types: {
690
+ DraftField: EditingDraftFieldType,
691
+ Draft: EditingDraftTypeFor,
692
+ DraftGroup: EditingDraftGroupTypeFor,
693
+ Entry: EditingEntryTypeFor,
694
+ DraftEntry: EditingDraftEntryTypeFor,
695
+ DraftChange: EditingDraftChangeTypeFor,
696
+ Change: EditingChangeTypeFor,
697
+ ChangeSet: EditingChangeSetTypeFor,
698
+ Base: EditingBaseTypeFor,
699
+ Applied: EditingAppliedTypeFor,
700
+ ApplyResult: EditingApplyResultType,
701
+ Issue: EditingIssueType,
702
+ FieldIssue: EditingFieldIssueType,
703
+ Readiness: EditingReadinessType,
704
+ BatchReadiness: EditingBatchReadinessType,
705
+ Origin: EditingOriginType,
706
+ PatchEvent: EditingPatchEventTypeFor,
707
+ Placement: EditingPlacementType,
708
+ Position: EditingPositionType,
709
+ },
710
+ };
711
+ //# sourceMappingURL=editing.js.map