@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 +1 @@
1
- {"version":3,"file":"shared-DWYnjItP.js","names":["say","say","say","say","fillPageComposer","served","React","ReactDOM","ui","page"],"sources":["../../../kit/src/client/components/composerDraft.ts","../../src/shared/uiSdk.ts","../../src/client/components/sdk/rows.ts","../../src/client/copy/components/components/sdk/host.ts","../../src/client/copy/shell/appFlags.ts","../../src/client/appFlags.ts","../../src/shared/appAnalytics.ts","../../src/client/analyticsBeacon.ts","../../src/client/components/sdk/host.tsx","../../src/client/copy/components/components/sdk/componentLoader.ts","../../src/client/components/sdk/componentLoader.ts"],"sourcesContent":["/**\n * The page's one timeline composer, reachable from outside it: a custom\n * section's `useComposer().fill(...)` puts a template's words in the box\n * the reader then reads, edits and sends. Filling never sends — the send\n * stays the reader's, through the composer's own commands.\n *\n * One slot, not a list: a page draws at most one conversation, and the\n * latest composer mounted is the one in view.\n */\ntype ComposerMode = 'reply' | 'note';\ntype Fill = (text: string, mode?: ComposerMode) => void;\n\nlet current: Fill | null = null;\n\n/** The composer takes the slot while it is mounted; the returned function gives it back. */\nexport function holdComposer(fill: Fill): () => void {\n current = fill;\n return () => {\n if (current === fill) current = null;\n };\n}\n\n/** Puts `text` in the composer (and chooses its mode, where the page offers it); false when the page draws none. */\nexport function fillComposer(text: string, mode?: ComposerMode): boolean {\n if (!current) return false;\n current(text, mode);\n return true;\n}\n","/**\n * The public SDK a custom component draws with, `@mistriwork/mistri/ui`, as both sides\n * need to name it: the server serves each host module a component imports as\n * a small module over the page's own copy (componentSdk.ts), and a\n * component's bare names are written as their paths when it is served\n * (http/componentRoutes.ts). One\n * React, one QueryClient: a component that brought its own React would break\n * hooks, and one with its own query cache would outlive a sign-out.\n *\n * `UI_EXPORTS` is the SDK's runtime surface, pinned against the module that\n * implements it (packages/mistri/src/client/components/sdk/index.ts) by a component test, so\n * the served module can never offer a name the host does not have.\n */\n\n/** Where the host modules are served, and the bare names a served component's imports are written from. */\nexport const SDK_PATH = '/_mistri/sdk/';\nexport const HOST_MODULES = {\n react: 'react.js',\n 'react/jsx-runtime': 'react-jsx-runtime.js',\n 'react-dom': 'react-dom.js',\n '@mistriwork/mistri/ui': 'ui.js',\n '@mistriwork/mistri/page': 'page.js',\n} as const;\nexport type HostModule = keyof typeof HOST_MODULES;\n/** The host modules once each. Pure, so the page's bundle, which reads only `HOST_GLOBAL` here, drops it. */\nexport const SERVED_MODULES = /* @__PURE__ */ Object.keys(HOST_MODULES) as HostModule[];\n\n/** The global the page puts its modules on, read only by the served host modules. */\nexport const HOST_GLOBAL = '__mistri';\n\n/** Every value `@mistriwork/mistri/ui` exports. */\nexport const UI_EXPORTS = [\n 'React',\n 'Fragment',\n 'useState',\n 'useEffect',\n 'useMemo',\n 'useRef',\n 'useCallback',\n 'useId',\n 'useReducer',\n 'useContext',\n 'Card',\n 'Stack',\n 'Row',\n 'Heading',\n 'Button',\n 'Dropdown',\n 'SplitListDetail',\n 'Value',\n 'Tone',\n 'Meter',\n 'Empty',\n 'Loaded',\n 'Icon',\n 'Segmented',\n 'Stat',\n 'Columns',\n 'Table',\n 'useRows',\n 'useRecord',\n 'useBreakdown',\n 'useNavigate',\n 'useComposer',\n 'useFormat',\n 'useLook',\n 'useToken',\n 'tokens',\n 'useSectionSize',\n 'useCommand',\n 'useViewer',\n 'useFile',\n 'useFlags',\n 'useVisitor',\n 'useAnalytics',\n 'useMessage',\n] as const;\n\n/**\n * Every value `@mistriwork/mistri/page` exports: `definePage`, and the blocks a\n * free-form page draws with — the kit's layout and parts, and the\n * platform's own command form (components/sdk/page.tsx).\n */\nexport const PAGE_EXPORTS = [\n 'definePage',\n 'useAddressState',\n 'CommandForm',\n 'Stack',\n 'Row',\n 'Columns',\n 'Card',\n 'Heading',\n 'Button',\n 'Empty',\n 'Loaded',\n 'Stat',\n 'Value',\n 'Grid',\n 'Panel',\n 'Tabs',\n 'Rows',\n 'RecordCard',\n 'Metric',\n 'Chart',\n 'Breakdown',\n 'Timeline',\n 'Tree',\n 'Gantt',\n 'Assistant',\n] as const;\n\n/** Where an App's compiled components are served: `/{app}/_components/<file>`. */\nexport const COMPONENTS_SEGMENT = '_components';\n","/**\n * A view's answer as a component reads it: each row keyed by the paths it\n * asked for, in the words it wrote them (`customer_id.name`), whatever name\n * the server's result gave the column. Shared by the declared reads of a\n * custom section and the SDK's hooks, so both hand a component one shape.\n */\nimport type { UiRow } from './context.js';\nimport { resolvePath } from '@mistriwork/engine/shared/viewPaths.js';\nimport type { DatabaseSchema } from '@mistriwork/engine/shared/schema.js';\n\n/** Where a read's paths start, so a column's declared type can be found for each. */\ninterface RowsBase {\n schema: DatabaseSchema | null | undefined;\n base: string;\n}\n\ninterface ViewAnswer {\n view?: unknown;\n columns?: string[];\n rows?: UiRow[];\n errors?: Array<{ message: string }>;\n}\n\n/* The server hands a Postgres timestamp as the text the database stores\n (postgresDates.ts, on purpose: the grid shows what is stored), so\n `2026-10-12 19:16:00-04` reaches a component, and `Date.parse` reads that,\n and the `+00` of UTC, as NaN. A component computes with its times, so it is\n handed ISO 8601 with a full offset. Only the strict shape of a database's\n timestamp text is touched, and only in a column declared a timestamp: a\n string that merely looks like one is the author's. A timestamp without a\n zone stays without one; an offset is never invented. */\nconst TIMESTAMP_TEXT = /^(\\d{4}-\\d{2}-\\d{2})[ T](\\d{2}:\\d{2}(?::\\d{2}(?:\\.\\d+)?)?)\\s*(Z|[+-]\\d{2}(?::?\\d{2})?)?$/;\n\nfunction isoTimestamp(value: unknown): unknown {\n if (typeof value !== 'string') return value;\n const match = TIMESTAMP_TEXT.exec(value.trim());\n if (!match) return value;\n const [, day, time, zone] = match;\n let offset = '';\n if (zone === 'Z') offset = 'Z';\n else if (zone) {\n const digits = zone.slice(1).replace(':', '');\n offset = `${zone[0]}${digits.slice(0, 2)}:${digits.slice(2) || '00'}`;\n }\n return `${day}T${time.length === 5 ? `${time}:00` : time}${offset}`;\n}\n\nconst isTimestampColumn = (type: string) => /timestamp|datetime/i.test(type ?? '');\n\nfunction timestampPaths(paths: readonly string[], typed: RowsBase | undefined): Set<string> {\n const found = new Set<string>();\n if (!typed?.schema) return found;\n for (const path of paths) {\n try {\n const resolved = resolvePath(typed.schema, typed.base, path);\n if (!resolved.rollup && !resolved.computed && !resolved.tags && !resolved.jsonKey && isTimestampColumn(resolved.column.type))\n found.add(path);\n } catch {\n /* A path the schema cannot resolve is the server's to refuse; it is read as it came. */\n }\n }\n return found;\n}\n\nexport function rowsByPath(paths: readonly string[], got: ViewAnswer, fallback: string, typed?: RowsBase): UiRow[] {\n if (!got || !('view' in got) || !Array.isArray(got.rows)) throw new Error(got?.errors?.[0]?.message ?? fallback);\n const columns = got.columns ?? [...paths];\n /* Each value by its path's own column, not by where the path stands in the\n asking list: a record page reads its row once for every section, in the\n order the first one named the columns, and hands each section its own\n columns of that one answer (composedReads.ts). Zipped by position, a\n section that named shared columns in another order read one column's\n value under another's name. The answer's view says which path each of its\n columns is. */\n const answered = (got.view as { columns?: Array<{ path?: unknown }> } | null | undefined)?.columns;\n const nameOf = new Map<string, string>();\n if (Array.isArray(answered))\n answered.forEach((column, i) => {\n if (typeof column?.path === 'string' && columns[i] !== undefined && !nameOf.has(column.path)) nameOf.set(column.path, columns[i]);\n });\n const stamps = timestampPaths(paths, typed);\n return got.rows.map((row) =>\n Object.fromEntries(\n paths.map((path, i) => {\n const value = row[nameOf.get(path) ?? columns[i] ?? path];\n return [path, stamps.has(path) ? isoTimestamp(value) : value];\n }),\n ),\n );\n}\n","/** What sdk/host 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 isNotOneOfThisApps: '\"{resource}\" is not one of this App\\'s resources.',\n theRowsOfCould: 'The rows of \"{name}\" could not be read.',\n isNotAList: '\"{view}\" is not a list or dashboard this reader is served.',\n thePageCannotOpen: 'The page cannot open a form yet; try again once it has loaded.',\n thisPageCannotRun: 'This page cannot run commands.',\n});\n","/** What appFlags says, in the shell 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 visitorUnavailable: 'Visitor experiments are unavailable for this App or session.',\n ownerUnavailable: 'No active App flag owner.',\n requestOwnerRetired: 'Flag request owner retired.',\n responseOwnerChanged: 'Flag response owner changed.',\n valuesUnavailable: 'Evaluated flag values unavailable.',\n responseTooLarge: 'Flag response too large.',\n valuesNotReady: 'Evaluated flag values are not ready for this App.',\n undeclaredFlag: 'Undeclared evaluated flag: {key}.',\n});\n","/** Called once, on first SDK flags use. Nothing is hydrated from HTML/storage. */\nimport {\n APP_FLAG_VALUES_PATH,\n EXPERIMENT_VISITOR_PATH,\n EXPERIMENT_FORM_HEADER,\n EXPERIMENT_ADDRESS_HEADER,\n type ExperimentVisitorSelection,\n captureAppFlagValues,\n type AppFlagReader,\n type AppFlagValues,\n} from '../shared/appFlagValues.js';\nimport {\n assertSessionCurrent,\n captureTenantLease,\n sessionIdentity,\n subscribeSessionIdentity,\n subscribeTenantLease,\n tenantLeaseActive,\n} from '@mistriwork/kit/client/sessionIdentity.js';\nimport { appPresentation, subscribeAppPresentation } from '@mistriwork/kit/client/connectionTransition.js';\nimport type { createExperimentExposureQueue, ExposureCoverage } from './experimentExposure.js';\nimport { say } from './copy/shell/appFlags.js';\nimport { fetchServer } from '@mistriwork/kit/client/transport.js';\n\nconst emptyExposureCoverage = (): ExposureCoverage => ({\n queued: 0,\n inFlight: 0,\n recorded: 0,\n duplicate: 0,\n failed: 0,\n unknown: 0,\n dropped: 0,\n});\ntype ExposureSender = Parameters<typeof createExperimentExposureQueue>[0];\n\nexport interface AppFlagsSource extends AppFlagReader {\n snapshot(): AppFlagReader;\n subscribe(listener: () => void): () => void;\n load(): Promise<void>;\n /** Explicit browser actual-use lifecycle port. get/snapshot/load are passive;\n * only a committed render (or an explicit consumed feature) calls this. */\n commitUse?(reader: AppFlagReader, keys: readonly string[]): void;\n exposureCoverage?(): ExposureCoverage;\n /** Explicit user action only. Never called by flag reads or rendering. */\n establishVisitor?(selection?: ExperimentVisitorSelection): Promise<void>;\n}\n\nexport function createPageAppFlags(active: () => string | null) {\n let disposed = false;\n let visitorSelection: ExperimentVisitorSelection = Object.freeze({});\n const visitorHeaders = () => ({\n ...(visitorSelection.form ? { [EXPERIMENT_FORM_HEADER]: visitorSelection.form } : {}),\n ...(visitorSelection.address ? { [EXPERIMENT_ADDRESS_HEADER]: visitorSelection.address } : {}),\n });\n const source = createAppFlagsState({\n async exposure(owner, signal) {\n // Capture native ownership before loading optional experiment delivery.\n const identity = sessionIdentity(),\n lease = captureTenantLease(identity);\n if (identity.mode !== 'authenticated' && identity.mode !== 'anonymous') return;\n const { captureExperimentExposureSender } = await import('./experimentExposure.js');\n if (signal.aborted || !owner.current() || identity !== sessionIdentity() || lease !== captureTenantLease(identity)) return;\n return captureExperimentExposureSender(owner, { visitor: identity.mode === 'anonymous', selection: visitorSelection });\n },\n capture() {\n const appId = active(),\n identity = sessionIdentity(),\n presentation = appPresentation(),\n selection = visitorSelection;\n if (disposed || !appId || !presentation.available || identity.appId !== appId) throw new Error(say('ownerUnavailable'));\n assertSessionCurrent(identity);\n return {\n appId,\n current: () =>\n !disposed &&\n visitorSelection === selection &&\n active() === appId &&\n identity === sessionIdentity() &&\n presentation.generation === appPresentation().generation &&\n appPresentation().available &&\n (!identity.tenantRequired || tenantLeaseActive(identity)),\n };\n },\n async read(owner, signal) {\n const identity = sessionIdentity();\n if (!owner.current()) throw new Error(say('requestOwnerRetired'));\n const path = `${APP_FLAG_VALUES_PATH}?${new URLSearchParams({ app: owner.appId })}`;\n if (identity.tenantRequired) {\n const { tenantReadApi } = await import('./tenantTransport.js');\n if (!owner.current() || signal.aborted) throw new Error(say('requestOwnerRetired'));\n return tenantReadApi(path, undefined, owner.appId, signal);\n }\n const response = await fetchServer(path, {\n signal,\n method: 'GET',\n credentials: 'same-origin',\n cache: 'no-store',\n headers: identity.mode === 'authenticated' ? { 'x-mistri-account': identity.accountId! } : visitorHeaders(),\n });\n if (!owner.current() || signal.aborted) throw new Error(say('requestOwnerRetired'));\n try {\n assertSessionCurrent(identity, response.headers.get('x-mistri-account'));\n if (\n (identity.mode === 'anonymous' && response.headers.get('x-mistri-account')) ||\n response.status === 401 ||\n response.headers.get('x-mistri-app') !== owner.appId\n )\n throw new Error(say('responseOwnerChanged'));\n } catch (error) {\n const { invalidateSession } = await import('@mistriwork/kit/client/sessionLifecycle.js');\n if (owner.current()) invalidateSession('account-changed');\n throw error;\n }\n if (!response.ok) throw new Error(say('valuesUnavailable'));\n const text = await response.text();\n if (text.length > 1024 * 1024) throw new Error(say('responseTooLarge'));\n return JSON.parse(text) as unknown;\n },\n });\n const unsubscribe = [\n subscribeSessionIdentity(source.retire),\n subscribeTenantLease(source.retire),\n subscribeAppPresentation(source.retire),\n ];\n return Object.freeze({\n ...source,\n get ready() {\n return source.ready;\n },\n async establishVisitor(selection: ExperimentVisitorSelection = {}) {\n if (\n Object.keys(selection).some((key) => !['form', 'address'].includes(key)) ||\n (selection.form !== undefined && !/^[a-z0-9][a-z0-9-]{0,63}$/.test(selection.form)) ||\n (selection.address !== undefined &&\n (!selection.form ||\n typeof selection.address !== 'string' ||\n selection.address.length > 512 ||\n /[\\p{Cc}\\p{Cs}]/u.test(selection.address)))\n )\n throw new Error(say('visitorUnavailable'));\n const selected = Object.freeze({ ...selection });\n visitorSelection = selected;\n source.retire();\n const identity = sessionIdentity(),\n appId = active(),\n presentation = appPresentation();\n if (disposed || !appId || identity.appId !== appId || identity.mode !== 'anonymous' || !presentation.available)\n throw new Error(say('visitorUnavailable'));\n const current = () =>\n !disposed &&\n visitorSelection === selected &&\n active() === appId &&\n identity === sessionIdentity() &&\n presentation.generation === appPresentation().generation &&\n appPresentation().available;\n const response = await fetchServer(EXPERIMENT_VISITOR_PATH, {\n method: 'POST',\n credentials: 'same-origin',\n cache: 'no-store',\n headers: { 'content-type': 'application/json', 'x-mistri-visitor': 'establish', ...visitorHeaders() },\n body: '{}',\n signal: AbortSignal.timeout(10000),\n });\n if (!current() || !response.ok || response.headers.get('x-mistri-app') !== appId || response.headers.has('x-mistri-account'))\n throw new Error(say('visitorUnavailable'));\n const text = await response.text();\n if (!current() || text.length > 128) throw new Error(say('visitorUnavailable'));\n const reply = JSON.parse(text) as unknown;\n if (!reply || typeof reply !== 'object' || Object.keys(reply).length !== 1 || (reply as { ready?: unknown }).ready !== true)\n throw new Error(say('visitorUnavailable'));\n source.retire();\n await source.load();\n },\n dispose() {\n disposed = true;\n for (const stop of unsubscribe) stop();\n source.retire();\n },\n });\n}\ninterface AppFlagsOwner {\n readonly appId: string;\n current(): boolean;\n}\n\n/** SDK-only state. The host supplies ordinary transport and synchronous owner\n * retirement. No persistence, SSR adoption or client targeting. Imperative get\n * is passive; reporting requires the explicit commitUse lifecycle port. */\nexport function createAppFlagsState(port: {\n capture(): AppFlagsOwner;\n read(owner: AppFlagsOwner, signal: AbortSignal): Promise<unknown>;\n exposure?(owner: AppFlagsOwner, signal: AbortSignal): ExposureSender | undefined | Promise<ExposureSender | undefined>;\n}) {\n const listeners = new Set<() => void>();\n let generation = 0,\n controller: AbortController | undefined,\n pending: Promise<void> | undefined;\n let attempted = false;\n let exposures: ReturnType<typeof createExperimentExposureQueue> | undefined;\n let assignmentReceipts: AppFlagValues['assignmentReceipts'];\n let retiredCoverage = emptyExposureCoverage();\n const unavailable = () => new Error(say('valuesNotReady'));\n const reader = (data?: AppFlagValues, owner?: AppFlagsOwner, failure?: unknown): AppFlagReader => {\n const captured = generation,\n values = data?.values;\n const current = () => captured === generation && !!owner?.current();\n return Object.freeze({\n get ready() {\n return !!values && current();\n },\n get(key: string) {\n if (!values || !current()) throw failure instanceof Error ? failure : unavailable();\n if (!Object.hasOwn(values, key)) throw new Error(say('undeclaredFlag', { key }));\n return values[key];\n },\n });\n };\n let snapshot = reader();\n const notify = () => {\n for (const listener of [...listeners]) {\n try {\n listener();\n } catch {\n /* Observers cannot veto retirement. */\n }\n }\n };\n const retire = () => {\n ++generation;\n assignmentReceipts = undefined;\n if (exposures) {\n exposures.retire();\n const ended = exposures.coverage();\n retiredCoverage = Object.fromEntries(\n Object.entries(retiredCoverage).map(([key, value]) => [key, value + ended[key as keyof ExposureCoverage]]),\n ) as unknown as ExposureCoverage;\n exposures = undefined;\n }\n controller?.abort();\n controller = undefined;\n pending = undefined;\n attempted = false;\n snapshot = reader();\n notify();\n };\n return Object.freeze({\n get ready() {\n return snapshot.ready;\n },\n get: (key: string) => snapshot.get(key),\n snapshot: () => snapshot,\n commitUse(reader: AppFlagReader, keys: readonly string[]) {\n if (reader !== snapshot || !reader.ready) return;\n for (const key of keys) {\n const receipt = assignmentReceipts && Object.hasOwn(assignmentReceipts, key) ? assignmentReceipts[key] : undefined;\n if (receipt) exposures?.consume(receipt);\n }\n },\n exposureCoverage(): ExposureCoverage {\n const active = exposures?.coverage() ?? emptyExposureCoverage();\n return Object.freeze(\n Object.fromEntries(Object.entries(retiredCoverage).map(([key, value]) => [key, value + active[key as keyof ExposureCoverage]])),\n ) as unknown as ExposureCoverage;\n },\n subscribe(listener: () => void) {\n listeners.add(listener);\n return () => {\n listeners.delete(listener);\n };\n },\n retire,\n load(): Promise<void> {\n if (pending) return pending;\n if (attempted) return Promise.resolve();\n attempted = true;\n const started = generation,\n abort = (controller = new AbortController());\n pending = (async () => {\n let owner: AppFlagsOwner | undefined;\n try {\n owner = port.capture();\n if (!owner.current()) throw unavailable();\n const raw = await port.read(owner, abort.signal);\n if (started !== generation || abort.signal.aborted || !owner.current()) return;\n const data = captureAppFlagValues(raw);\n if (started !== generation || abort.signal.aborted || !owner.current()) return;\n if (port.exposure && data.assignmentReceipts && Object.keys(data.assignmentReceipts).length) {\n const sender = await port.exposure(owner, abort.signal);\n if (started !== generation || abort.signal.aborted || !owner.current()) return;\n if (sender) {\n const { createExperimentExposureQueue } = await import('./experimentExposure.js');\n if (started !== generation || abort.signal.aborted || !owner.current()) return;\n assignmentReceipts = data.assignmentReceipts;\n exposures = createExperimentExposureQueue(sender);\n }\n }\n snapshot = reader(data, owner);\n notify();\n } catch (error) {\n if (started !== generation || abort.signal.aborted || (owner && !owner.current())) return;\n snapshot = reader(undefined, undefined, error);\n notify();\n } finally {\n if (started === generation) pending = undefined;\n }\n })();\n return pending;\n },\n });\n}\n","/**\n * Behavior analytics, declared: which built-in kinds an App collects, the\n * custom events its components may emit, and the funnels read over them.\n *\n * Off unless declared. A declaration only names things; what is stored, and\n * where, is the `analytics` store's (src/server/analytics/), bound by\n * configuration, never by the App. The finding codes `analytics-unknown-step`,\n * `analytics-not-collected` and `analytics-name-clash` are carried in\n * brackets, which is how `mistri check --json` reads a code.\n */\nimport { isFormView, type AppDef } from './appModel.js';\nimport { isRecord, VIEW_KEY } from '@mistriwork/engine/shared/model.js';\nimport { captureFlagDeclaration } from './appExperiments.js';\nimport { DURATION_WORDS, parseDuration } from '@mistriwork/engine/shared/duration.js';\n\nconst ANALYTICS_KINDS = ['views', 'commands', 'forms'] as const;\nexport type AnalyticsKind = (typeof ANALYTICS_KINDS)[number];\n\n/** Closed bounds: a declaration is data a person reads, not a pipeline. */\nexport const ANALYTICS_LIMITS = Object.freeze({ events: 64, eventFields: 16, funnels: 32, steps: 10, windowHours: 8760, valueLength: 200 });\n\n/** Exactly one of view, command, form (with an optional step) or event. */\nexport type AnalyticsStep =\n | { readonly view: string }\n | { readonly command: string }\n | { readonly form: string; readonly step?: string }\n | { readonly event: string };\n\nexport interface AnalyticsFunnel {\n readonly unit: 'subject' | 'visitor';\n /** `'72 hours'`: how long after its first step a subject may take the rest. */\n readonly conversionWindow: string;\n readonly steps: readonly AnalyticsStep[];\n}\n\nexport interface AnalyticsDeclaration {\n readonly collect?: readonly AnalyticsKind[];\n readonly events?: Readonly<Record<string, { readonly fields: readonly string[] }>>;\n readonly funnels?: Readonly<Record<string, AnalyticsFunnel>>;\n}\n\nconst NAME = /^[A-Za-z][A-Za-z0-9_.-]{0,127}$/;\nconst FIELD = /^[A-Za-z_][A-Za-z0-9_]{0,63}$/;\nconst FORBIDDEN = new Set(['__proto__', 'prototype', 'constructor']);\n\nfunction object(value: unknown, at: string, keys: readonly string[]): Record<string, unknown> {\n if (!isRecord(value)) throw new Error(`${at} must be an object.`);\n for (const key of Object.keys(value))\n if (!keys.includes(key)) throw new Error(`${at} has \"${key}\", which it does not take. It takes: ${keys.join(', ')}.`);\n return value;\n}\n\n/** The authored `analytics` block, closed and frozen. Throws a sentence naming where. */\nexport function normalizeAnalytics(input: unknown, where: string): AnalyticsDeclaration {\n const at = `${where}: analytics`;\n const raw = object(captureFlagDeclaration(input), at, ['collect', 'events', 'funnels']);\n let collect: AnalyticsKind[] | undefined;\n if (raw.collect !== undefined) {\n if (\n !Array.isArray(raw.collect) ||\n raw.collect.some((kind) => !ANALYTICS_KINDS.includes(kind as AnalyticsKind)) ||\n new Set(raw.collect).size !== raw.collect.length\n ) {\n if (Array.isArray(raw.collect) && raw.collect.includes('actions'))\n throw new Error(`${at} collect has \"actions\", which is now \"commands\": the command runs an action or a form starts.`);\n throw new Error(`${at} collect is a list of ${ANALYTICS_KINDS.map((kind) => `\"${kind}\"`).join(', ')}, each once.`);\n }\n collect = [...raw.collect] as AnalyticsKind[];\n }\n let events: Record<string, { fields: readonly string[] }> | undefined;\n if (raw.events !== undefined) {\n const declared = object(raw.events, `${at} events`, Object.keys(isRecord(raw.events) ? raw.events : {}));\n if (Object.keys(declared).length > ANALYTICS_LIMITS.events)\n throw new Error(`${at} events holds at most ${ANALYTICS_LIMITS.events} events.`);\n events = {};\n for (const [name, value] of Object.entries(declared)) {\n // An App's own names, a custom event's and a funnel's, are spelled as its view ids are.\n if (!VIEW_KEY.test(name))\n throw new Error(`${at} events \"${name}\" is not an id of lowercase letters, digits and \"-\", as a view id is ('compare-opened').`);\n const event = object(value, `${at} events \"${name}\"`, ['fields']);\n const fields = event.fields ?? [];\n if (\n !Array.isArray(fields) ||\n fields.length > ANALYTICS_LIMITS.eventFields ||\n fields.some((field) => typeof field !== 'string' || !FIELD.test(field) || FORBIDDEN.has(field)) ||\n new Set(fields).size !== fields.length\n ) {\n throw new Error(`${at} events \"${name}\" fields is a list of at most ${ANALYTICS_LIMITS.eventFields} distinct field names.`);\n }\n events[name] = Object.freeze({ fields: Object.freeze([...fields] as string[]) });\n }\n }\n let funnels: Record<string, AnalyticsFunnel> | undefined;\n if (raw.funnels !== undefined) {\n const declared = object(raw.funnels, `${at} funnels`, Object.keys(isRecord(raw.funnels) ? raw.funnels : {}));\n if (Object.keys(declared).length > ANALYTICS_LIMITS.funnels)\n throw new Error(`${at} funnels holds at most ${ANALYTICS_LIMITS.funnels} funnels.`);\n funnels = {};\n for (const [id, value] of Object.entries(declared)) {\n if (!VIEW_KEY.test(id))\n throw new Error(`${at} funnels \"${id}\" is not an id of lowercase letters, digits and \"-\", as a view id is ('apply-funnel').`);\n const here = `${at} funnel \"${id}\"`;\n const funnel = object(value, here, ['unit', 'conversionWindow', 'steps']);\n if (funnel.unit !== 'subject' && funnel.unit !== 'visitor') throw new Error(`${here} unit is \"subject\" or \"visitor\".`);\n const windowMs = parseDuration(funnel.conversionWindow);\n if (!windowMs || windowMs > ANALYTICS_LIMITS.windowHours * 3_600_000) {\n throw new Error(\n `${here} conversionWindow is ${DURATION_WORDS}, above zero and at most a year ('${ANALYTICS_LIMITS.windowHours} hours').`,\n );\n }\n if (!Array.isArray(funnel.steps) || funnel.steps.length < 2 || funnel.steps.length > ANALYTICS_LIMITS.steps) {\n throw new Error(`${here} steps is a list of 2 to ${ANALYTICS_LIMITS.steps} steps.`);\n }\n const steps = funnel.steps.map((entry, index): AnalyticsStep => {\n const step = `${here} step ${index + 1}`;\n if (isRecord(entry) && entry.action !== undefined)\n throw new Error(`${step} has \"action\", which is now \"command\": the id of the command it counts.`);\n const given = isRecord(entry) ? Object.keys(entry).filter((key) => ['view', 'command', 'form', 'event'].includes(key)) : [];\n if (given.length !== 1) throw new Error(`${step} names exactly one of view, command, form or event.`);\n const kind = given[0] as 'view' | 'command' | 'form' | 'event';\n const record = object(entry, step, kind === 'form' ? ['form', 'step'] : [kind]);\n const name = record[kind];\n if (typeof name !== 'string' || !NAME.test(name) || FORBIDDEN.has(name)) throw new Error(`${step} ${kind} is not a name.`);\n if (record.step !== undefined && (typeof record.step !== 'string' || !NAME.test(record.step)))\n throw new Error(`${step} step is not a name.`);\n return Object.freeze(\n kind === 'form' ? { form: name, ...(record.step === undefined ? {} : { step: record.step as string }) } : { [kind]: name },\n ) as AnalyticsStep;\n });\n funnels[id] = Object.freeze({\n unit: funnel.unit,\n conversionWindow: (funnel.conversionWindow as string).trim(),\n steps: Object.freeze(steps),\n });\n }\n }\n return Object.freeze({\n ...(collect ? { collect: Object.freeze(collect) } : {}),\n ...(events ? { events: Object.freeze(events) } : {}),\n ...(funnels ? { funnels: Object.freeze(funnels) } : {}),\n });\n}\n\n/** The beacon's path, after the App's mount. Reserved: no App id or view starts with an underscore. */\nexport const ANALYTICS_BEACON_PATH = '/_mistri/analytics';\n\n/** What a funnel's steps name, read off the parsed App: views and pages, the commands actions and forms run, forms and their steps. */\nexport function analyticsCatalog(app: AppDef, pages: ReadonlyArray<{ id: string }> = []): AnalyticsCatalog {\n const views = new Set<string>(pages.map((page) => page.id)),\n commands = new Set<string>();\n const forms = new Map<string, readonly string[]>();\n for (const [key, view] of Object.entries(app.views)) {\n if (isFormView(view)) {\n forms.set(\n key,\n (view.steps ?? []).map((step) => step.id),\n );\n commands.add(view.command.id);\n for (const step of view.steps ?? []) if (step.command) commands.add(step.command.id);\n } else views.add(key);\n }\n // The landing is kept apart from the views, and it is the first step of most funnels.\n if (app.landing) views.add(app.landing.view);\n for (const [name, resource] of Object.entries(app.resources ?? {})) {\n if (resource.form)\n forms.set(\n name,\n (resource.form.steps ?? []).map((step) => step.id),\n );\n for (const action of resource.actions ?? []) if ('command' in action && action.command) commands.add(action.command.id);\n }\n return { views, commands, forms };\n}\n\n/** What the references of a funnel are checked against. */\nexport interface AnalyticsCatalog {\n /** Every list or dashboard view key, the landing's, and every page id. */\n readonly views: ReadonlySet<string>;\n /** The command ids an action or a form runs: what the server sees at admission. */\n readonly commands: ReadonlySet<string>;\n /** A form's id (a form view key or a resource with a New form) to its step ids. */\n readonly forms: ReadonlyMap<string, readonly string[]>;\n /** The names `defineEvent` issued, when the caller can see them; absent, a business event is not judged. */\n readonly businessEvents?: ReadonlySet<string>;\n}\n\n/** The step's kind, and the built-in kind it needs collected. */\nexport const stepKind = (step: AnalyticsStep): 'view' | 'command' | 'form' | 'event' =>\n 'view' in step ? 'view' : 'command' in step ? 'command' : 'form' in step ? 'form' : 'event';\nconst COLLECTS = { view: 'views', command: 'commands', form: 'forms' } as const;\n\n/** Every problem a declaration has against the App it belongs to, each ending in its finding code. */\nexport function analyticsProblems(declaration: AnalyticsDeclaration, catalog: AnalyticsCatalog, where: string): string[] {\n const problems: string[] = [];\n const custom = Object.keys(declaration.events ?? {});\n for (const name of custom) {\n if (catalog.businessEvents?.has(name)) {\n problems.push(\n `${where}: analytics events \"${name}\" is also a business event of this App. Custom and business events share one namespace: rename the custom one. [analytics-name-clash]`,\n );\n }\n }\n for (const [id, funnel] of Object.entries(declaration.funnels ?? {})) {\n funnel.steps.forEach((step, index) => {\n const here = `${where}: analytics funnel \"${id}\" step ${index + 1}`;\n const kind = stepKind(step);\n let known = true;\n if ('view' in step) known = catalog.views.has(step.view);\n else if ('command' in step) known = catalog.commands.has(step.command);\n else if ('form' in step) {\n const steps = catalog.forms.get(step.form);\n known = !!steps && (step.step === undefined || steps.includes(step.step));\n } else known = custom.includes(step.event) || !catalog.businessEvents || catalog.businessEvents.has(step.event);\n if (!known) {\n problems.push(\n `${here} names ${kind} \"${(step as Record<string, string>)[kind]}${'step' in step && step.step ? `\", step \"${step.step}` : ''}\", which this App does not declare. [analytics-unknown-step]`,\n );\n return;\n }\n if (kind !== 'event' && !declaration.collect?.includes(COLLECTS[kind])) {\n problems.push(\n `${here} counts ${kind}s, and analytics.collect does not list \"${COLLECTS[kind]}\", so none is recorded. [analytics-not-collected]`,\n );\n }\n });\n }\n return problems;\n}\n","/**\n * Behavior events from the page, batched and sent to the App's one beacon\n * route. Nothing here identifies anyone: the server takes the unit from the\n * session or the visitor cookie, so a body carries only a kind, a declared\n * name, the declared fields and how long ago it happened. A failure is\n * dropped, never retried or stored: this is telemetry, not a record.\n */\nimport { ANALYTICS_BEACON_PATH } from '../shared/appAnalytics.js';\nimport { addHostListener } from '@mistriwork/kit/client/shellHost.js';\nimport { fetchServer } from '@mistriwork/kit/client/transport.js';\n\ntype AnalyticsFields = Readonly<Record<string, string | number | boolean>>;\ninterface Queued {\n readonly kind: 'event' | 'view' | 'form';\n readonly name: string;\n readonly at: number;\n readonly fields?: AnalyticsFields;\n readonly step?: string;\n readonly route?: string;\n}\n\nconst BATCH = 20,\n DELAY_MS = 1500;\n\nexport function createAnalyticsBeacon(options: {\n readonly send: (body: string) => void;\n readonly now?: () => number;\n readonly delayMs?: number;\n}) {\n const now = options.now ?? Date.now,\n delay = options.delayMs ?? DELAY_MS;\n let queue: Queued[] = [],\n timer: ReturnType<typeof setTimeout> | undefined;\n const flush = () => {\n if (timer) {\n clearTimeout(timer);\n timer = undefined;\n }\n if (!queue.length) return;\n const at = now(),\n events = queue.map(({ at: when, ...rest }) => ({ ...rest, age: Math.max(0, at - when) }));\n queue = [];\n try {\n options.send(JSON.stringify({ events }));\n } catch {\n /* telemetry is never a reason to fail a page */\n }\n };\n const add = (event: Omit<Queued, 'at'>) => {\n queue.push({ ...event, at: now() });\n if (queue.length >= BATCH) flush();\n else timer ??= setTimeout(flush, delay);\n };\n return Object.freeze({\n /** A component's own event: the name and fields the App declared (the server drops the rest). */\n emit(name: string, fields?: AnalyticsFields) {\n if (typeof name !== 'string' || !name || name.length > 128) throw new Error('An analytics event is named with its declared name.');\n add({ kind: 'event', name, ...(fields ? { fields: { ...fields } } : {}) });\n },\n view(name: string, route?: string) {\n add({ kind: 'view', name, ...(route ? { route } : {}) });\n },\n form(name: string, step?: string) {\n add({ kind: 'form', name, ...(step ? { step } : {}) });\n },\n flush,\n });\n}\n\n/** The page's beacon: a keepalive POST to this App's route, so a closing tab still sends. */\nexport function pageAnalyticsBeacon() {\n const beacon = createAnalyticsBeacon({\n send: (body) => {\n void fetchServer(ANALYTICS_BEACON_PATH, {\n method: 'POST',\n credentials: 'same-origin',\n cache: 'no-store',\n keepalive: true,\n headers: { 'content-type': 'application/json' },\n body,\n }).catch(() => {});\n },\n });\n if (typeof document !== 'undefined')\n addHostListener(document, 'visibilitychange', () => {\n if (document.visibilityState === 'hidden') beacon.flush();\n });\n return beacon;\n}\n","/**\n * The page's side of `@mistriwork/mistri/ui`: the host a component's kit and hooks\n * read (context.ts), over the App payload and the session endpoints, and the\n * page's own modules put on one frozen global for the host modules a\n * served component imports (packages/mistri/src/server/app/componentSdk.ts).\n *\n * Loaded with the first custom section or value renderer a page draws, never\n * before: an App without components pays nothing for it. Every read is an\n * ordinary request under the reader's session (`/api/view/run`,\n * `/api/breakdown`), authorized on the server; a resource is named as the\n * App names it, and one the App does not declare is refused here as a\n * mistake before it is refused there as a denial.\n */\nimport * as React from 'react';\nimport * as JsxRuntime from 'react/jsx-runtime';\nimport * as ReactDOM from 'react-dom';\nimport * as ui from './index.js';\nimport * as page from './page.js';\nimport './kit.css';\nimport { api, columnDisplay, columnLabel, openRecord, pageApi, primaryKey, quote, state } from '@mistriwork/kit/client/core.js';\nimport { PAGE_LOAD_PATH } from '@mistriwork/engine/shared/pageRoutes.js';\nimport { ownedBy } from '@mistriwork/kit/client/requestIdentity.js';\nimport { sessionIdentity, subscribeSessionIdentity } from '@mistriwork/kit/client/sessionIdentity.js';\nimport { batchedBreakdown } from '@mistriwork/kit/client/breakdownBatch.js';\nimport { densityChoice } from '@mistriwork/kit/client/density.js';\nimport { fillComposer as fillPageComposer } from '@mistriwork/kit/client/components/composerDraft.js';\nimport { tableNamed, type TableMeta } from '@mistriwork/engine/shared/schema.js';\nimport { HOST_GLOBAL } from '../../../shared/uiSdk.js';\nimport { pageBridge } from '@mistriwork/kit/client/uiBridge.js';\nimport type { DisplayRule } from '@mistriwork/kit/client/components/valueModel.js';\nimport { setPageHost, type UiHost, type UiLook, type UiRow } from './context.js';\nimport { rowsByPath } from './rows.js';\nimport { sayAppMessage } from './appMessage.js';\nimport { say } from '../../copy/components/components/sdk/host.js';\nimport { served, shownUnplaced } from '@mistriwork/kit/client/addressMount.js';\nimport { viewPath } from '../../publicAddress.js';\nimport { createPageAppFlags } from '../../appFlags.js';\nimport { pageAnalyticsBeacon } from '../../analyticsBeacon.js';\nimport { shellRoot } from '@mistriwork/kit/client/shellHost.js';\n\nfunction tableOf(resource: string): TableMeta {\n const table = state.schema ? (tableNamed(state.schema, resource) as TableMeta | undefined) : undefined;\n const declared = (pageBridge.activeApp() as { resources?: Record<string, unknown> } | null)?.resources ?? {};\n if (!table || (Object.keys(declared).length && !Object.hasOwn(declared, table.id) && !table.union)) {\n throw new Error(say('isNotOneOfThisApps', { resource }));\n }\n return table;\n}\n\n/* A free-form page's own reads say which page asks, so the server holds them to its manifest too. */\nasync function viewRows(\n table: TableMeta,\n show: readonly string[] | undefined,\n query: string,\n limit: number,\n page?: string,\n): Promise<UiRow[]> {\n const paths = show?.length ? [...show] : table.columns.map((column) => column.name);\n const body = {\n count: 'none' as const,\n ...(query.trim() ? { query: query.trim() } : {}),\n view: { id: `ui:${table.id}`, name: table.name, base: table.id, columns: paths.map((path) => ({ path })), limit },\n };\n const got = page ? await pageApi(page, '/api/view/run', body) : await api('/api/view/run', body);\n return rowsByPath(paths, got, say('theRowsOfCould', { name: table.name }), { schema: state.schema, base: table.id });\n}\n\nconst root = () => shellRoot();\n\nfunction look(): UiLook {\n const attribute = root().dataset.theme;\n const dark = attribute === 'dark' || (!attribute && window.matchMedia?.('(prefers-color-scheme: dark)').matches);\n const density = densityChoice() as UiLook['density'];\n return { look: root().dataset.visualTheme ?? 'workshop', mode: dark ? 'dark' : 'light', density };\n}\n\nlet flags: ReturnType<typeof createPageAppFlags> | undefined;\nlet beacon: ReturnType<typeof pageAnalyticsBeacon> | undefined;\nconst pageHost: UiHost = {\n analytics: { emit: (name, fields) => (beacon ??= pageAnalyticsBeacon()).emit(name, fields) },\n get flags() {\n return (flags ??= createPageAppFlags(() => {\n const app = pageBridge.activeApp() as { id?: string } | null;\n return app?.id && app.id === state.activeConnection ? app.id : null;\n }));\n },\n /* The connection and the session's epoch: a sign-in, a sign-out or another account never reads another's cached rows. */\n get scope() {\n return [state.activeConnection ?? '', sessionIdentity().epoch];\n },\n rows(resource, { query, show, sort, limit, page }) {\n const table = tableOf(resource);\n return viewRows(table, show, [query ?? '', sort ? `sort ${sort}` : ''].join(' '), limit ?? 20, page);\n },\n async record(resource, key, show, asking = {}) {\n const table = tableOf(resource);\n const where = (primaryKey(table) as string[]).map((column) => `${column} = ${quote(String(key[column]))}`).join(' and ');\n return (await viewRows(table, show, where, 1, asking.page))[0];\n },\n async breakdown(resource, { by, measure, query, limit, page }) {\n const table = tableOf(resource);\n const text = [table.id, query ?? '', `${measure ?? 'count'} by ${by}`].filter(Boolean).join(' ');\n /* A page's breakdown is asked alone: a batch is many sections' and carries no one page's name. */\n const got = page\n ? ((await pageApi(page, '/api/breakdown', { text, ...(limit ? { limit } : {}) })) as { rows?: UiRow[] })\n : await batchedBreakdown<{ rows?: UiRow[] }>({ text, limit });\n return got.rows ?? [];\n },\n async load(page, params) {\n /* A tenant's lease answers a refusal as a reply, not a throw (tenantTransport.ts): it is the page's error either way. */\n const got = (await pageApi(page, PAGE_LOAD_PATH, { page, params })) as { data?: unknown; error?: unknown };\n if (typeof got.error === 'string') throw new Error(got.error);\n return got.data;\n },\n openRecord(resource, key, options = {}) {\n const table = tableOf(resource);\n const label = options.label ?? '';\n if ((options.mode === 'drawer' || options.mode === 'modal') && pageBridge.openPeek)\n pageBridge.openPeek(table.id, { ...key }, label, options.mode);\n else void openRecord(table.id, { ...key }, label);\n },\n openView(view, options) {\n if (!pageBridge.openView?.(view, options)) throw new Error(say('isNotAList', { view }));\n },\n /* The page's command pipeline and forms, registered by sdk/commands.tsx (uiBridge.ts says why). */\n openForm(view, prefill = {}) {\n if (!pageBridge.commands) throw new Error(say('thePageCannotOpen'));\n pageBridge.commands.openForm(view, prefill);\n },\n /* A tenant's link to hand out: a view a visitor reads by the tenant's public address, a public\n form (never one of the payload's rooms) by its intake address. Only the tenant's own lease is served them. */\n publicLink(view) {\n const app = pageBridge.activeApp() as { id?: string; views?: object; addresses?: { intake?: string; public?: string } } | null;\n if (!app?.id || typeof view !== 'string' || !view) return undefined;\n const room = Boolean(app.views && Object.hasOwn(app.views, view));\n const address = room ? app.addresses?.public : app.addresses?.intake;\n const path = room ? viewPath(view) : `/${encodeURIComponent(app.id)}/form/${encodeURIComponent(view)}`;\n if (!address || !path) return undefined;\n return `${window.location.origin}${shownUnplaced(path)}?via=${encodeURIComponent(address)}`;\n },\n fillComposer(text, mode) {\n return fillPageComposer(text, mode);\n },\n fileAddress(resource, key, options = {}) {\n const table = tableOf(resource);\n return served(\n `/api/file?${new URLSearchParams({\n ...ownedBy(state.activeConnection ?? null),\n table: table.id,\n key: JSON.stringify(key),\n inline: '1',\n ...(options.thumbnail ? { variant: 'thumb' } : {}),\n })}`,\n );\n },\n command: (ref, page) =>\n pageBridge.commands?.command(ref, page) ?? {\n label: ref,\n granted: false,\n available: async () => false,\n run: async () => ({ status: 'refused', message: say('thisPageCannotRun') }),\n open: async () => ({ status: 'refused', message: say('thisPageCannotRun') }),\n },\n viewer() {\n const identity = sessionIdentity();\n return identity.mode === 'authenticated' && identity.accountId ? { signedIn: true, account: identity.accountId } : { signedIn: false };\n },\n subscribeViewer: (listener) => subscribeSessionIdentity(listener),\n column(resource, name) {\n const table = state.schema ? (tableNamed(state.schema, resource) as TableMeta | undefined) : undefined;\n if (!table) return undefined;\n return {\n meta: table.columns.find((column) => column.name === name),\n rule: columnDisplay(table.id, name) as DisplayRule | null,\n label: (columnLabel(table.id, name) as string | null) ?? name,\n };\n },\n look,\n token: (name) => getComputedStyle(root()).getPropertyValue(name).trim(),\n subscribeLook(listener) {\n const observer = new MutationObserver(listener);\n observer.observe(root(), { attributes: true, attributeFilter: ['data-theme', 'data-visual-theme', 'data-palette', 'style', 'class'] });\n const media = window.matchMedia?.('(prefers-color-scheme: dark)');\n media?.addEventListener?.('change', listener);\n return () => {\n observer.disconnect();\n media?.removeEventListener?.('change', listener);\n };\n },\n get app() {\n return pageBridge.inAppMode();\n },\n message: (key, args) =>\n sayAppMessage((pageBridge.activeApp() as { messages?: Readonly<Record<string, readonly unknown[]>> } | null)?.messages, key, args),\n};\n\n/* The page's modules, for the host modules a component's bare imports reach.\n Frozen: a component may read them, and none may swap one for another. */\nif (!(HOST_GLOBAL in globalThis)) {\n Object.defineProperty(globalThis, HOST_GLOBAL, {\n value: Object.freeze({\n modules: Object.freeze({\n react: React,\n 'react/jsx-runtime': JsxRuntime,\n 'react-dom': ReactDOM,\n '@mistriwork/mistri/ui': ui,\n '@mistriwork/mistri/page': page,\n }),\n }),\n enumerable: false,\n writable: false,\n configurable: false,\n });\n}\nsetPageHost(pageHost);\n","/** What sdk/componentLoader 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 theAppServesNoComponent: 'The App serves no component \"{id}\".',\n theComponentHasNoDefault: 'The component \"{id}\" has no default export.',\n});\n","/**\n * An App's custom component, fetched the first time the page draws it: its\n * stylesheet linked once, its module imported from where the App payload\n * says it is served (`/{app}/_components/<id>-<hash>.js`). Importing this\n * module installs the page's side of `@mistriwork/mistri/ui` first (host.tsx), so a\n * component's bare imports find the page's own React before it evaluates.\n *\n * A module that cannot be fetched is almost always a deploy — the page was\n * opened before it and the hashed name it holds is gone — which the section\n * says as the built-in chunks do (onDemand.tsx), with a Reload.\n */\nimport type { ComponentType } from 'react';\nimport { pageBridge } from '@mistriwork/kit/client/uiBridge.js';\nimport './host.js';\nimport { say } from '../../copy/components/components/sdk/componentLoader.js';\nimport { appFile } from '@mistriwork/kit/client/addressMount.js';\n\ninterface Served {\n kind: 'section' | 'value';\n href: string;\n css?: string;\n}\n\nconst modules = new Map<string, Promise<ComponentType<never>>>();\n\n/* The payload says each file's inside address (`/{app}/_components/…`);\n it is fetched where the browser reaches it (addressMount.js `appFile`): an\n embedded shell's from its endpoint, never under the host's address. */\nfunction served(id: string): Served | undefined {\n const components = (pageBridge.activeApp() as { components?: Record<string, Served> } | null)?.components;\n const entry = components && Object.hasOwn(components, id) ? components[id] : undefined;\n return entry && { kind: entry.kind, ...reached(entry) };\n}\n\nconst reached = (entry: { href: string; css?: string }) => ({\n href: appFile(entry.href),\n ...(entry.css ? { css: appFile(entry.css) } : {}),\n});\n\nfunction linkStylesheet(href: string, id: string): void {\n if (document.head.querySelector(`link[data-component-css=\"${CSS.escape(id)}\"][href=\"${CSS.escape(href)}\"]`)) return;\n const link = document.createElement('link');\n link.rel = 'stylesheet';\n link.href = href;\n link.dataset.componentCss = id;\n document.head.append(link);\n}\n\n/** The component the App declares under `id`, its default export; rejects when it is not served or will not load. */\nexport function loadComponent(id: string): Promise<ComponentType<never>> {\n return loadEntry(id, served(id));\n}\n\n/**\n * The component `id` from where `entry` says it is served (its inside address, `/{app}/_components/…`): what a public\n * form's page loads its input components by, from the form's own payload, having no App payload (sdk/publicInputs.ts).\n */\nexport function loadServedComponent(id: string, given: { href: string; css?: string } | undefined): Promise<ComponentType<never>> {\n return loadEntry(id, given && reached(given));\n}\n\nfunction loadEntry(id: string, entry: { href: string; css?: string } | undefined): Promise<ComponentType<never>> {\n if (!entry) return Promise.reject(new Error(say('theAppServesNoComponent', { id })));\n let loading = modules.get(entry.href);\n if (!loading) {\n if (entry.css) linkStylesheet(entry.css, id);\n loading = (import(/* @vite-ignore */ entry.href) as Promise<{ default?: unknown }>).then((module) => {\n const part = module.default;\n if (typeof part !== 'function' && (typeof part !== 'object' || part === null))\n throw new Error(say('theComponentHasNoDefault', { id }));\n return part as ComponentType<never>;\n });\n // A failed fetch is not kept: the next draw asks again (a Reload is offered meanwhile).\n loading.catch(() => {\n if (modules.get(entry.href) === loading) modules.delete(entry.href);\n });\n modules.set(entry.href, loading);\n }\n return loading;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"shared-B-MhiPIN.js","names":["say","say","say","say","fillPageComposer","served","React","ReactDOM","ui","page"],"sources":["../../../kit/src/client/components/composerDraft.ts","../../src/shared/uiSdk.ts","../../src/client/components/sdk/rows.ts","../../src/client/copy/components/components/sdk/host.ts","../../src/client/copy/shell/appFlags.ts","../../src/client/appFlags.ts","../../src/shared/appAnalytics.ts","../../src/client/analyticsBeacon.ts","../../src/client/components/sdk/host.tsx","../../src/client/copy/components/components/sdk/componentLoader.ts","../../src/client/components/sdk/componentLoader.ts"],"sourcesContent":["/**\n * The page's one timeline composer, reachable from outside it: a custom\n * section's `useComposer().fill(...)` puts a template's words in the box\n * the reader then reads, edits and sends. Filling never sends — the send\n * stays the reader's, through the composer's own commands.\n *\n * One slot, not a list: a page draws at most one conversation, and the\n * latest composer mounted is the one in view.\n */\ntype ComposerMode = 'reply' | 'note';\ntype Fill = (text: string, mode?: ComposerMode) => void;\n\nlet current: Fill | null = null;\n\n/** The composer takes the slot while it is mounted; the returned function gives it back. */\nexport function holdComposer(fill: Fill): () => void {\n current = fill;\n return () => {\n if (current === fill) current = null;\n };\n}\n\n/** Puts `text` in the composer (and chooses its mode, where the page offers it); false when the page draws none. */\nexport function fillComposer(text: string, mode?: ComposerMode): boolean {\n if (!current) return false;\n current(text, mode);\n return true;\n}\n","/**\n * The public SDK a custom component draws with, `@mistriwork/mistri/ui`, as both sides\n * need to name it: the server serves each host module a component imports as\n * a small module over the page's own copy (componentSdk.ts), and a\n * component's bare names are written as their paths when it is served\n * (http/componentRoutes.ts). One\n * React, one QueryClient: a component that brought its own React would break\n * hooks, and one with its own query cache would outlive a sign-out.\n *\n * `UI_EXPORTS` is the SDK's runtime surface, pinned against the module that\n * implements it (packages/mistri/src/client/components/sdk/index.ts) by a component test, so\n * the served module can never offer a name the host does not have.\n */\n\n/** Where the host modules are served, and the bare names a served component's imports are written from. */\nexport const SDK_PATH = '/_mistri/sdk/';\nexport const HOST_MODULES = {\n react: 'react.js',\n 'react/jsx-runtime': 'react-jsx-runtime.js',\n 'react-dom': 'react-dom.js',\n '@mistriwork/mistri/ui': 'ui.js',\n '@mistriwork/mistri/page': 'page.js',\n} as const;\nexport type HostModule = keyof typeof HOST_MODULES;\n/** The host modules once each. Pure, so the page's bundle, which reads only `HOST_GLOBAL` here, drops it. */\nexport const SERVED_MODULES = /* @__PURE__ */ Object.keys(HOST_MODULES) as HostModule[];\n\n/** The global the page puts its modules on, read only by the served host modules. */\nexport const HOST_GLOBAL = '__mistri';\n\n/** Every value `@mistriwork/mistri/ui` exports. */\nexport const UI_EXPORTS = [\n 'React',\n 'Fragment',\n 'useState',\n 'useEffect',\n 'useMemo',\n 'useRef',\n 'useCallback',\n 'useId',\n 'useReducer',\n 'useContext',\n 'Card',\n 'Stack',\n 'Row',\n 'Heading',\n 'Button',\n 'Dropdown',\n 'SplitListDetail',\n 'Value',\n 'Tone',\n 'Meter',\n 'Empty',\n 'Loaded',\n 'Icon',\n 'Segmented',\n 'Stat',\n 'Columns',\n 'Table',\n 'useRows',\n 'useRecord',\n 'useBreakdown',\n 'useNavigate',\n 'useComposer',\n 'useFormat',\n 'useLook',\n 'useToken',\n 'tokens',\n 'useSectionSize',\n 'useCommand',\n 'useViewer',\n 'useFile',\n 'useFlags',\n 'useVisitor',\n 'useAnalytics',\n 'useMessage',\n] as const;\n\n/**\n * Every value `@mistriwork/mistri/page` exports: `definePage`, and the blocks a\n * free-form page draws with — the kit's layout and parts, and the\n * platform's own command form (components/sdk/page.tsx).\n */\nexport const PAGE_EXPORTS = [\n 'definePage',\n 'useAddressState',\n 'CommandForm',\n 'Stack',\n 'Row',\n 'Columns',\n 'Card',\n 'Heading',\n 'Button',\n 'Empty',\n 'Loaded',\n 'Stat',\n 'Value',\n 'Grid',\n 'Panel',\n 'Tabs',\n 'Rows',\n 'RecordCard',\n 'Metric',\n 'Chart',\n 'Breakdown',\n 'Timeline',\n 'Tree',\n 'Gantt',\n 'Assistant',\n] as const;\n\n/** Where an App's compiled components are served: `/{app}/_components/<file>`. */\nexport const COMPONENTS_SEGMENT = '_components';\n","/**\n * A view's answer as a component reads it: each row keyed by the paths it\n * asked for, in the words it wrote them (`customer_id.name`), whatever name\n * the server's result gave the column. Shared by the declared reads of a\n * custom section and the SDK's hooks, so both hand a component one shape.\n */\nimport type { UiRow } from './context.js';\nimport { resolvePath } from '@mistriwork/engine/shared/viewPaths.js';\nimport type { DatabaseSchema } from '@mistriwork/engine/shared/schema.js';\n\n/** Where a read's paths start, so a column's declared type can be found for each. */\ninterface RowsBase {\n schema: DatabaseSchema | null | undefined;\n base: string;\n}\n\ninterface ViewAnswer {\n view?: unknown;\n columns?: string[];\n rows?: UiRow[];\n errors?: Array<{ message: string }>;\n}\n\n/* The server hands a Postgres timestamp as the text the database stores\n (postgresDates.ts, on purpose: the grid shows what is stored), so\n `2026-10-12 19:16:00-04` reaches a component, and `Date.parse` reads that,\n and the `+00` of UTC, as NaN. A component computes with its times, so it is\n handed ISO 8601 with a full offset. Only the strict shape of a database's\n timestamp text is touched, and only in a column declared a timestamp: a\n string that merely looks like one is the author's. A timestamp without a\n zone stays without one; an offset is never invented. */\nconst TIMESTAMP_TEXT = /^(\\d{4}-\\d{2}-\\d{2})[ T](\\d{2}:\\d{2}(?::\\d{2}(?:\\.\\d+)?)?)\\s*(Z|[+-]\\d{2}(?::?\\d{2})?)?$/;\n\nfunction isoTimestamp(value: unknown): unknown {\n if (typeof value !== 'string') return value;\n const match = TIMESTAMP_TEXT.exec(value.trim());\n if (!match) return value;\n const [, day, time, zone] = match;\n let offset = '';\n if (zone === 'Z') offset = 'Z';\n else if (zone) {\n const digits = zone.slice(1).replace(':', '');\n offset = `${zone[0]}${digits.slice(0, 2)}:${digits.slice(2) || '00'}`;\n }\n return `${day}T${time.length === 5 ? `${time}:00` : time}${offset}`;\n}\n\nconst isTimestampColumn = (type: string) => /timestamp|datetime/i.test(type ?? '');\n\nfunction timestampPaths(paths: readonly string[], typed: RowsBase | undefined): Set<string> {\n const found = new Set<string>();\n if (!typed?.schema) return found;\n for (const path of paths) {\n try {\n const resolved = resolvePath(typed.schema, typed.base, path);\n if (!resolved.rollup && !resolved.computed && !resolved.tags && !resolved.jsonKey && isTimestampColumn(resolved.column.type))\n found.add(path);\n } catch {\n /* A path the schema cannot resolve is the server's to refuse; it is read as it came. */\n }\n }\n return found;\n}\n\nexport function rowsByPath(paths: readonly string[], got: ViewAnswer, fallback: string, typed?: RowsBase): UiRow[] {\n if (!got || !('view' in got) || !Array.isArray(got.rows)) throw new Error(got?.errors?.[0]?.message ?? fallback);\n const columns = got.columns ?? [...paths];\n /* Each value by its path's own column, not by where the path stands in the\n asking list: a record page reads its row once for every section, in the\n order the first one named the columns, and hands each section its own\n columns of that one answer (composedReads.ts). Zipped by position, a\n section that named shared columns in another order read one column's\n value under another's name. The answer's view says which path each of its\n columns is. */\n const answered = (got.view as { columns?: Array<{ path?: unknown }> } | null | undefined)?.columns;\n const nameOf = new Map<string, string>();\n if (Array.isArray(answered))\n answered.forEach((column, i) => {\n if (typeof column?.path === 'string' && columns[i] !== undefined && !nameOf.has(column.path)) nameOf.set(column.path, columns[i]);\n });\n const stamps = timestampPaths(paths, typed);\n return got.rows.map((row) =>\n Object.fromEntries(\n paths.map((path, i) => {\n const value = row[nameOf.get(path) ?? columns[i] ?? path];\n return [path, stamps.has(path) ? isoTimestamp(value) : value];\n }),\n ),\n );\n}\n","/** What sdk/host 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 isNotOneOfThisApps: '\"{resource}\" is not one of this App\\'s resources.',\n theRowsOfCould: 'The rows of \"{name}\" could not be read.',\n isNotAList: '\"{view}\" is not a list or dashboard this reader is served.',\n thePageCannotOpen: 'The page cannot open a form yet; try again once it has loaded.',\n thisPageCannotRun: 'This page cannot run commands.',\n});\n","/** What appFlags says, in the shell 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 visitorUnavailable: 'Visitor experiments are unavailable for this App or session.',\n ownerUnavailable: 'No active App flag owner.',\n requestOwnerRetired: 'Flag request owner retired.',\n responseOwnerChanged: 'Flag response owner changed.',\n valuesUnavailable: 'Evaluated flag values unavailable.',\n responseTooLarge: 'Flag response too large.',\n valuesNotReady: 'Evaluated flag values are not ready for this App.',\n undeclaredFlag: 'Undeclared evaluated flag: {key}.',\n});\n","/** Called once, on first SDK flags use. Nothing is hydrated from HTML/storage. */\nimport {\n APP_FLAG_VALUES_PATH,\n EXPERIMENT_VISITOR_PATH,\n EXPERIMENT_FORM_HEADER,\n EXPERIMENT_ADDRESS_HEADER,\n type ExperimentVisitorSelection,\n captureAppFlagValues,\n type AppFlagReader,\n type AppFlagValues,\n} from '../shared/appFlagValues.js';\nimport {\n assertSessionCurrent,\n captureTenantLease,\n sessionIdentity,\n subscribeSessionIdentity,\n subscribeTenantLease,\n tenantLeaseActive,\n} from '@mistriwork/kit/client/sessionIdentity.js';\nimport { appPresentation, subscribeAppPresentation } from '@mistriwork/kit/client/connectionTransition.js';\nimport type { createExperimentExposureQueue, ExposureCoverage } from './experimentExposure.js';\nimport { say } from './copy/shell/appFlags.js';\nimport { fetchServer } from '@mistriwork/kit/client/transport.js';\n\nconst emptyExposureCoverage = (): ExposureCoverage => ({\n queued: 0,\n inFlight: 0,\n recorded: 0,\n duplicate: 0,\n failed: 0,\n unknown: 0,\n dropped: 0,\n});\ntype ExposureSender = Parameters<typeof createExperimentExposureQueue>[0];\n\nexport interface AppFlagsSource extends AppFlagReader {\n snapshot(): AppFlagReader;\n subscribe(listener: () => void): () => void;\n load(): Promise<void>;\n /** Explicit browser actual-use lifecycle port. get/snapshot/load are passive;\n * only a committed render (or an explicit consumed feature) calls this. */\n commitUse?(reader: AppFlagReader, keys: readonly string[]): void;\n exposureCoverage?(): ExposureCoverage;\n /** Explicit user action only. Never called by flag reads or rendering. */\n establishVisitor?(selection?: ExperimentVisitorSelection): Promise<void>;\n}\n\nexport function createPageAppFlags(active: () => string | null) {\n let disposed = false;\n let visitorSelection: ExperimentVisitorSelection = Object.freeze({});\n const visitorHeaders = () => ({\n ...(visitorSelection.form ? { [EXPERIMENT_FORM_HEADER]: visitorSelection.form } : {}),\n ...(visitorSelection.address ? { [EXPERIMENT_ADDRESS_HEADER]: visitorSelection.address } : {}),\n });\n const source = createAppFlagsState({\n async exposure(owner, signal) {\n // Capture native ownership before loading optional experiment delivery.\n const identity = sessionIdentity(),\n lease = captureTenantLease(identity);\n if (identity.mode !== 'authenticated' && identity.mode !== 'anonymous') return;\n const { captureExperimentExposureSender } = await import('./experimentExposure.js');\n if (signal.aborted || !owner.current() || identity !== sessionIdentity() || lease !== captureTenantLease(identity)) return;\n return captureExperimentExposureSender(owner, { visitor: identity.mode === 'anonymous', selection: visitorSelection });\n },\n capture() {\n const appId = active(),\n identity = sessionIdentity(),\n presentation = appPresentation(),\n selection = visitorSelection;\n if (disposed || !appId || !presentation.available || identity.appId !== appId) throw new Error(say('ownerUnavailable'));\n assertSessionCurrent(identity);\n return {\n appId,\n current: () =>\n !disposed &&\n visitorSelection === selection &&\n active() === appId &&\n identity === sessionIdentity() &&\n presentation.generation === appPresentation().generation &&\n appPresentation().available &&\n (!identity.tenantRequired || tenantLeaseActive(identity)),\n };\n },\n async read(owner, signal) {\n const identity = sessionIdentity();\n if (!owner.current()) throw new Error(say('requestOwnerRetired'));\n const path = `${APP_FLAG_VALUES_PATH}?${new URLSearchParams({ app: owner.appId })}`;\n if (identity.tenantRequired) {\n const { tenantReadApi } = await import('./tenantTransport.js');\n if (!owner.current() || signal.aborted) throw new Error(say('requestOwnerRetired'));\n return tenantReadApi(path, undefined, owner.appId, signal);\n }\n const response = await fetchServer(path, {\n signal,\n method: 'GET',\n credentials: 'same-origin',\n cache: 'no-store',\n headers: identity.mode === 'authenticated' ? { 'x-mistri-account': identity.accountId! } : visitorHeaders(),\n });\n if (!owner.current() || signal.aborted) throw new Error(say('requestOwnerRetired'));\n try {\n assertSessionCurrent(identity, response.headers.get('x-mistri-account'));\n if (\n (identity.mode === 'anonymous' && response.headers.get('x-mistri-account')) ||\n response.status === 401 ||\n response.headers.get('x-mistri-app') !== owner.appId\n )\n throw new Error(say('responseOwnerChanged'));\n } catch (error) {\n const { invalidateSession } = await import('@mistriwork/kit/client/sessionLifecycle.js');\n if (owner.current()) invalidateSession('account-changed');\n throw error;\n }\n if (!response.ok) throw new Error(say('valuesUnavailable'));\n const text = await response.text();\n if (text.length > 1024 * 1024) throw new Error(say('responseTooLarge'));\n return JSON.parse(text) as unknown;\n },\n });\n const unsubscribe = [\n subscribeSessionIdentity(source.retire),\n subscribeTenantLease(source.retire),\n subscribeAppPresentation(source.retire),\n ];\n return Object.freeze({\n ...source,\n get ready() {\n return source.ready;\n },\n async establishVisitor(selection: ExperimentVisitorSelection = {}) {\n if (\n Object.keys(selection).some((key) => !['form', 'address'].includes(key)) ||\n (selection.form !== undefined && !/^[a-z0-9][a-z0-9-]{0,63}$/.test(selection.form)) ||\n (selection.address !== undefined &&\n (!selection.form ||\n typeof selection.address !== 'string' ||\n selection.address.length > 512 ||\n /[\\p{Cc}\\p{Cs}]/u.test(selection.address)))\n )\n throw new Error(say('visitorUnavailable'));\n const selected = Object.freeze({ ...selection });\n visitorSelection = selected;\n source.retire();\n const identity = sessionIdentity(),\n appId = active(),\n presentation = appPresentation();\n if (disposed || !appId || identity.appId !== appId || identity.mode !== 'anonymous' || !presentation.available)\n throw new Error(say('visitorUnavailable'));\n const current = () =>\n !disposed &&\n visitorSelection === selected &&\n active() === appId &&\n identity === sessionIdentity() &&\n presentation.generation === appPresentation().generation &&\n appPresentation().available;\n const response = await fetchServer(EXPERIMENT_VISITOR_PATH, {\n method: 'POST',\n credentials: 'same-origin',\n cache: 'no-store',\n headers: { 'content-type': 'application/json', 'x-mistri-visitor': 'establish', ...visitorHeaders() },\n body: '{}',\n signal: AbortSignal.timeout(10000),\n });\n if (!current() || !response.ok || response.headers.get('x-mistri-app') !== appId || response.headers.has('x-mistri-account'))\n throw new Error(say('visitorUnavailable'));\n const text = await response.text();\n if (!current() || text.length > 128) throw new Error(say('visitorUnavailable'));\n const reply = JSON.parse(text) as unknown;\n if (!reply || typeof reply !== 'object' || Object.keys(reply).length !== 1 || (reply as { ready?: unknown }).ready !== true)\n throw new Error(say('visitorUnavailable'));\n source.retire();\n await source.load();\n },\n dispose() {\n disposed = true;\n for (const stop of unsubscribe) stop();\n source.retire();\n },\n });\n}\ninterface AppFlagsOwner {\n readonly appId: string;\n current(): boolean;\n}\n\n/** SDK-only state. The host supplies ordinary transport and synchronous owner\n * retirement. No persistence, SSR adoption or client targeting. Imperative get\n * is passive; reporting requires the explicit commitUse lifecycle port. */\nexport function createAppFlagsState(port: {\n capture(): AppFlagsOwner;\n read(owner: AppFlagsOwner, signal: AbortSignal): Promise<unknown>;\n exposure?(owner: AppFlagsOwner, signal: AbortSignal): ExposureSender | undefined | Promise<ExposureSender | undefined>;\n}) {\n const listeners = new Set<() => void>();\n let generation = 0,\n controller: AbortController | undefined,\n pending: Promise<void> | undefined;\n let attempted = false;\n let exposures: ReturnType<typeof createExperimentExposureQueue> | undefined;\n let assignmentReceipts: AppFlagValues['assignmentReceipts'];\n let retiredCoverage = emptyExposureCoverage();\n const unavailable = () => new Error(say('valuesNotReady'));\n const reader = (data?: AppFlagValues, owner?: AppFlagsOwner, failure?: unknown): AppFlagReader => {\n const captured = generation,\n values = data?.values;\n const current = () => captured === generation && !!owner?.current();\n return Object.freeze({\n get ready() {\n return !!values && current();\n },\n get(key: string) {\n if (!values || !current()) throw failure instanceof Error ? failure : unavailable();\n if (!Object.hasOwn(values, key)) throw new Error(say('undeclaredFlag', { key }));\n return values[key];\n },\n });\n };\n let snapshot = reader();\n const notify = () => {\n for (const listener of [...listeners]) {\n try {\n listener();\n } catch {\n /* Observers cannot veto retirement. */\n }\n }\n };\n const retire = () => {\n ++generation;\n assignmentReceipts = undefined;\n if (exposures) {\n exposures.retire();\n const ended = exposures.coverage();\n retiredCoverage = Object.fromEntries(\n Object.entries(retiredCoverage).map(([key, value]) => [key, value + ended[key as keyof ExposureCoverage]]),\n ) as unknown as ExposureCoverage;\n exposures = undefined;\n }\n controller?.abort();\n controller = undefined;\n pending = undefined;\n attempted = false;\n snapshot = reader();\n notify();\n };\n return Object.freeze({\n get ready() {\n return snapshot.ready;\n },\n get: (key: string) => snapshot.get(key),\n snapshot: () => snapshot,\n commitUse(reader: AppFlagReader, keys: readonly string[]) {\n if (reader !== snapshot || !reader.ready) return;\n for (const key of keys) {\n const receipt = assignmentReceipts && Object.hasOwn(assignmentReceipts, key) ? assignmentReceipts[key] : undefined;\n if (receipt) exposures?.consume(receipt);\n }\n },\n exposureCoverage(): ExposureCoverage {\n const active = exposures?.coverage() ?? emptyExposureCoverage();\n return Object.freeze(\n Object.fromEntries(Object.entries(retiredCoverage).map(([key, value]) => [key, value + active[key as keyof ExposureCoverage]])),\n ) as unknown as ExposureCoverage;\n },\n subscribe(listener: () => void) {\n listeners.add(listener);\n return () => {\n listeners.delete(listener);\n };\n },\n retire,\n load(): Promise<void> {\n if (pending) return pending;\n if (attempted) return Promise.resolve();\n attempted = true;\n const started = generation,\n abort = (controller = new AbortController());\n pending = (async () => {\n let owner: AppFlagsOwner | undefined;\n try {\n owner = port.capture();\n if (!owner.current()) throw unavailable();\n const raw = await port.read(owner, abort.signal);\n if (started !== generation || abort.signal.aborted || !owner.current()) return;\n const data = captureAppFlagValues(raw);\n if (started !== generation || abort.signal.aborted || !owner.current()) return;\n if (port.exposure && data.assignmentReceipts && Object.keys(data.assignmentReceipts).length) {\n const sender = await port.exposure(owner, abort.signal);\n if (started !== generation || abort.signal.aborted || !owner.current()) return;\n if (sender) {\n const { createExperimentExposureQueue } = await import('./experimentExposure.js');\n if (started !== generation || abort.signal.aborted || !owner.current()) return;\n assignmentReceipts = data.assignmentReceipts;\n exposures = createExperimentExposureQueue(sender);\n }\n }\n snapshot = reader(data, owner);\n notify();\n } catch (error) {\n if (started !== generation || abort.signal.aborted || (owner && !owner.current())) return;\n snapshot = reader(undefined, undefined, error);\n notify();\n } finally {\n if (started === generation) pending = undefined;\n }\n })();\n return pending;\n },\n });\n}\n","/**\n * Behavior analytics, declared: which built-in kinds an App collects, the\n * custom events its components may emit, and the funnels read over them.\n *\n * Off unless declared. A declaration only names things; what is stored, and\n * where, is the `analytics` store's (src/server/analytics/), bound by\n * configuration, never by the App. The finding codes `analytics-unknown-step`,\n * `analytics-not-collected` and `analytics-name-clash` are carried in\n * brackets, which is how `mistri check --json` reads a code.\n */\nimport { isFormView, type AppDef } from './appModel.js';\nimport { isRecord, VIEW_KEY } from '@mistriwork/engine/shared/model.js';\nimport { captureFlagDeclaration } from './appExperiments.js';\nimport { DURATION_WORDS, parseDuration } from '@mistriwork/engine/shared/duration.js';\n\nconst ANALYTICS_KINDS = ['views', 'commands', 'forms'] as const;\nexport type AnalyticsKind = (typeof ANALYTICS_KINDS)[number];\n\n/** Closed bounds: a declaration is data a person reads, not a pipeline. */\nexport const ANALYTICS_LIMITS = Object.freeze({ events: 64, eventFields: 16, funnels: 32, steps: 10, windowHours: 8760, valueLength: 200 });\n\n/** Exactly one of view, command, form (with an optional step) or event. */\nexport type AnalyticsStep =\n | { readonly view: string }\n | { readonly command: string }\n | { readonly form: string; readonly step?: string }\n | { readonly event: string };\n\nexport interface AnalyticsFunnel {\n readonly unit: 'subject' | 'visitor';\n /** `'72 hours'`: how long after its first step a subject may take the rest. */\n readonly conversionWindow: string;\n readonly steps: readonly AnalyticsStep[];\n}\n\nexport interface AnalyticsDeclaration {\n readonly collect?: readonly AnalyticsKind[];\n readonly events?: Readonly<Record<string, { readonly fields: readonly string[] }>>;\n readonly funnels?: Readonly<Record<string, AnalyticsFunnel>>;\n}\n\nconst NAME = /^[A-Za-z][A-Za-z0-9_.-]{0,127}$/;\nconst FIELD = /^[A-Za-z_][A-Za-z0-9_]{0,63}$/;\nconst FORBIDDEN = new Set(['__proto__', 'prototype', 'constructor']);\n\nfunction object(value: unknown, at: string, keys: readonly string[]): Record<string, unknown> {\n if (!isRecord(value)) throw new Error(`${at} must be an object.`);\n for (const key of Object.keys(value))\n if (!keys.includes(key)) throw new Error(`${at} has \"${key}\", which it does not take. It takes: ${keys.join(', ')}.`);\n return value;\n}\n\n/** The authored `analytics` block, closed and frozen. Throws a sentence naming where. */\nexport function normalizeAnalytics(input: unknown, where: string): AnalyticsDeclaration {\n const at = `${where}: analytics`;\n const raw = object(captureFlagDeclaration(input), at, ['collect', 'events', 'funnels']);\n let collect: AnalyticsKind[] | undefined;\n if (raw.collect !== undefined) {\n if (\n !Array.isArray(raw.collect) ||\n raw.collect.some((kind) => !ANALYTICS_KINDS.includes(kind as AnalyticsKind)) ||\n new Set(raw.collect).size !== raw.collect.length\n ) {\n if (Array.isArray(raw.collect) && raw.collect.includes('actions'))\n throw new Error(`${at} collect has \"actions\", which is now \"commands\": the command runs an action or a form starts.`);\n throw new Error(`${at} collect is a list of ${ANALYTICS_KINDS.map((kind) => `\"${kind}\"`).join(', ')}, each once.`);\n }\n collect = [...raw.collect] as AnalyticsKind[];\n }\n let events: Record<string, { fields: readonly string[] }> | undefined;\n if (raw.events !== undefined) {\n const declared = object(raw.events, `${at} events`, Object.keys(isRecord(raw.events) ? raw.events : {}));\n if (Object.keys(declared).length > ANALYTICS_LIMITS.events)\n throw new Error(`${at} events holds at most ${ANALYTICS_LIMITS.events} events.`);\n events = {};\n for (const [name, value] of Object.entries(declared)) {\n // An App's own names, a custom event's and a funnel's, are spelled as its view ids are.\n if (!VIEW_KEY.test(name))\n throw new Error(`${at} events \"${name}\" is not an id of lowercase letters, digits and \"-\", as a view id is ('compare-opened').`);\n const event = object(value, `${at} events \"${name}\"`, ['fields']);\n const fields = event.fields ?? [];\n if (\n !Array.isArray(fields) ||\n fields.length > ANALYTICS_LIMITS.eventFields ||\n fields.some((field) => typeof field !== 'string' || !FIELD.test(field) || FORBIDDEN.has(field)) ||\n new Set(fields).size !== fields.length\n ) {\n throw new Error(`${at} events \"${name}\" fields is a list of at most ${ANALYTICS_LIMITS.eventFields} distinct field names.`);\n }\n events[name] = Object.freeze({ fields: Object.freeze([...fields] as string[]) });\n }\n }\n let funnels: Record<string, AnalyticsFunnel> | undefined;\n if (raw.funnels !== undefined) {\n const declared = object(raw.funnels, `${at} funnels`, Object.keys(isRecord(raw.funnels) ? raw.funnels : {}));\n if (Object.keys(declared).length > ANALYTICS_LIMITS.funnels)\n throw new Error(`${at} funnels holds at most ${ANALYTICS_LIMITS.funnels} funnels.`);\n funnels = {};\n for (const [id, value] of Object.entries(declared)) {\n if (!VIEW_KEY.test(id))\n throw new Error(`${at} funnels \"${id}\" is not an id of lowercase letters, digits and \"-\", as a view id is ('apply-funnel').`);\n const here = `${at} funnel \"${id}\"`;\n const funnel = object(value, here, ['unit', 'conversionWindow', 'steps']);\n if (funnel.unit !== 'subject' && funnel.unit !== 'visitor') throw new Error(`${here} unit is \"subject\" or \"visitor\".`);\n const windowMs = parseDuration(funnel.conversionWindow);\n if (!windowMs || windowMs > ANALYTICS_LIMITS.windowHours * 3_600_000) {\n throw new Error(\n `${here} conversionWindow is ${DURATION_WORDS}, above zero and at most a year ('${ANALYTICS_LIMITS.windowHours} hours').`,\n );\n }\n if (!Array.isArray(funnel.steps) || funnel.steps.length < 2 || funnel.steps.length > ANALYTICS_LIMITS.steps) {\n throw new Error(`${here} steps is a list of 2 to ${ANALYTICS_LIMITS.steps} steps.`);\n }\n const steps = funnel.steps.map((entry, index): AnalyticsStep => {\n const step = `${here} step ${index + 1}`;\n if (isRecord(entry) && entry.action !== undefined)\n throw new Error(`${step} has \"action\", which is now \"command\": the id of the command it counts.`);\n const given = isRecord(entry) ? Object.keys(entry).filter((key) => ['view', 'command', 'form', 'event'].includes(key)) : [];\n if (given.length !== 1) throw new Error(`${step} names exactly one of view, command, form or event.`);\n const kind = given[0] as 'view' | 'command' | 'form' | 'event';\n const record = object(entry, step, kind === 'form' ? ['form', 'step'] : [kind]);\n const name = record[kind];\n if (typeof name !== 'string' || !NAME.test(name) || FORBIDDEN.has(name)) throw new Error(`${step} ${kind} is not a name.`);\n if (record.step !== undefined && (typeof record.step !== 'string' || !NAME.test(record.step)))\n throw new Error(`${step} step is not a name.`);\n return Object.freeze(\n kind === 'form' ? { form: name, ...(record.step === undefined ? {} : { step: record.step as string }) } : { [kind]: name },\n ) as AnalyticsStep;\n });\n funnels[id] = Object.freeze({\n unit: funnel.unit,\n conversionWindow: (funnel.conversionWindow as string).trim(),\n steps: Object.freeze(steps),\n });\n }\n }\n return Object.freeze({\n ...(collect ? { collect: Object.freeze(collect) } : {}),\n ...(events ? { events: Object.freeze(events) } : {}),\n ...(funnels ? { funnels: Object.freeze(funnels) } : {}),\n });\n}\n\n/** The beacon's path, after the App's mount. Reserved: no App id or view starts with an underscore. */\nexport const ANALYTICS_BEACON_PATH = '/_mistri/analytics';\n\n/** What a funnel's steps name, read off the parsed App: views and pages, the commands actions and forms run, forms and their steps. */\nexport function analyticsCatalog(app: AppDef, pages: ReadonlyArray<{ id: string }> = []): AnalyticsCatalog {\n const views = new Set<string>(pages.map((page) => page.id)),\n commands = new Set<string>();\n const forms = new Map<string, readonly string[]>();\n for (const [key, view] of Object.entries(app.views)) {\n if (isFormView(view)) {\n forms.set(\n key,\n (view.steps ?? []).map((step) => step.id),\n );\n commands.add(view.command.id);\n for (const step of view.steps ?? []) if (step.command) commands.add(step.command.id);\n } else views.add(key);\n }\n // The landing is kept apart from the views, and it is the first step of most funnels.\n if (app.landing) views.add(app.landing.view);\n for (const [name, resource] of Object.entries(app.resources ?? {})) {\n if (resource.form)\n forms.set(\n name,\n (resource.form.steps ?? []).map((step) => step.id),\n );\n for (const action of resource.actions ?? []) if ('command' in action && action.command) commands.add(action.command.id);\n }\n return { views, commands, forms };\n}\n\n/** What the references of a funnel are checked against. */\nexport interface AnalyticsCatalog {\n /** Every list or dashboard view key, the landing's, and every page id. */\n readonly views: ReadonlySet<string>;\n /** The command ids an action or a form runs: what the server sees at admission. */\n readonly commands: ReadonlySet<string>;\n /** A form's id (a form view key or a resource with a New form) to its step ids. */\n readonly forms: ReadonlyMap<string, readonly string[]>;\n /** The names `defineEvent` issued, when the caller can see them; absent, a business event is not judged. */\n readonly businessEvents?: ReadonlySet<string>;\n}\n\n/** The step's kind, and the built-in kind it needs collected. */\nexport const stepKind = (step: AnalyticsStep): 'view' | 'command' | 'form' | 'event' =>\n 'view' in step ? 'view' : 'command' in step ? 'command' : 'form' in step ? 'form' : 'event';\nconst COLLECTS = { view: 'views', command: 'commands', form: 'forms' } as const;\n\n/** Every problem a declaration has against the App it belongs to, each ending in its finding code. */\nexport function analyticsProblems(declaration: AnalyticsDeclaration, catalog: AnalyticsCatalog, where: string): string[] {\n const problems: string[] = [];\n const custom = Object.keys(declaration.events ?? {});\n for (const name of custom) {\n if (catalog.businessEvents?.has(name)) {\n problems.push(\n `${where}: analytics events \"${name}\" is also a business event of this App. Custom and business events share one namespace: rename the custom one. [analytics-name-clash]`,\n );\n }\n }\n for (const [id, funnel] of Object.entries(declaration.funnels ?? {})) {\n funnel.steps.forEach((step, index) => {\n const here = `${where}: analytics funnel \"${id}\" step ${index + 1}`;\n const kind = stepKind(step);\n let known = true;\n if ('view' in step) known = catalog.views.has(step.view);\n else if ('command' in step) known = catalog.commands.has(step.command);\n else if ('form' in step) {\n const steps = catalog.forms.get(step.form);\n known = !!steps && (step.step === undefined || steps.includes(step.step));\n } else known = custom.includes(step.event) || !catalog.businessEvents || catalog.businessEvents.has(step.event);\n if (!known) {\n problems.push(\n `${here} names ${kind} \"${(step as Record<string, string>)[kind]}${'step' in step && step.step ? `\", step \"${step.step}` : ''}\", which this App does not declare. [analytics-unknown-step]`,\n );\n return;\n }\n if (kind !== 'event' && !declaration.collect?.includes(COLLECTS[kind])) {\n problems.push(\n `${here} counts ${kind}s, and analytics.collect does not list \"${COLLECTS[kind]}\", so none is recorded. [analytics-not-collected]`,\n );\n }\n });\n }\n return problems;\n}\n","/**\n * Behavior events from the page, batched and sent to the App's one beacon\n * route. Nothing here identifies anyone: the server takes the unit from the\n * session or the visitor cookie, so a body carries only a kind, a declared\n * name, the declared fields and how long ago it happened. A failure is\n * dropped, never retried or stored: this is telemetry, not a record.\n */\nimport { ANALYTICS_BEACON_PATH } from '../shared/appAnalytics.js';\nimport { addHostListener } from '@mistriwork/kit/client/shellHost.js';\nimport { fetchServer } from '@mistriwork/kit/client/transport.js';\n\ntype AnalyticsFields = Readonly<Record<string, string | number | boolean>>;\ninterface Queued {\n readonly kind: 'event' | 'view' | 'form';\n readonly name: string;\n readonly at: number;\n readonly fields?: AnalyticsFields;\n readonly step?: string;\n readonly route?: string;\n}\n\nconst BATCH = 20,\n DELAY_MS = 1500;\n\nexport function createAnalyticsBeacon(options: {\n readonly send: (body: string) => void;\n readonly now?: () => number;\n readonly delayMs?: number;\n}) {\n const now = options.now ?? Date.now,\n delay = options.delayMs ?? DELAY_MS;\n let queue: Queued[] = [],\n timer: ReturnType<typeof setTimeout> | undefined;\n const flush = () => {\n if (timer) {\n clearTimeout(timer);\n timer = undefined;\n }\n if (!queue.length) return;\n const at = now(),\n events = queue.map(({ at: when, ...rest }) => ({ ...rest, age: Math.max(0, at - when) }));\n queue = [];\n try {\n options.send(JSON.stringify({ events }));\n } catch {\n /* telemetry is never a reason to fail a page */\n }\n };\n const add = (event: Omit<Queued, 'at'>) => {\n queue.push({ ...event, at: now() });\n if (queue.length >= BATCH) flush();\n else timer ??= setTimeout(flush, delay);\n };\n return Object.freeze({\n /** A component's own event: the name and fields the App declared (the server drops the rest). */\n emit(name: string, fields?: AnalyticsFields) {\n if (typeof name !== 'string' || !name || name.length > 128) throw new Error('An analytics event is named with its declared name.');\n add({ kind: 'event', name, ...(fields ? { fields: { ...fields } } : {}) });\n },\n view(name: string, route?: string) {\n add({ kind: 'view', name, ...(route ? { route } : {}) });\n },\n form(name: string, step?: string) {\n add({ kind: 'form', name, ...(step ? { step } : {}) });\n },\n flush,\n });\n}\n\n/** The page's beacon: a keepalive POST to this App's route, so a closing tab still sends. */\nexport function pageAnalyticsBeacon() {\n const beacon = createAnalyticsBeacon({\n send: (body) => {\n void fetchServer(ANALYTICS_BEACON_PATH, {\n method: 'POST',\n credentials: 'same-origin',\n cache: 'no-store',\n keepalive: true,\n headers: { 'content-type': 'application/json' },\n body,\n }).catch(() => {});\n },\n });\n if (typeof document !== 'undefined')\n addHostListener(document, 'visibilitychange', () => {\n if (document.visibilityState === 'hidden') beacon.flush();\n });\n return beacon;\n}\n","/**\n * The page's side of `@mistriwork/mistri/ui`: the host a component's kit and hooks\n * read (context.ts), over the App payload and the session endpoints, and the\n * page's own modules put on one frozen global for the host modules a\n * served component imports (packages/mistri/src/server/app/componentSdk.ts).\n *\n * Loaded with the first custom section or value renderer a page draws, never\n * before: an App without components pays nothing for it. Every read is an\n * ordinary request under the reader's session (`/api/view/run`,\n * `/api/breakdown`), authorized on the server; a resource is named as the\n * App names it, and one the App does not declare is refused here as a\n * mistake before it is refused there as a denial.\n */\nimport * as React from 'react';\nimport * as JsxRuntime from 'react/jsx-runtime';\nimport * as ReactDOM from 'react-dom';\nimport * as ui from './index.js';\nimport * as page from './page.js';\nimport './kit.css';\nimport { api, columnDisplay, columnLabel, openRecord, pageApi, primaryKey, quote, state } from '@mistriwork/kit/client/core.js';\nimport { PAGE_LOAD_PATH } from '@mistriwork/engine/shared/pageRoutes.js';\nimport { ownedBy } from '@mistriwork/kit/client/requestIdentity.js';\nimport { sessionIdentity, subscribeSessionIdentity } from '@mistriwork/kit/client/sessionIdentity.js';\nimport { batchedBreakdown } from '@mistriwork/kit/client/breakdownBatch.js';\nimport { densityChoice } from '@mistriwork/kit/client/density.js';\nimport { fillComposer as fillPageComposer } from '@mistriwork/kit/client/components/composerDraft.js';\nimport { tableNamed, type TableMeta } from '@mistriwork/engine/shared/schema.js';\nimport { HOST_GLOBAL } from '../../../shared/uiSdk.js';\nimport { pageBridge } from '@mistriwork/kit/client/uiBridge.js';\nimport type { DisplayRule } from '@mistriwork/kit/client/components/valueModel.js';\nimport { setPageHost, type UiHost, type UiLook, type UiRow } from './context.js';\nimport { rowsByPath } from './rows.js';\nimport { sayAppMessage } from './appMessage.js';\nimport { say } from '../../copy/components/components/sdk/host.js';\nimport { served, shownUnplaced } from '@mistriwork/kit/client/addressMount.js';\nimport { viewPath } from '../../publicAddress.js';\nimport { createPageAppFlags } from '../../appFlags.js';\nimport { pageAnalyticsBeacon } from '../../analyticsBeacon.js';\nimport { shellRoot } from '@mistriwork/kit/client/shellHost.js';\n\nfunction tableOf(resource: string): TableMeta {\n const table = state.schema ? (tableNamed(state.schema, resource) as TableMeta | undefined) : undefined;\n const declared = (pageBridge.activeApp() as { resources?: Record<string, unknown> } | null)?.resources ?? {};\n if (!table || (Object.keys(declared).length && !Object.hasOwn(declared, table.id) && !table.union)) {\n throw new Error(say('isNotOneOfThisApps', { resource }));\n }\n return table;\n}\n\n/* A free-form page's own reads say which page asks, so the server holds them to its manifest too. */\nasync function viewRows(\n table: TableMeta,\n show: readonly string[] | undefined,\n query: string,\n limit: number,\n page?: string,\n): Promise<UiRow[]> {\n const paths = show?.length ? [...show] : table.columns.map((column) => column.name);\n const body = {\n count: 'none' as const,\n ...(query.trim() ? { query: query.trim() } : {}),\n view: { id: `ui:${table.id}`, name: table.name, base: table.id, columns: paths.map((path) => ({ path })), limit },\n };\n const got = page ? await pageApi(page, '/api/view/run', body) : await api('/api/view/run', body);\n return rowsByPath(paths, got, say('theRowsOfCould', { name: table.name }), { schema: state.schema, base: table.id });\n}\n\nconst root = () => shellRoot();\n\nfunction look(): UiLook {\n const attribute = root().dataset.theme;\n const dark = attribute === 'dark' || (!attribute && window.matchMedia?.('(prefers-color-scheme: dark)').matches);\n const density = densityChoice() as UiLook['density'];\n return { look: root().dataset.visualTheme ?? 'workshop', mode: dark ? 'dark' : 'light', density };\n}\n\nlet flags: ReturnType<typeof createPageAppFlags> | undefined;\nlet beacon: ReturnType<typeof pageAnalyticsBeacon> | undefined;\nconst pageHost: UiHost = {\n analytics: { emit: (name, fields) => (beacon ??= pageAnalyticsBeacon()).emit(name, fields) },\n get flags() {\n return (flags ??= createPageAppFlags(() => {\n const app = pageBridge.activeApp() as { id?: string } | null;\n return app?.id && app.id === state.activeConnection ? app.id : null;\n }));\n },\n /* The connection and the session's epoch: a sign-in, a sign-out or another account never reads another's cached rows. */\n get scope() {\n return [state.activeConnection ?? '', sessionIdentity().epoch];\n },\n rows(resource, { query, show, sort, limit, page }) {\n const table = tableOf(resource);\n return viewRows(table, show, [query ?? '', sort ? `sort ${sort}` : ''].join(' '), limit ?? 20, page);\n },\n async record(resource, key, show, asking = {}) {\n const table = tableOf(resource);\n const where = (primaryKey(table) as string[]).map((column) => `${column} = ${quote(String(key[column]))}`).join(' and ');\n return (await viewRows(table, show, where, 1, asking.page))[0];\n },\n async breakdown(resource, { by, measure, query, limit, page }) {\n const table = tableOf(resource);\n const text = [table.id, query ?? '', `${measure ?? 'count'} by ${by}`].filter(Boolean).join(' ');\n /* A page's breakdown is asked alone: a batch is many sections' and carries no one page's name. */\n const got = page\n ? ((await pageApi(page, '/api/breakdown', { text, ...(limit ? { limit } : {}) })) as { rows?: UiRow[] })\n : await batchedBreakdown<{ rows?: UiRow[] }>({ text, limit });\n return got.rows ?? [];\n },\n async load(page, params) {\n /* A tenant's lease answers a refusal as a reply, not a throw (tenantTransport.ts): it is the page's error either way. */\n const got = (await pageApi(page, PAGE_LOAD_PATH, { page, params })) as { data?: unknown; error?: unknown };\n if (typeof got.error === 'string') throw new Error(got.error);\n return got.data;\n },\n openRecord(resource, key, options = {}) {\n const table = tableOf(resource);\n const label = options.label ?? '';\n if ((options.mode === 'drawer' || options.mode === 'modal') && pageBridge.openPeek)\n pageBridge.openPeek(table.id, { ...key }, label, options.mode);\n else void openRecord(table.id, { ...key }, label);\n },\n openView(view, options) {\n if (!pageBridge.openView?.(view, options)) throw new Error(say('isNotAList', { view }));\n },\n /* The page's command pipeline and forms, registered by sdk/commands.tsx (uiBridge.ts says why). */\n openForm(view, prefill = {}) {\n if (!pageBridge.commands) throw new Error(say('thePageCannotOpen'));\n pageBridge.commands.openForm(view, prefill);\n },\n /* A tenant's link to hand out: a view a visitor reads by the tenant's public address, a public\n form (never one of the payload's rooms) by its intake address. Only the tenant's own lease is served them. */\n publicLink(view) {\n const app = pageBridge.activeApp() as { id?: string; views?: object; addresses?: { intake?: string; public?: string } } | null;\n if (!app?.id || typeof view !== 'string' || !view) return undefined;\n const room = Boolean(app.views && Object.hasOwn(app.views, view));\n const address = room ? app.addresses?.public : app.addresses?.intake;\n const path = room ? viewPath(view) : `/${encodeURIComponent(app.id)}/form/${encodeURIComponent(view)}`;\n if (!address || !path) return undefined;\n return `${window.location.origin}${shownUnplaced(path)}?via=${encodeURIComponent(address)}`;\n },\n fillComposer(text, mode) {\n return fillPageComposer(text, mode);\n },\n fileAddress(resource, key, options = {}) {\n const table = tableOf(resource);\n return served(\n `/api/file?${new URLSearchParams({\n ...ownedBy(state.activeConnection ?? null),\n table: table.id,\n key: JSON.stringify(key),\n inline: '1',\n ...(options.thumbnail ? { variant: 'thumb' } : {}),\n })}`,\n );\n },\n command: (ref, page) =>\n pageBridge.commands?.command(ref, page) ?? {\n label: ref,\n granted: false,\n available: async () => false,\n run: async () => ({ status: 'refused', message: say('thisPageCannotRun') }),\n open: async () => ({ status: 'refused', message: say('thisPageCannotRun') }),\n },\n viewer() {\n const identity = sessionIdentity();\n return identity.mode === 'authenticated' && identity.accountId ? { signedIn: true, account: identity.accountId } : { signedIn: false };\n },\n subscribeViewer: (listener) => subscribeSessionIdentity(listener),\n column(resource, name) {\n const table = state.schema ? (tableNamed(state.schema, resource) as TableMeta | undefined) : undefined;\n if (!table) return undefined;\n return {\n meta: table.columns.find((column) => column.name === name),\n rule: columnDisplay(table.id, name) as DisplayRule | null,\n label: (columnLabel(table.id, name) as string | null) ?? name,\n };\n },\n look,\n token: (name) => getComputedStyle(root()).getPropertyValue(name).trim(),\n subscribeLook(listener) {\n const observer = new MutationObserver(listener);\n observer.observe(root(), { attributes: true, attributeFilter: ['data-theme', 'data-visual-theme', 'data-palette', 'style', 'class'] });\n const media = window.matchMedia?.('(prefers-color-scheme: dark)');\n media?.addEventListener?.('change', listener);\n return () => {\n observer.disconnect();\n media?.removeEventListener?.('change', listener);\n };\n },\n get app() {\n return pageBridge.inAppMode();\n },\n message: (key, args) =>\n sayAppMessage((pageBridge.activeApp() as { messages?: Readonly<Record<string, readonly unknown[]>> } | null)?.messages, key, args),\n};\n\n/* The page's modules, for the host modules a component's bare imports reach.\n Frozen: a component may read them, and none may swap one for another. */\nif (!(HOST_GLOBAL in globalThis)) {\n Object.defineProperty(globalThis, HOST_GLOBAL, {\n value: Object.freeze({\n modules: Object.freeze({\n react: React,\n 'react/jsx-runtime': JsxRuntime,\n 'react-dom': ReactDOM,\n '@mistriwork/mistri/ui': ui,\n '@mistriwork/mistri/page': page,\n }),\n }),\n enumerable: false,\n writable: false,\n configurable: false,\n });\n}\nsetPageHost(pageHost);\n","/** What sdk/componentLoader 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 theAppServesNoComponent: 'The App serves no component \"{id}\".',\n theComponentHasNoDefault: 'The component \"{id}\" has no default export.',\n});\n","/**\n * An App's custom component, fetched the first time the page draws it: its\n * stylesheet linked once, its module imported from where the App payload\n * says it is served (`/{app}/_components/<id>-<hash>.js`). Importing this\n * module installs the page's side of `@mistriwork/mistri/ui` first (host.tsx), so a\n * component's bare imports find the page's own React before it evaluates.\n *\n * A module that cannot be fetched is almost always a deploy — the page was\n * opened before it and the hashed name it holds is gone — which the section\n * says as the built-in chunks do (onDemand.tsx), with a Reload.\n */\nimport type { ComponentType } from 'react';\nimport { pageBridge } from '@mistriwork/kit/client/uiBridge.js';\nimport './host.js';\nimport { say } from '../../copy/components/components/sdk/componentLoader.js';\nimport { appFile } from '@mistriwork/kit/client/addressMount.js';\n\ninterface Served {\n kind: 'section' | 'value';\n href: string;\n css?: string;\n}\n\nconst modules = new Map<string, Promise<ComponentType<never>>>();\n\n/* The payload says each file's inside address (`/{app}/_components/…`);\n it is fetched where the browser reaches it (addressMount.js `appFile`): an\n embedded shell's from its endpoint, never under the host's address. */\nfunction served(id: string): Served | undefined {\n const components = (pageBridge.activeApp() as { components?: Record<string, Served> } | null)?.components;\n const entry = components && Object.hasOwn(components, id) ? components[id] : undefined;\n return entry && { kind: entry.kind, ...reached(entry) };\n}\n\nconst reached = (entry: { href: string; css?: string }) => ({\n href: appFile(entry.href),\n ...(entry.css ? { css: appFile(entry.css) } : {}),\n});\n\nfunction linkStylesheet(href: string, id: string): void {\n if (document.head.querySelector(`link[data-component-css=\"${CSS.escape(id)}\"][href=\"${CSS.escape(href)}\"]`)) return;\n const link = document.createElement('link');\n link.rel = 'stylesheet';\n link.href = href;\n link.dataset.componentCss = id;\n document.head.append(link);\n}\n\n/** The component the App declares under `id`, its default export; rejects when it is not served or will not load. */\nexport function loadComponent(id: string): Promise<ComponentType<never>> {\n return loadEntry(id, served(id));\n}\n\n/**\n * The component `id` from where `entry` says it is served (its inside address, `/{app}/_components/…`): what a public\n * form's page loads its input components by, from the form's own payload, having no App payload (sdk/publicInputs.ts).\n */\nexport function loadServedComponent(id: string, given: { href: string; css?: string } | undefined): Promise<ComponentType<never>> {\n return loadEntry(id, given && reached(given));\n}\n\nfunction loadEntry(id: string, entry: { href: string; css?: string } | undefined): Promise<ComponentType<never>> {\n if (!entry) return Promise.reject(new Error(say('theAppServesNoComponent', { id })));\n let loading = modules.get(entry.href);\n if (!loading) {\n if (entry.css) linkStylesheet(entry.css, id);\n loading = (import(/* @vite-ignore */ entry.href) as Promise<{ default?: unknown }>).then((module) => {\n const part = module.default;\n if (typeof part !== 'function' && (typeof part !== 'object' || part === null))\n throw new Error(say('theComponentHasNoDefault', { id }));\n return part as ComponentType<never>;\n });\n // A failed fetch is not kept: the next draw asks again (a Reload is offered meanwhile).\n loading.catch(() => {\n if (modules.get(entry.href) === loading) modules.delete(entry.href);\n });\n modules.set(entry.href, loading);\n }\n return loading;\n}\n"],"mappings":"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"}
@@ -1,11 +1,11 @@
1
1
  import { it as useQuery } from "./shared-poc11xxo.js";
2
2
  import { gt as defineMessages, kt as portalRoot, rn as shell } from "./shared-DJZjSi3J.js";
3
- import { E as dismissEditNotice, F as useRecentChange, M as useEditNotice, O as liveKeyText } from "./shared-CNmaAv64.js";
4
- import { c as columnLabel, i as api } from "./shared-DPAVoWY0.js";
3
+ import { E as dismissEditNotice, F as useRecentChange, M as useEditNotice, O as liveKeyText } from "./shared-BHsjawAG.js";
4
+ import { c as columnLabel, i as api } from "./shared-BoLbc2WD.js";
5
5
  import { r as recordNoun } from "./shared-BZ8KfT9k.js";
6
6
  import { n as pathEqualityFilter } from "./shared-_IMKuuvy.js";
7
- import { s as historyBody } from "./shared-DJrJaE73.js";
8
- import { E as subscribeStaged, T as stagedVersion, _ as sameRow, f as pendingCount, k as takeTheirs, o as dirtyDraft } from "./shared-CMAg58rY.js";
7
+ import { s as historyBody } from "./shared-CZJE4Bmp.js";
8
+ import { E as subscribeStaged, T as stagedVersion, _ as sameRow, f as pendingCount, k as takeTheirs, o as dirtyDraft } from "./shared-Z4uBJU6I.js";
9
9
  import { useCallback, useEffect, useState, useSyncExternalStore } from "react";
10
10
  import { jsx, jsxs } from "react/jsx-runtime";
11
11
  import { createPortal } from "react-dom";
@@ -318,4 +318,4 @@ function LiveEditNotice({ table, recordKey, place }) {
318
318
  }
319
319
  export { LiveEditNotice, LivePill, LiveUpdatedLine, resetChangedBy };
320
320
 
321
- //# sourceMappingURL=shared-0fNuhSbG.js.map
321
+ //# sourceMappingURL=shared-B07qIMlE.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"shared-0fNuhSbG.js","names":[],"sources":["../../../kit/src/client/copy/record/components/LiveNotices.ts","../../../kit/src/client/components/LiveNotices.tsx"],"sourcesContent":["/** What live sync says beside a list, a record and a draft (components/LiveNotices.tsx). */\nimport { defineMessages } from '../../../messages.js';\n\nexport const say = defineMessages({\n updates: { one: '{count} update', other: '{count} updates' },\n pill: '{updates} · Show',\n pillMany: 'Updates · Show',\n showUpdates: 'Show the updates',\n justNow: 'just now',\n minutesAgo: { one: '{count} minute ago', other: '{count} minutes ago' },\n you: 'you',\n updatedBy: 'Updated by {who} {when}',\n updated: 'Updated {when}',\n changedBy: '{name} changed this {record}',\n changedBySomeone: 'Someone changed this {record}',\n changedByYou: 'You changed this {record} in another tab',\n deletedBy: '{name} deleted this {record}',\n deletedBySomeone: 'Someone deleted this {record}',\n review: 'Review changes',\n keepEditing: 'Keep editing',\n theirChanges: 'Their changes',\n original: 'Before',\n yours: 'Yours',\n theirs: 'Theirs',\n takeTheirs: 'Take theirs',\n nothingDiffers: 'None of the fields you changed were changed.',\n reading: 'Reading their changes…',\n couldNotRead: 'Their changes could not be read.',\n empty: 'empty',\n});\n","/**\n * What live sync says where a change from elsewhere lands (docs/design.md, rule 11): the pill over a list that is\n * held, the line under a record's head, and the notice over a draft with the changes laid beside it.\n *\n * Out of flow, all of it: the pill is fixed to the window, the line sits in the head's top row without taking room\n * from it, the notice over a record's draft hangs from the record's head, over the gap above its fields, and a\n * command form's stands in its status line. None of it moves what the reader is looking at. A part of its own\n * (onDemand.tsx), fetched when the first change that needs it arrives.\n */\nimport { useCallback, useEffect, useState, useSyncExternalStore } from 'react';\nimport { createPortal } from 'react-dom';\nimport { useQuery } from '@tanstack/react-query';\nimport { api, columnLabel } from '../core.js';\nimport { shell } from '../shellMode.js';\nimport { dirtyDraft, pendingCount, sameRow, stagedVersion, subscribeStaged, takeTheirs } from '../write.js';\nimport { pathEqualityFilter } from '../resourceRequests.js';\nimport { historyBody } from '@mistriwork/engine/shared/recordReads.js';\nimport { recordNoun } from '@mistriwork/engine/shared/appNoun.js';\nimport { dismissEditNotice, liveKeyText, useEditNotice, useRecentChange } from '../liveState.js';\nimport type { HistoryEntry } from './PageHistory.js';\nimport type { TableMeta } from '@mistriwork/engine/shared/schema.js';\nimport { say } from '../copy/record/components/LiveNotices.js';\nimport './LiveNotices.css';\nimport { portalRoot } from '../shellHost.js';\n\n/* ---------- the pill over a held list ---------- */\n\nexport function LivePill({ held, show }: { held: number | 'many'; show: () => void }) {\n const label = held === 'many' ? say('pillMany') : say('pill', { updates: say('updates', { count: held }) });\n return createPortal(\n <div className=\"live-pill-host\" role=\"status\">\n <button type=\"button\" className=\"live-pill\" onClick={show} aria-label={say('showUpdates')} title={say('showUpdates')}>\n {label}\n </button>\n </div>,\n portalRoot(),\n );\n}\n\n/* ---------- who changed it, without leaking ---------- */\n\n/* Tables whose history the reader cannot read (or that keep none): not asked again. */\nconst NO_HISTORY = new Set<string>();\n\n/* At most one history read a second for a record, however fast its changes come: a busy record's line under its head\n and the notice over its draft both asked again on every live batch, about four reads a second each. The first change\n in a second is asked at once, so it is named as fast as before; the ones after it wait out the second and are asked\n as one, for the newest, so the name said is still the last author's. Shared by everything drawn for the record. */\nconst READ_GAP = 1000;\ninterface Paced {\n /** The change the name is read for now, and the newest one offered. */\n asked: number;\n newest: number;\n /** When it was last read. */\n read: number;\n timer?: ReturnType<typeof setTimeout>;\n readonly listeners: Set<() => void>;\n}\nconst paced = new Map<string, Paced>();\n/* The records kept: past it, the longest-kept one nothing draws is let go. */\nconst PACED_MOST = 200;\nfunction pacedFor(id: string): Paced {\n let found = paced.get(id);\n if (!found) {\n paced.set(id, (found = { asked: 0, newest: 0, read: -Infinity, listeners: new Set() }));\n for (const [other, p] of paced) {\n if (paced.size <= PACED_MOST) break;\n if (!p.listeners.size && !p.timer) paced.delete(other);\n }\n }\n return found;\n}\nfunction subscribePaced(id: string, listener: () => void): () => void {\n const p = pacedFor(id);\n p.listeners.add(listener);\n return () => p.listeners.delete(listener);\n}\nfunction offerChange(id: string, at: number): void {\n const p = pacedFor(id);\n if (at <= p.newest) return;\n p.newest = at;\n if (p.timer) return;\n const ask = () => {\n p.timer = undefined;\n p.read = Date.now();\n p.asked = p.newest;\n for (const listener of p.listeners) listener();\n };\n const wait = p.read + READ_GAP - Date.now();\n if (wait <= 0) ask();\n else p.timer = setTimeout(ask, wait);\n}\n/** Tests only: forget every record's pace. */\nexport function resetChangedBy(): void {\n for (const p of paced.values()) clearTimeout(p.timer);\n paced.clear();\n}\n\n/**\n * The name of the newest author of a record, by the record's history under the reader's own grants: undefined where\n * the reader may not read it (the server answers as it does for anyone) or it names no person. The event itself\n * never carries an actor.\n */\nfunction useChangedBy(table: TableMeta, key: Readonly<Record<string, unknown>>, at: number, wanted: boolean): string | undefined {\n const id = `${table.id}\\u0000${liveKeyText(key)}`;\n const subscribe = useCallback((listener: () => void) => subscribePaced(id, listener), [id]);\n const asked = useSyncExternalStore(\n subscribe,\n () => paced.get(id)?.asked ?? 0,\n () => 0,\n );\n useEffect(() => {\n if (wanted && at) offerChange(id, at);\n }, [id, at, wanted]);\n const read = useQuery<string | null>({\n queryKey: ['live-history', table.id, liveKeyText(key), asked],\n enabled: wanted && asked > 0 && !NO_HISTORY.has(table.id),\n retry: false,\n staleTime: 60_000,\n gcTime: 60_000,\n /* The name read for the change before stays while the next is read: no flicker to \"someone\" between them. */\n placeholderData: (previous) => previous,\n queryFn: async () => {\n try {\n const page = (await api('/api/record-history', historyBody(table, key, 1))) as { entries?: HistoryEntry[] };\n const by = page.entries?.[0]?.by;\n return by && !/[^\\s@]+@[^\\s@]+\\.[^\\s@]+/.test(by) ? by : null;\n } catch {\n NO_HISTORY.add(table.id);\n return null;\n }\n },\n });\n return read.data ?? undefined;\n}\n\n/* ---------- the line under a record's head ---------- */\n\nconst GONE_AFTER = 10 * 60_000;\n\n/**\n * \"Updated by Ana just now\", for ten minutes, said again each minute; \"by you\" for the reader's own change in another\n * tab. Not while the reader has a draft of the record: the notice over the draft says it, with what to do about it.\n */\nexport function LiveUpdatedLine({ table, recordKey }: { table: TableMeta; recordKey: Readonly<Record<string, unknown>> }) {\n useSyncExternalStore(subscribeStaged, stagedVersion, stagedVersion);\n const drafting = sameRow(table.id, recordKey) && pendingCount() > 0;\n const recent = useRecentChange(table.id, liveKeyText(recordKey));\n const [now, setNow] = useState(() => Date.now());\n useEffect(() => {\n const timer = setInterval(() => setNow(Date.now()), 60_000);\n return () => clearInterval(timer);\n }, []);\n const name = useChangedBy(table, recordKey, recent?.at ?? 0, Boolean(recent && !recent.self));\n if (!recent || drafting || now - recent.at >= GONE_AFTER) return null;\n const minutes = Math.floor((now - recent.at) / 60_000);\n const when = minutes < 1 ? say('justNow') : say('minutesAgo', { count: minutes });\n const who = recent.self ? say('you') : name;\n return (\n <span className=\"live-updated\" role=\"status\">\n {who ? say('updatedBy', { who, when }) : say('updated', { when })}\n </span>\n );\n}\n\n/* ---------- the notice over a draft ---------- */\n\n/** What another person changed of the fields the reader is changing, side by side. */\nfunction Review({ table, recordKey }: { table: TableMeta; recordKey: Readonly<Record<string, unknown>> }) {\n const draft = dirtyDraft();\n const columns = draft ? Object.keys(draft.values) : [];\n const theirs = useQuery<Record<string, unknown> | null>({\n // A copy of its own: the record the form is drawn from is not read over a draft.\n queryKey: ['live-review', table.id, liveKeyText(recordKey), columns.join(',')],\n enabled: columns.length > 0,\n retry: false,\n staleTime: 0,\n gcTime: 0,\n queryFn: async () => {\n const reply = (await api('/api/view/run', {\n count: 'none',\n view: {\n id: `live:${table.id}`,\n name: table.name,\n base: table.id,\n columns: columns.map((path) => ({ path })),\n filter: pathEqualityFilter(recordKey as Record<string, unknown>),\n limit: 1,\n },\n })) as { rows?: Array<Record<string, unknown>> };\n return reply.rows?.[0] ?? null;\n },\n });\n if (!draft) return null;\n if (theirs.isPending) return <p className=\"live-review-note\">{say('reading')}</p>;\n if (theirs.isError || !theirs.data) return <p className=\"live-review-note\">{say('couldNotRead')}</p>;\n const said = (value: unknown) => (value === null || value === undefined || value === '' ? say('empty') : String(value));\n const differing = columns.filter((column) => said(theirs.data![column]) !== said(draft.originals[column]));\n if (!differing.length) return <p className=\"live-review-note\">{say('nothingDiffers')}</p>;\n return (\n <dl className=\"live-review\" aria-label={say('theirChanges')}>\n {differing.map((column) => (\n <div key={column} className=\"live-review-field\">\n <dt>{(columnLabel(table.id, column) as string | null) ?? column}</dt>\n <dd>\n <span className=\"live-review-col\">\n <small>{say('original')}</small>\n {said(draft.originals[column])}\n </span>\n <span className=\"live-review-col\">\n <small>{say('yours')}</small>\n {said(draft.values[column])}\n </span>\n <span className=\"live-review-col\">\n <small>{say('theirs')}</small>\n {said(theirs.data![column])}\n </span>\n <button type=\"button\" className=\"ghost\" onClick={() => takeTheirs(column, theirs.data![column])}>\n {say('takeTheirs')}\n </button>\n </dd>\n </div>\n ))}\n </dl>\n );\n}\n\n/**\n * \"Ana changed this ticket\", beside a draft of that ticket, with Review changes and Keep editing. `anchored` hangs it\n * from the record's head over the gap above the fields, out of flow (a record room's draft); `inline` says it in a\n * form's status line, without Review, since what a command form holds is not the record's fields.\n */\nexport function LiveEditNotice({\n table,\n recordKey,\n place,\n}: {\n table: TableMeta;\n recordKey: Readonly<Record<string, unknown>>;\n place?: 'anchored' | 'inline';\n}) {\n const text = liveKeyText(recordKey);\n const notice = useEditNotice(table.id, text);\n const [reviewing, setReviewing] = useState(false);\n /* Asked for this change, not the last one: a second person's change under the same draft names the second person. */\n const name = useChangedBy(table, recordKey, notice?.at ?? 0, Boolean(notice && !notice.self));\n useEffect(() => {\n if (!notice) setReviewing(false);\n }, [notice]);\n if (!notice) return null;\n const record = recordNoun(shell().app()?.resources[table.id]?.noun, table.name);\n const sentence =\n notice.kind === 'delete'\n ? name\n ? say('deletedBy', { name, record })\n : say('deletedBySomeone', { record })\n : notice.self\n ? say('changedByYou', { record })\n : name\n ? say('changedBy', { name, record })\n : say('changedBySomeone', { record });\n if (place === 'inline')\n return (\n <span className=\"live-notice is-inline\">\n <span className=\"live-notice-text\">{sentence}</span>\n <button type=\"button\" className=\"ghost\" onClick={() => dismissEditNotice(table.id, text)}>\n {say('keepEditing')}\n </button>\n </span>\n );\n return (\n <div className={`live-notice${place === 'anchored' ? ' is-anchored' : ''}${reviewing ? ' is-reviewing' : ''}`} role=\"status\">\n <span className=\"live-notice-text\" title={sentence}>\n {sentence}\n </span>\n {notice.kind === 'update' && (\n <button\n type=\"button\"\n className={`ghost${place === 'anchored' ? ' live-act' : ''}`}\n aria-expanded={reviewing}\n onClick={() => setReviewing((on) => !on)}\n >\n {say('review')}\n </button>\n )}\n <button type=\"button\" className={`ghost${place === 'anchored' ? ' live-act' : ''}`} onClick={() => dismissEditNotice(table.id, text)}>\n {say('keepEditing')}\n </button>\n {reviewing && notice.kind === 'update' && <Review table={table} recordKey={recordKey} />}\n </div>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"shared-B07qIMlE.js","names":[],"sources":["../../../kit/src/client/copy/record/components/LiveNotices.ts","../../../kit/src/client/components/LiveNotices.tsx"],"sourcesContent":["/** What live sync says beside a list, a record and a draft (components/LiveNotices.tsx). */\nimport { defineMessages } from '../../../messages.js';\n\nexport const say = defineMessages({\n updates: { one: '{count} update', other: '{count} updates' },\n pill: '{updates} · Show',\n pillMany: 'Updates · Show',\n showUpdates: 'Show the updates',\n justNow: 'just now',\n minutesAgo: { one: '{count} minute ago', other: '{count} minutes ago' },\n you: 'you',\n updatedBy: 'Updated by {who} {when}',\n updated: 'Updated {when}',\n changedBy: '{name} changed this {record}',\n changedBySomeone: 'Someone changed this {record}',\n changedByYou: 'You changed this {record} in another tab',\n deletedBy: '{name} deleted this {record}',\n deletedBySomeone: 'Someone deleted this {record}',\n review: 'Review changes',\n keepEditing: 'Keep editing',\n theirChanges: 'Their changes',\n original: 'Before',\n yours: 'Yours',\n theirs: 'Theirs',\n takeTheirs: 'Take theirs',\n nothingDiffers: 'None of the fields you changed were changed.',\n reading: 'Reading their changes…',\n couldNotRead: 'Their changes could not be read.',\n empty: 'empty',\n});\n","/**\n * What live sync says where a change from elsewhere lands (docs/design.md, rule 11): the pill over a list that is\n * held, the line under a record's head, and the notice over a draft with the changes laid beside it.\n *\n * Out of flow, all of it: the pill is fixed to the window, the line sits in the head's top row without taking room\n * from it, the notice over a record's draft hangs from the record's head, over the gap above its fields, and a\n * command form's stands in its status line. None of it moves what the reader is looking at. A part of its own\n * (onDemand.tsx), fetched when the first change that needs it arrives.\n */\nimport { useCallback, useEffect, useState, useSyncExternalStore } from 'react';\nimport { createPortal } from 'react-dom';\nimport { useQuery } from '@tanstack/react-query';\nimport { api, columnLabel } from '../core.js';\nimport { shell } from '../shellMode.js';\nimport { dirtyDraft, pendingCount, sameRow, stagedVersion, subscribeStaged, takeTheirs } from '../write.js';\nimport { pathEqualityFilter } from '../resourceRequests.js';\nimport { historyBody } from '@mistriwork/engine/shared/recordReads.js';\nimport { recordNoun } from '@mistriwork/engine/shared/appNoun.js';\nimport { dismissEditNotice, liveKeyText, useEditNotice, useRecentChange } from '../liveState.js';\nimport type { HistoryEntry } from './PageHistory.js';\nimport type { TableMeta } from '@mistriwork/engine/shared/schema.js';\nimport { say } from '../copy/record/components/LiveNotices.js';\nimport './LiveNotices.css';\nimport { portalRoot } from '../shellHost.js';\n\n/* ---------- the pill over a held list ---------- */\n\nexport function LivePill({ held, show }: { held: number | 'many'; show: () => void }) {\n const label = held === 'many' ? say('pillMany') : say('pill', { updates: say('updates', { count: held }) });\n return createPortal(\n <div className=\"live-pill-host\" role=\"status\">\n <button type=\"button\" className=\"live-pill\" onClick={show} aria-label={say('showUpdates')} title={say('showUpdates')}>\n {label}\n </button>\n </div>,\n portalRoot(),\n );\n}\n\n/* ---------- who changed it, without leaking ---------- */\n\n/* Tables whose history the reader cannot read (or that keep none): not asked again. */\nconst NO_HISTORY = new Set<string>();\n\n/* At most one history read a second for a record, however fast its changes come: a busy record's line under its head\n and the notice over its draft both asked again on every live batch, about four reads a second each. The first change\n in a second is asked at once, so it is named as fast as before; the ones after it wait out the second and are asked\n as one, for the newest, so the name said is still the last author's. Shared by everything drawn for the record. */\nconst READ_GAP = 1000;\ninterface Paced {\n /** The change the name is read for now, and the newest one offered. */\n asked: number;\n newest: number;\n /** When it was last read. */\n read: number;\n timer?: ReturnType<typeof setTimeout>;\n readonly listeners: Set<() => void>;\n}\nconst paced = new Map<string, Paced>();\n/* The records kept: past it, the longest-kept one nothing draws is let go. */\nconst PACED_MOST = 200;\nfunction pacedFor(id: string): Paced {\n let found = paced.get(id);\n if (!found) {\n paced.set(id, (found = { asked: 0, newest: 0, read: -Infinity, listeners: new Set() }));\n for (const [other, p] of paced) {\n if (paced.size <= PACED_MOST) break;\n if (!p.listeners.size && !p.timer) paced.delete(other);\n }\n }\n return found;\n}\nfunction subscribePaced(id: string, listener: () => void): () => void {\n const p = pacedFor(id);\n p.listeners.add(listener);\n return () => p.listeners.delete(listener);\n}\nfunction offerChange(id: string, at: number): void {\n const p = pacedFor(id);\n if (at <= p.newest) return;\n p.newest = at;\n if (p.timer) return;\n const ask = () => {\n p.timer = undefined;\n p.read = Date.now();\n p.asked = p.newest;\n for (const listener of p.listeners) listener();\n };\n const wait = p.read + READ_GAP - Date.now();\n if (wait <= 0) ask();\n else p.timer = setTimeout(ask, wait);\n}\n/** Tests only: forget every record's pace. */\nexport function resetChangedBy(): void {\n for (const p of paced.values()) clearTimeout(p.timer);\n paced.clear();\n}\n\n/**\n * The name of the newest author of a record, by the record's history under the reader's own grants: undefined where\n * the reader may not read it (the server answers as it does for anyone) or it names no person. The event itself\n * never carries an actor.\n */\nfunction useChangedBy(table: TableMeta, key: Readonly<Record<string, unknown>>, at: number, wanted: boolean): string | undefined {\n const id = `${table.id}\\u0000${liveKeyText(key)}`;\n const subscribe = useCallback((listener: () => void) => subscribePaced(id, listener), [id]);\n const asked = useSyncExternalStore(\n subscribe,\n () => paced.get(id)?.asked ?? 0,\n () => 0,\n );\n useEffect(() => {\n if (wanted && at) offerChange(id, at);\n }, [id, at, wanted]);\n const read = useQuery<string | null>({\n queryKey: ['live-history', table.id, liveKeyText(key), asked],\n enabled: wanted && asked > 0 && !NO_HISTORY.has(table.id),\n retry: false,\n staleTime: 60_000,\n gcTime: 60_000,\n /* The name read for the change before stays while the next is read: no flicker to \"someone\" between them. */\n placeholderData: (previous) => previous,\n queryFn: async () => {\n try {\n const page = (await api('/api/record-history', historyBody(table, key, 1))) as { entries?: HistoryEntry[] };\n const by = page.entries?.[0]?.by;\n return by && !/[^\\s@]+@[^\\s@]+\\.[^\\s@]+/.test(by) ? by : null;\n } catch {\n NO_HISTORY.add(table.id);\n return null;\n }\n },\n });\n return read.data ?? undefined;\n}\n\n/* ---------- the line under a record's head ---------- */\n\nconst GONE_AFTER = 10 * 60_000;\n\n/**\n * \"Updated by Ana just now\", for ten minutes, said again each minute; \"by you\" for the reader's own change in another\n * tab. Not while the reader has a draft of the record: the notice over the draft says it, with what to do about it.\n */\nexport function LiveUpdatedLine({ table, recordKey }: { table: TableMeta; recordKey: Readonly<Record<string, unknown>> }) {\n useSyncExternalStore(subscribeStaged, stagedVersion, stagedVersion);\n const drafting = sameRow(table.id, recordKey) && pendingCount() > 0;\n const recent = useRecentChange(table.id, liveKeyText(recordKey));\n const [now, setNow] = useState(() => Date.now());\n useEffect(() => {\n const timer = setInterval(() => setNow(Date.now()), 60_000);\n return () => clearInterval(timer);\n }, []);\n const name = useChangedBy(table, recordKey, recent?.at ?? 0, Boolean(recent && !recent.self));\n if (!recent || drafting || now - recent.at >= GONE_AFTER) return null;\n const minutes = Math.floor((now - recent.at) / 60_000);\n const when = minutes < 1 ? say('justNow') : say('minutesAgo', { count: minutes });\n const who = recent.self ? say('you') : name;\n return (\n <span className=\"live-updated\" role=\"status\">\n {who ? say('updatedBy', { who, when }) : say('updated', { when })}\n </span>\n );\n}\n\n/* ---------- the notice over a draft ---------- */\n\n/** What another person changed of the fields the reader is changing, side by side. */\nfunction Review({ table, recordKey }: { table: TableMeta; recordKey: Readonly<Record<string, unknown>> }) {\n const draft = dirtyDraft();\n const columns = draft ? Object.keys(draft.values) : [];\n const theirs = useQuery<Record<string, unknown> | null>({\n // A copy of its own: the record the form is drawn from is not read over a draft.\n queryKey: ['live-review', table.id, liveKeyText(recordKey), columns.join(',')],\n enabled: columns.length > 0,\n retry: false,\n staleTime: 0,\n gcTime: 0,\n queryFn: async () => {\n const reply = (await api('/api/view/run', {\n count: 'none',\n view: {\n id: `live:${table.id}`,\n name: table.name,\n base: table.id,\n columns: columns.map((path) => ({ path })),\n filter: pathEqualityFilter(recordKey as Record<string, unknown>),\n limit: 1,\n },\n })) as { rows?: Array<Record<string, unknown>> };\n return reply.rows?.[0] ?? null;\n },\n });\n if (!draft) return null;\n if (theirs.isPending) return <p className=\"live-review-note\">{say('reading')}</p>;\n if (theirs.isError || !theirs.data) return <p className=\"live-review-note\">{say('couldNotRead')}</p>;\n const said = (value: unknown) => (value === null || value === undefined || value === '' ? say('empty') : String(value));\n const differing = columns.filter((column) => said(theirs.data![column]) !== said(draft.originals[column]));\n if (!differing.length) return <p className=\"live-review-note\">{say('nothingDiffers')}</p>;\n return (\n <dl className=\"live-review\" aria-label={say('theirChanges')}>\n {differing.map((column) => (\n <div key={column} className=\"live-review-field\">\n <dt>{(columnLabel(table.id, column) as string | null) ?? column}</dt>\n <dd>\n <span className=\"live-review-col\">\n <small>{say('original')}</small>\n {said(draft.originals[column])}\n </span>\n <span className=\"live-review-col\">\n <small>{say('yours')}</small>\n {said(draft.values[column])}\n </span>\n <span className=\"live-review-col\">\n <small>{say('theirs')}</small>\n {said(theirs.data![column])}\n </span>\n <button type=\"button\" className=\"ghost\" onClick={() => takeTheirs(column, theirs.data![column])}>\n {say('takeTheirs')}\n </button>\n </dd>\n </div>\n ))}\n </dl>\n );\n}\n\n/**\n * \"Ana changed this ticket\", beside a draft of that ticket, with Review changes and Keep editing. `anchored` hangs it\n * from the record's head over the gap above the fields, out of flow (a record room's draft); `inline` says it in a\n * form's status line, without Review, since what a command form holds is not the record's fields.\n */\nexport function LiveEditNotice({\n table,\n recordKey,\n place,\n}: {\n table: TableMeta;\n recordKey: Readonly<Record<string, unknown>>;\n place?: 'anchored' | 'inline';\n}) {\n const text = liveKeyText(recordKey);\n const notice = useEditNotice(table.id, text);\n const [reviewing, setReviewing] = useState(false);\n /* Asked for this change, not the last one: a second person's change under the same draft names the second person. */\n const name = useChangedBy(table, recordKey, notice?.at ?? 0, Boolean(notice && !notice.self));\n useEffect(() => {\n if (!notice) setReviewing(false);\n }, [notice]);\n if (!notice) return null;\n const record = recordNoun(shell().app()?.resources[table.id]?.noun, table.name);\n const sentence =\n notice.kind === 'delete'\n ? name\n ? say('deletedBy', { name, record })\n : say('deletedBySomeone', { record })\n : notice.self\n ? say('changedByYou', { record })\n : name\n ? say('changedBy', { name, record })\n : say('changedBySomeone', { record });\n if (place === 'inline')\n return (\n <span className=\"live-notice is-inline\">\n <span className=\"live-notice-text\">{sentence}</span>\n <button type=\"button\" className=\"ghost\" onClick={() => dismissEditNotice(table.id, text)}>\n {say('keepEditing')}\n </button>\n </span>\n );\n return (\n <div className={`live-notice${place === 'anchored' ? ' is-anchored' : ''}${reviewing ? ' is-reviewing' : ''}`} role=\"status\">\n <span className=\"live-notice-text\" title={sentence}>\n {sentence}\n </span>\n {notice.kind === 'update' && (\n <button\n type=\"button\"\n className={`ghost${place === 'anchored' ? ' live-act' : ''}`}\n aria-expanded={reviewing}\n onClick={() => setReviewing((on) => !on)}\n >\n {say('review')}\n </button>\n )}\n <button type=\"button\" className={`ghost${place === 'anchored' ? ' live-act' : ''}`} onClick={() => dismissEditNotice(table.id, text)}>\n {say('keepEditing')}\n </button>\n {reviewing && notice.kind === 'update' && <Review table={table} recordKey={recordKey} />}\n </div>\n );\n}\n"],"mappings":"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"}
@@ -1,8 +1,8 @@
1
1
  import { E as sessionIdentity } from "./shared-poc11xxo.js";
2
2
  import { gt as defineMessages } from "./shared-DJZjSi3J.js";
3
- import { B as toast, L as state, i as api, st as ownedBy } from "./shared-DPAVoWY0.js";
3
+ import { B as toast, L as state, i as api, st as ownedBy } from "./shared-BoLbc2WD.js";
4
4
  import { r as queryClient } from "./shared-C3MTHv9P.js";
5
- import { a as commandInput, f as readyToJudge, u as prefilledCommandValues } from "./shared-D1mMBLdj.js";
5
+ import { a as commandInput, f as readyToJudge, u as prefilledCommandValues } from "./shared-JvcI-LWp.js";
6
6
  // packages/mistri/src/client/copy/components/components/sdk/formCommandRun.ts
7
7
  /** What sdk/formCommandRun says, in the custom components room (packages/kit/src/client/messages.ts says how the catalog is split). */
8
8
  var say = defineMessages({
@@ -100,4 +100,4 @@ async function sendFormCommand(label, envelope, identity, checking) {
100
100
  }
101
101
  export { attemptKey, runFormCommand };
102
102
 
103
- //# sourceMappingURL=shared-lYtMadRU.js.map
103
+ //# sourceMappingURL=shared-B1SAS_J-.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"shared-lYtMadRU.js","names":[],"sources":["../../src/client/copy/components/components/sdk/formCommandRun.ts","../../src/client/components/sdk/formCommandRun.ts"],"sourcesContent":["/** What sdk/formCommandRun 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 isNotSomethingYouCanDo: '{label} is not something you can do here.',\n notKnown: '{label} was sent, and its result is not known yet. Check it before you send it again.',\n checkedElsewhere: 'You signed in again since {label} was sent, so its result cannot be checked here.',\n attemptIsAUuid: \"A run's attempt is the key it is sent under: a UUID made once per intent, crypto.randomUUID().\",\n});\n","/**\n * A component's run of a command that names no record, and the key a run is\n * sent under: fetched when a component holds such a command (commands.tsx),\n * never on the App's first paint.\n */\nimport { api, state, toast } from '@mistriwork/kit/client/core.js';\nimport { ownedBy } from '@mistriwork/kit/client/requestIdentity.js';\nimport { sessionIdentity } from '@mistriwork/kit/client/sessionIdentity.js';\nimport { queryClient } from '@mistriwork/kit/client/components/mount.js';\nimport type { ServedForm as RoomForm } from '@mistriwork/kit/client/components/appRooms.js';\nimport type { AppPayloadApp } from '../../../shared/appPayload.js';\nimport { commandInput, prefilledCommandValues, readyToJudge } from '../CommandFields.js';\nimport type { UiCommandOptions, UiCommandOutcome } from './context.js';\nimport { say } from '../../copy/components/components/sdk/formCommandRun.js';\n\ntype Served = { form: RoomForm<AppPayloadApp>; appName: string };\n\nconst UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;\n/** The key a run is sent under: the component's own attempt, a UUID, or a fresh one. */\nexport function attemptKey(options: UiCommandOptions | undefined): string {\n const given = options?.attempt;\n if (given === undefined) return crypto.randomUUID();\n if (typeof given !== 'string' || !UUID.test(given)) throw new TypeError(say('attemptIsAUuid'));\n return given.toLowerCase();\n}\n\n/**\n * A form's command run as its form's submit would: checked by the form's own\n * rules once the logic they need is here (an incomplete or invalid input opens\n * the form instead, filled with it), then sent once, with no record and so\n * nothing to prepare, under one key for this run (or the component's own\n * `attempt`). A refusal is said in the server's words; an answer that never\n * said whether it ran is `unknown`, and its `check()` sends the same run\n * again under the same key — the server answers a run it already has with\n * its receipt, so it never runs twice. A command that names no record has no\n * receipt to look up by its record (`/api/commands/status` asks one).\n */\nexport async function runFormCommand(\n served: Served,\n input: Readonly<Record<string, unknown>> | undefined,\n options: UiCommandOptions | undefined,\n openForm: (served: Served, input: Readonly<Record<string, unknown>> | undefined) => Promise<UiCommandOutcome>,\n): Promise<UiCommandOutcome> {\n const fields = served.form.command.input;\n const key = attemptKey(options);\n // Judged as the form judges it: what a `when` hides is neither asked for nor sent.\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(served, input);\n }\n // As the form's own submit sends it (FormRoom.tsx): no record, so no key and no version to expect.\n const envelope = Object.freeze({\n command: served.form.command.id,\n commandVersion: served.form.command.version,\n key: {},\n expectedVersion: 0,\n idempotencyKey: key,\n input: values,\n });\n return sendFormCommand(served.form.label, envelope, sessionIdentity(), false);\n}\n\nasync function sendFormCommand(\n label: string,\n envelope: Readonly<Record<string, unknown>>,\n identity: ReturnType<typeof sessionIdentity>,\n checking: boolean,\n): Promise<UiCommandOutcome> {\n const check = (): Promise<UiCommandOutcome> => {\n // The key is the session's: under another account the same key is another run, so it is not asked there.\n if (sessionIdentity() !== identity) {\n const message = say('checkedElsewhere', { label });\n return Promise.resolve({ status: 'unknown', message, check });\n }\n return sendFormCommand(label, envelope, identity, true);\n };\n try {\n const sent = (await api('/api/commands/execute', { ...envelope, ...ownedBy(state.activeConnection ?? '') })) as {\n result?: unknown;\n } | null;\n void queryClient.invalidateQueries();\n return { status: 'applied', ...(sent?.result !== undefined ? { output: sent.result } : {}) };\n } catch (error) {\n const failure = error as Error & { outcome?: unknown };\n // Only an answer that says nothing ran is a refusal; a lost or uncertain one is not known (commandState.ts settleFailure).\n if (failure.outcome === 'not_applied') {\n const message = failure.message || say('isNotSomethingYouCanDo', { label });\n toast(message, 'error');\n return { status: 'refused', message };\n }\n const message = say('notKnown', { label });\n if (!checking) toast(message, 'error');\n return { status: 'unknown', message, check };\n }\n}\n"],"mappings":";;;;;;;AAGA,IAAa,MAAM,eAAe;CAChC,wBAAwB;CACxB,UAAU;CACV,kBAAkB;CAClB,gBAAgB;AAClB,CAAC;;;;;;;ACSD,IAAM,OAAO;;AAEb,SAAgB,WAAW,SAA+C;CACxE,MAAM,QAAQ,SAAS;CACvB,IAAI,UAAU,KAAA,GAAW,OAAO,OAAO,WAAW;CAClD,IAAI,OAAO,UAAU,YAAY,CAAC,KAAK,KAAK,KAAK,GAAG,MAAM,IAAI,UAAU,IAAI,gBAAgB,CAAC;CAC7F,OAAO,MAAM,YAAY;AAC3B;;;;;;;;;;;;AAaA,eAAsB,eACpB,QACA,OACA,SACA,UAC2B;CAC3B,MAAM,SAAS,OAAO,KAAK,QAAQ;CACnC,MAAM,MAAM,WAAW,OAAO;CAE9B,MAAM,UAAU,aAAa,MAAM;CACnC,IAAI,SAAS,MAAM;CACnB,IAAI;CACJ,IAAI;EACF,SAAS,aAAa,QAAQ,uBAAuB,QAAQ,SAAS,CAAC,CAAC,CAAC;CAC3E,QAAQ;EACN,OAAO,SAAS,QAAQ,KAAK;CAC/B;CAEA,MAAM,WAAW,OAAO,OAAO;EAC7B,SAAS,OAAO,KAAK,QAAQ;EAC7B,gBAAgB,OAAO,KAAK,QAAQ;EACpC,KAAK,CAAC;EACN,iBAAiB;EACjB,gBAAgB;EAChB,OAAO;CACT,CAAC;CACD,OAAO,gBAAgB,OAAO,KAAK,OAAO,UAAU,gBAAgB,GAAG,KAAK;AAC9E;AAEA,eAAe,gBACb,OACA,UACA,UACA,UAC2B;CAC3B,MAAM,cAAyC;EAE7C,IAAI,gBAAgB,MAAM,UAAU;GAClC,MAAM,UAAU,IAAI,oBAAoB,EAAE,MAAM,CAAC;GACjD,OAAO,QAAQ,QAAQ;IAAE,QAAQ;IAAW;IAAS;GAAM,CAAC;EAC9D;EACA,OAAO,gBAAgB,OAAO,UAAU,UAAU,IAAI;CACxD;CACA,IAAI;EACF,MAAM,OAAQ,MAAM,IAAI,yBAAyB;GAAE,GAAG;GAAU,GAAG,QAAQ,MAAM,oBAAoB,EAAE;EAAE,CAAC;EAG1G,YAAiB,kBAAkB;EACnC,OAAO;GAAE,QAAQ;GAAW,GAAI,MAAM,WAAW,KAAA,IAAY,EAAE,QAAQ,KAAK,OAAO,IAAI,CAAC;EAAG;CAC7F,SAAS,OAAO;EACd,MAAM,UAAU;EAEhB,IAAI,QAAQ,YAAY,eAAe;GACrC,MAAM,UAAU,QAAQ,WAAW,IAAI,0BAA0B,EAAE,MAAM,CAAC;GAC1E,MAAM,SAAS,OAAO;GACtB,OAAO;IAAE,QAAQ;IAAW;GAAQ;EACtC;EACA,MAAM,UAAU,IAAI,YAAY,EAAE,MAAM,CAAC;EACzC,IAAI,CAAC,UAAU,MAAM,SAAS,OAAO;EACrC,OAAO;GAAE,QAAQ;GAAW;GAAS;EAAM;CAC7C;AACF"}
1
+ {"version":3,"file":"shared-B1SAS_J-.js","names":[],"sources":["../../src/client/copy/components/components/sdk/formCommandRun.ts","../../src/client/components/sdk/formCommandRun.ts"],"sourcesContent":["/** What sdk/formCommandRun 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 isNotSomethingYouCanDo: '{label} is not something you can do here.',\n notKnown: '{label} was sent, and its result is not known yet. Check it before you send it again.',\n checkedElsewhere: 'You signed in again since {label} was sent, so its result cannot be checked here.',\n attemptIsAUuid: \"A run's attempt is the key it is sent under: a UUID made once per intent, crypto.randomUUID().\",\n});\n","/**\n * A component's run of a command that names no record, and the key a run is\n * sent under: fetched when a component holds such a command (commands.tsx),\n * never on the App's first paint.\n */\nimport { api, state, toast } from '@mistriwork/kit/client/core.js';\nimport { ownedBy } from '@mistriwork/kit/client/requestIdentity.js';\nimport { sessionIdentity } from '@mistriwork/kit/client/sessionIdentity.js';\nimport { queryClient } from '@mistriwork/kit/client/components/mount.js';\nimport type { ServedForm as RoomForm } from '@mistriwork/kit/client/components/appRooms.js';\nimport type { AppPayloadApp } from '../../../shared/appPayload.js';\nimport { commandInput, prefilledCommandValues, readyToJudge } from '../CommandFields.js';\nimport type { UiCommandOptions, UiCommandOutcome } from './context.js';\nimport { say } from '../../copy/components/components/sdk/formCommandRun.js';\n\ntype Served = { form: RoomForm<AppPayloadApp>; appName: string };\n\nconst UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;\n/** The key a run is sent under: the component's own attempt, a UUID, or a fresh one. */\nexport function attemptKey(options: UiCommandOptions | undefined): string {\n const given = options?.attempt;\n if (given === undefined) return crypto.randomUUID();\n if (typeof given !== 'string' || !UUID.test(given)) throw new TypeError(say('attemptIsAUuid'));\n return given.toLowerCase();\n}\n\n/**\n * A form's command run as its form's submit would: checked by the form's own\n * rules once the logic they need is here (an incomplete or invalid input opens\n * the form instead, filled with it), then sent once, with no record and so\n * nothing to prepare, under one key for this run (or the component's own\n * `attempt`). A refusal is said in the server's words; an answer that never\n * said whether it ran is `unknown`, and its `check()` sends the same run\n * again under the same key — the server answers a run it already has with\n * its receipt, so it never runs twice. A command that names no record has no\n * receipt to look up by its record (`/api/commands/status` asks one).\n */\nexport async function runFormCommand(\n served: Served,\n input: Readonly<Record<string, unknown>> | undefined,\n options: UiCommandOptions | undefined,\n openForm: (served: Served, input: Readonly<Record<string, unknown>> | undefined) => Promise<UiCommandOutcome>,\n): Promise<UiCommandOutcome> {\n const fields = served.form.command.input;\n const key = attemptKey(options);\n // Judged as the form judges it: what a `when` hides is neither asked for nor sent.\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(served, input);\n }\n // As the form's own submit sends it (FormRoom.tsx): no record, so no key and no version to expect.\n const envelope = Object.freeze({\n command: served.form.command.id,\n commandVersion: served.form.command.version,\n key: {},\n expectedVersion: 0,\n idempotencyKey: key,\n input: values,\n });\n return sendFormCommand(served.form.label, envelope, sessionIdentity(), false);\n}\n\nasync function sendFormCommand(\n label: string,\n envelope: Readonly<Record<string, unknown>>,\n identity: ReturnType<typeof sessionIdentity>,\n checking: boolean,\n): Promise<UiCommandOutcome> {\n const check = (): Promise<UiCommandOutcome> => {\n // The key is the session's: under another account the same key is another run, so it is not asked there.\n if (sessionIdentity() !== identity) {\n const message = say('checkedElsewhere', { label });\n return Promise.resolve({ status: 'unknown', message, check });\n }\n return sendFormCommand(label, envelope, identity, true);\n };\n try {\n const sent = (await api('/api/commands/execute', { ...envelope, ...ownedBy(state.activeConnection ?? '') })) as {\n result?: unknown;\n } | null;\n void queryClient.invalidateQueries();\n return { status: 'applied', ...(sent?.result !== undefined ? { output: sent.result } : {}) };\n } catch (error) {\n const failure = error as Error & { outcome?: unknown };\n // Only an answer that says nothing ran is a refusal; a lost or uncertain one is not known (commandState.ts settleFailure).\n if (failure.outcome === 'not_applied') {\n const message = failure.message || say('isNotSomethingYouCanDo', { label });\n toast(message, 'error');\n return { status: 'refused', message };\n }\n const message = say('notKnown', { label });\n if (!checking) toast(message, 'error');\n return { status: 'unknown', message, check };\n }\n}\n"],"mappings":";;;;;;;AAGA,IAAa,MAAM,eAAe;CAChC,wBAAwB;CACxB,UAAU;CACV,kBAAkB;CAClB,gBAAgB;AAClB,CAAC;;;;;;;ACSD,IAAM,OAAO;;AAEb,SAAgB,WAAW,SAA+C;CACxE,MAAM,QAAQ,SAAS;CACvB,IAAI,UAAU,KAAA,GAAW,OAAO,OAAO,WAAW;CAClD,IAAI,OAAO,UAAU,YAAY,CAAC,KAAK,KAAK,KAAK,GAAG,MAAM,IAAI,UAAU,IAAI,gBAAgB,CAAC;CAC7F,OAAO,MAAM,YAAY;AAC3B;;;;;;;;;;;;AAaA,eAAsB,eACpB,QACA,OACA,SACA,UAC2B;CAC3B,MAAM,SAAS,OAAO,KAAK,QAAQ;CACnC,MAAM,MAAM,WAAW,OAAO;CAE9B,MAAM,UAAU,aAAa,MAAM;CACnC,IAAI,SAAS,MAAM;CACnB,IAAI;CACJ,IAAI;EACF,SAAS,aAAa,QAAQ,uBAAuB,QAAQ,SAAS,CAAC,CAAC,CAAC;CAC3E,QAAQ;EACN,OAAO,SAAS,QAAQ,KAAK;CAC/B;CAEA,MAAM,WAAW,OAAO,OAAO;EAC7B,SAAS,OAAO,KAAK,QAAQ;EAC7B,gBAAgB,OAAO,KAAK,QAAQ;EACpC,KAAK,CAAC;EACN,iBAAiB;EACjB,gBAAgB;EAChB,OAAO;CACT,CAAC;CACD,OAAO,gBAAgB,OAAO,KAAK,OAAO,UAAU,gBAAgB,GAAG,KAAK;AAC9E;AAEA,eAAe,gBACb,OACA,UACA,UACA,UAC2B;CAC3B,MAAM,cAAyC;EAE7C,IAAI,gBAAgB,MAAM,UAAU;GAClC,MAAM,UAAU,IAAI,oBAAoB,EAAE,MAAM,CAAC;GACjD,OAAO,QAAQ,QAAQ;IAAE,QAAQ;IAAW;IAAS;GAAM,CAAC;EAC9D;EACA,OAAO,gBAAgB,OAAO,UAAU,UAAU,IAAI;CACxD;CACA,IAAI;EACF,MAAM,OAAQ,MAAM,IAAI,yBAAyB;GAAE,GAAG;GAAU,GAAG,QAAQ,MAAM,oBAAoB,EAAE;EAAE,CAAC;EAG1G,YAAiB,kBAAkB;EACnC,OAAO;GAAE,QAAQ;GAAW,GAAI,MAAM,WAAW,KAAA,IAAY,EAAE,QAAQ,KAAK,OAAO,IAAI,CAAC;EAAG;CAC7F,SAAS,OAAO;EACd,MAAM,UAAU;EAEhB,IAAI,QAAQ,YAAY,eAAe;GACrC,MAAM,UAAU,QAAQ,WAAW,IAAI,0BAA0B,EAAE,MAAM,CAAC;GAC1E,MAAM,SAAS,OAAO;GACtB,OAAO;IAAE,QAAQ;IAAW;GAAQ;EACtC;EACA,MAAM,UAAU,IAAI,YAAY,EAAE,MAAM,CAAC;EACzC,IAAI,CAAC,UAAU,MAAM,SAAS,OAAO;EACrC,OAAO;GAAE,QAAQ;GAAW;GAAS;EAAM;CAC7C;AACF"}
@@ -1,8 +1,8 @@
1
1
  import { ht as Icon, nt as Button, x as fetchServer } from "./shared-poc11xxo.js";
2
2
  import { At as removeHostListener, Ct as addHostListener, gt as defineMessages } from "./shared-DJZjSi3J.js";
3
- import { k as registerSurfaceMutationPendingProbe } from "./shared-DPAVoWY0.js";
4
- import { n as useArrived, t as onDemand } from "./shared-DpLeIATZ.js";
5
- import { a as commandInput, c as draftHidden, i as blankCommandValues, l as draftLogic, m as commandFieldAt, n as CommandLive, o as commandPathLabel, r as asksDraftLogic, s as commandProblems, t as CommandFields, u as prefilledCommandValues } from "./shared-D1mMBLdj.js";
3
+ import { k as registerSurfaceMutationPendingProbe } from "./shared-BoLbc2WD.js";
4
+ import { n as useArrived, t as onDemand } from "./shared-B-BUF9fx.js";
5
+ import { a as commandInput, c as draftHidden, i as blankCommandValues, l as draftLogic, m as commandFieldAt, n as CommandLive, o as commandPathLabel, r as asksDraftLogic, s as commandProblems, t as CommandFields, u as prefilledCommandValues } from "./shared-JvcI-LWp.js";
6
6
  import { a as sensitiveText, d as knownReferenceName, i as sayInput, n as maskedLast4, o as stepSaid, r as reviewLines, t as answered } from "./shared-CxovRZz5.js";
7
7
  import { Fragment, useEffect, useId, useMemo, useRef, useState } from "react";
8
8
  import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
@@ -76,7 +76,7 @@ function IntakeNote({ note }) {
76
76
  });
77
77
  }
78
78
  // packages/mistri/src/client/components/ReviewValue.tsx
79
- var ReviewNamed = onDemand(() => import("./shared-DQYNI9wO.js"), "ReviewNamed", { quiet: true });
79
+ var ReviewNamed = onDemand(() => import("./shared-C42f07hJ.js"), "ReviewNamed", { quiet: true });
80
80
  function ReviewValue({ field, value, from }) {
81
81
  if (from && (field.type === "reference" ? value !== "" && value != null : field.type === "group" && field.fields.some((member) => member.type === "reference"))) return /* @__PURE__ */ jsx(ReviewNamed, {
82
82
  field,
@@ -153,7 +153,7 @@ async function formArrives(form) {
153
153
  asksDraftLogic(fields, form.rules) ? draftLogic.ready() : void 0,
154
154
  lives(fields) ? CommandLive.ready() : void 0,
155
155
  form.challenge ? PublicGuard.ready() : void 0,
156
- form.components && Object.keys(form.components).length ? import("./shared-BKGJgjog.js").then(({ installPublicInputs }) => installPublicInputs(form.components)) : void 0
156
+ form.components && Object.keys(form.components).length ? import("./shared-DkOdSpSK.js").then(({ installPublicInputs }) => installPublicInputs(form.components)) : void 0
157
157
  ]).catch(() => {});
158
158
  }
159
159
  async function submitPublicForm(id, submission, input, via, guard = {}) {
@@ -695,4 +695,4 @@ function FormSurface({ form, appName, submit, connection, visitor, identityEpoch
695
695
  }
696
696
  export { formRefusal as a, say as c, armLeaveGuard as d, formArrives as i, ReviewValue as l, PublicGuard as n, shownOnReview as o, drawsField as r, submitPublicForm as s, FormSurface as t, IntakeNote as u };
697
697
 
698
- //# sourceMappingURL=shared-CpI0Y8M5.js.map
698
+ //# sourceMappingURL=shared-B4jgU8h9.js.map