@mistriwork/mistri 1.0.0-rc.12 → 1.0.0-rc.13

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 (221) hide show
  1. package/README.md +4 -3
  2. package/dist/client/assets/LayoutBuilder-MPzkVU2e.js.map +1 -1
  3. package/dist/client/assets/index-D2dHI6hR.js.map +1 -1
  4. package/dist/client/assets/shell-TreN_uLs.js.map +1 -1
  5. package/dist/docs/access-model.md +1 -1
  6. package/dist/docs/build-and-deploy.md +0 -1
  7. package/dist/docs/cli.md +1 -1
  8. package/dist/docs/glossary.md +3 -3
  9. package/dist/docs/query.md +9 -21
  10. package/dist/docs/status.md +3 -3
  11. package/dist/embed/react/chunks/LayoutBuilder-Cbxa_wve.js.map +1 -1
  12. package/dist/embed/react/chunks/app-0UZ1Re1k.js.map +1 -1
  13. package/dist/embed/react/chunks/page-Bx4o1kpQ.js.map +1 -1
  14. package/dist/embed/react/chunks/palette-Bb7Lf6eo.js.map +1 -1
  15. package/dist/embed/react/chunks/shell-DZRACiB9.js.map +1 -1
  16. package/dist/embed/react/chunks/write-BQO4CFc9.js.map +1 -1
  17. package/dist/embed/react/index.js +1 -1
  18. package/dist/server/build/dockerfile.js +1 -1
  19. package/dist/server/cli/usage.js +2 -2
  20. package/dist/ui/index.js +2 -2
  21. package/dist/ui/page.js +2 -2
  22. package/dist/ui/{shared-N4Ej8yRD.js → shared-1PD7TOTJ.js} +5 -5
  23. package/dist/ui/{shared-N4Ej8yRD.js.map → shared-1PD7TOTJ.js.map} +1 -1
  24. package/dist/ui/{shared-D5m86-4o.js → shared-1gMnOu9J.js} +6 -6
  25. package/dist/ui/{shared-D5m86-4o.js.map → shared-1gMnOu9J.js.map} +1 -1
  26. package/dist/ui/{shared-Ctaj8mR2.js → shared-5RQMi4BR.js} +3 -3
  27. package/dist/ui/{shared-Ctaj8mR2.js.map → shared-5RQMi4BR.js.map} +1 -1
  28. package/dist/ui/{shared-DpLeIATZ.js → shared-B-BUF9fx.js} +2 -2
  29. package/dist/ui/{shared-DpLeIATZ.js.map → shared-B-BUF9fx.js.map} +1 -1
  30. package/dist/ui/{shared-DWYnjItP.js → shared-B-MhiPIN.js} +9 -9
  31. package/dist/ui/{shared-DWYnjItP.js.map → shared-B-MhiPIN.js.map} +1 -1
  32. package/dist/ui/{shared-0fNuhSbG.js → shared-B07qIMlE.js} +5 -5
  33. package/dist/ui/{shared-0fNuhSbG.js.map → shared-B07qIMlE.js.map} +1 -1
  34. package/dist/ui/{shared-lYtMadRU.js → shared-B1SAS_J-.js} +3 -3
  35. package/dist/ui/{shared-lYtMadRU.js.map → shared-B1SAS_J-.js.map} +1 -1
  36. package/dist/ui/{shared-CpI0Y8M5.js → shared-B4jgU8h9.js} +6 -6
  37. package/dist/ui/{shared-CpI0Y8M5.js.map → shared-B4jgU8h9.js.map} +1 -1
  38. package/dist/ui/{shared-Cxu1c35l.js → shared-B5aBCUi7.js} +30 -30
  39. package/dist/ui/{shared-Cxu1c35l.js.map → shared-B5aBCUi7.js.map} +1 -1
  40. package/dist/ui/{shared-CAe-US1q.js → shared-B9H7_Pji.js} +5 -5
  41. package/dist/ui/{shared-CAe-US1q.js.map → shared-B9H7_Pji.js.map} +1 -1
  42. package/dist/ui/{shared-Q2bgBaYo.js → shared-BAXr20S-.js} +4 -4
  43. package/dist/ui/{shared-Q2bgBaYo.js.map → shared-BAXr20S-.js.map} +1 -1
  44. package/dist/ui/{shared-CyEefFFb.js → shared-BDDUzH-f.js} +19 -19
  45. package/dist/ui/{shared-CyEefFFb.js.map → shared-BDDUzH-f.js.map} +1 -1
  46. package/dist/ui/{shared-BdhPI6dq.js → shared-BGmkeDeW.js} +3 -3
  47. package/dist/ui/{shared-BdhPI6dq.js.map → shared-BGmkeDeW.js.map} +1 -1
  48. package/dist/ui/{shared-DONIpq2q.js → shared-BHCQ60yN.js} +2 -2
  49. package/dist/ui/{shared-DONIpq2q.js.map → shared-BHCQ60yN.js.map} +1 -1
  50. package/dist/ui/{shared-CNmaAv64.js → shared-BHsjawAG.js} +8 -8
  51. package/dist/ui/{shared-CNmaAv64.js.map → shared-BHsjawAG.js.map} +1 -1
  52. package/dist/ui/{shared-DgjU9kOy.js → shared-BIQuK_nq.js} +4 -4
  53. package/dist/ui/{shared-DgjU9kOy.js.map → shared-BIQuK_nq.js.map} +1 -1
  54. package/dist/ui/{shared-icSQAj21.js → shared-BOe4W2FI.js} +3 -3
  55. package/dist/ui/{shared-icSQAj21.js.map → shared-BOe4W2FI.js.map} +1 -1
  56. package/dist/ui/{shared-BlxoOJSk.js → shared-BPpC08ip.js} +3 -3
  57. package/dist/ui/{shared-BlxoOJSk.js.map → shared-BPpC08ip.js.map} +1 -1
  58. package/dist/ui/{shared-BtiFL37J.js → shared-BdA3LPCB.js} +2 -2
  59. package/dist/ui/{shared-BtiFL37J.js.map → shared-BdA3LPCB.js.map} +1 -1
  60. package/dist/ui/{shared-CvR94vn4.js → shared-Be3nbWsd.js} +11 -11
  61. package/dist/ui/{shared-CvR94vn4.js.map → shared-Be3nbWsd.js.map} +1 -1
  62. package/dist/ui/{shared-Bl_nF_IH.js → shared-Bf30ZLoS.js} +8 -4
  63. package/dist/ui/shared-Bf30ZLoS.js.map +1 -0
  64. package/dist/ui/{shared-DijrJ_V-.js → shared-BguP_BaR.js} +7 -7
  65. package/dist/ui/{shared-DijrJ_V-.js.map → shared-BguP_BaR.js.map} +1 -1
  66. package/dist/ui/{shared-DPAVoWY0.js → shared-BoLbc2WD.js} +17 -2
  67. package/dist/ui/{shared-DPAVoWY0.js.map → shared-BoLbc2WD.js.map} +1 -1
  68. package/dist/ui/{shared-BkdBTYwx.js → shared-BttyOW4W.js} +3 -3
  69. package/dist/ui/{shared-BkdBTYwx.js.map → shared-BttyOW4W.js.map} +1 -1
  70. package/dist/ui/{shared-CQWLz8uT.js → shared-BumxsBlA.js} +10 -10
  71. package/dist/ui/{shared-CQWLz8uT.js.map → shared-BumxsBlA.js.map} +1 -1
  72. package/dist/ui/{shared-Dzu7tFiC.js → shared-Bw73ktBk.js} +3 -3
  73. package/dist/ui/{shared-Dzu7tFiC.js.map → shared-Bw73ktBk.js.map} +1 -1
  74. package/dist/ui/{shared-BhAYErSx.js → shared-C1B0GH0e.js} +4 -4
  75. package/dist/ui/{shared-BhAYErSx.js.map → shared-C1B0GH0e.js.map} +1 -1
  76. package/dist/ui/{shared-BQJQcGgj.js → shared-C2FsyYr7.js} +4 -4
  77. package/dist/ui/{shared-BQJQcGgj.js.map → shared-C2FsyYr7.js.map} +1 -1
  78. package/dist/ui/{shared-B9lw2Ryh.js → shared-C2RU1qjv.js} +4 -4
  79. package/dist/ui/{shared-B9lw2Ryh.js.map → shared-C2RU1qjv.js.map} +1 -1
  80. package/dist/ui/{shared-DQYNI9wO.js → shared-C42f07hJ.js} +5 -5
  81. package/dist/ui/{shared-DQYNI9wO.js.map → shared-C42f07hJ.js.map} +1 -1
  82. package/dist/ui/{shared-CqCZ8wMY.js → shared-C4LkPCU4.js} +3 -3
  83. package/dist/ui/{shared-CqCZ8wMY.js.map → shared-C4LkPCU4.js.map} +1 -1
  84. package/dist/ui/{shared-BhtpgOpa.js → shared-C4wSfz6k.js} +9 -9
  85. package/dist/ui/{shared-BhtpgOpa.js.map → shared-C4wSfz6k.js.map} +1 -1
  86. package/dist/ui/{shared-BHc2Izkj.js → shared-C9DZtSFH.js} +2 -2
  87. package/dist/ui/{shared-BHc2Izkj.js.map → shared-C9DZtSFH.js.map} +1 -1
  88. package/dist/ui/{shared-DW1YuiNS.js → shared-CA52ClGo.js} +2 -2
  89. package/dist/ui/{shared-DW1YuiNS.js.map → shared-CA52ClGo.js.map} +1 -1
  90. package/dist/ui/{shared-BbSbilkh.js → shared-CBciTwm6.js} +9 -9
  91. package/dist/ui/{shared-BbSbilkh.js.map → shared-CBciTwm6.js.map} +1 -1
  92. package/dist/ui/{shared-C-J32eBn.js → shared-CL3RLKDA.js} +16 -16
  93. package/dist/ui/{shared-C-J32eBn.js.map → shared-CL3RLKDA.js.map} +1 -1
  94. package/dist/ui/{shared-Ck8S4OxW.js → shared-CLq3-_hW.js} +3 -3
  95. package/dist/ui/{shared-Ck8S4OxW.js.map → shared-CLq3-_hW.js.map} +1 -1
  96. package/dist/ui/{shared-Q5WefT7G.js → shared-CMjK-Ucd.js} +3 -3
  97. package/dist/ui/{shared-Q5WefT7G.js.map → shared-CMjK-Ucd.js.map} +1 -1
  98. package/dist/ui/{shared-D3MAuEA3.js → shared-CPjpSFGh.js} +2 -2
  99. package/dist/ui/{shared-D3MAuEA3.js.map → shared-CPjpSFGh.js.map} +1 -1
  100. package/dist/ui/{shared-VshXGwXP.js → shared-CSPhENq3.js} +2 -2
  101. package/dist/ui/{shared-VshXGwXP.js.map → shared-CSPhENq3.js.map} +1 -1
  102. package/dist/ui/{shared-DJrJaE73.js → shared-CZJE4Bmp.js} +3 -3
  103. package/dist/ui/{shared-DJrJaE73.js.map → shared-CZJE4Bmp.js.map} +1 -1
  104. package/dist/ui/{shared-D7ONOwI7.js → shared-C_BhUL2I.js} +7 -7
  105. package/dist/ui/{shared-D7ONOwI7.js.map → shared-C_BhUL2I.js.map} +1 -1
  106. package/dist/ui/{shared-j-2peBIB.js → shared-CbeujwdU.js} +4 -4
  107. package/dist/ui/{shared-j-2peBIB.js.map → shared-CbeujwdU.js.map} +1 -1
  108. package/dist/ui/{shared-D5GrOEa2.js → shared-Cbf-o4Dt.js} +4 -4
  109. package/dist/ui/{shared-D5GrOEa2.js.map → shared-Cbf-o4Dt.js.map} +1 -1
  110. package/dist/ui/{shared-HwiPIajr.js → shared-CdNmeNHh.js} +3 -3
  111. package/dist/ui/{shared-HwiPIajr.js.map → shared-CdNmeNHh.js.map} +1 -1
  112. package/dist/ui/{shared-ZCFt-CPb.js → shared-CdQOMD8J.js} +3 -3
  113. package/dist/ui/{shared-ZCFt-CPb.js.map → shared-CdQOMD8J.js.map} +1 -1
  114. package/dist/ui/{shared-ClhXSGGK.js → shared-CdiPYlTh.js} +2 -2
  115. package/dist/ui/{shared-ClhXSGGK.js.map → shared-CdiPYlTh.js.map} +1 -1
  116. package/dist/ui/{shared-DA8_pVRZ.js → shared-CepLAhwm.js} +2 -2
  117. package/dist/ui/{shared-DA8_pVRZ.js.map → shared-CepLAhwm.js.map} +1 -1
  118. package/dist/ui/{shared-BrYKjrnM.js → shared-Ch82h_Fu.js} +6 -6
  119. package/dist/ui/{shared-BrYKjrnM.js.map → shared-Ch82h_Fu.js.map} +1 -1
  120. package/dist/ui/{shared-C4UrE8Fb.js → shared-Chp88all.js} +3 -3
  121. package/dist/ui/{shared-C4UrE8Fb.js.map → shared-Chp88all.js.map} +1 -1
  122. package/dist/ui/{shared-CWa80DTO.js → shared-Ci16s2rN.js} +9 -9
  123. package/dist/ui/{shared-CWa80DTO.js.map → shared-Ci16s2rN.js.map} +1 -1
  124. package/dist/ui/{shared-tksTLD6Q.js → shared-CiqNkoE1.js} +5 -5
  125. package/dist/ui/{shared-tksTLD6Q.js.map → shared-CiqNkoE1.js.map} +1 -1
  126. package/dist/ui/{shared-yt7DjSrq.js → shared-CpMhOq8F.js} +2 -2
  127. package/dist/ui/{shared-yt7DjSrq.js.map → shared-CpMhOq8F.js.map} +1 -1
  128. package/dist/ui/{shared-Dm0z5WUl.js → shared-CrWv5JKH.js} +6 -6
  129. package/dist/ui/{shared-Dm0z5WUl.js.map → shared-CrWv5JKH.js.map} +1 -1
  130. package/dist/ui/{shared-CQL3FGHc.js → shared-Csfi3Pti.js} +2 -2
  131. package/dist/ui/{shared-CQL3FGHc.js.map → shared-Csfi3Pti.js.map} +1 -1
  132. package/dist/ui/{shared-BKNRbm-V.js → shared-CuZt26rm.js} +2 -2
  133. package/dist/ui/{shared-BKNRbm-V.js.map → shared-CuZt26rm.js.map} +1 -1
  134. package/dist/ui/{shared-Guq3upiR.js → shared-Cws_z-TS.js} +2 -2
  135. package/dist/ui/{shared-Guq3upiR.js.map → shared-Cws_z-TS.js.map} +1 -1
  136. package/dist/ui/{shared-Bw_qZeIj.js → shared-D1KWuCg6.js} +2 -2
  137. package/dist/ui/{shared-Bw_qZeIj.js.map → shared-D1KWuCg6.js.map} +1 -1
  138. package/dist/ui/{shared-CuCZKwXW.js → shared-D66ju_Cb.js} +23 -23
  139. package/dist/ui/{shared-CuCZKwXW.js.map → shared-D66ju_Cb.js.map} +1 -1
  140. package/dist/ui/{shared-DYfX7NSM.js → shared-DGaQZXnw.js} +2 -2
  141. package/dist/ui/{shared-DYfX7NSM.js.map → shared-DGaQZXnw.js.map} +1 -1
  142. package/dist/ui/{shared-B3Hp8tOv.js → shared-DHy41sET.js} +6 -6
  143. package/dist/ui/{shared-B3Hp8tOv.js.map → shared-DHy41sET.js.map} +1 -1
  144. package/dist/ui/{shared-CXyd7IKi.js → shared-DKEOMQ6l.js} +2 -2
  145. package/dist/ui/{shared-CXyd7IKi.js.map → shared-DKEOMQ6l.js.map} +1 -1
  146. package/dist/ui/{shared-Ccmc8YO0.js → shared-DSUICuaJ.js} +33 -33
  147. package/dist/ui/{shared-Ccmc8YO0.js.map → shared-DSUICuaJ.js.map} +1 -1
  148. package/dist/ui/{shared-CL2iw_js.js → shared-DUPMRoO0.js} +13 -13
  149. package/dist/ui/{shared-CL2iw_js.js.map → shared-DUPMRoO0.js.map} +1 -1
  150. package/dist/ui/{shared-Dtp4eRul.js → shared-DVfdm6ah.js} +2 -2
  151. package/dist/ui/{shared-Dtp4eRul.js.map → shared-DVfdm6ah.js.map} +1 -1
  152. package/dist/ui/{shared-BJ5Ex32G.js → shared-DXM7d7lJ.js} +3 -3
  153. package/dist/ui/{shared-BJ5Ex32G.js.map → shared-DXM7d7lJ.js.map} +1 -1
  154. package/dist/ui/{shared-BFr6ld0e.js → shared-DXbMlcev.js} +2 -2
  155. package/dist/ui/{shared-BFr6ld0e.js.map → shared-DXbMlcev.js.map} +1 -1
  156. package/dist/ui/{shared-BUp3jv-N.js → shared-D_SkPtJ9.js} +6 -6
  157. package/dist/ui/{shared-BUp3jv-N.js.map → shared-D_SkPtJ9.js.map} +1 -1
  158. package/dist/ui/{shared-CdNomVzH.js → shared-Dd21k2ic.js} +4 -4
  159. package/dist/ui/{shared-CdNomVzH.js.map → shared-Dd21k2ic.js.map} +1 -1
  160. package/dist/ui/{shared-gRMbxmpu.js → shared-Dh0nHtLZ.js} +8 -8
  161. package/dist/ui/{shared-gRMbxmpu.js.map → shared-Dh0nHtLZ.js.map} +1 -1
  162. package/dist/ui/{shared-BKGJgjog.js → shared-DkOdSpSK.js} +3 -3
  163. package/dist/ui/{shared-BKGJgjog.js.map → shared-DkOdSpSK.js.map} +1 -1
  164. package/dist/ui/{shared-BMsh72Uq.js → shared-Dkph5ckT.js} +2 -2
  165. package/dist/ui/{shared-BMsh72Uq.js.map → shared-Dkph5ckT.js.map} +1 -1
  166. package/dist/ui/{shared-Be1HpDOB.js → shared-Dl1_Nx--.js} +3 -3
  167. package/dist/ui/{shared-Be1HpDOB.js.map → shared-Dl1_Nx--.js.map} +1 -1
  168. package/dist/ui/{shared-BQIZWOoJ.js → shared-Dm0IGbAf.js} +2 -2
  169. package/dist/ui/{shared-BQIZWOoJ.js.map → shared-Dm0IGbAf.js.map} +1 -1
  170. package/dist/ui/{shared-DSUtcU5S.js → shared-DnIkTpPr.js} +5 -5
  171. package/dist/ui/{shared-DSUtcU5S.js.map → shared-DnIkTpPr.js.map} +1 -1
  172. package/dist/ui/{shared-DsxGbYlV.js → shared-Docl_0tq.js} +3 -3
  173. package/dist/ui/{shared-DsxGbYlV.js.map → shared-Docl_0tq.js.map} +1 -1
  174. package/dist/ui/{shared-DZskrV26.js → shared-DprrHC72.js} +2 -2
  175. package/dist/ui/{shared-DZskrV26.js.map → shared-DprrHC72.js.map} +1 -1
  176. package/dist/ui/{shared-Bmw43Hwf.js → shared-DyKsJTZs.js} +2 -2
  177. package/dist/ui/{shared-Bmw43Hwf.js.map → shared-DyKsJTZs.js.map} +1 -1
  178. package/dist/ui/{shared-BLG88Pya.js → shared-FO7vfI3F.js} +4 -4
  179. package/dist/ui/{shared-BLG88Pya.js.map → shared-FO7vfI3F.js.map} +1 -1
  180. package/dist/ui/{shared-DLSd80D1.js → shared-HalAVHjv.js} +3 -3
  181. package/dist/ui/{shared-DLSd80D1.js.map → shared-HalAVHjv.js.map} +1 -1
  182. package/dist/ui/{shared-D1mMBLdj.js → shared-JvcI-LWp.js} +15 -15
  183. package/dist/ui/{shared-D1mMBLdj.js.map → shared-JvcI-LWp.js.map} +1 -1
  184. package/dist/ui/{shared-C6Hv_4O0.js → shared-K7Ym27yg.js} +2 -2
  185. package/dist/ui/{shared-C6Hv_4O0.js.map → shared-K7Ym27yg.js.map} +1 -1
  186. package/dist/ui/{shared-B39ln7oi.js → shared-SzlnwfJO.js} +3 -3
  187. package/dist/ui/{shared-B39ln7oi.js.map → shared-SzlnwfJO.js.map} +1 -1
  188. package/dist/ui/{shared-DgPn_Jll.js → shared-TrGbd1FY.js} +3 -3
  189. package/dist/ui/{shared-DgPn_Jll.js.map → shared-TrGbd1FY.js.map} +1 -1
  190. package/dist/ui/{shared-DrFb-XtA.js → shared-WhbuObEW.js} +2 -2
  191. package/dist/ui/{shared-DrFb-XtA.js.map → shared-WhbuObEW.js.map} +1 -1
  192. package/dist/ui/{shared-DiFQljcq.js → shared-XcSKDp6N.js} +11 -11
  193. package/dist/ui/{shared-DiFQljcq.js.map → shared-XcSKDp6N.js.map} +1 -1
  194. package/dist/ui/{shared-CMAg58rY.js → shared-Z4uBJU6I.js} +7 -6
  195. package/dist/ui/shared-Z4uBJU6I.js.map +1 -0
  196. package/dist/ui/{shared-BnUptuUp.js → shared-bAgeiRa5.js} +2 -2
  197. package/dist/ui/{shared-BnUptuUp.js.map → shared-bAgeiRa5.js.map} +1 -1
  198. package/dist/ui/{shared-BxMvSjey.js → shared-cgXG7OgZ.js} +5 -5
  199. package/dist/ui/{shared-BxMvSjey.js.map → shared-cgXG7OgZ.js.map} +1 -1
  200. package/dist/ui/{shared-u4CG2kQJ.js → shared-eZ0SB_zm.js} +2 -2
  201. package/dist/ui/{shared-u4CG2kQJ.js.map → shared-eZ0SB_zm.js.map} +1 -1
  202. package/dist/ui/{shared-L90bWW8e.js → shared-frKFb79C.js} +2 -2
  203. package/dist/ui/{shared-L90bWW8e.js.map → shared-frKFb79C.js.map} +1 -1
  204. package/dist/ui/{shared-Dd34nhkw.js → shared-hAayNSRA.js} +3 -3
  205. package/dist/ui/{shared-Dd34nhkw.js.map → shared-hAayNSRA.js.map} +1 -1
  206. package/dist/ui/{shared-DzC64cpp.js → shared-j_J16p2B.js} +2 -2
  207. package/dist/ui/{shared-DzC64cpp.js.map → shared-j_J16p2B.js.map} +1 -1
  208. package/dist/ui/{shared-DX7HRIV-.js → shared-tqpl5N3g.js} +6 -6
  209. package/dist/ui/{shared-DX7HRIV-.js.map → shared-tqpl5N3g.js.map} +1 -1
  210. package/dist/ui/{shared-BS5dBMpA.js → shared-y-6_ZDts.js} +2 -2
  211. package/dist/ui/{shared-BS5dBMpA.js.map → shared-y-6_ZDts.js.map} +1 -1
  212. package/dist/ui/{shared-Cv5v_MP1.js → shared-zG6e1Rhz.js} +13 -13
  213. package/dist/ui/{shared-Cv5v_MP1.js.map → shared-zG6e1Rhz.js.map} +1 -1
  214. package/dist/ui/testing.js +1 -1
  215. package/package.json +4 -4
  216. package/dist/docs/cli-browser.md +0 -232
  217. package/dist/docs/database-browser.md +0 -115
  218. package/dist/docs/keyboard.md +0 -63
  219. package/dist/docs/mcp.md +0 -86
  220. package/dist/ui/shared-Bl_nF_IH.js.map +0 -1
  221. package/dist/ui/shared-CMAg58rY.js.map +0 -1
@@ -1,14 +1,14 @@
1
1
  import { D as subscribeSessionIdentity, E as sessionIdentity, it as useQuery, nt as Button } from "./shared-poc11xxo.js";
2
2
  import { F as primaryKey, Wt as formatDateTime, gt as defineMessages, kt as portalRoot, ut as humanName } from "./shared-DJZjSi3J.js";
3
- import { L as DropItem, R as DropMenu } from "./shared-CNmaAv64.js";
4
- import { B as toast, L as state, d as findTable, f as go, i as api, x as pageView } from "./shared-DPAVoWY0.js";
3
+ import { L as DropItem, R as DropMenu } from "./shared-BHsjawAG.js";
4
+ import { B as toast, L as state, d as findTable, f as go, i as api, x as pageView } from "./shared-BoLbc2WD.js";
5
5
  import { t as Modal } from "./shared-CRr4kJXB.js";
6
- import { t as onDemand } from "./shared-DpLeIATZ.js";
6
+ import { t as onDemand } from "./shared-B-BUF9fx.js";
7
7
  import { n as mount, r as queryClient } from "./shared-C3MTHv9P.js";
8
- import { _ as registerCommandHost, f as Value, g as pageBridge } from "./shared-C4UrE8Fb.js";
8
+ import { _ as registerCommandHost, f as Value, g as pageBridge } from "./shared-Chp88all.js";
9
9
  import { a as formAt, o as formPageId } from "./shared-DpVb48sM.js";
10
- import { t as commandOperations } from "./shared-DsxGbYlV.js";
11
- import { a as commandInput, f as readyToJudge, h as commandAvailable, u as prefilledCommandValues, v as sendCommand } from "./shared-D1mMBLdj.js";
10
+ import { t as commandOperations } from "./shared-Docl_0tq.js";
11
+ import { a as commandInput, f as readyToJudge, h as commandAvailable, u as prefilledCommandValues, v as sendCommand } from "./shared-JvcI-LWp.js";
12
12
  import { createElement, useRef, useState } from "react";
13
13
  import { jsx, jsxs } from "react/jsx-runtime";
14
14
  // packages/mistri/src/shared/decisionSuggestions.ts
@@ -57,7 +57,7 @@ var say$1 = defineMessages({
57
57
  * offers is not one a component can reach; one only a component runs is an
58
58
  * action with `header: false`, offered in no menu.
59
59
  */
60
- var CommandForm = onDemand(() => import("./shared-BbSbilkh.js"), "CommandForm", { quiet: true });
60
+ var CommandForm = onDemand(() => import("./shared-CBciTwm6.js"), "CommandForm", { quiet: true });
61
61
  /** The action that offers this command, for this reader: the first whose command it is. */
62
62
  function actionOf(id) {
63
63
  const app = pageBridge.activeApp();
@@ -94,10 +94,10 @@ var labelled = (served, options) => options?.label ? {
94
94
  label: options.label
95
95
  }
96
96
  } : served;
97
- var formRun = () => import("./shared-lYtMadRU.js");
97
+ var formRun = () => import("./shared-B1SAS_J-.js");
98
98
  /** The form itself over the page, filled with what was given; it settles as closed, its own Done saying what it sent. */
99
99
  async function openFormCommand(served, input) {
100
- const { SignedInFormDialog } = await import("./shared-CdNomVzH.js");
100
+ const { SignedInFormDialog } = await import("./shared-Dd21k2ic.js");
101
101
  return new Promise((resolve) => {
102
102
  const host = document.createElement("div");
103
103
  portalRoot().append(host);
@@ -231,7 +231,7 @@ async function runCommand(action, key, input, options) {
231
231
  return outcome;
232
232
  }
233
233
  async function openPublicForm(view, prefill, appId) {
234
- const { FormDialog } = await import("./shared-CvR94vn4.js");
234
+ const { FormDialog } = await import("./shared-Be3nbWsd.js");
235
235
  const host = document.createElement("div");
236
236
  portalRoot().append(host);
237
237
  const query = new URLSearchParams(Object.entries(prefill).map(([name, value]) => [name, String(value)])).toString();
@@ -246,7 +246,7 @@ async function openPublicForm(view, prefill, appId) {
246
246
  }));
247
247
  }
248
248
  async function openSignedInForm(form, appName, prefill) {
249
- const { SignedInFormDialog } = await import("./shared-CdNomVzH.js");
249
+ const { SignedInFormDialog } = await import("./shared-Dd21k2ic.js");
250
250
  const host = document.createElement("div");
251
251
  portalRoot().append(host);
252
252
  const query = new URLSearchParams(Object.entries(prefill).map(([name, value]) => [name, String(value)])).toString();
@@ -284,7 +284,7 @@ function servedChoices(input, name) {
284
284
  }));
285
285
  }
286
286
  function publicPageHandle(page, id, reference) {
287
- const door = import("./shared-B39ln7oi.js").then(({ publicPageCommand }) => publicPageCommand(page, id, reference));
287
+ const door = import("./shared-SzlnwfJO.js").then(({ publicPageCommand }) => publicPageCommand(page, id, reference));
288
288
  return {
289
289
  label: humanName(id),
290
290
  granted: true,
@@ -546,4 +546,4 @@ function WhyThis({ suggestion, table, onClose }) {
546
546
  }
547
547
  export { DecisionChip as default };
548
548
 
549
- //# sourceMappingURL=shared-CL2iw_js.js.map
549
+ //# sourceMappingURL=shared-DUPMRoO0.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"shared-CL2iw_js.js","names":["say","say"],"sources":["../../src/shared/decisionSuggestions.ts","../../src/client/copy/components/components/sdk/commands.ts","../../src/client/components/sdk/commands.tsx","../../src/client/copy/record/components/DecisionChip.ts","../../src/client/components/DecisionChip.tsx"],"sourcesContent":["/**\n * A decision as the person reading a record meets it (server/http/decisionRoutes.ts serves these): a suggestion at a\n * field, a list row's mark, and \"Why this?\". Confidence is said in words; the percent is \"Why this?\"'s alone.\n */\n\n/** One waiting suggestion, as a record's field shows it. */\nexport interface FieldSuggestion {\n readonly id: string;\n readonly decision: string;\n readonly field: string;\n readonly command: string;\n readonly answer: unknown;\n /** What the answer is called: a reference's record by its label, a choice as itself. */\n readonly label: string;\n readonly probability: number;\n /** The field held a value when it was asked: the suggestion trails that value rather than standing in its place. */\n readonly filled: boolean;\n readonly at: string;\n}\n\n/** A list row with a suggestion waiting on an empty field: the row's place among the keys asked, the field, the answer's words. */\nexport interface DecisionMark {\n readonly row: number;\n readonly field: string;\n readonly label: string;\n}\n\nexport interface DecisionWhy {\n readonly decision: string;\n readonly question: string;\n /** The inputs it was asked with, by name, with the value each holds now where this reader may read it. */\n readonly inputs: readonly Readonly<{ name: string; label: string; value?: unknown; readable: boolean }>[];\n readonly provider: string;\n readonly model: string;\n readonly modelVersion: string;\n readonly probability: number | null;\n readonly outcome: string;\n readonly at: string;\n}\n\ntype Confidence = 'almostCertain' | 'veryLikely' | 'likely' | 'possible';\n\n/** A probability in words (design §7): at least 0.95 almost certain, 0.85 very likely, 0.70 likely, below that possible. */\nexport function confidenceOf(probability: number): Confidence {\n return probability >= 0.95 ? 'almostCertain' : probability >= 0.85 ? 'veryLikely' : probability >= 0.7 ? 'likely' : 'possible';\n}\n\n/** The words in English, for what the server writes down itself: an applied value's history line names its decision and how sure it was. */\nexport const CONFIDENCE_WORDS: Readonly<Record<Confidence, string>> = Object.freeze({\n almostCertain: 'almost certain',\n veryLikely: 'very likely',\n likely: 'likely',\n possible: 'possible',\n});\n","/** What sdk/commands says, in the custom components room (packages/kit/src/client/messages.ts says how the catalog is split). */\nimport { defineMessages } from '@mistriwork/kit/client/messages.js';\n\nexport const say = defineMessages({\n theRecordHanded: 'The record handed to \"{label}\" has no {column}.',\n isNotAvailableOnThisRecord: '{label} is not available on this record now.',\n isNotSomethingYouCanDo: '{label} is not something you can do here.',\n signInToDo: 'Sign in to do that.',\n this: 'This',\n notConfirmed: '{label} was sent, and its result is not confirmed. Check the record before you send it again.',\n});\n","/**\n * The page's side of `useCommand`: a command a component names, found among\n * the App's own actions for this reader, run through the one command\n * pipeline the action bar uses (commandState.ts) and opened in its own form\n * (CommandForm.tsx). Nothing here is a write of its own: a run is prepared\n * for the record's revision, sent once under a request key and refused in\n * the server's words; an unconfirmed one is handed to the form, whose Check\n * result and Retry are the only ways on.\n *\n * Registered on the page's bridge when loaded (with the list and queue\n * code, useBulkSelection.tsx), never imported by the SDK's host: it draws\n * the command form, whose fields may be components, which the host loads.\n *\n * Found through an action because an action is where the App offers a\n * command to a reader: its label, its inputs as the form draws them, and\n * whether this reader is served it at all (`grantedCommands`). A command no\n * action offers is reached through the signed-in form that does, if one\n * does: it names no record (`targets: 'none'`), so it is sent as its form\n * sends it, with an empty key. A granted command that names no record and\n * that no form runs is served by name (`formCommands`), and its\n * form is drawn from its own inputs. A command on a record that no action\n * offers is not one a component can reach; one only a component runs is an\n * action with `header: false`, offered in no menu.\n */\nimport { createElement } from 'react';\nimport type { AppCommandAction } from '../../../shared/app.js';\nimport { humanName } from '@mistriwork/engine/shared/model.js';\nimport type { AppCommandField, AppFormCommandReference } from '../../../shared/command.js';\nimport { findTable, go, pageView, primaryKey, state, toast } from '@mistriwork/kit/client/core.js';\nimport { commandOperations, type CommandOperation, type CommandOwner } from '../../commandState.js';\nimport { sendCommand } from '../../commandSend.js';\nimport { commandAvailable, useCommandAvailability } from '../../commandAvailability.js';\nimport { sessionIdentity, subscribeSessionIdentity } from '@mistriwork/kit/client/sessionIdentity.js';\nimport { pageBridge, registerCommandHost } from '@mistriwork/kit/client/uiBridge.js';\nimport { formAt, formPageId, type ServedForm as RoomForm } from '@mistriwork/kit/client/components/appRooms.js';\nimport type { AppPayloadApp } from '../../../shared/appPayload.js';\n\n/** A signed-in form as the App serves it: the whole form, which the kit's room type reads only part of. */\ntype ServedForm = RoomForm<AppPayloadApp>;\nimport { onDemand } from '@mistriwork/kit/client/components/onDemand.js';\nimport { commandInput, prefilledCommandValues, readyToJudge } from '../CommandFields.js';\nimport { mount, queryClient } from '@mistriwork/kit/client/components/mount.js';\nimport type { UiChoice, UiCommandHandle, UiCommandOptions, UiCommandOutcome, UiCommandRef } from './context.js';\nimport { say } from '../../copy/components/components/sdk/commands.js';\nimport { portalRoot } from '@mistriwork/kit/client/shellHost.js';\n\nconst CommandForm = onDemand(() => import('../CommandForm.js'), 'CommandForm', { quiet: true });\n\ninterface ServedApp {\n resources?: Record<string, { actions?: Array<{ label: string; command?: unknown }> }>;\n grantedCommands?: string[];\n formCommands?: Record<string, AppFormCommandReference>;\n}\n\n/** The action that offers this command, for this reader: the first whose command it is. */\nexport function actionOf(id: UiCommandRef): AppCommandAction | undefined {\n const app = pageBridge.activeApp() as ServedApp | null;\n for (const resource of Object.values(app?.resources ?? {})) {\n for (const action of resource.actions ?? []) {\n const command = action.command as AppCommandAction['command'] | undefined;\n if (command?.id === id) return action as AppCommandAction;\n }\n }\n return undefined;\n}\n\n/** The signed-in form this reader is served over this command, where no action offers it. */\nfunction formOf(id: UiCommandRef): { form: ServedForm; appName: string } | undefined {\n const app = pageBridge.activeApp() as (ServedApp & { name?: string; views?: Record<string, { command?: { id?: unknown } }> }) | null;\n for (const [view, served] of Object.entries(app?.views ?? {})) {\n if (served.command?.id !== id) continue;\n const form = formAt(app as unknown as AppPayloadApp, formPageId(view));\n if (form && !form.error) return { form, appName: app?.name ?? '' };\n }\n return undefined;\n}\n\n/* A granted command that names no record and that no form runs: its own form, drawn from its inputs, under\n its name — or the word the component gives it. */\nfunction unformedOf(id: UiCommandRef): { form: ServedForm; appName: string } | undefined {\n const app = pageBridge.activeApp() as (ServedApp & { name?: string }) | null;\n const command = app?.formCommands && Object.hasOwn(app.formCommands, id) ? app.formCommands[id] : undefined;\n return command && { form: { id, label: humanName(id), command } as ServedForm, appName: app?.name ?? '' };\n}\n\n/* A served form under the word the component gives it, where it gives one. */\nconst labelled = (served: { form: ServedForm; appName: string }, options?: UiCommandOptions) =>\n options?.label ? { ...served, form: { ...served.form, label: options.label } } : served;\n\n/* A form's command run as its form's submit would (formCommandRun.ts): fetched as the handle is made, so the App's\n first paint does not carry it. */\nconst formRun = () => import('./formCommandRun.js');\n\n/** The form itself over the page, filled with what was given; it settles as closed, its own Done saying what it sent. */\nasync function openFormCommand(\n served: { form: ServedForm; appName: string },\n input: Readonly<Record<string, unknown>> | undefined,\n): Promise<UiCommandOutcome> {\n const { SignedInFormDialog } = await import('../SignedInFormDialog.js');\n return new Promise((resolve) => {\n const host = document.createElement('div');\n portalRoot().append(host);\n const take = mount(\n host,\n createElement(SignedInFormDialog, {\n form: served.form,\n appName: served.appName,\n // Every field the component gave, as typed values: not an address, which only a `prefillable` field reads.\n ...(input ? { initial: input } : {}),\n onClose: () => {\n take();\n host.remove();\n resolve({ status: 'closed' });\n },\n }),\n );\n });\n}\n\n/** The record's key, as the command's target names it: its primary key columns, each a string or a safe integer. */\nfunction keyFor(action: AppCommandAction, record: Readonly<Record<string, unknown>>): Record<string, string | number> {\n const table = findTable(action.command.target);\n const columns = table ? (primaryKey(table) as string[]) : Object.keys(record);\n const key: Record<string, string | number> = {};\n for (const column of columns) {\n const value = record[column];\n if (typeof value === 'string' || (typeof value === 'number' && Number.isSafeInteger(value))) key[column] = value;\n else throw new Error(say('theRecordHanded', { label: action.label, column }));\n }\n return key;\n}\n\nconst ownerFor = (action: AppCommandAction, key: Record<string, unknown>): CommandOwner => ({\n connection: state.activeConnection ?? '',\n target: action.command.target,\n command: action.command.id,\n commandVersion: action.command.version,\n key,\n});\n\n/** How an operation the pipeline settled ended, for the component that ran it. */\nfunction outcomeOf(operation: CommandOperation | undefined): UiCommandOutcome {\n // The command's own words, when its output said any, go back with it: a caller with no form to say them in says them.\n // So does the output itself: a component acts on what it made (the ticket it opened) by its id, not by looking it up.\n if (operation?.phase === 'success')\n return {\n status: 'applied',\n ...(operation.said ? { message: operation.said } : {}),\n ...(operation.output !== undefined ? { output: operation.output } : {}),\n };\n if (operation?.phase === 'error') return { status: 'refused', message: operation.message };\n return { status: 'closed' };\n}\n\n/** The platform's own form over the page, resolved when it closes. */\nfunction openForm(\n action: AppCommandAction,\n key: Record<string, unknown>,\n input: Readonly<Record<string, unknown>> | undefined,\n options: UiCommandOptions = {},\n): Promise<UiCommandOutcome> {\n return new Promise((resolve) => {\n const host = document.createElement('div');\n host.className = 'custom-command-host';\n portalRoot().append(host);\n let take = () => {};\n let leave = () => {};\n const close = (settled?: CommandOperation) => {\n leave();\n take();\n host.remove();\n resolve(outcomeOf(settled));\n };\n /* The form belongs to the session it opened under and draws nothing once the tab's session is taken again (a\n tenant context chosen again after a cut request): it could never close, and the run waited on it for good — a\n composer said Sending… with no word. It lets go instead, saying what is not known. */\n const opened = sessionIdentity();\n // Held now: a new session forgets every operation before this hears of it (commandState.ts).\n const owned = commandOperations.get(ownerFor(action, key));\n leave = subscribeSessionIdentity(() => {\n if (sessionIdentity() === opened) return;\n if (owned?.phase === 'pending' || owned?.phase === 'unknown')\n toast(say('notConfirmed', { label: options.label || action.label }), 'error');\n close();\n });\n take = mount(\n host,\n createElement(CommandForm, {\n action,\n owner: ownerFor(action, key),\n label: options.label ?? '',\n initial: input,\n headless: true,\n onClose: close,\n onDone: () => {\n void queryClient.invalidateQueries();\n },\n }),\n );\n });\n}\n\nconst STALE_TRIES = 3;\n\n/**\n * Send it with this input, as the form's submit would: prepared for the\n * record's revision, checked by the form's own rules (an incomplete or\n * invalid input opens the form instead, filled with it), sent once. A\n * refusal is said in the server's words, as the action bar says one; an\n * answer that did not arrive is the form's to resolve.\n */\nasync function runCommand(\n action: AppCommandAction,\n key: Record<string, string | number>,\n input: Readonly<Record<string, unknown>> | undefined,\n options: UiCommandOptions,\n): Promise<UiCommandOutcome> {\n const fields = action.command.input;\n const judging = readyToJudge(fields);\n if (judging) await judging;\n let values: Record<string, unknown>;\n try {\n values = commandInput(fields, prefilledCommandValues(fields, input ?? {}));\n } catch {\n return openForm(action, key, input, options);\n }\n const owner = ownerFor(action, key);\n const before = commandOperations.get(owner);\n if (before?.phase === 'pending' || before?.phase === 'unknown') return openForm(action, key, input, options);\n if (before) commandOperations.forget(owner);\n /* The record is prepared here, not shown: a change another person made between this prepare and the send (live\n sync keeps a busy record changing) refused a reply nobody had judged against either revision. Prepared again and\n sent again, a few times: the refusal was definite, so nothing ran twice. */\n let sent: Awaited<ReturnType<typeof sendCommand>>;\n for (let tries = 1; ; tries++) {\n sent = await sendCommand(action, owner, values, {\n headless: true,\n refresh: () => {\n void queryClient.invalidateQueries();\n },\n });\n if ('refused' in sent || sent.operation.phase !== 'error' || sent.operation.code !== 'stale_record' || tries === STALE_TRIES) break;\n commandOperations.forget(owner);\n }\n if ('refused' in sent) {\n const message = sent.refused || say('isNotAvailableOnThisRecord', { label: action.label });\n toast(message, 'error');\n return { status: 'refused', message };\n }\n const { operation } = sent;\n if (operation.phase === 'unknown' || operation.phase === 'pending') return openForm(action, key, input, options);\n const outcome = outcomeOf(operation);\n commandOperations.forget(owner);\n if (outcome.status === 'refused') toast(outcome.message, 'error');\n return outcome;\n}\n\n/* A public form over the page, fetched the first time a component opens one: it draws command fields too. */\nasync function openPublicForm(view: string, prefill: Readonly<Record<string, string | number>>, appId?: string): Promise<void> {\n const { FormDialog } = await import('../FormDialog.js');\n const host = document.createElement('div');\n portalRoot().append(host);\n const query = new URLSearchParams(Object.entries(prefill).map(([name, value]) => [name, String(value)])).toString();\n const take = mount(\n host,\n createElement(FormDialog, {\n view,\n appId,\n prefill: query,\n onClose: () => {\n take();\n host.remove();\n },\n }),\n );\n}\n\n/* A signed-in form over the page, fetched the first time a component opens one; Cancel, Done or Escape\n leave the reader where they were, and what the submit changed is read again there. */\nasync function openSignedInForm(form: ServedForm, appName: string, prefill: Readonly<Record<string, string | number>>): Promise<void> {\n const { SignedInFormDialog } = await import('../SignedInFormDialog.js');\n const host = document.createElement('div');\n portalRoot().append(host);\n const query = new URLSearchParams(Object.entries(prefill).map(([name, value]) => [name, String(value)])).toString();\n const take = mount(\n host,\n createElement(SignedInFormDialog, {\n form,\n appName,\n prefill: query,\n onClose: () => {\n take();\n host.remove();\n },\n }),\n );\n}\n\n/* One of the App's forms, over the page the component is on: a signed-in form the reader is served, as its\n room draws it, and a public form, which the App serves at its own address and never in its views, from\n there — each with its prefillable inputs filled. A signed-in form without its room's form (not served to\n this reader) is its room, which says so. */\nfunction openViewForm(view: string, prefill: Readonly<Record<string, string | number>>): void {\n const app = pageBridge.activeApp() as (ServedApp & { id?: string; name?: string; views?: Record<string, { command?: unknown }> }) | null;\n if (app?.views && Object.hasOwn(app.views, view) && app.views[view].command) {\n const form = formAt(app as unknown as AppPayloadApp, formPageId(view));\n if (form && !form.error) {\n void openSignedInForm(form, app.name ?? '', prefill);\n return;\n }\n go(pageView(formPageId(view)));\n return;\n }\n void openPublicForm(view, prefill, app?.id);\n}\n\n/** The choices an input of `input` offers as served: a choice's options — a table's rows where they were served with\n it — or undefined for a field that offers none, or none yet. */\nfunction servedChoices(input: readonly AppCommandField[] | undefined, name: string): readonly UiChoice[] | undefined {\n const field = input?.find((each) => each.name === name);\n if (!field || (field.type !== 'choice' && field.type !== 'choices') || !field.options.length) return undefined;\n return field.options.map((option) => ({ value: option.value, label: option.label }));\n}\n\n/* A public page's command, its module fetched as the handle is made (publicPageCommand.ts): the App's first paint does\n not carry the door, and the page's ticket is still asked at once, so it has aged by the time a person submits. */\nfunction publicPageHandle(page: string, id: string, reference: AppFormCommandReference): UiCommandHandle {\n const door = import('./publicPageCommand.js').then(({ publicPageCommand }) => publicPageCommand(page, id, reference));\n return {\n label: humanName(id),\n granted: true,\n available: async () => true,\n run: (record, input, options) => door.then((handle) => handle.run(record, input, options)),\n open: (record, input, options) => door.then((handle) => handle.open(record, input, options)),\n choices: (field) => servedChoices(reference.input, field),\n };\n}\n\n/** The command a component named, as this reader is served it; on a public page, a public command it names runs\n through the page's own door (publicPageCommand.ts), whoever is signed in. */\nexport function commandHandle(ref: UiCommandRef, page?: string): UiCommandHandle {\n const publicCommands = (pageBridge.activeApp() as { publicCommands?: Record<string, AppFormCommandReference> } | null)?.publicCommands;\n if (page !== undefined && publicCommands && Object.hasOwn(publicCommands, ref)) return publicPageHandle(page, ref, publicCommands[ref]);\n const action = actionOf(ref);\n const identity = sessionIdentity();\n const served = action ? undefined : (formOf(ref) ?? unformedOf(ref));\n if (served) {\n const granted =\n identity.mode === 'authenticated' && ((pageBridge.activeApp() as ServedApp | null)?.grantedCommands ?? []).includes(ref);\n const refuse = (): Promise<UiCommandOutcome> => {\n const message = identity.mode === 'authenticated' ? say('isNotSomethingYouCanDo', { label: served.form.label }) : say('signInToDo');\n toast(message, 'error');\n return Promise.resolve({ status: 'refused', message });\n };\n if (granted) void formRun();\n // No record to ask about: granted is available, and the record a caller hands in is not read.\n return {\n label: served.form.label,\n granted,\n available: async () => granted,\n run: (_record, input, options) =>\n granted\n ? formRun().then(({ runFormCommand }) => runFormCommand(labelled(served, options), input, options, openFormCommand))\n : refuse(),\n open: (_record, input, options) => (granted ? openFormCommand(labelled(served, options), input) : refuse()),\n choices: (field) => servedChoices(served.form.command.input, field),\n };\n }\n const granted =\n Boolean(action) &&\n identity.mode === 'authenticated' &&\n ((pageBridge.activeApp() as ServedApp | null)?.grantedCommands ?? []).includes(action!.command.id);\n const refuse = (): Promise<UiCommandOutcome> => {\n const message =\n identity.mode === 'authenticated' ? say('isNotSomethingYouCanDo', { label: action?.label ?? say('this') }) : say('signInToDo');\n toast(message, 'error');\n return Promise.resolve({ status: 'refused', message });\n };\n return {\n label: action?.label ?? ref,\n granted,\n available: async (record) => {\n if (!granted) return false;\n try {\n return await commandAvailable({\n command: action!.command.id,\n commandVersion: action!.command.version,\n key: keyFor(action!, record),\n });\n } catch {\n return false;\n }\n },\n run: (record, input, options = {}) => (granted ? runCommand(action!, keyFor(action!, record), input, options) : refuse()),\n open: (record, input, options = {}) => (granted ? openForm(action!, keyFor(action!, record), input, options) : refuse()),\n choices: (field) => servedChoices(action?.command.input, field),\n };\n}\n\n/**\n * A command the App names outside any action (a tag picker's add and remove,\n * G58), run on one record as an action's button would, if this reader is\n * granted it; undefined when it is not, so the caller draws nothing to press.\n */\nexport function recordCommand(\n command: AppCommandAction['command'],\n label: string,\n): ((key: Record<string, string | number>, input: Readonly<Record<string, unknown>>) => Promise<UiCommandOutcome>) | undefined {\n const granted =\n sessionIdentity().mode === 'authenticated' &&\n ((pageBridge.activeApp() as ServedApp | null)?.grantedCommands ?? []).includes(command.id);\n if (!granted) return undefined;\n const action = { id: command.id, label, command } as AppCommandAction;\n return (key, input) => runCommand(action, key, input, {});\n}\n\n/** A selection's commands in the kit's lists (shellMode.ts `bulkCommands`): the same pipeline and form, sent once for the group. */\nexport const bulkCommands = { operations: commandOperations, useAvailability: useCommandAvailability, Form: CommandForm };\n\nregisterCommandHost({ command: commandHandle, openForm: openViewForm });\n","/** What a decision's suggestion says at a record's field (packages/kit/src/client/messages.ts says how the catalog is split). */\nimport { defineMessages } from '@mistriwork/kit/client/messages.js';\n\nexport const say = defineMessages({\n almostCertain: 'almost certain',\n veryLikely: 'very likely',\n likely: 'likely',\n possible: 'possible',\n suggestion: 'Suggested: {value}, {confidence}',\n accept: 'Accept',\n more: 'More about the suggestion {value}',\n change: 'Change…',\n dismiss: 'Dismiss',\n whyThis: 'Why this?',\n whyTitle: 'Why {value}?',\n asked: 'Asked',\n inputs: 'What it was given',\n notYours: 'not shown to you',\n answeredBy: 'Answered by',\n sure: 'How sure',\n when: 'When',\n close: 'Close',\n couldNotSettle: 'The suggestion could not be updated. Try again.',\n reading: 'Reading…',\n});\n","/**\n * A decision's suggestion at a record's field (design §7): the answer in muted ink and how sure it was in a word,\n * Accept (quiet) and ⋯ — Change…, Dismiss, Why this?. In the empty mark's place on an empty field, trailing the value\n * on a filled one; the same height either way, so nothing moves when it arrives or goes.\n *\n * Accept and Change… run the answer command as the person, through the one command pipeline (sdk/commands.tsx):\n * their grants, their click. What landed is then told to the server, which reads the record to see whether it was\n * the suggestion or something else. A reader not granted the command sees the suggestion and why, and nothing to press.\n */\nimport { useRef, useState } from 'react';\nimport { useQuery } from '@tanstack/react-query';\nimport { Button } from '@mistriwork/ui/Button.js';\nimport { DropItem, DropMenu } from '@mistriwork/ui/DropMenu.js';\nimport { Modal } from '@mistriwork/ui/Modal.js';\nimport { api, findTable, toast } from '@mistriwork/kit/client/core.js';\nimport { formatDateTime } from '@mistriwork/kit/client/locale.js';\nimport { Value } from '@mistriwork/kit/client/components/Value.js';\nimport type { ColumnMeta, TableMeta } from '@mistriwork/engine/shared/schema.js';\nimport { confidenceOf, type DecisionWhy, type FieldSuggestion } from '../../shared/decisionSuggestions.js';\nimport { commandHandle } from './sdk/commands.js';\nimport { say } from '../copy/record/components/DecisionChip.js';\nimport './DecisionChip.css';\n\n/* The confidence in words (design: a percent only in \"Why this?\"), each said by its key so the catalog knows it is. */\nconst sayConfidence = (probability: number): string =>\n ({ almostCertain: say('almostCertain'), veryLikely: say('veryLikely'), likely: say('likely'), possible: say('possible') })[\n confidenceOf(probability)\n ];\n\nexport default function DecisionChip({\n suggestion,\n table,\n recordKey,\n onSettled,\n}: {\n suggestion: FieldSuggestion;\n table: string;\n recordKey: Readonly<Record<string, unknown>>;\n /** The suggestion moved on (accepted, corrected, dismissed): the record and its suggestions are asked again. */\n onSettled: () => void;\n}) {\n const [busy, setBusy] = useState(false);\n const [why, setWhy] = useState(false);\n const more = useRef<HTMLButtonElement>(null);\n const handle = commandHandle(suggestion.command);\n const confidence = sayConfidence(suggestion.probability);\n const settle = async (action: 'done' | 'dismiss') => {\n try {\n await api('/api/record-decisions/settle', { id: suggestion.id, action });\n } catch {\n toast(say('couldNotSettle'), 'error');\n }\n onSettled();\n };\n const run = async (how: 'run' | 'open') => {\n setBusy(true);\n try {\n const outcome = await handle[how](recordKey, { [suggestion.field]: suggestion.answer });\n if (outcome.status === 'applied') await settle('done');\n } finally {\n setBusy(false);\n }\n };\n return (\n <span className={`decision-chip${suggestion.filled ? ' decision-chip-trailing' : ''}`}>\n <span className=\"decision-chip-value\" aria-label={say('suggestion', { value: suggestion.label, confidence })}>\n <span aria-hidden=\"true\">{suggestion.label}</span>\n <span className=\"decision-chip-word\" aria-hidden=\"true\">\n {confidence}\n </span>\n </span>\n {handle.granted && (\n <Button intent=\"quiet\" size=\"compact\" className=\"decision-chip-accept\" busy={busy} onClick={() => void run('run')}>\n {say('accept')}\n </Button>\n )}\n <DropMenu\n className=\"decision-chip-menu\"\n triggerClassName=\"decision-chip-more\"\n triggerLabel={say('more', { value: suggestion.label })}\n triggerTitle={say('more', { value: suggestion.label })}\n label=\"⋯\"\n popupClassName=\"page-actions-popup\"\n align=\"start\"\n finalFocus={more}\n >\n {handle.granted && (\n <DropItem className=\"page-actions-item\" disabled={busy} onClick={() => void run('open')}>\n {say('change')}\n </DropItem>\n )}\n {handle.granted && (\n <DropItem className=\"page-actions-item\" disabled={busy} onClick={() => void settle('dismiss')}>\n {say('dismiss')}\n </DropItem>\n )}\n <DropItem className=\"page-actions-item\" onClick={() => setWhy(true)}>\n {say('whyThis')}\n </DropItem>\n </DropMenu>\n {why && <WhyThis suggestion={suggestion} table={table} onClose={() => setWhy(false)} />}\n </span>\n );\n}\n\n/** What was asked, of whom, how surely and when: the inputs by name with what this reader may read of them now. No reasoning. */\nfunction WhyThis({ suggestion, table, onClose }: { suggestion: FieldSuggestion; table: string; onClose: () => void }) {\n const asked = useQuery({\n queryKey: ['record-decision-why', suggestion.id],\n queryFn: async () => (await api('/api/record-decisions/why', { id: suggestion.id })) as DecisionWhy,\n staleTime: 60_000,\n });\n const meta = findTable(table) as TableMeta | undefined;\n const column = (name: string): ColumnMeta =>\n meta?.columns.find((each) => each.name === name) ?? ({ name, type: 'TEXT', nullable: true, primaryKey: false } as ColumnMeta);\n const reason = asked.data;\n return (\n <Modal className=\"decision-why\" ariaLabel={say('whyTitle', { value: suggestion.label })} onClose={onClose} fullscreen={false}>\n <h2>{say('whyTitle', { value: suggestion.label })}</h2>\n {!reason ? (\n <p className=\"note\">{say('reading')}</p>\n ) : (\n <dl className=\"decision-why-facts\">\n <div>\n <dt>{say('asked')}</dt>\n <dd>{reason.question}</dd>\n </div>\n <div>\n <dt>{say('inputs')}</dt>\n <dd>\n <dl className=\"decision-why-inputs\">\n {reason.inputs.map((input) => (\n <div key={input.name}>\n <dt>{input.label}</dt>\n <dd>\n {input.readable ? (\n <Value col={column(input.name)} value={input.value} tableId={table} compact links={false} />\n ) : (\n <span className=\"decision-why-hidden\">{say('notYours')}</span>\n )}\n </dd>\n </div>\n ))}\n </dl>\n </dd>\n </div>\n <div>\n <dt>{say('answeredBy')}</dt>\n <dd>{[reason.provider, reason.model, reason.modelVersion].filter(Boolean).join(' · ')}</dd>\n </div>\n {reason.probability !== null && (\n <div>\n <dt>{say('sure')}</dt>\n <dd>{`${Math.round(reason.probability * 100)}% · ${sayConfidence(reason.probability)}`}</dd>\n </div>\n )}\n <div>\n <dt>{say('when')}</dt>\n <dd>{formatDateTime(reason.at)}</dd>\n </div>\n </dl>\n )}\n <div className=\"decision-why-actions\">\n <Button onClick={onClose}>{say('close')}</Button>\n </div>\n </Modal>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"shared-DUPMRoO0.js","names":["say","say"],"sources":["../../src/shared/decisionSuggestions.ts","../../src/client/copy/components/components/sdk/commands.ts","../../src/client/components/sdk/commands.tsx","../../src/client/copy/record/components/DecisionChip.ts","../../src/client/components/DecisionChip.tsx"],"sourcesContent":["/**\n * A decision as the person reading a record meets it (server/http/decisionRoutes.ts serves these): a suggestion at a\n * field, a list row's mark, and \"Why this?\". Confidence is said in words; the percent is \"Why this?\"'s alone.\n */\n\n/** One waiting suggestion, as a record's field shows it. */\nexport interface FieldSuggestion {\n readonly id: string;\n readonly decision: string;\n readonly field: string;\n readonly command: string;\n readonly answer: unknown;\n /** What the answer is called: a reference's record by its label, a choice as itself. */\n readonly label: string;\n readonly probability: number;\n /** The field held a value when it was asked: the suggestion trails that value rather than standing in its place. */\n readonly filled: boolean;\n readonly at: string;\n}\n\n/** A list row with a suggestion waiting on an empty field: the row's place among the keys asked, the field, the answer's words. */\nexport interface DecisionMark {\n readonly row: number;\n readonly field: string;\n readonly label: string;\n}\n\nexport interface DecisionWhy {\n readonly decision: string;\n readonly question: string;\n /** The inputs it was asked with, by name, with the value each holds now where this reader may read it. */\n readonly inputs: readonly Readonly<{ name: string; label: string; value?: unknown; readable: boolean }>[];\n readonly provider: string;\n readonly model: string;\n readonly modelVersion: string;\n readonly probability: number | null;\n readonly outcome: string;\n readonly at: string;\n}\n\ntype Confidence = 'almostCertain' | 'veryLikely' | 'likely' | 'possible';\n\n/** A probability in words (design §7): at least 0.95 almost certain, 0.85 very likely, 0.70 likely, below that possible. */\nexport function confidenceOf(probability: number): Confidence {\n return probability >= 0.95 ? 'almostCertain' : probability >= 0.85 ? 'veryLikely' : probability >= 0.7 ? 'likely' : 'possible';\n}\n\n/** The words in English, for what the server writes down itself: an applied value's history line names its decision and how sure it was. */\nexport const CONFIDENCE_WORDS: Readonly<Record<Confidence, string>> = Object.freeze({\n almostCertain: 'almost certain',\n veryLikely: 'very likely',\n likely: 'likely',\n possible: 'possible',\n});\n","/** What sdk/commands says, in the custom components room (packages/kit/src/client/messages.ts says how the catalog is split). */\nimport { defineMessages } from '@mistriwork/kit/client/messages.js';\n\nexport const say = defineMessages({\n theRecordHanded: 'The record handed to \"{label}\" has no {column}.',\n isNotAvailableOnThisRecord: '{label} is not available on this record now.',\n isNotSomethingYouCanDo: '{label} is not something you can do here.',\n signInToDo: 'Sign in to do that.',\n this: 'This',\n notConfirmed: '{label} was sent, and its result is not confirmed. Check the record before you send it again.',\n});\n","/**\n * The page's side of `useCommand`: a command a component names, found among\n * the App's own actions for this reader, run through the one command\n * pipeline the action bar uses (commandState.ts) and opened in its own form\n * (CommandForm.tsx). Nothing here is a write of its own: a run is prepared\n * for the record's revision, sent once under a request key and refused in\n * the server's words; an unconfirmed one is handed to the form, whose Check\n * result and Retry are the only ways on.\n *\n * Registered on the page's bridge when loaded (with the list and queue\n * code, useBulkSelection.tsx), never imported by the SDK's host: it draws\n * the command form, whose fields may be components, which the host loads.\n *\n * Found through an action because an action is where the App offers a\n * command to a reader: its label, its inputs as the form draws them, and\n * whether this reader is served it at all (`grantedCommands`). A command no\n * action offers is reached through the signed-in form that does, if one\n * does: it names no record (`targets: 'none'`), so it is sent as its form\n * sends it, with an empty key. A granted command that names no record and\n * that no form runs is served by name (`formCommands`), and its\n * form is drawn from its own inputs. A command on a record that no action\n * offers is not one a component can reach; one only a component runs is an\n * action with `header: false`, offered in no menu.\n */\nimport { createElement } from 'react';\nimport type { AppCommandAction } from '../../../shared/app.js';\nimport { humanName } from '@mistriwork/engine/shared/model.js';\nimport type { AppCommandField, AppFormCommandReference } from '../../../shared/command.js';\nimport { findTable, go, pageView, primaryKey, state, toast } from '@mistriwork/kit/client/core.js';\nimport { commandOperations, type CommandOperation, type CommandOwner } from '../../commandState.js';\nimport { sendCommand } from '../../commandSend.js';\nimport { commandAvailable, useCommandAvailability } from '../../commandAvailability.js';\nimport { sessionIdentity, subscribeSessionIdentity } from '@mistriwork/kit/client/sessionIdentity.js';\nimport { pageBridge, registerCommandHost } from '@mistriwork/kit/client/uiBridge.js';\nimport { formAt, formPageId, type ServedForm as RoomForm } from '@mistriwork/kit/client/components/appRooms.js';\nimport type { AppPayloadApp } from '../../../shared/appPayload.js';\n\n/** A signed-in form as the App serves it: the whole form, which the kit's room type reads only part of. */\ntype ServedForm = RoomForm<AppPayloadApp>;\nimport { onDemand } from '@mistriwork/kit/client/components/onDemand.js';\nimport { commandInput, prefilledCommandValues, readyToJudge } from '../CommandFields.js';\nimport { mount, queryClient } from '@mistriwork/kit/client/components/mount.js';\nimport type { UiChoice, UiCommandHandle, UiCommandOptions, UiCommandOutcome, UiCommandRef } from './context.js';\nimport { say } from '../../copy/components/components/sdk/commands.js';\nimport { portalRoot } from '@mistriwork/kit/client/shellHost.js';\n\nconst CommandForm = onDemand(() => import('../CommandForm.js'), 'CommandForm', { quiet: true });\n\ninterface ServedApp {\n resources?: Record<string, { actions?: Array<{ label: string; command?: unknown }> }>;\n grantedCommands?: string[];\n formCommands?: Record<string, AppFormCommandReference>;\n}\n\n/** The action that offers this command, for this reader: the first whose command it is. */\nexport function actionOf(id: UiCommandRef): AppCommandAction | undefined {\n const app = pageBridge.activeApp() as ServedApp | null;\n for (const resource of Object.values(app?.resources ?? {})) {\n for (const action of resource.actions ?? []) {\n const command = action.command as AppCommandAction['command'] | undefined;\n if (command?.id === id) return action as AppCommandAction;\n }\n }\n return undefined;\n}\n\n/** The signed-in form this reader is served over this command, where no action offers it. */\nfunction formOf(id: UiCommandRef): { form: ServedForm; appName: string } | undefined {\n const app = pageBridge.activeApp() as (ServedApp & { name?: string; views?: Record<string, { command?: { id?: unknown } }> }) | null;\n for (const [view, served] of Object.entries(app?.views ?? {})) {\n if (served.command?.id !== id) continue;\n const form = formAt(app as unknown as AppPayloadApp, formPageId(view));\n if (form && !form.error) return { form, appName: app?.name ?? '' };\n }\n return undefined;\n}\n\n/* A granted command that names no record and that no form runs: its own form, drawn from its inputs, under\n its name — or the word the component gives it. */\nfunction unformedOf(id: UiCommandRef): { form: ServedForm; appName: string } | undefined {\n const app = pageBridge.activeApp() as (ServedApp & { name?: string }) | null;\n const command = app?.formCommands && Object.hasOwn(app.formCommands, id) ? app.formCommands[id] : undefined;\n return command && { form: { id, label: humanName(id), command } as ServedForm, appName: app?.name ?? '' };\n}\n\n/* A served form under the word the component gives it, where it gives one. */\nconst labelled = (served: { form: ServedForm; appName: string }, options?: UiCommandOptions) =>\n options?.label ? { ...served, form: { ...served.form, label: options.label } } : served;\n\n/* A form's command run as its form's submit would (formCommandRun.ts): fetched as the handle is made, so the App's\n first paint does not carry it. */\nconst formRun = () => import('./formCommandRun.js');\n\n/** The form itself over the page, filled with what was given; it settles as closed, its own Done saying what it sent. */\nasync function openFormCommand(\n served: { form: ServedForm; appName: string },\n input: Readonly<Record<string, unknown>> | undefined,\n): Promise<UiCommandOutcome> {\n const { SignedInFormDialog } = await import('../SignedInFormDialog.js');\n return new Promise((resolve) => {\n const host = document.createElement('div');\n portalRoot().append(host);\n const take = mount(\n host,\n createElement(SignedInFormDialog, {\n form: served.form,\n appName: served.appName,\n // Every field the component gave, as typed values: not an address, which only a `prefillable` field reads.\n ...(input ? { initial: input } : {}),\n onClose: () => {\n take();\n host.remove();\n resolve({ status: 'closed' });\n },\n }),\n );\n });\n}\n\n/** The record's key, as the command's target names it: its primary key columns, each a string or a safe integer. */\nfunction keyFor(action: AppCommandAction, record: Readonly<Record<string, unknown>>): Record<string, string | number> {\n const table = findTable(action.command.target);\n const columns = table ? (primaryKey(table) as string[]) : Object.keys(record);\n const key: Record<string, string | number> = {};\n for (const column of columns) {\n const value = record[column];\n if (typeof value === 'string' || (typeof value === 'number' && Number.isSafeInteger(value))) key[column] = value;\n else throw new Error(say('theRecordHanded', { label: action.label, column }));\n }\n return key;\n}\n\nconst ownerFor = (action: AppCommandAction, key: Record<string, unknown>): CommandOwner => ({\n connection: state.activeConnection ?? '',\n target: action.command.target,\n command: action.command.id,\n commandVersion: action.command.version,\n key,\n});\n\n/** How an operation the pipeline settled ended, for the component that ran it. */\nfunction outcomeOf(operation: CommandOperation | undefined): UiCommandOutcome {\n // The command's own words, when its output said any, go back with it: a caller with no form to say them in says them.\n // So does the output itself: a component acts on what it made (the ticket it opened) by its id, not by looking it up.\n if (operation?.phase === 'success')\n return {\n status: 'applied',\n ...(operation.said ? { message: operation.said } : {}),\n ...(operation.output !== undefined ? { output: operation.output } : {}),\n };\n if (operation?.phase === 'error') return { status: 'refused', message: operation.message };\n return { status: 'closed' };\n}\n\n/** The platform's own form over the page, resolved when it closes. */\nfunction openForm(\n action: AppCommandAction,\n key: Record<string, unknown>,\n input: Readonly<Record<string, unknown>> | undefined,\n options: UiCommandOptions = {},\n): Promise<UiCommandOutcome> {\n return new Promise((resolve) => {\n const host = document.createElement('div');\n host.className = 'custom-command-host';\n portalRoot().append(host);\n let take = () => {};\n let leave = () => {};\n const close = (settled?: CommandOperation) => {\n leave();\n take();\n host.remove();\n resolve(outcomeOf(settled));\n };\n /* The form belongs to the session it opened under and draws nothing once the tab's session is taken again (a\n tenant context chosen again after a cut request): it could never close, and the run waited on it for good — a\n composer said Sending… with no word. It lets go instead, saying what is not known. */\n const opened = sessionIdentity();\n // Held now: a new session forgets every operation before this hears of it (commandState.ts).\n const owned = commandOperations.get(ownerFor(action, key));\n leave = subscribeSessionIdentity(() => {\n if (sessionIdentity() === opened) return;\n if (owned?.phase === 'pending' || owned?.phase === 'unknown')\n toast(say('notConfirmed', { label: options.label || action.label }), 'error');\n close();\n });\n take = mount(\n host,\n createElement(CommandForm, {\n action,\n owner: ownerFor(action, key),\n label: options.label ?? '',\n initial: input,\n headless: true,\n onClose: close,\n onDone: () => {\n void queryClient.invalidateQueries();\n },\n }),\n );\n });\n}\n\nconst STALE_TRIES = 3;\n\n/**\n * Send it with this input, as the form's submit would: prepared for the\n * record's revision, checked by the form's own rules (an incomplete or\n * invalid input opens the form instead, filled with it), sent once. A\n * refusal is said in the server's words, as the action bar says one; an\n * answer that did not arrive is the form's to resolve.\n */\nasync function runCommand(\n action: AppCommandAction,\n key: Record<string, string | number>,\n input: Readonly<Record<string, unknown>> | undefined,\n options: UiCommandOptions,\n): Promise<UiCommandOutcome> {\n const fields = action.command.input;\n const judging = readyToJudge(fields);\n if (judging) await judging;\n let values: Record<string, unknown>;\n try {\n values = commandInput(fields, prefilledCommandValues(fields, input ?? {}));\n } catch {\n return openForm(action, key, input, options);\n }\n const owner = ownerFor(action, key);\n const before = commandOperations.get(owner);\n if (before?.phase === 'pending' || before?.phase === 'unknown') return openForm(action, key, input, options);\n if (before) commandOperations.forget(owner);\n /* The record is prepared here, not shown: a change another person made between this prepare and the send (live\n sync keeps a busy record changing) refused a reply nobody had judged against either revision. Prepared again and\n sent again, a few times: the refusal was definite, so nothing ran twice. */\n let sent: Awaited<ReturnType<typeof sendCommand>>;\n for (let tries = 1; ; tries++) {\n sent = await sendCommand(action, owner, values, {\n headless: true,\n refresh: () => {\n void queryClient.invalidateQueries();\n },\n });\n if ('refused' in sent || sent.operation.phase !== 'error' || sent.operation.code !== 'stale_record' || tries === STALE_TRIES) break;\n commandOperations.forget(owner);\n }\n if ('refused' in sent) {\n const message = sent.refused || say('isNotAvailableOnThisRecord', { label: action.label });\n toast(message, 'error');\n return { status: 'refused', message };\n }\n const { operation } = sent;\n if (operation.phase === 'unknown' || operation.phase === 'pending') return openForm(action, key, input, options);\n const outcome = outcomeOf(operation);\n commandOperations.forget(owner);\n if (outcome.status === 'refused') toast(outcome.message, 'error');\n return outcome;\n}\n\n/* A public form over the page, fetched the first time a component opens one: it draws command fields too. */\nasync function openPublicForm(view: string, prefill: Readonly<Record<string, string | number>>, appId?: string): Promise<void> {\n const { FormDialog } = await import('../FormDialog.js');\n const host = document.createElement('div');\n portalRoot().append(host);\n const query = new URLSearchParams(Object.entries(prefill).map(([name, value]) => [name, String(value)])).toString();\n const take = mount(\n host,\n createElement(FormDialog, {\n view,\n appId,\n prefill: query,\n onClose: () => {\n take();\n host.remove();\n },\n }),\n );\n}\n\n/* A signed-in form over the page, fetched the first time a component opens one; Cancel, Done or Escape\n leave the reader where they were, and what the submit changed is read again there. */\nasync function openSignedInForm(form: ServedForm, appName: string, prefill: Readonly<Record<string, string | number>>): Promise<void> {\n const { SignedInFormDialog } = await import('../SignedInFormDialog.js');\n const host = document.createElement('div');\n portalRoot().append(host);\n const query = new URLSearchParams(Object.entries(prefill).map(([name, value]) => [name, String(value)])).toString();\n const take = mount(\n host,\n createElement(SignedInFormDialog, {\n form,\n appName,\n prefill: query,\n onClose: () => {\n take();\n host.remove();\n },\n }),\n );\n}\n\n/* One of the App's forms, over the page the component is on: a signed-in form the reader is served, as its\n room draws it, and a public form, which the App serves at its own address and never in its views, from\n there — each with its prefillable inputs filled. A signed-in form without its room's form (not served to\n this reader) is its room, which says so. */\nfunction openViewForm(view: string, prefill: Readonly<Record<string, string | number>>): void {\n const app = pageBridge.activeApp() as (ServedApp & { id?: string; name?: string; views?: Record<string, { command?: unknown }> }) | null;\n if (app?.views && Object.hasOwn(app.views, view) && app.views[view].command) {\n const form = formAt(app as unknown as AppPayloadApp, formPageId(view));\n if (form && !form.error) {\n void openSignedInForm(form, app.name ?? '', prefill);\n return;\n }\n go(pageView(formPageId(view)));\n return;\n }\n void openPublicForm(view, prefill, app?.id);\n}\n\n/** The choices an input of `input` offers as served: a choice's options — a table's rows where they were served with\n it — or undefined for a field that offers none, or none yet. */\nfunction servedChoices(input: readonly AppCommandField[] | undefined, name: string): readonly UiChoice[] | undefined {\n const field = input?.find((each) => each.name === name);\n if (!field || (field.type !== 'choice' && field.type !== 'choices') || !field.options.length) return undefined;\n return field.options.map((option) => ({ value: option.value, label: option.label }));\n}\n\n/* A public page's command, its module fetched as the handle is made (publicPageCommand.ts): the App's first paint does\n not carry the door, and the page's ticket is still asked at once, so it has aged by the time a person submits. */\nfunction publicPageHandle(page: string, id: string, reference: AppFormCommandReference): UiCommandHandle {\n const door = import('./publicPageCommand.js').then(({ publicPageCommand }) => publicPageCommand(page, id, reference));\n return {\n label: humanName(id),\n granted: true,\n available: async () => true,\n run: (record, input, options) => door.then((handle) => handle.run(record, input, options)),\n open: (record, input, options) => door.then((handle) => handle.open(record, input, options)),\n choices: (field) => servedChoices(reference.input, field),\n };\n}\n\n/** The command a component named, as this reader is served it; on a public page, a public command it names runs\n through the page's own door (publicPageCommand.ts), whoever is signed in. */\nexport function commandHandle(ref: UiCommandRef, page?: string): UiCommandHandle {\n const publicCommands = (pageBridge.activeApp() as { publicCommands?: Record<string, AppFormCommandReference> } | null)?.publicCommands;\n if (page !== undefined && publicCommands && Object.hasOwn(publicCommands, ref)) return publicPageHandle(page, ref, publicCommands[ref]);\n const action = actionOf(ref);\n const identity = sessionIdentity();\n const served = action ? undefined : (formOf(ref) ?? unformedOf(ref));\n if (served) {\n const granted =\n identity.mode === 'authenticated' && ((pageBridge.activeApp() as ServedApp | null)?.grantedCommands ?? []).includes(ref);\n const refuse = (): Promise<UiCommandOutcome> => {\n const message = identity.mode === 'authenticated' ? say('isNotSomethingYouCanDo', { label: served.form.label }) : say('signInToDo');\n toast(message, 'error');\n return Promise.resolve({ status: 'refused', message });\n };\n if (granted) void formRun();\n // No record to ask about: granted is available, and the record a caller hands in is not read.\n return {\n label: served.form.label,\n granted,\n available: async () => granted,\n run: (_record, input, options) =>\n granted\n ? formRun().then(({ runFormCommand }) => runFormCommand(labelled(served, options), input, options, openFormCommand))\n : refuse(),\n open: (_record, input, options) => (granted ? openFormCommand(labelled(served, options), input) : refuse()),\n choices: (field) => servedChoices(served.form.command.input, field),\n };\n }\n const granted =\n Boolean(action) &&\n identity.mode === 'authenticated' &&\n ((pageBridge.activeApp() as ServedApp | null)?.grantedCommands ?? []).includes(action!.command.id);\n const refuse = (): Promise<UiCommandOutcome> => {\n const message =\n identity.mode === 'authenticated' ? say('isNotSomethingYouCanDo', { label: action?.label ?? say('this') }) : say('signInToDo');\n toast(message, 'error');\n return Promise.resolve({ status: 'refused', message });\n };\n return {\n label: action?.label ?? ref,\n granted,\n available: async (record) => {\n if (!granted) return false;\n try {\n return await commandAvailable({\n command: action!.command.id,\n commandVersion: action!.command.version,\n key: keyFor(action!, record),\n });\n } catch {\n return false;\n }\n },\n run: (record, input, options = {}) => (granted ? runCommand(action!, keyFor(action!, record), input, options) : refuse()),\n open: (record, input, options = {}) => (granted ? openForm(action!, keyFor(action!, record), input, options) : refuse()),\n choices: (field) => servedChoices(action?.command.input, field),\n };\n}\n\n/**\n * A command the App names outside any action (a tag picker's add and remove,\n * G58), run on one record as an action's button would, if this reader is\n * granted it; undefined when it is not, so the caller draws nothing to press.\n */\nexport function recordCommand(\n command: AppCommandAction['command'],\n label: string,\n): ((key: Record<string, string | number>, input: Readonly<Record<string, unknown>>) => Promise<UiCommandOutcome>) | undefined {\n const granted =\n sessionIdentity().mode === 'authenticated' &&\n ((pageBridge.activeApp() as ServedApp | null)?.grantedCommands ?? []).includes(command.id);\n if (!granted) return undefined;\n const action = { id: command.id, label, command } as AppCommandAction;\n return (key, input) => runCommand(action, key, input, {});\n}\n\n/** A selection's commands in the kit's lists (shellMode.ts `bulkCommands`): the same pipeline and form, sent once for the group. */\nexport const bulkCommands = { operations: commandOperations, useAvailability: useCommandAvailability, Form: CommandForm };\n\nregisterCommandHost({ command: commandHandle, openForm: openViewForm });\n","/** What a decision's suggestion says at a record's field (packages/kit/src/client/messages.ts says how the catalog is split). */\nimport { defineMessages } from '@mistriwork/kit/client/messages.js';\n\nexport const say = defineMessages({\n almostCertain: 'almost certain',\n veryLikely: 'very likely',\n likely: 'likely',\n possible: 'possible',\n suggestion: 'Suggested: {value}, {confidence}',\n accept: 'Accept',\n more: 'More about the suggestion {value}',\n change: 'Change…',\n dismiss: 'Dismiss',\n whyThis: 'Why this?',\n whyTitle: 'Why {value}?',\n asked: 'Asked',\n inputs: 'What it was given',\n notYours: 'not shown to you',\n answeredBy: 'Answered by',\n sure: 'How sure',\n when: 'When',\n close: 'Close',\n couldNotSettle: 'The suggestion could not be updated. Try again.',\n reading: 'Reading…',\n});\n","/**\n * A decision's suggestion at a record's field (design §7): the answer in muted ink and how sure it was in a word,\n * Accept (quiet) and ⋯ — Change…, Dismiss, Why this?. In the empty mark's place on an empty field, trailing the value\n * on a filled one; the same height either way, so nothing moves when it arrives or goes.\n *\n * Accept and Change… run the answer command as the person, through the one command pipeline (sdk/commands.tsx):\n * their grants, their click. What landed is then told to the server, which reads the record to see whether it was\n * the suggestion or something else. A reader not granted the command sees the suggestion and why, and nothing to press.\n */\nimport { useRef, useState } from 'react';\nimport { useQuery } from '@tanstack/react-query';\nimport { Button } from '@mistriwork/ui/Button.js';\nimport { DropItem, DropMenu } from '@mistriwork/ui/DropMenu.js';\nimport { Modal } from '@mistriwork/ui/Modal.js';\nimport { api, findTable, toast } from '@mistriwork/kit/client/core.js';\nimport { formatDateTime } from '@mistriwork/kit/client/locale.js';\nimport { Value } from '@mistriwork/kit/client/components/Value.js';\nimport type { ColumnMeta, TableMeta } from '@mistriwork/engine/shared/schema.js';\nimport { confidenceOf, type DecisionWhy, type FieldSuggestion } from '../../shared/decisionSuggestions.js';\nimport { commandHandle } from './sdk/commands.js';\nimport { say } from '../copy/record/components/DecisionChip.js';\nimport './DecisionChip.css';\n\n/* The confidence in words (design: a percent only in \"Why this?\"), each said by its key so the catalog knows it is. */\nconst sayConfidence = (probability: number): string =>\n ({ almostCertain: say('almostCertain'), veryLikely: say('veryLikely'), likely: say('likely'), possible: say('possible') })[\n confidenceOf(probability)\n ];\n\nexport default function DecisionChip({\n suggestion,\n table,\n recordKey,\n onSettled,\n}: {\n suggestion: FieldSuggestion;\n table: string;\n recordKey: Readonly<Record<string, unknown>>;\n /** The suggestion moved on (accepted, corrected, dismissed): the record and its suggestions are asked again. */\n onSettled: () => void;\n}) {\n const [busy, setBusy] = useState(false);\n const [why, setWhy] = useState(false);\n const more = useRef<HTMLButtonElement>(null);\n const handle = commandHandle(suggestion.command);\n const confidence = sayConfidence(suggestion.probability);\n const settle = async (action: 'done' | 'dismiss') => {\n try {\n await api('/api/record-decisions/settle', { id: suggestion.id, action });\n } catch {\n toast(say('couldNotSettle'), 'error');\n }\n onSettled();\n };\n const run = async (how: 'run' | 'open') => {\n setBusy(true);\n try {\n const outcome = await handle[how](recordKey, { [suggestion.field]: suggestion.answer });\n if (outcome.status === 'applied') await settle('done');\n } finally {\n setBusy(false);\n }\n };\n return (\n <span className={`decision-chip${suggestion.filled ? ' decision-chip-trailing' : ''}`}>\n <span className=\"decision-chip-value\" aria-label={say('suggestion', { value: suggestion.label, confidence })}>\n <span aria-hidden=\"true\">{suggestion.label}</span>\n <span className=\"decision-chip-word\" aria-hidden=\"true\">\n {confidence}\n </span>\n </span>\n {handle.granted && (\n <Button intent=\"quiet\" size=\"compact\" className=\"decision-chip-accept\" busy={busy} onClick={() => void run('run')}>\n {say('accept')}\n </Button>\n )}\n <DropMenu\n className=\"decision-chip-menu\"\n triggerClassName=\"decision-chip-more\"\n triggerLabel={say('more', { value: suggestion.label })}\n triggerTitle={say('more', { value: suggestion.label })}\n label=\"⋯\"\n popupClassName=\"page-actions-popup\"\n align=\"start\"\n finalFocus={more}\n >\n {handle.granted && (\n <DropItem className=\"page-actions-item\" disabled={busy} onClick={() => void run('open')}>\n {say('change')}\n </DropItem>\n )}\n {handle.granted && (\n <DropItem className=\"page-actions-item\" disabled={busy} onClick={() => void settle('dismiss')}>\n {say('dismiss')}\n </DropItem>\n )}\n <DropItem className=\"page-actions-item\" onClick={() => setWhy(true)}>\n {say('whyThis')}\n </DropItem>\n </DropMenu>\n {why && <WhyThis suggestion={suggestion} table={table} onClose={() => setWhy(false)} />}\n </span>\n );\n}\n\n/** What was asked, of whom, how surely and when: the inputs by name with what this reader may read of them now. No reasoning. */\nfunction WhyThis({ suggestion, table, onClose }: { suggestion: FieldSuggestion; table: string; onClose: () => void }) {\n const asked = useQuery({\n queryKey: ['record-decision-why', suggestion.id],\n queryFn: async () => (await api('/api/record-decisions/why', { id: suggestion.id })) as DecisionWhy,\n staleTime: 60_000,\n });\n const meta = findTable(table) as TableMeta | undefined;\n const column = (name: string): ColumnMeta =>\n meta?.columns.find((each) => each.name === name) ?? ({ name, type: 'TEXT', nullable: true, primaryKey: false } as ColumnMeta);\n const reason = asked.data;\n return (\n <Modal className=\"decision-why\" ariaLabel={say('whyTitle', { value: suggestion.label })} onClose={onClose} fullscreen={false}>\n <h2>{say('whyTitle', { value: suggestion.label })}</h2>\n {!reason ? (\n <p className=\"note\">{say('reading')}</p>\n ) : (\n <dl className=\"decision-why-facts\">\n <div>\n <dt>{say('asked')}</dt>\n <dd>{reason.question}</dd>\n </div>\n <div>\n <dt>{say('inputs')}</dt>\n <dd>\n <dl className=\"decision-why-inputs\">\n {reason.inputs.map((input) => (\n <div key={input.name}>\n <dt>{input.label}</dt>\n <dd>\n {input.readable ? (\n <Value col={column(input.name)} value={input.value} tableId={table} compact links={false} />\n ) : (\n <span className=\"decision-why-hidden\">{say('notYours')}</span>\n )}\n </dd>\n </div>\n ))}\n </dl>\n </dd>\n </div>\n <div>\n <dt>{say('answeredBy')}</dt>\n <dd>{[reason.provider, reason.model, reason.modelVersion].filter(Boolean).join(' · ')}</dd>\n </div>\n {reason.probability !== null && (\n <div>\n <dt>{say('sure')}</dt>\n <dd>{`${Math.round(reason.probability * 100)}% · ${sayConfidence(reason.probability)}`}</dd>\n </div>\n )}\n <div>\n <dt>{say('when')}</dt>\n <dd>{formatDateTime(reason.at)}</dd>\n </div>\n </dl>\n )}\n <div className=\"decision-why-actions\">\n <Button onClick={onClose}>{say('close')}</Button>\n </div>\n </Modal>\n );\n}\n"],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  import { I as quoteValue } from "./shared-poc11xxo.js";
2
- import { C as conditionResult, S as compileCondition } from "./shared-C-J32eBn.js";
2
+ import { C as conditionResult, S as compileCondition } from "./shared-CL3RLKDA.js";
3
3
  // packages/mistri/src/shared/commandDraft.ts
4
4
  /** The record's own value in a condition: `record.<column>`. */
5
5
  var RECORD_PREFIX = "record.";
@@ -192,4 +192,4 @@ function brokenRules(rules, values, fields, now = /* @__PURE__ */ new Date()) {
192
192
  }
193
193
  export { bindRecord, boundText, brokenRules, draftHolds, draftNames, readsRecord, recordComparisons };
194
194
 
195
- //# sourceMappingURL=shared-Dtp4eRul.js.map
195
+ //# sourceMappingURL=shared-DVfdm6ah.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"shared-Dtp4eRul.js","names":[],"sources":["../../src/shared/commandDraft.ts"],"sourcesContent":["/**\n * A command's conditions over its draft: a field's `when` and the command's `rules`, judged by one evaluator in the\n * browser as someone types and on the server as the command runs (and at each step's check). The language is the\n * form conditions' (formValues.ts), read against the input's own fields as columns: a bare name is another field of\n * the input, and on a command over one record `record.<column>` is the target's own value — bound where the record\n * is read (prepare in the browser's case, the run's transaction on the server), so the browser is told only whether\n * each record part holds, never a value it was not shown.\n *\n * A condition is kept as its text and compiled where it is judged, so `today` is the day it is judged on. Date\n * arithmetic the query language does not say — `today - 18 years` — is worked out to a day first (`dateWords`).\n */\nimport type { ColumnMeta } from '@mistriwork/engine/shared/schema.js';\nimport { compileCondition, conditionResult, type CompiledCondition } from '@mistriwork/engine/shared/formValues.js';\nimport { quoteValue } from '@mistriwork/engine/shared/query.js';\nimport type { AppCommandField } from './command.js';\n\ntype Field = AppCommandField;\ntype Comparison = CompiledCondition[number][number];\n\n/** The record's own value in a condition: `record.<column>`. */\nconst RECORD_PREFIX = 'record.';\n\nconst UNITS: Record<string, 'day' | 'month' | 'year'> = {\n day: 'day',\n days: 'day',\n week: 'day',\n weeks: 'day',\n month: 'month',\n months: 'month',\n year: 'year',\n years: 'year',\n};\nconst ARITHMETIC = /\\btoday\\s*([+-])\\s*(\\d{1,4})\\s*(days?|weeks?|months?|years?)\\b/gi;\n\n/** The day `today ± N units` names, from `today` (YYYY-MM-DD); a month or a year past the month's end lands on its last day. */\nfunction shifted(today: string, sign: string, count: number, unit: string): string {\n const [y, m, d] = today.split('-').map(Number);\n const by = (sign === '-' ? -1 : 1) * count * (unit.startsWith('week') ? 7 : 1);\n const kind = UNITS[unit.toLowerCase()];\n if (kind === 'day') return new Date(Date.UTC(y, m - 1, d + by)).toISOString().slice(0, 10);\n const months = kind === 'year' ? by * 12 : by;\n const first = new Date(Date.UTC(y, m - 1 + months, 1));\n const last = new Date(Date.UTC(first.getUTCFullYear(), first.getUTCMonth() + 1, 0)).getUTCDate();\n return new Date(Date.UTC(first.getUTCFullYear(), first.getUTCMonth(), Math.min(d, last))).toISOString().slice(0, 10);\n}\n\n/** A condition with each `today - 18 years` (days, weeks, months, years) said as the day it names. */\nfunction dateWords(text: string, today: string): string {\n return text.replace(ARITHMETIC, (_, sign: string, count: string, unit: string) => shifted(today, sign, Number(count), unit));\n}\n\n/* The column a field reads as, so a literal compares as its kind does: an amount as a number, a day as a day. */\nfunction columnType(field: Field): string | undefined {\n switch (field.type) {\n case 'number':\n case 'money':\n return 'NUMERIC';\n case 'boolean':\n return 'BOOLEAN';\n case 'date':\n return 'DATE';\n case 'datetime':\n return 'TIMESTAMPTZ';\n case 'choice':\n return field.options.length && field.options.every((option) => typeof option.value === 'number') ? 'NUMERIC' : 'TEXT';\n case 'text':\n case 'textarea':\n case 'month':\n case 'reference':\n return 'TEXT';\n default:\n return undefined;\n }\n}\n\n/** The input's fields a condition may name, as the columns it is judged against: never a group, lines, rich text,\n several choices, questions in rows, or a sensitive value. */\nfunction draftColumns(fields: readonly Field[]): ColumnMeta[] {\n return fields.flatMap((field) => {\n const type = columnType(field);\n if (!type || (field.type === 'text' && field.sensitive)) return [];\n return [{ name: field.name, type, nullable: true, primaryKey: false }];\n });\n}\n\nconst today = (now: Date) => now.toISOString().slice(0, 10);\n\n/**\n * A condition read as its words alone, for the parser: each comparison's name, and the fault in it. A bare word\n * equal to a field's name, on the right, is that field (`confirm_email = email`): quote a literal that would read\n * as one.\n */\nfunction draftCondition(text: string, where: string, now = new Date(), fields?: readonly Field[]): CompiledCondition {\n const said = dateWords(text, today(now));\n const untyped = compileCondition(said, where, undefined, 'record', true);\n if (!fields) return untyped;\n /* Read again against the fields' own kinds, so a bare word is the kind its field holds: `battery != no` over a\n choice of words compares the word \"no\", and only a yes-or-no field reads yes and no as true and false. Untyped,\n every bare yes or no was a boolean, which a text choice never equals, so the condition never held. A name that is\n no judgeable field (a record's column) stays untyped, read as it was. */\n const columns = draftColumns(fields);\n const known = new Set(columns.map((column) => column.name));\n for (const c of untyped.flat())\n for (const name of [c.field, ...(c.other === undefined ? [] : [c.other])])\n if (!known.has(name)) {\n known.add(name);\n columns.push({ name, type: '', nullable: true, primaryKey: false });\n }\n try {\n return compileCondition(said, where, columns, 'record', true);\n } catch {\n return untyped;\n }\n}\n\n/** The names a condition reads: the input's fields, and the record's columns (`record.<column>`). */\nexport function draftNames(text: string, where: string): { fields: string[]; record: string[] } {\n const fields = new Set<string>();\n const record = new Set<string>();\n for (const c of draftCondition(text, where).flat()) {\n for (const name of [c.field, ...(c.other === undefined ? [] : [c.other])]) {\n if (name.startsWith(RECORD_PREFIX)) record.add(name.slice(RECORD_PREFIX.length));\n else if (name.includes('.'))\n throw new Error(\n `${where}: \"${name}\" is a path; a condition here names a field of the input, or record.<column> for the record's own.`,\n );\n else fields.add(name);\n }\n }\n return { fields: [...fields], record: [...record] };\n}\n\n/* A comparison whose one value is a bare word naming another field compares the two fields. */\nfunction withFields(condition: CompiledCondition, names: ReadonlySet<string>): CompiledCondition {\n return condition.map((group) =>\n group.map((c) =>\n c.other === undefined && c.values.length === 1 && typeof c.values[0] === 'string' && names.has(c.values[0]) && c.values[0] !== c.field\n ? ({ field: c.field, operator: c.operator, values: [], other: c.values[0] } as Comparison)\n : c,\n ),\n );\n}\n\n/** One comparison as the query language says it: a record's over the target (its `record.` dropped), a draft's as written. */\nfunction recordComparisonText(c: Comparison): string {\n const column = c.field.startsWith(RECORD_PREFIX) ? c.field.slice(RECORD_PREFIX.length) : c.field;\n if (c.other !== undefined) return `${column} ${{ eq: '=', ne: '!=', lt: '<', lte: '<=', gt: '>', gte: '>=' }[c.operator]} ${c.other}`;\n if (c.values.length === 1 && c.values[0] === null) return `${column} ${c.operator === 'ne' ? 'is not empty' : 'is empty'}`;\n if (c.values.length > 1) return `${column} in (${c.values.map((v) => quoteValue(v)).join(', ')})`;\n const op = { eq: '=', ne: '!=', lt: '<', lte: '<=', gt: '>', gte: '>=' }[c.operator];\n return `${column} ${op} ${quoteValue(c.values[0])}`;\n}\n\n/** Each `record.<column>` comparison a condition makes, as the query language says it over the target. */\nexport const recordComparisons = (text: string): string[] =>\n draftCondition(text, 'Condition')\n .flat()\n .filter((c) => c.field.startsWith(RECORD_PREFIX))\n .map(recordComparisonText);\n\n/** A condition bound to a record: each `record.<column>` comparison replaced by whether it holds, so what is left\n reads the draft alone. `[]` holds never; a group of no comparisons always. */\nexport type BoundCondition = CompiledCondition;\n\n/** Bind a condition's record parts by `holds` (the server's judgement of each one over the target). */\nexport async function bindRecord(\n text: string,\n where: string,\n holds: (comparison: string) => Promise<boolean>,\n now = new Date(),\n fields?: readonly Field[],\n): Promise<BoundCondition> {\n const groups: Comparison[][] = [];\n for (const group of draftCondition(text, where, now, fields)) {\n const kept: Comparison[] = [];\n let alive = true;\n for (const c of group) {\n if (!c.field.startsWith(RECORD_PREFIX)) kept.push(c);\n else if (!(await holds(recordComparisonText(c)))) {\n alive = false;\n break;\n }\n }\n if (alive) groups.push(kept);\n }\n return groups;\n}\n\n/** A bound condition said again as text over the draft alone, as prepare serves it: `true` where it always holds,\n `false` where it never does. */\nexport function boundText(bound: BoundCondition): string | boolean {\n if (!bound.length) return false;\n if (bound.some((group) => !group.length)) return true;\n return bound.map((group) => group.map(recordComparisonText).join(' and ')).join(' or ');\n}\n\n/** Whether a condition that names the record has been bound: one with no record part needs no binding. */\nexport const readsRecord = (text: string): boolean =>\n draftCondition(text, 'Condition')\n .flat()\n .some((c) => c.field.startsWith(RECORD_PREFIX));\n\n/* An answer not given: absent, null, or an empty box. */\nconst unanswered = (value: unknown): boolean => value === undefined || value === null || value === '';\n\n/* A comparison that asks whether a field is empty (`is empty`, `is not empty`): the one kind an unanswered field answers. */\nconst asksEmpty = (c: Comparison): boolean => c.other === undefined && c.values.length === 1 && c.values[0] === null;\n\n/**\n * Whether a condition holds of a draft: its text (compiled now) or a bound condition. Three-valued, as SQL is: a field\n * not yet answered is null, and a comparison with null is unknown — `entry_ok = false` and `entry_ok != true` alike —\n * so it does not hold until someone answers. Only `is empty` and `is not empty` read the null itself. A comparison\n * that cannot be judged otherwise (an order over text) is unknown too. A group holds where every comparison in it\n * holds; the condition holds where one group does, so an `or` whose other side is unanswered still holds.\n */\nexport function draftHolds(\n condition: string | BoundCondition,\n values: Readonly<Record<string, unknown>>,\n fields: readonly Field[],\n now = new Date(),\n): boolean {\n const columns = draftColumns(fields);\n const names = new Set(columns.map((column) => column.name));\n const compiled = withFields(typeof condition === 'string' ? draftCondition(condition, 'Condition', now, fields) : condition, names);\n if (!compiled.length) return false;\n // A group bound to nothing but record parts that held: it holds.\n if (compiled.some((group) => !group.length)) return true;\n const row = Object.fromEntries(columns.map((column) => [column.name, unanswered(values[column.name]) ? null : values[column.name]]));\n const holds = (c: Comparison): boolean => {\n if (!asksEmpty(c) && [c.field, ...(c.other === undefined ? [] : [c.other])].some((name) => row[name] === null)) return false;\n return conditionResult([[c]], row, columns) === true;\n };\n return compiled.some((group) => group.every(holds));\n}\n\n/** The rule as the command declares it (CommandRule) and serves it. */\nexport interface DraftRule {\n must: string;\n when?: string;\n message: string;\n}\n\n/** The field a rule's message is said at: the first one its `must` names. */\nconst ruleField = (rule: DraftRule): string => draftNames(rule.must, 'Rule').fields[0];\n\n/** The rules a draft breaks, each at its field: those whose `when` holds (or that have none) and whose `must` does not. */\nexport function brokenRules(\n rules: readonly DraftRule[],\n values: Readonly<Record<string, unknown>>,\n fields: readonly Field[],\n now = new Date(),\n): Array<{ field: string; message: string }> {\n const broken: Array<{ field: string; message: string }> = [];\n for (const rule of rules) {\n const names = draftNames(rule.must, 'Rule').fields;\n // A rule is judged once every field it names is answered: an empty field is its own field's to say (required).\n if (names.some((name) => values[name] === undefined || values[name] === null || values[name] === '')) continue;\n if (rule.when !== undefined && !draftHolds(rule.when, values, fields, now)) continue;\n if (!draftHolds(rule.must, values, fields, now)) broken.push({ field: ruleField(rule), message: rule.message });\n }\n return broken;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"shared-DVfdm6ah.js","names":[],"sources":["../../src/shared/commandDraft.ts"],"sourcesContent":["/**\n * A command's conditions over its draft: a field's `when` and the command's `rules`, judged by one evaluator in the\n * browser as someone types and on the server as the command runs (and at each step's check). The language is the\n * form conditions' (formValues.ts), read against the input's own fields as columns: a bare name is another field of\n * the input, and on a command over one record `record.<column>` is the target's own value — bound where the record\n * is read (prepare in the browser's case, the run's transaction on the server), so the browser is told only whether\n * each record part holds, never a value it was not shown.\n *\n * A condition is kept as its text and compiled where it is judged, so `today` is the day it is judged on. Date\n * arithmetic the query language does not say — `today - 18 years` — is worked out to a day first (`dateWords`).\n */\nimport type { ColumnMeta } from '@mistriwork/engine/shared/schema.js';\nimport { compileCondition, conditionResult, type CompiledCondition } from '@mistriwork/engine/shared/formValues.js';\nimport { quoteValue } from '@mistriwork/engine/shared/query.js';\nimport type { AppCommandField } from './command.js';\n\ntype Field = AppCommandField;\ntype Comparison = CompiledCondition[number][number];\n\n/** The record's own value in a condition: `record.<column>`. */\nconst RECORD_PREFIX = 'record.';\n\nconst UNITS: Record<string, 'day' | 'month' | 'year'> = {\n day: 'day',\n days: 'day',\n week: 'day',\n weeks: 'day',\n month: 'month',\n months: 'month',\n year: 'year',\n years: 'year',\n};\nconst ARITHMETIC = /\\btoday\\s*([+-])\\s*(\\d{1,4})\\s*(days?|weeks?|months?|years?)\\b/gi;\n\n/** The day `today ± N units` names, from `today` (YYYY-MM-DD); a month or a year past the month's end lands on its last day. */\nfunction shifted(today: string, sign: string, count: number, unit: string): string {\n const [y, m, d] = today.split('-').map(Number);\n const by = (sign === '-' ? -1 : 1) * count * (unit.startsWith('week') ? 7 : 1);\n const kind = UNITS[unit.toLowerCase()];\n if (kind === 'day') return new Date(Date.UTC(y, m - 1, d + by)).toISOString().slice(0, 10);\n const months = kind === 'year' ? by * 12 : by;\n const first = new Date(Date.UTC(y, m - 1 + months, 1));\n const last = new Date(Date.UTC(first.getUTCFullYear(), first.getUTCMonth() + 1, 0)).getUTCDate();\n return new Date(Date.UTC(first.getUTCFullYear(), first.getUTCMonth(), Math.min(d, last))).toISOString().slice(0, 10);\n}\n\n/** A condition with each `today - 18 years` (days, weeks, months, years) said as the day it names. */\nfunction dateWords(text: string, today: string): string {\n return text.replace(ARITHMETIC, (_, sign: string, count: string, unit: string) => shifted(today, sign, Number(count), unit));\n}\n\n/* The column a field reads as, so a literal compares as its kind does: an amount as a number, a day as a day. */\nfunction columnType(field: Field): string | undefined {\n switch (field.type) {\n case 'number':\n case 'money':\n return 'NUMERIC';\n case 'boolean':\n return 'BOOLEAN';\n case 'date':\n return 'DATE';\n case 'datetime':\n return 'TIMESTAMPTZ';\n case 'choice':\n return field.options.length && field.options.every((option) => typeof option.value === 'number') ? 'NUMERIC' : 'TEXT';\n case 'text':\n case 'textarea':\n case 'month':\n case 'reference':\n return 'TEXT';\n default:\n return undefined;\n }\n}\n\n/** The input's fields a condition may name, as the columns it is judged against: never a group, lines, rich text,\n several choices, questions in rows, or a sensitive value. */\nfunction draftColumns(fields: readonly Field[]): ColumnMeta[] {\n return fields.flatMap((field) => {\n const type = columnType(field);\n if (!type || (field.type === 'text' && field.sensitive)) return [];\n return [{ name: field.name, type, nullable: true, primaryKey: false }];\n });\n}\n\nconst today = (now: Date) => now.toISOString().slice(0, 10);\n\n/**\n * A condition read as its words alone, for the parser: each comparison's name, and the fault in it. A bare word\n * equal to a field's name, on the right, is that field (`confirm_email = email`): quote a literal that would read\n * as one.\n */\nfunction draftCondition(text: string, where: string, now = new Date(), fields?: readonly Field[]): CompiledCondition {\n const said = dateWords(text, today(now));\n const untyped = compileCondition(said, where, undefined, 'record', true);\n if (!fields) return untyped;\n /* Read again against the fields' own kinds, so a bare word is the kind its field holds: `battery != no` over a\n choice of words compares the word \"no\", and only a yes-or-no field reads yes and no as true and false. Untyped,\n every bare yes or no was a boolean, which a text choice never equals, so the condition never held. A name that is\n no judgeable field (a record's column) stays untyped, read as it was. */\n const columns = draftColumns(fields);\n const known = new Set(columns.map((column) => column.name));\n for (const c of untyped.flat())\n for (const name of [c.field, ...(c.other === undefined ? [] : [c.other])])\n if (!known.has(name)) {\n known.add(name);\n columns.push({ name, type: '', nullable: true, primaryKey: false });\n }\n try {\n return compileCondition(said, where, columns, 'record', true);\n } catch {\n return untyped;\n }\n}\n\n/** The names a condition reads: the input's fields, and the record's columns (`record.<column>`). */\nexport function draftNames(text: string, where: string): { fields: string[]; record: string[] } {\n const fields = new Set<string>();\n const record = new Set<string>();\n for (const c of draftCondition(text, where).flat()) {\n for (const name of [c.field, ...(c.other === undefined ? [] : [c.other])]) {\n if (name.startsWith(RECORD_PREFIX)) record.add(name.slice(RECORD_PREFIX.length));\n else if (name.includes('.'))\n throw new Error(\n `${where}: \"${name}\" is a path; a condition here names a field of the input, or record.<column> for the record's own.`,\n );\n else fields.add(name);\n }\n }\n return { fields: [...fields], record: [...record] };\n}\n\n/* A comparison whose one value is a bare word naming another field compares the two fields. */\nfunction withFields(condition: CompiledCondition, names: ReadonlySet<string>): CompiledCondition {\n return condition.map((group) =>\n group.map((c) =>\n c.other === undefined && c.values.length === 1 && typeof c.values[0] === 'string' && names.has(c.values[0]) && c.values[0] !== c.field\n ? ({ field: c.field, operator: c.operator, values: [], other: c.values[0] } as Comparison)\n : c,\n ),\n );\n}\n\n/** One comparison as the query language says it: a record's over the target (its `record.` dropped), a draft's as written. */\nfunction recordComparisonText(c: Comparison): string {\n const column = c.field.startsWith(RECORD_PREFIX) ? c.field.slice(RECORD_PREFIX.length) : c.field;\n if (c.other !== undefined) return `${column} ${{ eq: '=', ne: '!=', lt: '<', lte: '<=', gt: '>', gte: '>=' }[c.operator]} ${c.other}`;\n if (c.values.length === 1 && c.values[0] === null) return `${column} ${c.operator === 'ne' ? 'is not empty' : 'is empty'}`;\n if (c.values.length > 1) return `${column} in (${c.values.map((v) => quoteValue(v)).join(', ')})`;\n const op = { eq: '=', ne: '!=', lt: '<', lte: '<=', gt: '>', gte: '>=' }[c.operator];\n return `${column} ${op} ${quoteValue(c.values[0])}`;\n}\n\n/** Each `record.<column>` comparison a condition makes, as the query language says it over the target. */\nexport const recordComparisons = (text: string): string[] =>\n draftCondition(text, 'Condition')\n .flat()\n .filter((c) => c.field.startsWith(RECORD_PREFIX))\n .map(recordComparisonText);\n\n/** A condition bound to a record: each `record.<column>` comparison replaced by whether it holds, so what is left\n reads the draft alone. `[]` holds never; a group of no comparisons always. */\nexport type BoundCondition = CompiledCondition;\n\n/** Bind a condition's record parts by `holds` (the server's judgement of each one over the target). */\nexport async function bindRecord(\n text: string,\n where: string,\n holds: (comparison: string) => Promise<boolean>,\n now = new Date(),\n fields?: readonly Field[],\n): Promise<BoundCondition> {\n const groups: Comparison[][] = [];\n for (const group of draftCondition(text, where, now, fields)) {\n const kept: Comparison[] = [];\n let alive = true;\n for (const c of group) {\n if (!c.field.startsWith(RECORD_PREFIX)) kept.push(c);\n else if (!(await holds(recordComparisonText(c)))) {\n alive = false;\n break;\n }\n }\n if (alive) groups.push(kept);\n }\n return groups;\n}\n\n/** A bound condition said again as text over the draft alone, as prepare serves it: `true` where it always holds,\n `false` where it never does. */\nexport function boundText(bound: BoundCondition): string | boolean {\n if (!bound.length) return false;\n if (bound.some((group) => !group.length)) return true;\n return bound.map((group) => group.map(recordComparisonText).join(' and ')).join(' or ');\n}\n\n/** Whether a condition that names the record has been bound: one with no record part needs no binding. */\nexport const readsRecord = (text: string): boolean =>\n draftCondition(text, 'Condition')\n .flat()\n .some((c) => c.field.startsWith(RECORD_PREFIX));\n\n/* An answer not given: absent, null, or an empty box. */\nconst unanswered = (value: unknown): boolean => value === undefined || value === null || value === '';\n\n/* A comparison that asks whether a field is empty (`is empty`, `is not empty`): the one kind an unanswered field answers. */\nconst asksEmpty = (c: Comparison): boolean => c.other === undefined && c.values.length === 1 && c.values[0] === null;\n\n/**\n * Whether a condition holds of a draft: its text (compiled now) or a bound condition. Three-valued, as SQL is: a field\n * not yet answered is null, and a comparison with null is unknown — `entry_ok = false` and `entry_ok != true` alike —\n * so it does not hold until someone answers. Only `is empty` and `is not empty` read the null itself. A comparison\n * that cannot be judged otherwise (an order over text) is unknown too. A group holds where every comparison in it\n * holds; the condition holds where one group does, so an `or` whose other side is unanswered still holds.\n */\nexport function draftHolds(\n condition: string | BoundCondition,\n values: Readonly<Record<string, unknown>>,\n fields: readonly Field[],\n now = new Date(),\n): boolean {\n const columns = draftColumns(fields);\n const names = new Set(columns.map((column) => column.name));\n const compiled = withFields(typeof condition === 'string' ? draftCondition(condition, 'Condition', now, fields) : condition, names);\n if (!compiled.length) return false;\n // A group bound to nothing but record parts that held: it holds.\n if (compiled.some((group) => !group.length)) return true;\n const row = Object.fromEntries(columns.map((column) => [column.name, unanswered(values[column.name]) ? null : values[column.name]]));\n const holds = (c: Comparison): boolean => {\n if (!asksEmpty(c) && [c.field, ...(c.other === undefined ? [] : [c.other])].some((name) => row[name] === null)) return false;\n return conditionResult([[c]], row, columns) === true;\n };\n return compiled.some((group) => group.every(holds));\n}\n\n/** The rule as the command declares it (CommandRule) and serves it. */\nexport interface DraftRule {\n must: string;\n when?: string;\n message: string;\n}\n\n/** The field a rule's message is said at: the first one its `must` names. */\nconst ruleField = (rule: DraftRule): string => draftNames(rule.must, 'Rule').fields[0];\n\n/** The rules a draft breaks, each at its field: those whose `when` holds (or that have none) and whose `must` does not. */\nexport function brokenRules(\n rules: readonly DraftRule[],\n values: Readonly<Record<string, unknown>>,\n fields: readonly Field[],\n now = new Date(),\n): Array<{ field: string; message: string }> {\n const broken: Array<{ field: string; message: string }> = [];\n for (const rule of rules) {\n const names = draftNames(rule.must, 'Rule').fields;\n // A rule is judged once every field it names is answered: an empty field is its own field's to say (required).\n if (names.some((name) => values[name] === undefined || values[name] === null || values[name] === '')) continue;\n if (rule.when !== undefined && !draftHolds(rule.when, values, fields, now)) continue;\n if (!draftHolds(rule.must, values, fields, now)) broken.push({ field: ruleField(rule), message: rule.message });\n }\n return broken;\n}\n"],"mappings":"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"}
@@ -1,7 +1,7 @@
1
1
  import { nt as Button } from "./shared-poc11xxo.js";
2
2
  import { gt as defineMessages } from "./shared-DJZjSi3J.js";
3
- import { t as FormSurface } from "./shared-CpI0Y8M5.js";
4
- import { publicPlacementOperation } from "./shared-CQL3FGHc.js";
3
+ import { t as FormSurface } from "./shared-B4jgU8h9.js";
4
+ import { publicPlacementOperation } from "./shared-Csfi3Pti.js";
5
5
  import { useMemo, useSyncExternalStore } from "react";
6
6
  import { jsx, jsxs } from "react/jsx-runtime";
7
7
  // packages/mistri/src/client/copy/forms/components/PlacedFormSurface.ts
@@ -73,4 +73,4 @@ function PlacedFormSurface({ prepared, prefill, review, onDismiss }) {
73
73
  }
74
74
  export { PlacedFormSurface };
75
75
 
76
- //# sourceMappingURL=shared-BJ5Ex32G.js.map
76
+ //# sourceMappingURL=shared-DXM7d7lJ.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"shared-BJ5Ex32G.js","names":[],"sources":["../../src/client/copy/forms/components/PlacedFormSurface.ts","../../src/client/components/PlacedFormSurface.tsx"],"sourcesContent":["/** What PlacedFormSurface says, in the forms room (packages/kit/src/client/messages.ts says how the catalog is split). */\nimport { defineMessages } from '@mistriwork/kit/client/messages.js';\n\nexport const say = defineMessages({\n placementRecoveryExpired:\n 'The time to check this result has ended. It may have been received. Contact the form’s owner before submitting another form.',\n placementCheckResult: 'Check result',\n placementRetry: 'Retry the same submission',\n});\n","/** The placed form's receipt and retry controls. Loaded on demand; the operation\n * owner keeps unanswered attempts independently of this presentation's lifetime. */\nimport { useMemo, useSyncExternalStore } from 'react';\nimport { publicPlacementOperation, type PreparedPublicForm } from '../publicPlacement.js';\nimport { FormSurface } from './FormSurface.js';\nimport { Button } from '@mistriwork/ui/Button.js';\nimport { say } from '../copy/forms/components/PlacedFormSurface.js';\n\nexport function PlacedFormSurface({\n prepared,\n prefill,\n review,\n onDismiss,\n}: {\n prepared: PreparedPublicForm;\n prefill?: string;\n review?: boolean;\n onDismiss?: () => void;\n}) {\n const operation = useMemo(() => publicPlacementOperation(prepared), [prepared]);\n const state = useSyncExternalStore(operation.subscribe, operation.snapshot);\n const held = operation.prepared;\n const via = new URLSearchParams(window.location.search).get('via') ?? undefined;\n const recovery =\n state.phase === 'unknown' || (state.phase === 'pending' && state.message) ? (\n <div>\n <p className=\"form-page-failure\" role=\"alert\" tabIndex={-1}>\n {operation.canRecover() ? state.message : say('placementRecoveryExpired')}\n </p>\n <div className=\"form-actions\">\n <Button\n intent=\"primary\"\n onClick={() => void operation.check()}\n busy={state.phase === 'pending'}\n busyLabel={say('common.checking')}\n disabled={!operation.canRecover()}\n >\n {say('placementCheckResult')}\n </Button>\n {operation.canRetry() && (\n <Button\n intent=\"secondary\"\n onClick={() => void operation.retry()}\n busy={state.phase === 'pending'}\n busyLabel={say('common.submitting')}\n >\n {say('placementRetry')}\n </Button>\n )}\n {onDismiss && (\n <Button intent=\"secondary\" onClick={onDismiss}>\n {say('common.close')}\n </Button>\n )}\n </div>\n </div>\n ) : undefined;\n return (\n <FormSurface\n key={operation.placement.submission}\n form={held.form}\n appName={held.app.name}\n prefill={prefill}\n review={review}\n onDismiss={onDismiss}\n inDialog={Boolean(onDismiss)}\n // A reference input's choices, read as this tenant's visitor (the intake address the page was published with).\n visitor={{ app: held.app.id, ...(via ? { via } : {}) }}\n submit={operation.send}\n attempt={{\n submission: operation.placement.submission,\n values: operation.values,\n receipt: state.receipt,\n locked: state.phase !== 'ready',\n recovery,\n capture: operation.capture,\n }}\n />\n );\n}\n"],"mappings":";;;;;;;;AAGA,IAAa,MAAM,eAAe;CAChC,0BACE;CACF,sBAAsB;CACtB,gBAAgB;AAClB,CAAC;;;;ACAD,SAAgB,kBAAkB,EAChC,UACA,SACA,QACA,aAMC;CACD,MAAM,YAAY,cAAc,yBAAyB,QAAQ,GAAG,CAAC,QAAQ,CAAC;CAC9E,MAAM,QAAQ,qBAAqB,UAAU,WAAW,UAAU,QAAQ;CAC1E,MAAM,OAAO,UAAU;CACvB,MAAM,MAAM,IAAI,gBAAgB,OAAO,SAAS,MAAM,CAAC,CAAC,IAAI,KAAK,KAAK,KAAA;CACtE,MAAM,WACJ,MAAM,UAAU,aAAc,MAAM,UAAU,aAAa,MAAM,UAC/D,qBAAC,OAAD,EAAA,UAAA,CACE,oBAAC,KAAD;EAAG,WAAU;EAAoB,MAAK;EAAQ,UAAU;EACrD,UAAA,UAAU,WAAW,IAAI,MAAM,UAAU,IAAI,0BAA0B;CACvE,CAAA,GACH,qBAAC,OAAD;EAAK,WAAU;EAAf,UAAA;GACE,oBAAC,QAAD;IACE,QAAO;IACP,eAAe,KAAK,UAAU,MAAM;IACpC,MAAM,MAAM,UAAU;IACtB,WAAW,IAAI,iBAAiB;IAChC,UAAU,CAAC,UAAU,WAAW;IAE/B,UAAA,IAAI,sBAAsB;GACrB,CAAA;GACP,UAAU,SAAS,KAClB,oBAAC,QAAD;IACE,QAAO;IACP,eAAe,KAAK,UAAU,MAAM;IACpC,MAAM,MAAM,UAAU;IACtB,WAAW,IAAI,mBAAmB;IAEjC,UAAA,IAAI,gBAAgB;GACf,CAAA;GAET,aACC,oBAAC,QAAD;IAAQ,QAAO;IAAY,SAAS;IACjC,UAAA,IAAI,cAAc;GACb,CAAA;EAEP;CACF,CAAA,CAAA,EAAA,CAAA,IACH,KAAA;CACN,OACE,oBAAC,aAAD;EAEE,MAAM,KAAK;EACX,SAAS,KAAK,IAAI;EACT;EACD;EACG;EACX,UAAU,QAAQ,SAAS;EAE3B,SAAS;GAAE,KAAK,KAAK,IAAI;GAAI,GAAI,MAAM,EAAE,IAAI,IAAI,CAAC;EAAG;EACrD,QAAQ,UAAU;EAClB,SAAS;GACP,YAAY,UAAU,UAAU;GAChC,QAAQ,UAAU;GAClB,SAAS,MAAM;GACf,QAAQ,MAAM,UAAU;GACxB;GACA,SAAS,UAAU;EACrB;CACD,GAlBM,UAAU,UAAU,UAkB1B;AAEL"}
1
+ {"version":3,"file":"shared-DXM7d7lJ.js","names":[],"sources":["../../src/client/copy/forms/components/PlacedFormSurface.ts","../../src/client/components/PlacedFormSurface.tsx"],"sourcesContent":["/** What PlacedFormSurface says, in the forms room (packages/kit/src/client/messages.ts says how the catalog is split). */\nimport { defineMessages } from '@mistriwork/kit/client/messages.js';\n\nexport const say = defineMessages({\n placementRecoveryExpired:\n 'The time to check this result has ended. It may have been received. Contact the form’s owner before submitting another form.',\n placementCheckResult: 'Check result',\n placementRetry: 'Retry the same submission',\n});\n","/** The placed form's receipt and retry controls. Loaded on demand; the operation\n * owner keeps unanswered attempts independently of this presentation's lifetime. */\nimport { useMemo, useSyncExternalStore } from 'react';\nimport { publicPlacementOperation, type PreparedPublicForm } from '../publicPlacement.js';\nimport { FormSurface } from './FormSurface.js';\nimport { Button } from '@mistriwork/ui/Button.js';\nimport { say } from '../copy/forms/components/PlacedFormSurface.js';\n\nexport function PlacedFormSurface({\n prepared,\n prefill,\n review,\n onDismiss,\n}: {\n prepared: PreparedPublicForm;\n prefill?: string;\n review?: boolean;\n onDismiss?: () => void;\n}) {\n const operation = useMemo(() => publicPlacementOperation(prepared), [prepared]);\n const state = useSyncExternalStore(operation.subscribe, operation.snapshot);\n const held = operation.prepared;\n const via = new URLSearchParams(window.location.search).get('via') ?? undefined;\n const recovery =\n state.phase === 'unknown' || (state.phase === 'pending' && state.message) ? (\n <div>\n <p className=\"form-page-failure\" role=\"alert\" tabIndex={-1}>\n {operation.canRecover() ? state.message : say('placementRecoveryExpired')}\n </p>\n <div className=\"form-actions\">\n <Button\n intent=\"primary\"\n onClick={() => void operation.check()}\n busy={state.phase === 'pending'}\n busyLabel={say('common.checking')}\n disabled={!operation.canRecover()}\n >\n {say('placementCheckResult')}\n </Button>\n {operation.canRetry() && (\n <Button\n intent=\"secondary\"\n onClick={() => void operation.retry()}\n busy={state.phase === 'pending'}\n busyLabel={say('common.submitting')}\n >\n {say('placementRetry')}\n </Button>\n )}\n {onDismiss && (\n <Button intent=\"secondary\" onClick={onDismiss}>\n {say('common.close')}\n </Button>\n )}\n </div>\n </div>\n ) : undefined;\n return (\n <FormSurface\n key={operation.placement.submission}\n form={held.form}\n appName={held.app.name}\n prefill={prefill}\n review={review}\n onDismiss={onDismiss}\n inDialog={Boolean(onDismiss)}\n // A reference input's choices, read as this tenant's visitor (the intake address the page was published with).\n visitor={{ app: held.app.id, ...(via ? { via } : {}) }}\n submit={operation.send}\n attempt={{\n submission: operation.placement.submission,\n values: operation.values,\n receipt: state.receipt,\n locked: state.phase !== 'ready',\n recovery,\n capture: operation.capture,\n }}\n />\n );\n}\n"],"mappings":";;;;;;;;AAGA,IAAa,MAAM,eAAe;CAChC,0BACE;CACF,sBAAsB;CACtB,gBAAgB;AAClB,CAAC;;;;ACAD,SAAgB,kBAAkB,EAChC,UACA,SACA,QACA,aAMC;CACD,MAAM,YAAY,cAAc,yBAAyB,QAAQ,GAAG,CAAC,QAAQ,CAAC;CAC9E,MAAM,QAAQ,qBAAqB,UAAU,WAAW,UAAU,QAAQ;CAC1E,MAAM,OAAO,UAAU;CACvB,MAAM,MAAM,IAAI,gBAAgB,OAAO,SAAS,MAAM,CAAC,CAAC,IAAI,KAAK,KAAK,KAAA;CACtE,MAAM,WACJ,MAAM,UAAU,aAAc,MAAM,UAAU,aAAa,MAAM,UAC/D,qBAAC,OAAD,EAAA,UAAA,CACE,oBAAC,KAAD;EAAG,WAAU;EAAoB,MAAK;EAAQ,UAAU;EACrD,UAAA,UAAU,WAAW,IAAI,MAAM,UAAU,IAAI,0BAA0B;CACvE,CAAA,GACH,qBAAC,OAAD;EAAK,WAAU;EAAf,UAAA;GACE,oBAAC,QAAD;IACE,QAAO;IACP,eAAe,KAAK,UAAU,MAAM;IACpC,MAAM,MAAM,UAAU;IACtB,WAAW,IAAI,iBAAiB;IAChC,UAAU,CAAC,UAAU,WAAW;IAE/B,UAAA,IAAI,sBAAsB;GACrB,CAAA;GACP,UAAU,SAAS,KAClB,oBAAC,QAAD;IACE,QAAO;IACP,eAAe,KAAK,UAAU,MAAM;IACpC,MAAM,MAAM,UAAU;IACtB,WAAW,IAAI,mBAAmB;IAEjC,UAAA,IAAI,gBAAgB;GACf,CAAA;GAET,aACC,oBAAC,QAAD;IAAQ,QAAO;IAAY,SAAS;IACjC,UAAA,IAAI,cAAc;GACb,CAAA;EAEP;CACF,CAAA,CAAA,EAAA,CAAA,IACH,KAAA;CACN,OACE,oBAAC,aAAD;EAEE,MAAM,KAAK;EACX,SAAS,KAAK,IAAI;EACT;EACD;EACG;EACX,UAAU,QAAQ,SAAS;EAE3B,SAAS;GAAE,KAAK,KAAK,IAAI;GAAI,GAAI,MAAM,EAAE,IAAI,IAAI,CAAC;EAAG;EACrD,QAAQ,UAAU;EAClB,SAAS;GACP,YAAY,UAAU,UAAU;GAChC,QAAQ,UAAU;GAClB,SAAS,MAAM;GACf,QAAQ,MAAM,UAAU;GACxB;GACA,SAAS,UAAU;EACrB;CACD,GAlBM,UAAU,UAAU,UAkB1B;AAEL"}
@@ -1,6 +1,6 @@
1
1
  import { it as useQuery, n as GridSkeleton, t as Delayed } from "./shared-poc11xxo.js";
2
2
  import { gt as defineMessages } from "./shared-DJZjSi3J.js";
3
- import { L as state, f as go, i as api, w as quote, z as tableView } from "./shared-DPAVoWY0.js";
3
+ import { L as state, f as go, i as api, w as quote, z as tableView } from "./shared-BoLbc2WD.js";
4
4
  import { JsonView } from "./shared-PlvbuQ1q.js";
5
5
  import { useState } from "react";
6
6
  import { jsx, jsxs } from "react/jsx-runtime";
@@ -337,4 +337,4 @@ function ApiOperations({ table }) {
337
337
  }
338
338
  export { ApiOperations };
339
339
 
340
- //# sourceMappingURL=shared-BFr6ld0e.js.map
340
+ //# sourceMappingURL=shared-DXbMlcev.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"shared-BFr6ld0e.js","names":[],"sources":["../../../kit/src/client/copy/workbench/components/ApiOperations.ts","../../../kit/src/client/components/ApiOperations.tsx"],"sourcesContent":["/** What ApiOperations says, in the Workbench room (packages/kit/src/client/messages.ts says how the catalog is split). */\nimport { defineMessages } from '../../../messages.js';\n\nexport const say = defineMessages({\n theApisOwnSearch: \"the API's own search\",\n rowsToSkip: 'rows to skip',\n rowsPerPage: 'rows per page',\n pageNumber: 'page number',\n oneValueOrSeveral: 'one value, or several separated by commas',\n theApisOwnOrder: \"The API's own order\",\n theApisAnswer: \"The API's answer\",\n statusTime: '{status} · {ms} ms',\n theApiAnsweredTablewalk: 'The API answered {status}. tablewalk does not read the body of an error.',\n tryTheApi: 'Try the {table} API',\n read: 'Read',\n aList: 'A list',\n oneRecord: 'One record',\n theKeyTheItem: 'the key the item path names',\n thisListTakesNoParameters: 'This list takes no parameters.',\n send: 'Send',\n nextPage: 'Next page',\n theApisSearchOrASort: \"The API's search, or a sort that names no column, has no equivalent in the table view.\",\n openAsTable: 'Open as table',\n});\n","/**\n * The explorer's API tab, on a table read from an HTTP connection: the\n * resource's two documented reads — its list GET and its item GET — as a\n * form drawn from the description alone, sent by the server, and answered\n * exactly as the API answered.\n *\n * Narrower than a request builder on purpose. The browser never names a URL,\n * a header or a parameter the description does not declare: the server builds\n * the request from the description, attaches the connection's credential and\n * sends it through egress, then says back the path, the query string, the\n * status and the body — never a header (packages/engine/src/server/http/httpOperationRoutes.ts).\n * A list's question can be opened as the table view asking the same thing,\n * where its parameters are filters and a sort the table view can say.\n */\nimport { useState, type FormEvent } from 'react';\nimport { useQuery } from '@tanstack/react-query';\nimport { api, go, quote, state, tableView } from '../core.js';\nimport type { HttpOperationReply, HttpOperations, HttpParam } from '@mistriwork/engine/shared/httpOperations.js';\nimport { JsonView } from './JsonView.js';\nimport { Delayed, GridSkeleton } from './Skeleton.js';\nimport { say } from '../copy/workbench/components/ApiOperations.js';\n\ntype Kind = 'list' | 'item';\ninterface SchemaLike {\n dialect?: string;\n tables?: Array<{ id: string; columns: Array<{ name: string }> }>;\n}\nconst schema = () => (state as { schema?: SchemaLike | null }).schema ?? null;\nconst connection = () => (state as { activeConnection?: string | null }).activeConnection ?? '';\n\n/* What a box is, said under it; a filter's own label is its column. */\nconst HINT: Record<HttpParam['kind'], string> = {\n filter: 'equals',\n search: say('theApisOwnSearch'),\n sort: '',\n offset: say('rowsToSkip'),\n limit: say('rowsPerPage'),\n page: say('pageNumber'),\n size: 'rows per page',\n cursor: '',\n};\n\n/** RFC 6901: where a cursor-paged answer names its next page. */\nfunction at(value: unknown, pointer: string): unknown {\n let current = value;\n for (const raw of pointer.slice(1).split('/')) {\n const key = raw.replace(/~1/g, '/').replace(/~0/g, '~');\n current =\n current && typeof current === 'object' && !Array.isArray(current) && Object.hasOwn(current, key)\n ? (current as Record<string, unknown>)[key]\n : undefined;\n }\n return current;\n}\n\n/* A documented sort value as the table view says it — \"-shipped_at\" is \"sort\n shipped_at desc\" — the spellings the adapter itself reads. Undefined when\n the value names no column of the table. */\nfunction sortClause(value: string, columns: readonly string[]): string | undefined {\n const suffixed = /^(.+?)(?::| |_)(asc|desc)$/.exec(value);\n const spelled = value.startsWith('-')\n ? { column: value.slice(1), desc: true }\n : value.startsWith('+')\n ? { column: value.slice(1), desc: false }\n : suffixed\n ? { column: suffixed[1], desc: suffixed[2] === 'desc' }\n : { column: value, desc: false };\n if (!columns.includes(spelled.column)) return undefined;\n return `sort ${spelled.column}${spelled.desc ? ' desc' : ''}`;\n}\n\n/**\n * The table view's question for a list's parameters, or undefined when a\n * parameter has no equivalent there: the API's search is its own, and a\n * sort value that names no column cannot be said.\n */\nfunction tableQuery(table: string, params: readonly HttpParam[], values: Record<string, string>): string | undefined {\n const columns =\n schema()\n ?.tables?.find((each) => each.id === table)\n ?.columns.map((column) => column.name) ?? [];\n const conditions: string[] = [];\n let sort = '';\n for (const param of params) {\n const value = (values[param.name] ?? '').trim();\n if (!value) continue;\n if (param.kind === 'search') return undefined;\n if (param.kind === 'filter' && param.column) {\n const each = param.many\n ? value\n .split(',')\n .map((part) => part.trim())\n .filter(Boolean)\n : [value];\n conditions.push(each.length > 1 ? `${param.column} in (${each.map(quote).join(', ')})` : `${param.column} = ${quote(each[0])}`);\n }\n if (param.kind === 'sort') {\n const clause = sortClause(value, columns);\n if (!clause) return undefined;\n sort = clause;\n }\n }\n return [table, conditions.join(' and '), sort].filter(Boolean).join(' ');\n}\n\nfunction ParamField({ param, value, onChange }: { param: HttpParam; value: string; onChange: (value: string) => void }) {\n const label = param.kind === 'filter' ? (param.column ?? param.name) : param.kind === 'search' ? say('navigation.search') : param.name;\n const hint =\n param.kind === 'filter'\n ? `${param.many ? say('oneValueOrSeveral') : HINT.filter} · ?${param.name}=`\n : HINT[param.kind]\n ? `${HINT[param.kind]} · ?${param.name}=`\n : `?${param.name}=`;\n return (\n <label className=\"field-stack\">\n <span>{label}</span>\n {param.kind === 'sort' ? (\n <select value={value} onChange={(event) => onChange(event.target.value)} aria-label={label}>\n <option value=\"\">{say('theApisOwnOrder')}</option>\n {(param.values ?? []).map((each) => (\n <option key={each} value={each}>\n {each}\n </option>\n ))}\n </select>\n ) : (\n <input\n value={value}\n onChange={(event) => onChange(event.target.value)}\n aria-label={label}\n inputMode={['offset', 'limit', 'page', 'size'].includes(param.kind) ? 'numeric' : undefined}\n />\n )}\n <span className=\"field-hint\">{hint}</span>\n </label>\n );\n}\n\nfunction Answer({ reply }: { reply: HttpOperationReply }) {\n const line = `${reply.request.method} ${reply.request.path}${reply.request.query ? `?${reply.request.query}` : ''}`;\n const answered = reply.status >= 200 && reply.status <= 299;\n return (\n <section className=\"api-answer\" aria-label={say('theApisAnswer')}>\n <p className=\"api-request\">\n <code>{line}</code>\n <span className=\"api-meta\">{say('statusTime', { status: reply.status, ms: reply.ms })}</span>\n </p>\n {!answered ? (\n <p className=\"note\">{say('theApiAnsweredTablewalk', { status: reply.status })}</p>\n ) : reply.json !== null && typeof reply.json === 'object' ? (\n <JsonView value={reply.json} />\n ) : (\n <pre className=\"ddl\">{JSON.stringify(reply.json)}</pre>\n )}\n </section>\n );\n}\n\nexport function ApiOperations({ table }: { table: string }) {\n const described = useQuery<HttpOperations>({\n queryKey: ['api-operations', connection(), table],\n queryFn: () => api('/api/http/operations', { resource: table }) as Promise<HttpOperations>,\n });\n const [kind, setKind] = useState<Kind>('list');\n const [values, setValues] = useState<Record<string, string>>({});\n const [key, setKey] = useState('');\n const [reply, setReply] = useState<HttpOperationReply | null>(null);\n const [error, setError] = useState<string | null>(null);\n const [pending, setPending] = useState(false);\n\n if (described.isError) return <p className=\"note\">{(described.error as Error).message}</p>;\n if (!described.data)\n return (\n <Delayed>\n <div className=\"host-contents\">\n <GridSkeleton columns={2} rows={4} />\n </div>\n </Delayed>\n );\n const operations = described.data;\n const boxes = operations.list.params.filter((param) => param.kind !== 'cursor');\n const cursor = operations.list.params.find((param) => param.kind === 'cursor');\n // Only what was typed: an empty box asks nothing of the API.\n const filled = Object.fromEntries(boxes.map((param) => [param.name, (values[param.name] ?? '').trim()]).filter(([, value]) => value));\n\n const send = async (params: Record<string, string>) => {\n setPending(true);\n setError(null);\n try {\n setReply((await api('/api/http/operation', { resource: table, operation: kind, params })) as HttpOperationReply);\n } catch (failure) {\n setReply(null);\n setError((failure as Error).message);\n } finally {\n setPending(false);\n }\n };\n const submit = (event: FormEvent) => {\n event.preventDefault();\n void send(kind === 'list' ? filled : { [operations.item.key]: key });\n };\n const choose = (next: Kind) => {\n setKind(next);\n setReply(null);\n setError(null);\n };\n /* A cursor-paged answer names its next page; asking for it sends that cursor with the same question. */\n const next =\n kind === 'list' && cursor && operations.list.next && reply?.json !== undefined ? at(reply.json, operations.list.next) : undefined;\n const question = kind === 'list' ? tableQuery(table, boxes, values) : undefined;\n\n return (\n <div className=\"panel-pad api-ops\">\n <form className=\"api-form\" onSubmit={submit} aria-label={say('tryTheApi', { table })}>\n <fieldset className=\"api-kind\">\n <legend>{say('read')}</legend>\n <label>\n <input type=\"radio\" name=\"api-kind\" checked={kind === 'list'} onChange={() => choose('list')} /> {say('aList')}{' '}\n <code>GET {operations.list.path}</code>\n </label>\n <label>\n <input type=\"radio\" name=\"api-kind\" checked={kind === 'item'} onChange={() => choose('item')} /> {say('oneRecord')}{' '}\n <code>GET {operations.item.path}</code>\n </label>\n </fieldset>\n <div className=\"api-fields\">\n {kind === 'item' ? (\n <label className=\"field-stack\">\n <span>{operations.item.key}</span>\n <input value={key} onChange={(event) => setKey(event.target.value)} aria-label={operations.item.key} />\n <span className=\"field-hint\">{say('theKeyTheItem')}</span>\n </label>\n ) : boxes.length ? (\n boxes.map((param) => (\n <ParamField\n key={param.name}\n param={param}\n value={values[param.name] ?? ''}\n onChange={(value) => setValues((current) => ({ ...current, [param.name]: value }))}\n />\n ))\n ) : (\n <p className=\"field-hint\">{say('thisListTakesNoParameters')}</p>\n )}\n </div>\n <div className=\"api-actions\">\n <button type=\"submit\" className=\"primary\" disabled={pending || (kind === 'item' && !key.trim())}>\n {say('send')}\n </button>\n {typeof next === 'string' && next && cursor && (\n <button type=\"button\" className=\"ghost\" disabled={pending} onClick={() => void send({ ...filled, [cursor.name]: next })}>\n {say('nextPage')}\n </button>\n )}\n {kind === 'list' && (\n <button\n type=\"button\"\n className=\"ghost\"\n disabled={question === undefined}\n title={question === undefined ? say('theApisSearchOrASort') : undefined}\n onClick={() => {\n if (question !== undefined) go(tableView(table, question), 'push');\n }}\n >\n {say('openAsTable')}\n </button>\n )}\n </div>\n </form>\n {error && (\n <p className=\"note\" role=\"alert\">\n {error}\n </p>\n )}\n {reply && <Answer reply={reply} />}\n </div>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"shared-DXbMlcev.js","names":[],"sources":["../../../kit/src/client/copy/workbench/components/ApiOperations.ts","../../../kit/src/client/components/ApiOperations.tsx"],"sourcesContent":["/** What ApiOperations says, in the Workbench room (packages/kit/src/client/messages.ts says how the catalog is split). */\nimport { defineMessages } from '../../../messages.js';\n\nexport const say = defineMessages({\n theApisOwnSearch: \"the API's own search\",\n rowsToSkip: 'rows to skip',\n rowsPerPage: 'rows per page',\n pageNumber: 'page number',\n oneValueOrSeveral: 'one value, or several separated by commas',\n theApisOwnOrder: \"The API's own order\",\n theApisAnswer: \"The API's answer\",\n statusTime: '{status} · {ms} ms',\n theApiAnsweredTablewalk: 'The API answered {status}. tablewalk does not read the body of an error.',\n tryTheApi: 'Try the {table} API',\n read: 'Read',\n aList: 'A list',\n oneRecord: 'One record',\n theKeyTheItem: 'the key the item path names',\n thisListTakesNoParameters: 'This list takes no parameters.',\n send: 'Send',\n nextPage: 'Next page',\n theApisSearchOrASort: \"The API's search, or a sort that names no column, has no equivalent in the table view.\",\n openAsTable: 'Open as table',\n});\n","/**\n * The explorer's API tab, on a table read from an HTTP connection: the\n * resource's two documented reads — its list GET and its item GET — as a\n * form drawn from the description alone, sent by the server, and answered\n * exactly as the API answered.\n *\n * Narrower than a request builder on purpose. The browser never names a URL,\n * a header or a parameter the description does not declare: the server builds\n * the request from the description, attaches the connection's credential and\n * sends it through egress, then says back the path, the query string, the\n * status and the body — never a header (packages/engine/src/server/http/httpOperationRoutes.ts).\n * A list's question can be opened as the table view asking the same thing,\n * where its parameters are filters and a sort the table view can say.\n */\nimport { useState, type FormEvent } from 'react';\nimport { useQuery } from '@tanstack/react-query';\nimport { api, go, quote, state, tableView } from '../core.js';\nimport type { HttpOperationReply, HttpOperations, HttpParam } from '@mistriwork/engine/shared/httpOperations.js';\nimport { JsonView } from './JsonView.js';\nimport { Delayed, GridSkeleton } from './Skeleton.js';\nimport { say } from '../copy/workbench/components/ApiOperations.js';\n\ntype Kind = 'list' | 'item';\ninterface SchemaLike {\n dialect?: string;\n tables?: Array<{ id: string; columns: Array<{ name: string }> }>;\n}\nconst schema = () => (state as { schema?: SchemaLike | null }).schema ?? null;\nconst connection = () => (state as { activeConnection?: string | null }).activeConnection ?? '';\n\n/* What a box is, said under it; a filter's own label is its column. */\nconst HINT: Record<HttpParam['kind'], string> = {\n filter: 'equals',\n search: say('theApisOwnSearch'),\n sort: '',\n offset: say('rowsToSkip'),\n limit: say('rowsPerPage'),\n page: say('pageNumber'),\n size: 'rows per page',\n cursor: '',\n};\n\n/** RFC 6901: where a cursor-paged answer names its next page. */\nfunction at(value: unknown, pointer: string): unknown {\n let current = value;\n for (const raw of pointer.slice(1).split('/')) {\n const key = raw.replace(/~1/g, '/').replace(/~0/g, '~');\n current =\n current && typeof current === 'object' && !Array.isArray(current) && Object.hasOwn(current, key)\n ? (current as Record<string, unknown>)[key]\n : undefined;\n }\n return current;\n}\n\n/* A documented sort value as the table view says it — \"-shipped_at\" is \"sort\n shipped_at desc\" — the spellings the adapter itself reads. Undefined when\n the value names no column of the table. */\nfunction sortClause(value: string, columns: readonly string[]): string | undefined {\n const suffixed = /^(.+?)(?::| |_)(asc|desc)$/.exec(value);\n const spelled = value.startsWith('-')\n ? { column: value.slice(1), desc: true }\n : value.startsWith('+')\n ? { column: value.slice(1), desc: false }\n : suffixed\n ? { column: suffixed[1], desc: suffixed[2] === 'desc' }\n : { column: value, desc: false };\n if (!columns.includes(spelled.column)) return undefined;\n return `sort ${spelled.column}${spelled.desc ? ' desc' : ''}`;\n}\n\n/**\n * The table view's question for a list's parameters, or undefined when a\n * parameter has no equivalent there: the API's search is its own, and a\n * sort value that names no column cannot be said.\n */\nfunction tableQuery(table: string, params: readonly HttpParam[], values: Record<string, string>): string | undefined {\n const columns =\n schema()\n ?.tables?.find((each) => each.id === table)\n ?.columns.map((column) => column.name) ?? [];\n const conditions: string[] = [];\n let sort = '';\n for (const param of params) {\n const value = (values[param.name] ?? '').trim();\n if (!value) continue;\n if (param.kind === 'search') return undefined;\n if (param.kind === 'filter' && param.column) {\n const each = param.many\n ? value\n .split(',')\n .map((part) => part.trim())\n .filter(Boolean)\n : [value];\n conditions.push(each.length > 1 ? `${param.column} in (${each.map(quote).join(', ')})` : `${param.column} = ${quote(each[0])}`);\n }\n if (param.kind === 'sort') {\n const clause = sortClause(value, columns);\n if (!clause) return undefined;\n sort = clause;\n }\n }\n return [table, conditions.join(' and '), sort].filter(Boolean).join(' ');\n}\n\nfunction ParamField({ param, value, onChange }: { param: HttpParam; value: string; onChange: (value: string) => void }) {\n const label = param.kind === 'filter' ? (param.column ?? param.name) : param.kind === 'search' ? say('navigation.search') : param.name;\n const hint =\n param.kind === 'filter'\n ? `${param.many ? say('oneValueOrSeveral') : HINT.filter} · ?${param.name}=`\n : HINT[param.kind]\n ? `${HINT[param.kind]} · ?${param.name}=`\n : `?${param.name}=`;\n return (\n <label className=\"field-stack\">\n <span>{label}</span>\n {param.kind === 'sort' ? (\n <select value={value} onChange={(event) => onChange(event.target.value)} aria-label={label}>\n <option value=\"\">{say('theApisOwnOrder')}</option>\n {(param.values ?? []).map((each) => (\n <option key={each} value={each}>\n {each}\n </option>\n ))}\n </select>\n ) : (\n <input\n value={value}\n onChange={(event) => onChange(event.target.value)}\n aria-label={label}\n inputMode={['offset', 'limit', 'page', 'size'].includes(param.kind) ? 'numeric' : undefined}\n />\n )}\n <span className=\"field-hint\">{hint}</span>\n </label>\n );\n}\n\nfunction Answer({ reply }: { reply: HttpOperationReply }) {\n const line = `${reply.request.method} ${reply.request.path}${reply.request.query ? `?${reply.request.query}` : ''}`;\n const answered = reply.status >= 200 && reply.status <= 299;\n return (\n <section className=\"api-answer\" aria-label={say('theApisAnswer')}>\n <p className=\"api-request\">\n <code>{line}</code>\n <span className=\"api-meta\">{say('statusTime', { status: reply.status, ms: reply.ms })}</span>\n </p>\n {!answered ? (\n <p className=\"note\">{say('theApiAnsweredTablewalk', { status: reply.status })}</p>\n ) : reply.json !== null && typeof reply.json === 'object' ? (\n <JsonView value={reply.json} />\n ) : (\n <pre className=\"ddl\">{JSON.stringify(reply.json)}</pre>\n )}\n </section>\n );\n}\n\nexport function ApiOperations({ table }: { table: string }) {\n const described = useQuery<HttpOperations>({\n queryKey: ['api-operations', connection(), table],\n queryFn: () => api('/api/http/operations', { resource: table }) as Promise<HttpOperations>,\n });\n const [kind, setKind] = useState<Kind>('list');\n const [values, setValues] = useState<Record<string, string>>({});\n const [key, setKey] = useState('');\n const [reply, setReply] = useState<HttpOperationReply | null>(null);\n const [error, setError] = useState<string | null>(null);\n const [pending, setPending] = useState(false);\n\n if (described.isError) return <p className=\"note\">{(described.error as Error).message}</p>;\n if (!described.data)\n return (\n <Delayed>\n <div className=\"host-contents\">\n <GridSkeleton columns={2} rows={4} />\n </div>\n </Delayed>\n );\n const operations = described.data;\n const boxes = operations.list.params.filter((param) => param.kind !== 'cursor');\n const cursor = operations.list.params.find((param) => param.kind === 'cursor');\n // Only what was typed: an empty box asks nothing of the API.\n const filled = Object.fromEntries(boxes.map((param) => [param.name, (values[param.name] ?? '').trim()]).filter(([, value]) => value));\n\n const send = async (params: Record<string, string>) => {\n setPending(true);\n setError(null);\n try {\n setReply((await api('/api/http/operation', { resource: table, operation: kind, params })) as HttpOperationReply);\n } catch (failure) {\n setReply(null);\n setError((failure as Error).message);\n } finally {\n setPending(false);\n }\n };\n const submit = (event: FormEvent) => {\n event.preventDefault();\n void send(kind === 'list' ? filled : { [operations.item.key]: key });\n };\n const choose = (next: Kind) => {\n setKind(next);\n setReply(null);\n setError(null);\n };\n /* A cursor-paged answer names its next page; asking for it sends that cursor with the same question. */\n const next =\n kind === 'list' && cursor && operations.list.next && reply?.json !== undefined ? at(reply.json, operations.list.next) : undefined;\n const question = kind === 'list' ? tableQuery(table, boxes, values) : undefined;\n\n return (\n <div className=\"panel-pad api-ops\">\n <form className=\"api-form\" onSubmit={submit} aria-label={say('tryTheApi', { table })}>\n <fieldset className=\"api-kind\">\n <legend>{say('read')}</legend>\n <label>\n <input type=\"radio\" name=\"api-kind\" checked={kind === 'list'} onChange={() => choose('list')} /> {say('aList')}{' '}\n <code>GET {operations.list.path}</code>\n </label>\n <label>\n <input type=\"radio\" name=\"api-kind\" checked={kind === 'item'} onChange={() => choose('item')} /> {say('oneRecord')}{' '}\n <code>GET {operations.item.path}</code>\n </label>\n </fieldset>\n <div className=\"api-fields\">\n {kind === 'item' ? (\n <label className=\"field-stack\">\n <span>{operations.item.key}</span>\n <input value={key} onChange={(event) => setKey(event.target.value)} aria-label={operations.item.key} />\n <span className=\"field-hint\">{say('theKeyTheItem')}</span>\n </label>\n ) : boxes.length ? (\n boxes.map((param) => (\n <ParamField\n key={param.name}\n param={param}\n value={values[param.name] ?? ''}\n onChange={(value) => setValues((current) => ({ ...current, [param.name]: value }))}\n />\n ))\n ) : (\n <p className=\"field-hint\">{say('thisListTakesNoParameters')}</p>\n )}\n </div>\n <div className=\"api-actions\">\n <button type=\"submit\" className=\"primary\" disabled={pending || (kind === 'item' && !key.trim())}>\n {say('send')}\n </button>\n {typeof next === 'string' && next && cursor && (\n <button type=\"button\" className=\"ghost\" disabled={pending} onClick={() => void send({ ...filled, [cursor.name]: next })}>\n {say('nextPage')}\n </button>\n )}\n {kind === 'list' && (\n <button\n type=\"button\"\n className=\"ghost\"\n disabled={question === undefined}\n title={question === undefined ? say('theApisSearchOrASort') : undefined}\n onClick={() => {\n if (question !== undefined) go(tableView(table, question), 'push');\n }}\n >\n {say('openAsTable')}\n </button>\n )}\n </div>\n </form>\n {error && (\n <p className=\"note\" role=\"alert\">\n {error}\n </p>\n )}\n {reply && <Answer reply={reply} />}\n </div>\n );\n}\n"],"mappings":"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"}