@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.
- package/README.md +4 -3
- package/dist/client/assets/LayoutBuilder-MPzkVU2e.js.map +1 -1
- package/dist/client/assets/index-D2dHI6hR.js.map +1 -1
- package/dist/client/assets/shell-TreN_uLs.js.map +1 -1
- package/dist/docs/access-model.md +1 -1
- package/dist/docs/build-and-deploy.md +0 -1
- package/dist/docs/cli.md +1 -1
- package/dist/docs/glossary.md +3 -3
- package/dist/docs/query.md +9 -21
- package/dist/docs/status.md +3 -3
- package/dist/embed/react/chunks/LayoutBuilder-Cbxa_wve.js.map +1 -1
- package/dist/embed/react/chunks/app-0UZ1Re1k.js.map +1 -1
- package/dist/embed/react/chunks/page-Bx4o1kpQ.js.map +1 -1
- package/dist/embed/react/chunks/palette-Bb7Lf6eo.js.map +1 -1
- package/dist/embed/react/chunks/shell-DZRACiB9.js.map +1 -1
- package/dist/embed/react/chunks/write-BQO4CFc9.js.map +1 -1
- package/dist/embed/react/index.js +1 -1
- package/dist/server/build/dockerfile.js +1 -1
- package/dist/server/cli/usage.js +2 -2
- package/dist/ui/index.js +2 -2
- package/dist/ui/page.js +2 -2
- package/dist/ui/{shared-N4Ej8yRD.js → shared-1PD7TOTJ.js} +5 -5
- package/dist/ui/{shared-N4Ej8yRD.js.map → shared-1PD7TOTJ.js.map} +1 -1
- package/dist/ui/{shared-D5m86-4o.js → shared-1gMnOu9J.js} +6 -6
- package/dist/ui/{shared-D5m86-4o.js.map → shared-1gMnOu9J.js.map} +1 -1
- package/dist/ui/{shared-Ctaj8mR2.js → shared-5RQMi4BR.js} +3 -3
- package/dist/ui/{shared-Ctaj8mR2.js.map → shared-5RQMi4BR.js.map} +1 -1
- package/dist/ui/{shared-DpLeIATZ.js → shared-B-BUF9fx.js} +2 -2
- package/dist/ui/{shared-DpLeIATZ.js.map → shared-B-BUF9fx.js.map} +1 -1
- package/dist/ui/{shared-DWYnjItP.js → shared-B-MhiPIN.js} +9 -9
- package/dist/ui/{shared-DWYnjItP.js.map → shared-B-MhiPIN.js.map} +1 -1
- package/dist/ui/{shared-0fNuhSbG.js → shared-B07qIMlE.js} +5 -5
- package/dist/ui/{shared-0fNuhSbG.js.map → shared-B07qIMlE.js.map} +1 -1
- package/dist/ui/{shared-lYtMadRU.js → shared-B1SAS_J-.js} +3 -3
- package/dist/ui/{shared-lYtMadRU.js.map → shared-B1SAS_J-.js.map} +1 -1
- package/dist/ui/{shared-CpI0Y8M5.js → shared-B4jgU8h9.js} +6 -6
- package/dist/ui/{shared-CpI0Y8M5.js.map → shared-B4jgU8h9.js.map} +1 -1
- package/dist/ui/{shared-Cxu1c35l.js → shared-B5aBCUi7.js} +30 -30
- package/dist/ui/{shared-Cxu1c35l.js.map → shared-B5aBCUi7.js.map} +1 -1
- package/dist/ui/{shared-CAe-US1q.js → shared-B9H7_Pji.js} +5 -5
- package/dist/ui/{shared-CAe-US1q.js.map → shared-B9H7_Pji.js.map} +1 -1
- package/dist/ui/{shared-Q2bgBaYo.js → shared-BAXr20S-.js} +4 -4
- package/dist/ui/{shared-Q2bgBaYo.js.map → shared-BAXr20S-.js.map} +1 -1
- package/dist/ui/{shared-CyEefFFb.js → shared-BDDUzH-f.js} +19 -19
- package/dist/ui/{shared-CyEefFFb.js.map → shared-BDDUzH-f.js.map} +1 -1
- package/dist/ui/{shared-BdhPI6dq.js → shared-BGmkeDeW.js} +3 -3
- package/dist/ui/{shared-BdhPI6dq.js.map → shared-BGmkeDeW.js.map} +1 -1
- package/dist/ui/{shared-DONIpq2q.js → shared-BHCQ60yN.js} +2 -2
- package/dist/ui/{shared-DONIpq2q.js.map → shared-BHCQ60yN.js.map} +1 -1
- package/dist/ui/{shared-CNmaAv64.js → shared-BHsjawAG.js} +8 -8
- package/dist/ui/{shared-CNmaAv64.js.map → shared-BHsjawAG.js.map} +1 -1
- package/dist/ui/{shared-DgjU9kOy.js → shared-BIQuK_nq.js} +4 -4
- package/dist/ui/{shared-DgjU9kOy.js.map → shared-BIQuK_nq.js.map} +1 -1
- package/dist/ui/{shared-icSQAj21.js → shared-BOe4W2FI.js} +3 -3
- package/dist/ui/{shared-icSQAj21.js.map → shared-BOe4W2FI.js.map} +1 -1
- package/dist/ui/{shared-BlxoOJSk.js → shared-BPpC08ip.js} +3 -3
- package/dist/ui/{shared-BlxoOJSk.js.map → shared-BPpC08ip.js.map} +1 -1
- package/dist/ui/{shared-BtiFL37J.js → shared-BdA3LPCB.js} +2 -2
- package/dist/ui/{shared-BtiFL37J.js.map → shared-BdA3LPCB.js.map} +1 -1
- package/dist/ui/{shared-CvR94vn4.js → shared-Be3nbWsd.js} +11 -11
- package/dist/ui/{shared-CvR94vn4.js.map → shared-Be3nbWsd.js.map} +1 -1
- package/dist/ui/{shared-Bl_nF_IH.js → shared-Bf30ZLoS.js} +8 -4
- package/dist/ui/shared-Bf30ZLoS.js.map +1 -0
- package/dist/ui/{shared-DijrJ_V-.js → shared-BguP_BaR.js} +7 -7
- package/dist/ui/{shared-DijrJ_V-.js.map → shared-BguP_BaR.js.map} +1 -1
- package/dist/ui/{shared-DPAVoWY0.js → shared-BoLbc2WD.js} +17 -2
- package/dist/ui/{shared-DPAVoWY0.js.map → shared-BoLbc2WD.js.map} +1 -1
- package/dist/ui/{shared-BkdBTYwx.js → shared-BttyOW4W.js} +3 -3
- package/dist/ui/{shared-BkdBTYwx.js.map → shared-BttyOW4W.js.map} +1 -1
- package/dist/ui/{shared-CQWLz8uT.js → shared-BumxsBlA.js} +10 -10
- package/dist/ui/{shared-CQWLz8uT.js.map → shared-BumxsBlA.js.map} +1 -1
- package/dist/ui/{shared-Dzu7tFiC.js → shared-Bw73ktBk.js} +3 -3
- package/dist/ui/{shared-Dzu7tFiC.js.map → shared-Bw73ktBk.js.map} +1 -1
- package/dist/ui/{shared-BhAYErSx.js → shared-C1B0GH0e.js} +4 -4
- package/dist/ui/{shared-BhAYErSx.js.map → shared-C1B0GH0e.js.map} +1 -1
- package/dist/ui/{shared-BQJQcGgj.js → shared-C2FsyYr7.js} +4 -4
- package/dist/ui/{shared-BQJQcGgj.js.map → shared-C2FsyYr7.js.map} +1 -1
- package/dist/ui/{shared-B9lw2Ryh.js → shared-C2RU1qjv.js} +4 -4
- package/dist/ui/{shared-B9lw2Ryh.js.map → shared-C2RU1qjv.js.map} +1 -1
- package/dist/ui/{shared-DQYNI9wO.js → shared-C42f07hJ.js} +5 -5
- package/dist/ui/{shared-DQYNI9wO.js.map → shared-C42f07hJ.js.map} +1 -1
- package/dist/ui/{shared-CqCZ8wMY.js → shared-C4LkPCU4.js} +3 -3
- package/dist/ui/{shared-CqCZ8wMY.js.map → shared-C4LkPCU4.js.map} +1 -1
- package/dist/ui/{shared-BhtpgOpa.js → shared-C4wSfz6k.js} +9 -9
- package/dist/ui/{shared-BhtpgOpa.js.map → shared-C4wSfz6k.js.map} +1 -1
- package/dist/ui/{shared-BHc2Izkj.js → shared-C9DZtSFH.js} +2 -2
- package/dist/ui/{shared-BHc2Izkj.js.map → shared-C9DZtSFH.js.map} +1 -1
- package/dist/ui/{shared-DW1YuiNS.js → shared-CA52ClGo.js} +2 -2
- package/dist/ui/{shared-DW1YuiNS.js.map → shared-CA52ClGo.js.map} +1 -1
- package/dist/ui/{shared-BbSbilkh.js → shared-CBciTwm6.js} +9 -9
- package/dist/ui/{shared-BbSbilkh.js.map → shared-CBciTwm6.js.map} +1 -1
- package/dist/ui/{shared-C-J32eBn.js → shared-CL3RLKDA.js} +16 -16
- package/dist/ui/{shared-C-J32eBn.js.map → shared-CL3RLKDA.js.map} +1 -1
- package/dist/ui/{shared-Ck8S4OxW.js → shared-CLq3-_hW.js} +3 -3
- package/dist/ui/{shared-Ck8S4OxW.js.map → shared-CLq3-_hW.js.map} +1 -1
- package/dist/ui/{shared-Q5WefT7G.js → shared-CMjK-Ucd.js} +3 -3
- package/dist/ui/{shared-Q5WefT7G.js.map → shared-CMjK-Ucd.js.map} +1 -1
- package/dist/ui/{shared-D3MAuEA3.js → shared-CPjpSFGh.js} +2 -2
- package/dist/ui/{shared-D3MAuEA3.js.map → shared-CPjpSFGh.js.map} +1 -1
- package/dist/ui/{shared-VshXGwXP.js → shared-CSPhENq3.js} +2 -2
- package/dist/ui/{shared-VshXGwXP.js.map → shared-CSPhENq3.js.map} +1 -1
- package/dist/ui/{shared-DJrJaE73.js → shared-CZJE4Bmp.js} +3 -3
- package/dist/ui/{shared-DJrJaE73.js.map → shared-CZJE4Bmp.js.map} +1 -1
- package/dist/ui/{shared-D7ONOwI7.js → shared-C_BhUL2I.js} +7 -7
- package/dist/ui/{shared-D7ONOwI7.js.map → shared-C_BhUL2I.js.map} +1 -1
- package/dist/ui/{shared-j-2peBIB.js → shared-CbeujwdU.js} +4 -4
- package/dist/ui/{shared-j-2peBIB.js.map → shared-CbeujwdU.js.map} +1 -1
- package/dist/ui/{shared-D5GrOEa2.js → shared-Cbf-o4Dt.js} +4 -4
- package/dist/ui/{shared-D5GrOEa2.js.map → shared-Cbf-o4Dt.js.map} +1 -1
- package/dist/ui/{shared-HwiPIajr.js → shared-CdNmeNHh.js} +3 -3
- package/dist/ui/{shared-HwiPIajr.js.map → shared-CdNmeNHh.js.map} +1 -1
- package/dist/ui/{shared-ZCFt-CPb.js → shared-CdQOMD8J.js} +3 -3
- package/dist/ui/{shared-ZCFt-CPb.js.map → shared-CdQOMD8J.js.map} +1 -1
- package/dist/ui/{shared-ClhXSGGK.js → shared-CdiPYlTh.js} +2 -2
- package/dist/ui/{shared-ClhXSGGK.js.map → shared-CdiPYlTh.js.map} +1 -1
- package/dist/ui/{shared-DA8_pVRZ.js → shared-CepLAhwm.js} +2 -2
- package/dist/ui/{shared-DA8_pVRZ.js.map → shared-CepLAhwm.js.map} +1 -1
- package/dist/ui/{shared-BrYKjrnM.js → shared-Ch82h_Fu.js} +6 -6
- package/dist/ui/{shared-BrYKjrnM.js.map → shared-Ch82h_Fu.js.map} +1 -1
- package/dist/ui/{shared-C4UrE8Fb.js → shared-Chp88all.js} +3 -3
- package/dist/ui/{shared-C4UrE8Fb.js.map → shared-Chp88all.js.map} +1 -1
- package/dist/ui/{shared-CWa80DTO.js → shared-Ci16s2rN.js} +9 -9
- package/dist/ui/{shared-CWa80DTO.js.map → shared-Ci16s2rN.js.map} +1 -1
- package/dist/ui/{shared-tksTLD6Q.js → shared-CiqNkoE1.js} +5 -5
- package/dist/ui/{shared-tksTLD6Q.js.map → shared-CiqNkoE1.js.map} +1 -1
- package/dist/ui/{shared-yt7DjSrq.js → shared-CpMhOq8F.js} +2 -2
- package/dist/ui/{shared-yt7DjSrq.js.map → shared-CpMhOq8F.js.map} +1 -1
- package/dist/ui/{shared-Dm0z5WUl.js → shared-CrWv5JKH.js} +6 -6
- package/dist/ui/{shared-Dm0z5WUl.js.map → shared-CrWv5JKH.js.map} +1 -1
- package/dist/ui/{shared-CQL3FGHc.js → shared-Csfi3Pti.js} +2 -2
- package/dist/ui/{shared-CQL3FGHc.js.map → shared-Csfi3Pti.js.map} +1 -1
- package/dist/ui/{shared-BKNRbm-V.js → shared-CuZt26rm.js} +2 -2
- package/dist/ui/{shared-BKNRbm-V.js.map → shared-CuZt26rm.js.map} +1 -1
- package/dist/ui/{shared-Guq3upiR.js → shared-Cws_z-TS.js} +2 -2
- package/dist/ui/{shared-Guq3upiR.js.map → shared-Cws_z-TS.js.map} +1 -1
- package/dist/ui/{shared-Bw_qZeIj.js → shared-D1KWuCg6.js} +2 -2
- package/dist/ui/{shared-Bw_qZeIj.js.map → shared-D1KWuCg6.js.map} +1 -1
- package/dist/ui/{shared-CuCZKwXW.js → shared-D66ju_Cb.js} +23 -23
- package/dist/ui/{shared-CuCZKwXW.js.map → shared-D66ju_Cb.js.map} +1 -1
- package/dist/ui/{shared-DYfX7NSM.js → shared-DGaQZXnw.js} +2 -2
- package/dist/ui/{shared-DYfX7NSM.js.map → shared-DGaQZXnw.js.map} +1 -1
- package/dist/ui/{shared-B3Hp8tOv.js → shared-DHy41sET.js} +6 -6
- package/dist/ui/{shared-B3Hp8tOv.js.map → shared-DHy41sET.js.map} +1 -1
- package/dist/ui/{shared-CXyd7IKi.js → shared-DKEOMQ6l.js} +2 -2
- package/dist/ui/{shared-CXyd7IKi.js.map → shared-DKEOMQ6l.js.map} +1 -1
- package/dist/ui/{shared-Ccmc8YO0.js → shared-DSUICuaJ.js} +33 -33
- package/dist/ui/{shared-Ccmc8YO0.js.map → shared-DSUICuaJ.js.map} +1 -1
- package/dist/ui/{shared-CL2iw_js.js → shared-DUPMRoO0.js} +13 -13
- package/dist/ui/{shared-CL2iw_js.js.map → shared-DUPMRoO0.js.map} +1 -1
- package/dist/ui/{shared-Dtp4eRul.js → shared-DVfdm6ah.js} +2 -2
- package/dist/ui/{shared-Dtp4eRul.js.map → shared-DVfdm6ah.js.map} +1 -1
- package/dist/ui/{shared-BJ5Ex32G.js → shared-DXM7d7lJ.js} +3 -3
- package/dist/ui/{shared-BJ5Ex32G.js.map → shared-DXM7d7lJ.js.map} +1 -1
- package/dist/ui/{shared-BFr6ld0e.js → shared-DXbMlcev.js} +2 -2
- package/dist/ui/{shared-BFr6ld0e.js.map → shared-DXbMlcev.js.map} +1 -1
- package/dist/ui/{shared-BUp3jv-N.js → shared-D_SkPtJ9.js} +6 -6
- package/dist/ui/{shared-BUp3jv-N.js.map → shared-D_SkPtJ9.js.map} +1 -1
- package/dist/ui/{shared-CdNomVzH.js → shared-Dd21k2ic.js} +4 -4
- package/dist/ui/{shared-CdNomVzH.js.map → shared-Dd21k2ic.js.map} +1 -1
- package/dist/ui/{shared-gRMbxmpu.js → shared-Dh0nHtLZ.js} +8 -8
- package/dist/ui/{shared-gRMbxmpu.js.map → shared-Dh0nHtLZ.js.map} +1 -1
- package/dist/ui/{shared-BKGJgjog.js → shared-DkOdSpSK.js} +3 -3
- package/dist/ui/{shared-BKGJgjog.js.map → shared-DkOdSpSK.js.map} +1 -1
- package/dist/ui/{shared-BMsh72Uq.js → shared-Dkph5ckT.js} +2 -2
- package/dist/ui/{shared-BMsh72Uq.js.map → shared-Dkph5ckT.js.map} +1 -1
- package/dist/ui/{shared-Be1HpDOB.js → shared-Dl1_Nx--.js} +3 -3
- package/dist/ui/{shared-Be1HpDOB.js.map → shared-Dl1_Nx--.js.map} +1 -1
- package/dist/ui/{shared-BQIZWOoJ.js → shared-Dm0IGbAf.js} +2 -2
- package/dist/ui/{shared-BQIZWOoJ.js.map → shared-Dm0IGbAf.js.map} +1 -1
- package/dist/ui/{shared-DSUtcU5S.js → shared-DnIkTpPr.js} +5 -5
- package/dist/ui/{shared-DSUtcU5S.js.map → shared-DnIkTpPr.js.map} +1 -1
- package/dist/ui/{shared-DsxGbYlV.js → shared-Docl_0tq.js} +3 -3
- package/dist/ui/{shared-DsxGbYlV.js.map → shared-Docl_0tq.js.map} +1 -1
- package/dist/ui/{shared-DZskrV26.js → shared-DprrHC72.js} +2 -2
- package/dist/ui/{shared-DZskrV26.js.map → shared-DprrHC72.js.map} +1 -1
- package/dist/ui/{shared-Bmw43Hwf.js → shared-DyKsJTZs.js} +2 -2
- package/dist/ui/{shared-Bmw43Hwf.js.map → shared-DyKsJTZs.js.map} +1 -1
- package/dist/ui/{shared-BLG88Pya.js → shared-FO7vfI3F.js} +4 -4
- package/dist/ui/{shared-BLG88Pya.js.map → shared-FO7vfI3F.js.map} +1 -1
- package/dist/ui/{shared-DLSd80D1.js → shared-HalAVHjv.js} +3 -3
- package/dist/ui/{shared-DLSd80D1.js.map → shared-HalAVHjv.js.map} +1 -1
- package/dist/ui/{shared-D1mMBLdj.js → shared-JvcI-LWp.js} +15 -15
- package/dist/ui/{shared-D1mMBLdj.js.map → shared-JvcI-LWp.js.map} +1 -1
- package/dist/ui/{shared-C6Hv_4O0.js → shared-K7Ym27yg.js} +2 -2
- package/dist/ui/{shared-C6Hv_4O0.js.map → shared-K7Ym27yg.js.map} +1 -1
- package/dist/ui/{shared-B39ln7oi.js → shared-SzlnwfJO.js} +3 -3
- package/dist/ui/{shared-B39ln7oi.js.map → shared-SzlnwfJO.js.map} +1 -1
- package/dist/ui/{shared-DgPn_Jll.js → shared-TrGbd1FY.js} +3 -3
- package/dist/ui/{shared-DgPn_Jll.js.map → shared-TrGbd1FY.js.map} +1 -1
- package/dist/ui/{shared-DrFb-XtA.js → shared-WhbuObEW.js} +2 -2
- package/dist/ui/{shared-DrFb-XtA.js.map → shared-WhbuObEW.js.map} +1 -1
- package/dist/ui/{shared-DiFQljcq.js → shared-XcSKDp6N.js} +11 -11
- package/dist/ui/{shared-DiFQljcq.js.map → shared-XcSKDp6N.js.map} +1 -1
- package/dist/ui/{shared-CMAg58rY.js → shared-Z4uBJU6I.js} +7 -6
- package/dist/ui/shared-Z4uBJU6I.js.map +1 -0
- package/dist/ui/{shared-BnUptuUp.js → shared-bAgeiRa5.js} +2 -2
- package/dist/ui/{shared-BnUptuUp.js.map → shared-bAgeiRa5.js.map} +1 -1
- package/dist/ui/{shared-BxMvSjey.js → shared-cgXG7OgZ.js} +5 -5
- package/dist/ui/{shared-BxMvSjey.js.map → shared-cgXG7OgZ.js.map} +1 -1
- package/dist/ui/{shared-u4CG2kQJ.js → shared-eZ0SB_zm.js} +2 -2
- package/dist/ui/{shared-u4CG2kQJ.js.map → shared-eZ0SB_zm.js.map} +1 -1
- package/dist/ui/{shared-L90bWW8e.js → shared-frKFb79C.js} +2 -2
- package/dist/ui/{shared-L90bWW8e.js.map → shared-frKFb79C.js.map} +1 -1
- package/dist/ui/{shared-Dd34nhkw.js → shared-hAayNSRA.js} +3 -3
- package/dist/ui/{shared-Dd34nhkw.js.map → shared-hAayNSRA.js.map} +1 -1
- package/dist/ui/{shared-DzC64cpp.js → shared-j_J16p2B.js} +2 -2
- package/dist/ui/{shared-DzC64cpp.js.map → shared-j_J16p2B.js.map} +1 -1
- package/dist/ui/{shared-DX7HRIV-.js → shared-tqpl5N3g.js} +6 -6
- package/dist/ui/{shared-DX7HRIV-.js.map → shared-tqpl5N3g.js.map} +1 -1
- package/dist/ui/{shared-BS5dBMpA.js → shared-y-6_ZDts.js} +2 -2
- package/dist/ui/{shared-BS5dBMpA.js.map → shared-y-6_ZDts.js.map} +1 -1
- package/dist/ui/{shared-Cv5v_MP1.js → shared-zG6e1Rhz.js} +13 -13
- package/dist/ui/{shared-Cv5v_MP1.js.map → shared-zG6e1Rhz.js.map} +1 -1
- package/dist/ui/testing.js +1 -1
- package/package.json +4 -4
- package/dist/docs/cli-browser.md +0 -232
- package/dist/docs/database-browser.md +0 -115
- package/dist/docs/keyboard.md +0 -63
- package/dist/docs/mcp.md +0 -86
- package/dist/ui/shared-Bl_nF_IH.js.map +0 -1
- package/dist/ui/shared-CMAg58rY.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shared-Guq3upiR.js","names":[],"sources":["../../../engine/src/shared/csv.ts","../../../kit/src/client/copy/workbench/export.ts","../../../kit/src/client/export.js"],"sourcesContent":["/*\n * One CSV field and one JSON record, as an export writes them — shared, so\n * the file the browser writes from rows in hand and the file the server\n * streams (exportRoute.ts) are the same file, byte for byte.\n */\n\n/* RFC 4180 §2.6: a field containing a comma, a quote or a line break must be\n quoted. CR and LF are listed separately because a lone CR inside a value is\n just as capable of splitting a record as a full CRLF. */\nconst NEEDS_QUOTES = /[\",\\r\\n]/;\n\n/* Excel, Sheets and LibreOffice all treat a cell beginning with one of these\n as a formula to evaluate rather than text to show — so a value like\n `=HYPERLINK(...)` or `@SUM(A1)` out of a database column becomes code the\n moment someone opens the file. Prefixing a single quote is the standard\n mitigation: spreadsheets show the rest as literal text.\n Tab and CR are included because they are skipped before the parse, which\n makes `\\t=cmd` a formula too. */\nconst FORMULA_LEAD = /^[=+\\-@\\t\\r]/;\n\n/* ...but `-5` and `+1.5e3` are numbers, not formulas, and prefixing them\n would corrupt every negative amount in the export to buy nothing. Only a\n leading sign that is *not* part of a plain number is dangerous. */\nconst PLAIN_NUMBER = /^[+-]?(\\d+(\\.\\d*)?|\\.\\d+)([eE][+-]?\\d+)?$/;\n\nexport const CRLF = '\\r\\n';\n\n/**\n * One CSV field.\n *\n * null and undefined emit nothing at all, while an empty string emits `\"\"`.\n * That asymmetry is the whole point: `a,,b` and `a,\"\",b` are different\n * documents, and collapsing them means an export cannot tell you whether a\n * column was never set or set to blank — often the exact question the export\n * was taken to answer.\n */\nexport function csvField(value: unknown): string {\n if (value === null || value === undefined) return '';\n // A JSON/JSONB column arrives as a parsed object; `String(obj)` would write\n // \"[object Object]\" into every row of it.\n const text = typeof value === 'object' ? JSON.stringify(value) : String(value);\n const safe = FORMULA_LEAD.test(text) && !PLAIN_NUMBER.test(text) ? `'${text}` : text;\n if (safe === '' || NEEDS_QUOTES.test(safe)) return `\"${safe.replace(/\"/g, '\"\"')}\"`;\n return safe;\n}\n\n/* A row's own value for a column, never one it inherits: an export's column\n list is the caller's, and `constructor` or `__proto__` named there would\n otherwise write out Object's own members as if they were data. */\nconst own = (row: Record<string, unknown> | undefined, name: string): unknown => (row && Object.hasOwn(row, name) ? row[name] : undefined);\n\n/** One CSV record: the fields of `row` in `columns` order, without its line break. */\nexport function csvRecord(columns: readonly string[], row: Record<string, unknown> | undefined): string {\n return columns.map((name) => csvField(own(row, name))).join(',');\n}\n\n/**\n * One record as an export's JSON writes it: rebuilt from `columns` rather\n * than emitted as-is so the shape matches the CSV exactly — including a key\n * whose value is missing, which `JSON.stringify` would silently drop and\n * leave the two formats disagreeing about the row.\n */\nexport function jsonRecord(columns: readonly string[], row: Record<string, unknown> | undefined): Record<string, unknown> {\n /* No prototype, so a column called `__proto__` is a key like any other. */\n const out: Record<string, unknown> = Object.create(null);\n for (const name of columns) out[name] = own(row, name) ?? null;\n return out;\n}\n","/** What export says, in the Workbench room (packages/kit/src/client/messages.ts says how the catalog is split). */\nimport { defineMessages } from '../../messages.js';\n\nexport const say = defineMessages({\n exportedRows: { one: 'Exported {count} row.', other: 'Exported {count} rows.' },\n exportedAllMatchingRows: 'Exported all matching rows.',\n theExportCouldNotBeRead: 'The export could not be read.',\n});\n","/**\n * Export the result you are looking at, as CSV or JSON.\n *\n * The serialisers at the top are pure — columns and rows in, a string out —\n * because CSV is the part of this feature that is easy to get subtly wrong\n * and the only way to know it is right is to test it without a browser. Their\n * field and record rules are `shared/csv.ts`, which the server's streamed\n * export writes with too. The DOM half below is a thin wrapper over them.\n *\n * The rule the format has to hold up to: a spreadsheet reading the file back\n * must see exactly the values the grid showed, including the distinction\n * between a null and an empty string, which every naive `join(',')` loses.\n *\n * The control itself — the menu, the column chooser — is `components/Export.tsx`.\n */\nimport { el, findTable, loadJson, saveJson, state, toast } from './core.js';\nimport { maskQuoted } from './clauses.js';\nimport { MAX_LIMIT } from '@mistriwork/engine/shared/reads.js';\nimport { plural } from './locale.js';\nimport { CRLF, csvField, csvRecord, jsonRecord } from '@mistriwork/engine/shared/csv.js';\nimport { scopeApiRequest } from './requestIdentity.js';\nimport { captureSessionIdentity } from './sessionIdentity.js';\nimport { say } from './copy/workbench/export.js';\nimport { portalRoot } from './shellHost.js';\nimport { fetchServer } from './transport.js';\n\nexport { csvField };\n\n/* Mirrors MAX_LIMIT in packages/engine/src/shared/reads.ts. The server clamps to it\n regardless, so this is only here to keep the button honest about how many\n rows \"all matching\" can actually mean. */\nexport const EXPORT_MAX_ROWS = MAX_LIMIT;\n\n/** A CSV document: a header row of column names, then one row per record. */\nexport function toCsv(columns, rows) {\n const lines = [columns.map(csvField).join(',')];\n for (const row of rows ?? []) lines.push(csvRecord(columns, row));\n // CRLF, per RFC 4180, and a trailing one so the file ends on a record\n // boundary rather than mid-line.\n return lines.join(CRLF) + CRLF;\n}\n\n/** A JSON document: an array of objects, in the column order on screen (jsonRecord). */\nexport function toJson(columns, rows) {\n return `${JSON.stringify(\n (rows ?? []).map((row) => jsonRecord(columns, row)),\n null,\n 2,\n )}\\n`;\n}\n\n/**\n * Put the selected columns into a query, replacing any `show` clause it has.\n *\n * The language is parsed on the server and nowhere else, so the only way for\n * the client to ask for different columns is to edit the text — the same\n * trick the sortable headers use. Replacing rather than appending is the part\n * that matters: the parser concatenates repeated clauses with `and`, so a\n * second `show` would arrive as one column named \"b and c\" and the export\n * would fail with a column error instead of exporting anything.\n *\n * An empty list means \"every column\", which is what no `show` clause means.\n */\nexport function withColumns(query, names) {\n const marks = clauseMarks(query);\n let out = '';\n let cut = 0;\n marks.forEach((mark, i) => {\n if (mark.word !== 'show' && mark.word !== 'select') return;\n out += query.slice(cut, mark.start);\n cut = i + 1 < marks.length ? marks[i + 1].start : query.length;\n });\n const base = `${out}${query.slice(cut)}`.trim();\n return names.length ? `${base} show ${names.join(', ')}` : base;\n}\n\n/* Mirrors CLAUSE_RE in packages/engine/src/shared/query.ts. Two copies of a rule is a cost,\n but the alternative is a build step to share one — and the client is a\n static file on purpose. */\nconst CLAUSE_RE = /\\b(filter|where|show|select|sort|order\\s+by|limit)\\b/gi;\n\n/* ...including the rule that makes a clause word a column name instead. A\n table with a column called `show` is unusual but `show = 3` is a filter,\n and cutting from there would silently drop the rest of the query. */\nconst FOLLOWED_BY_OPERATOR = /^\\s*(?:=|!=|>=|<=|>|<|\\bis\\b|\\bcontains\\b|\\bstartswith\\b|\\bendswith\\b|\\bin\\b|\\bnot\\s+in\\b)/i;\n\nfunction clauseMarks(text) {\n /* Scanned with quoted values blanked out, and the offsets used against the\n real text — the same masking the parser does, for the same reason. Without\n it `name contains \"show me\"` was cut at the value's own word, and the\n rewritten query came back with a filter holding `\"sort name show id, name`:\n a string assembled out of the query's punctuation, exported as though it\n were what the user asked for. */\n const scannable = maskQuoted(text);\n const marks = [];\n CLAUSE_RE.lastIndex = 0;\n let m;\n while ((m = CLAUSE_RE.exec(scannable))) {\n if (FOLLOWED_BY_OPERATOR.test(scannable.slice(CLAUSE_RE.lastIndex))) continue;\n marks.push({ word: m[1].toLowerCase().replace(/\\s+/g, ' '), start: m.index });\n }\n return marks;\n}\n\n/**\n * The chosen columns, in the order the table declares them.\n *\n * Not the order they were ticked in: two exports of the same table a week\n * apart should differ only where the data differs, and a column list that\n * depends on which checkbox someone clicked first makes every diff noise.\n * A name the table does not declare keeps its relative position at the end,\n * which is where a computed column from a view lands.\n */\nexport function orderColumns(selected, declared) {\n const rank = new Map(declared.map((name, i) => [name, i]));\n return [...new Set(selected)].sort((a, b) => (rank.get(a) ?? Number.MAX_SAFE_INTEGER) - (rank.get(b) ?? Number.MAX_SAFE_INTEGER));\n}\n\nexport const sameList = (a, b) => a.length === b.length && a.every((name, i) => name === b[i]);\n\n/* ---------- which columns ---------- */\n\nconst COLUMN_KEY = 'mistri.export-columns.v1';\n\n/* Per connection as well as per table: `orders` on staging and `orders` on\n production are not the same table, and neither are their useful columns. */\nconst scope = () => state.activeConnection ?? 'default';\n\n/* Survives a re-render within the session even when nothing can be persisted,\n which is the case in private mode and with site data blocked. */\nconst chosen = new Map();\n\nexport function rememberColumns(tableId, names) {\n chosen.set(`${scope()}::${tableId}`, names);\n // loadJson/saveJson swallow a throwing or full localStorage: a column\n // preference that cannot be saved is not a reason to fail the export.\n const all = loadJson(COLUMN_KEY, {}) ?? {};\n all[scope()] = { ...(all[scope()] ?? {}), [tableId]: names };\n saveJson(COLUMN_KEY, all);\n}\n\n/** Column names of the table as the catalog declares them, or [] if unknown. */\nexport function declaredColumns(tableId) {\n if (!state.schema) return [];\n return (findTable(tableId)?.columns ?? []).map((c) => c.name);\n}\n\n/**\n * What to export, before anyone opens the chooser: last time's selection if\n * there is one, otherwise exactly what is on screen — which already respects\n * a `show` clause in the query.\n */\nexport function selectionFor(tableId, displayed, declared) {\n const key = `${scope()}::${tableId}`;\n const remembered = chosen.get(key) ?? loadJson(COLUMN_KEY, {})?.[scope()]?.[tableId];\n const known = new Set([...declared, ...displayed]);\n // A remembered column that no longer exists is dropped rather than sent:\n // the query would fail on it, and the export would fail with it.\n const valid = Array.isArray(remembered) ? remembered.filter((n) => known.has(n)) : [];\n return orderColumns(valid.length ? valid : displayed, declared);\n}\n\n/** `customer-2026-08-22.csv` — the table and the day, which is what you look for later. */\nexport function exportFilename(table, extension, now = new Date()) {\n const stem = String(table ?? 'export').replace(/[^\\w.-]+/g, '_');\n return `${stem}-${now.toISOString().slice(0, 10)}.${extension}`;\n}\n\nexport function download(filename, text, mime) {\n /* A UTF-8 CSV with no BOM opens in Excel as the local codepage, which turns\n every accented name into mojibake. The BOM is the one thing that makes it\n read the file as UTF-8, and other tools skip it. */\n const body = mime === 'text/csv' ? `\\ufeff${text}` : text;\n const url = URL.createObjectURL(new Blob([body], { type: `${mime};charset=utf-8` }));\n const link = el('a', { href: url, download: filename });\n portalRoot().append(link);\n link.click();\n link.remove();\n /* Revoked, or the blob is held for the life of the page — but not until the\n next tick: revoking in the same task can cancel the download that click\n just started. */\n setTimeout(() => URL.revokeObjectURL(url), 0);\n}\n\nexport function saveExport(kind, table, columns, rows) {\n if (kind === 'csv') download(exportFilename(table, 'csv'), toCsv(columns, rows), 'text/csv');\n else download(exportFilename(table, 'json'), toJson(columns, rows), 'application/json');\n toast(say('exportedRows', { count: rows.length }));\n}\n\n/**\n * All matching rows, as a file the server streams (`POST /api/export`):\n * read in batches and written as each arrives, so neither side holds the\n * whole result as objects and nothing is counted. False where the server\n * does not offer it — a tenant host, a row-policy App (its replies wait for\n * the policy to settle, which a stream cannot) — and the caller exports\n * through `/api/run` as before.\n *\n * @param {'csv' | 'json'} kind\n * @param {string} table\n * @param {string} q\n * @param {string[]} columns the file's columns, in order\n * @returns {Promise<boolean>}\n */\nexport async function streamExport(kind, table, q, columns) {\n const identity = captureSessionIdentity();\n if (identity.tenantRequired) return false;\n const { url, payload } = scopeApiRequest('/api/export', { q, format: kind, columns }, state.activeConnection);\n const res = await fetchServer(url, {\n method: 'POST',\n credentials: 'same-origin',\n cache: 'no-store',\n headers: {\n 'content-type': 'application/json',\n ...(identity.mode === 'authenticated' ? { 'x-mistri-account': identity.accountId } : {}),\n },\n body: JSON.stringify(payload),\n });\n /* The file is the one answer with a disposition; anything else is JSON\n saying why not — a refusal to fall back from, or the query's error. */\n if (res.ok && res.headers.get('content-disposition')) {\n const blob = await res.blob();\n const link = el('a', { href: URL.createObjectURL(blob), download: exportFilename(table, kind) });\n portalRoot().append(link);\n link.click();\n link.remove();\n setTimeout(() => URL.revokeObjectURL(link.href), 0);\n toast(say('exportedAllMatchingRows'));\n return true;\n }\n if ([401, 403, 404, 405].includes(res.status)) return false;\n const said = await res.json().catch(() => null);\n throw new Error(said?.errors?.[0]?.message ?? said?.error ?? say('theExportCouldNotBeRead'));\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"shared-Cws_z-TS.js","names":[],"sources":["../../../engine/src/shared/csv.ts","../../../kit/src/client/copy/workbench/export.ts","../../../kit/src/client/export.js"],"sourcesContent":["/*\n * One CSV field and one JSON record, as an export writes them — shared, so\n * the file the browser writes from rows in hand and the file the server\n * streams (exportRoute.ts) are the same file, byte for byte.\n */\n\n/* RFC 4180 §2.6: a field containing a comma, a quote or a line break must be\n quoted. CR and LF are listed separately because a lone CR inside a value is\n just as capable of splitting a record as a full CRLF. */\nconst NEEDS_QUOTES = /[\",\\r\\n]/;\n\n/* Excel, Sheets and LibreOffice all treat a cell beginning with one of these\n as a formula to evaluate rather than text to show — so a value like\n `=HYPERLINK(...)` or `@SUM(A1)` out of a database column becomes code the\n moment someone opens the file. Prefixing a single quote is the standard\n mitigation: spreadsheets show the rest as literal text.\n Tab and CR are included because they are skipped before the parse, which\n makes `\\t=cmd` a formula too. */\nconst FORMULA_LEAD = /^[=+\\-@\\t\\r]/;\n\n/* ...but `-5` and `+1.5e3` are numbers, not formulas, and prefixing them\n would corrupt every negative amount in the export to buy nothing. Only a\n leading sign that is *not* part of a plain number is dangerous. */\nconst PLAIN_NUMBER = /^[+-]?(\\d+(\\.\\d*)?|\\.\\d+)([eE][+-]?\\d+)?$/;\n\nexport const CRLF = '\\r\\n';\n\n/**\n * One CSV field.\n *\n * null and undefined emit nothing at all, while an empty string emits `\"\"`.\n * That asymmetry is the whole point: `a,,b` and `a,\"\",b` are different\n * documents, and collapsing them means an export cannot tell you whether a\n * column was never set or set to blank — often the exact question the export\n * was taken to answer.\n */\nexport function csvField(value: unknown): string {\n if (value === null || value === undefined) return '';\n // A JSON/JSONB column arrives as a parsed object; `String(obj)` would write\n // \"[object Object]\" into every row of it.\n const text = typeof value === 'object' ? JSON.stringify(value) : String(value);\n const safe = FORMULA_LEAD.test(text) && !PLAIN_NUMBER.test(text) ? `'${text}` : text;\n if (safe === '' || NEEDS_QUOTES.test(safe)) return `\"${safe.replace(/\"/g, '\"\"')}\"`;\n return safe;\n}\n\n/* A row's own value for a column, never one it inherits: an export's column\n list is the caller's, and `constructor` or `__proto__` named there would\n otherwise write out Object's own members as if they were data. */\nconst own = (row: Record<string, unknown> | undefined, name: string): unknown => (row && Object.hasOwn(row, name) ? row[name] : undefined);\n\n/** One CSV record: the fields of `row` in `columns` order, without its line break. */\nexport function csvRecord(columns: readonly string[], row: Record<string, unknown> | undefined): string {\n return columns.map((name) => csvField(own(row, name))).join(',');\n}\n\n/**\n * One record as an export's JSON writes it: rebuilt from `columns` rather\n * than emitted as-is so the shape matches the CSV exactly — including a key\n * whose value is missing, which `JSON.stringify` would silently drop and\n * leave the two formats disagreeing about the row.\n */\nexport function jsonRecord(columns: readonly string[], row: Record<string, unknown> | undefined): Record<string, unknown> {\n /* No prototype, so a column called `__proto__` is a key like any other. */\n const out: Record<string, unknown> = Object.create(null);\n for (const name of columns) out[name] = own(row, name) ?? null;\n return out;\n}\n","/** What export says, in the Workbench room (packages/kit/src/client/messages.ts says how the catalog is split). */\nimport { defineMessages } from '../../messages.js';\n\nexport const say = defineMessages({\n exportedRows: { one: 'Exported {count} row.', other: 'Exported {count} rows.' },\n exportedAllMatchingRows: 'Exported all matching rows.',\n theExportCouldNotBeRead: 'The export could not be read.',\n});\n","/**\n * Export the result you are looking at, as CSV or JSON.\n *\n * The serialisers at the top are pure — columns and rows in, a string out —\n * because CSV is the part of this feature that is easy to get subtly wrong\n * and the only way to know it is right is to test it without a browser. Their\n * field and record rules are `shared/csv.ts`, which the server's streamed\n * export writes with too. The DOM half below is a thin wrapper over them.\n *\n * The rule the format has to hold up to: a spreadsheet reading the file back\n * must see exactly the values the grid showed, including the distinction\n * between a null and an empty string, which every naive `join(',')` loses.\n *\n * The control itself — the menu, the column chooser — is `components/Export.tsx`.\n */\nimport { el, findTable, loadJson, saveJson, state, toast } from './core.js';\nimport { maskQuoted } from './clauses.js';\nimport { MAX_LIMIT } from '@mistriwork/engine/shared/reads.js';\nimport { plural } from './locale.js';\nimport { CRLF, csvField, csvRecord, jsonRecord } from '@mistriwork/engine/shared/csv.js';\nimport { scopeApiRequest } from './requestIdentity.js';\nimport { captureSessionIdentity } from './sessionIdentity.js';\nimport { say } from './copy/workbench/export.js';\nimport { portalRoot } from './shellHost.js';\nimport { fetchServer } from './transport.js';\n\nexport { csvField };\n\n/* Mirrors MAX_LIMIT in packages/engine/src/shared/reads.ts. The server clamps to it\n regardless, so this is only here to keep the button honest about how many\n rows \"all matching\" can actually mean. */\nexport const EXPORT_MAX_ROWS = MAX_LIMIT;\n\n/** A CSV document: a header row of column names, then one row per record. */\nexport function toCsv(columns, rows) {\n const lines = [columns.map(csvField).join(',')];\n for (const row of rows ?? []) lines.push(csvRecord(columns, row));\n // CRLF, per RFC 4180, and a trailing one so the file ends on a record\n // boundary rather than mid-line.\n return lines.join(CRLF) + CRLF;\n}\n\n/** A JSON document: an array of objects, in the column order on screen (jsonRecord). */\nexport function toJson(columns, rows) {\n return `${JSON.stringify(\n (rows ?? []).map((row) => jsonRecord(columns, row)),\n null,\n 2,\n )}\\n`;\n}\n\n/**\n * Put the selected columns into a query, replacing any `show` clause it has.\n *\n * The language is parsed on the server and nowhere else, so the only way for\n * the client to ask for different columns is to edit the text — the same\n * trick the sortable headers use. Replacing rather than appending is the part\n * that matters: the parser concatenates repeated clauses with `and`, so a\n * second `show` would arrive as one column named \"b and c\" and the export\n * would fail with a column error instead of exporting anything.\n *\n * An empty list means \"every column\", which is what no `show` clause means.\n */\nexport function withColumns(query, names) {\n const marks = clauseMarks(query);\n let out = '';\n let cut = 0;\n marks.forEach((mark, i) => {\n if (mark.word !== 'show' && mark.word !== 'select') return;\n out += query.slice(cut, mark.start);\n cut = i + 1 < marks.length ? marks[i + 1].start : query.length;\n });\n const base = `${out}${query.slice(cut)}`.trim();\n return names.length ? `${base} show ${names.join(', ')}` : base;\n}\n\n/* Mirrors CLAUSE_RE in packages/engine/src/shared/query.ts. Two copies of a rule is a cost,\n but the alternative is a build step to share one — and the client is a\n static file on purpose. */\nconst CLAUSE_RE = /\\b(filter|where|show|select|sort|order\\s+by|limit)\\b/gi;\n\n/* ...including the rule that makes a clause word a column name instead. A\n table with a column called `show` is unusual but `show = 3` is a filter,\n and cutting from there would silently drop the rest of the query. */\nconst FOLLOWED_BY_OPERATOR = /^\\s*(?:=|!=|>=|<=|>|<|\\bis\\b|\\bcontains\\b|\\bstartswith\\b|\\bendswith\\b|\\bin\\b|\\bnot\\s+in\\b)/i;\n\nfunction clauseMarks(text) {\n /* Scanned with quoted values blanked out, and the offsets used against the\n real text — the same masking the parser does, for the same reason. Without\n it `name contains \"show me\"` was cut at the value's own word, and the\n rewritten query came back with a filter holding `\"sort name show id, name`:\n a string assembled out of the query's punctuation, exported as though it\n were what the user asked for. */\n const scannable = maskQuoted(text);\n const marks = [];\n CLAUSE_RE.lastIndex = 0;\n let m;\n while ((m = CLAUSE_RE.exec(scannable))) {\n if (FOLLOWED_BY_OPERATOR.test(scannable.slice(CLAUSE_RE.lastIndex))) continue;\n marks.push({ word: m[1].toLowerCase().replace(/\\s+/g, ' '), start: m.index });\n }\n return marks;\n}\n\n/**\n * The chosen columns, in the order the table declares them.\n *\n * Not the order they were ticked in: two exports of the same table a week\n * apart should differ only where the data differs, and a column list that\n * depends on which checkbox someone clicked first makes every diff noise.\n * A name the table does not declare keeps its relative position at the end,\n * which is where a computed column from a view lands.\n */\nexport function orderColumns(selected, declared) {\n const rank = new Map(declared.map((name, i) => [name, i]));\n return [...new Set(selected)].sort((a, b) => (rank.get(a) ?? Number.MAX_SAFE_INTEGER) - (rank.get(b) ?? Number.MAX_SAFE_INTEGER));\n}\n\nexport const sameList = (a, b) => a.length === b.length && a.every((name, i) => name === b[i]);\n\n/* ---------- which columns ---------- */\n\nconst COLUMN_KEY = 'mistri.export-columns.v1';\n\n/* Per connection as well as per table: `orders` on staging and `orders` on\n production are not the same table, and neither are their useful columns. */\nconst scope = () => state.activeConnection ?? 'default';\n\n/* Survives a re-render within the session even when nothing can be persisted,\n which is the case in private mode and with site data blocked. */\nconst chosen = new Map();\n\nexport function rememberColumns(tableId, names) {\n chosen.set(`${scope()}::${tableId}`, names);\n // loadJson/saveJson swallow a throwing or full localStorage: a column\n // preference that cannot be saved is not a reason to fail the export.\n const all = loadJson(COLUMN_KEY, {}) ?? {};\n all[scope()] = { ...(all[scope()] ?? {}), [tableId]: names };\n saveJson(COLUMN_KEY, all);\n}\n\n/** Column names of the table as the catalog declares them, or [] if unknown. */\nexport function declaredColumns(tableId) {\n if (!state.schema) return [];\n return (findTable(tableId)?.columns ?? []).map((c) => c.name);\n}\n\n/**\n * What to export, before anyone opens the chooser: last time's selection if\n * there is one, otherwise exactly what is on screen — which already respects\n * a `show` clause in the query.\n */\nexport function selectionFor(tableId, displayed, declared) {\n const key = `${scope()}::${tableId}`;\n const remembered = chosen.get(key) ?? loadJson(COLUMN_KEY, {})?.[scope()]?.[tableId];\n const known = new Set([...declared, ...displayed]);\n // A remembered column that no longer exists is dropped rather than sent:\n // the query would fail on it, and the export would fail with it.\n const valid = Array.isArray(remembered) ? remembered.filter((n) => known.has(n)) : [];\n return orderColumns(valid.length ? valid : displayed, declared);\n}\n\n/** `customer-2026-08-22.csv` — the table and the day, which is what you look for later. */\nexport function exportFilename(table, extension, now = new Date()) {\n const stem = String(table ?? 'export').replace(/[^\\w.-]+/g, '_');\n return `${stem}-${now.toISOString().slice(0, 10)}.${extension}`;\n}\n\nexport function download(filename, text, mime) {\n /* A UTF-8 CSV with no BOM opens in Excel as the local codepage, which turns\n every accented name into mojibake. The BOM is the one thing that makes it\n read the file as UTF-8, and other tools skip it. */\n const body = mime === 'text/csv' ? `\\ufeff${text}` : text;\n const url = URL.createObjectURL(new Blob([body], { type: `${mime};charset=utf-8` }));\n const link = el('a', { href: url, download: filename });\n portalRoot().append(link);\n link.click();\n link.remove();\n /* Revoked, or the blob is held for the life of the page — but not until the\n next tick: revoking in the same task can cancel the download that click\n just started. */\n setTimeout(() => URL.revokeObjectURL(url), 0);\n}\n\nexport function saveExport(kind, table, columns, rows) {\n if (kind === 'csv') download(exportFilename(table, 'csv'), toCsv(columns, rows), 'text/csv');\n else download(exportFilename(table, 'json'), toJson(columns, rows), 'application/json');\n toast(say('exportedRows', { count: rows.length }));\n}\n\n/**\n * All matching rows, as a file the server streams (`POST /api/export`):\n * read in batches and written as each arrives, so neither side holds the\n * whole result as objects and nothing is counted. False where the server\n * does not offer it — a tenant host, a row-policy App (its replies wait for\n * the policy to settle, which a stream cannot) — and the caller exports\n * through `/api/run` as before.\n *\n * @param {'csv' | 'json'} kind\n * @param {string} table\n * @param {string} q\n * @param {string[]} columns the file's columns, in order\n * @returns {Promise<boolean>}\n */\nexport async function streamExport(kind, table, q, columns) {\n const identity = captureSessionIdentity();\n if (identity.tenantRequired) return false;\n const { url, payload } = scopeApiRequest('/api/export', { q, format: kind, columns }, state.activeConnection);\n const res = await fetchServer(url, {\n method: 'POST',\n credentials: 'same-origin',\n cache: 'no-store',\n headers: {\n 'content-type': 'application/json',\n ...(identity.mode === 'authenticated' ? { 'x-mistri-account': identity.accountId } : {}),\n },\n body: JSON.stringify(payload),\n });\n /* The file is the one answer with a disposition; anything else is JSON\n saying why not — a refusal to fall back from, or the query's error. */\n if (res.ok && res.headers.get('content-disposition')) {\n const blob = await res.blob();\n const link = el('a', { href: URL.createObjectURL(blob), download: exportFilename(table, kind) });\n portalRoot().append(link);\n link.click();\n link.remove();\n setTimeout(() => URL.revokeObjectURL(link.href), 0);\n toast(say('exportedAllMatchingRows'));\n return true;\n }\n if ([401, 403, 404, 405].includes(res.status)) return false;\n const said = await res.json().catch(() => null);\n throw new Error(said?.errors?.[0]?.message ?? said?.error ?? say('theExportCouldNotBeRead'));\n}\n"],"mappings":"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"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Z as Empty } from "./shared-poc11xxo.js";
|
|
2
2
|
import { gt as defineMessages } from "./shared-DJZjSi3J.js";
|
|
3
|
-
import { t as onDemand } from "./shared-
|
|
3
|
+
import { t as onDemand } from "./shared-B-BUF9fx.js";
|
|
4
4
|
import { i as imageSources, n as MEDIA_IMAGE_SIZES, r as imageFallbackSet } from "./shared-BLkDQ3VT.js";
|
|
5
5
|
import { useRef, useState } from "react";
|
|
6
6
|
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
|
|
@@ -172,4 +172,4 @@ function Gallery({ items, label, emptyText }) {
|
|
|
172
172
|
}
|
|
173
173
|
export { Gallery };
|
|
174
174
|
|
|
175
|
-
//# sourceMappingURL=shared-
|
|
175
|
+
//# sourceMappingURL=shared-D1KWuCg6.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shared-
|
|
1
|
+
{"version":3,"file":"shared-D1KWuCg6.js","names":["_Fragment"],"sources":["../../../kit/src/client/copy/lists/components/Gallery.ts","../../../kit/src/client/components/Gallery.tsx"],"sourcesContent":["/** What Gallery says, in the lists and grid room (packages/kit/src/client/messages.ts says how the catalog is split). */\nimport { defineMessages } from '../../../messages.js';\n\nexport const say = defineMessages({\n showThePreviousPhoto: 'Show the previous photo',\n showTheNextPhoto: 'Show the next photo',\n chooseAPhoto: 'Choose a photo',\n viewPhotoLarger: 'View photo {number} of {total} larger',\n photo: 'Photo {number} of {total}',\n});\n","/**\n * A related list of image files drawn as a gallery: one large lead photo\n * and a strip of thumbnails under it. A thumbnail chooses the lead; the lead\n * opens the lightbox at that photo, and closing it leaves the lead on the\n * photo the reader was last looking at. The strip is one tab stop, moved\n * with the arrow keys, Home and End — the house tab strip's gesture.\n *\n * With more than one photo the lead carries a previous and a next button, so\n * a pointer steps through the photos where they are, without opening the\n * lightbox. They are siblings of what opens it, not inside it: a button inside\n * a button is invalid, and each keeps its own name for a screen reader. The\n * photo is a frame, and what opens it a button over the frame that stops at the\n * steps' columns, so the three targets meet and never overlap: drawn as one\n * button under the steps, a phone's tap beside a step's edge opened the photo.\n */\nimport { useRef, useState, type KeyboardEvent } from 'react';\nimport type { LightboxImage } from './Lightbox.js';\nimport { onDemand } from './onDemand.js';\nimport { Empty } from './Notes.js';\nimport { say } from '../copy/lists/components/Gallery.js';\nimport { imageSources, imageFallbackSet, MEDIA_IMAGE_SIZES } from '@mistriwork/engine/shared/imageWidths.js';\n\n/* The lightbox draws its own dialog, fetched the first time a photo is opened. */\nconst Lightbox = onDemand(() => import('./Lightbox.js'), 'Lightbox', { quiet: true });\n\n/** `thumb` is the strip's smaller copy of `src`, when the file resource keeps one. */\nexport interface GalleryItem extends LightboxImage {\n id: string;\n thumb?: string;\n}\n\nconst STEPS: Record<string, number> = { ArrowRight: 1, ArrowLeft: -1 };\n\nfunction Chevron({ back }: { back?: boolean }) {\n return (\n <svg viewBox=\"0 0 16 16\" width=\"18\" height=\"18\" aria-hidden=\"true\" focusable=\"false\">\n <path\n d={back ? 'M10 3.5L5.5 8l4.5 4.5' : 'M6 3.5l4.5 4.5L6 12.5'}\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"1.7\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n );\n}\n\nexport function Gallery({ items, label, emptyText }: { items: GalleryItem[]; label: string; emptyText: string }) {\n const [current, setCurrent] = useState(0);\n const [viewing, setViewing] = useState<number | null>(null);\n const lead = useRef<HTMLButtonElement>(null);\n const thumbs = useRef<Array<HTMLButtonElement | null>>([]);\n if (!items.length) return <Empty className=\"gallery-empty\" text={emptyText} />;\n const at = Math.min(current, items.length - 1);\n const shown = items[at];\n const step = (by: number) => setCurrent((at + by + items.length) % items.length);\n const onThumbKey = (event: KeyboardEvent<HTMLButtonElement>, index: number) => {\n const move = STEPS[event.key];\n const to = move ? (index + move + items.length) % items.length : event.key === 'Home' ? 0 : event.key === 'End' ? items.length - 1 : -1;\n if (to < 0) return;\n event.preventDefault();\n setCurrent(to);\n thumbs.current[to]?.focus();\n };\n return (\n <div className=\"gallery\" role=\"group\" aria-label={label}>\n <div className=\"gallery-stage\">\n <div className={`gallery-lead${items.length > 1 ? ' has-steps' : ''}`}>\n <picture>\n {imageSources(shown.src).map((source) => (\n <source key={source.type} type={source.type} srcSet={source.srcSet} sizes={MEDIA_IMAGE_SIZES} />\n ))}\n <img\n className=\"gallery-lead-image\"\n src={shown.src}\n srcSet={imageFallbackSet(shown.src)}\n sizes={MEDIA_IMAGE_SIZES}\n alt=\"\"\n decoding=\"async\"\n />\n </picture>\n {items.length > 1 && (\n <span className=\"gallery-count\" aria-hidden=\"true\">\n {at + 1} / {items.length}\n </span>\n )}\n <button\n type=\"button\"\n ref={lead}\n className=\"gallery-open\"\n onClick={() => setViewing(at)}\n aria-label={`${say('viewPhotoLarger', { number: at + 1, total: items.length })}${shown.alt ? `: ${shown.alt}` : ''}`}\n />\n </div>\n {items.length > 1 && (\n <>\n <button type=\"button\" className=\"gallery-step is-prev\" aria-label={say('showThePreviousPhoto')} onClick={() => step(-1)}>\n <Chevron back />\n </button>\n <button type=\"button\" className=\"gallery-step is-next\" aria-label={say('showTheNextPhoto')} onClick={() => step(1)}>\n <Chevron />\n </button>\n </>\n )}\n </div>\n {shown.caption && <p className=\"gallery-caption\">{shown.caption}</p>}\n {items.length > 1 && (\n <div className=\"gallery-strip\" role=\"group\" aria-label={say('chooseAPhoto')}>\n {items.map((item, index) => (\n <button\n key={item.id}\n type=\"button\"\n className=\"gallery-thumb\"\n ref={(button) => {\n thumbs.current[index] = button;\n }}\n aria-label={`${say('photo', { number: index + 1, total: items.length })}${item.alt ? `: ${item.alt}` : ''}`}\n aria-current={index === at ? 'true' : undefined}\n tabIndex={index === at ? 0 : -1}\n onClick={() => setCurrent(index)}\n onKeyDown={(event) => onThumbKey(event, index)}\n >\n <img src={item.thumb ?? item.src} alt=\"\" loading=\"lazy\" decoding=\"async\" />\n </button>\n ))}\n </div>\n )}\n {viewing !== null && (\n <Lightbox\n images={items}\n start={viewing}\n label={label}\n finalFocus={lead}\n onClose={(index) => {\n setCurrent(index);\n setViewing(null);\n }}\n />\n )}\n </div>\n );\n}\n"],"mappings":"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"}
|
|
@@ -1,31 +1,31 @@
|
|
|
1
1
|
import { $ as ProblemScopeProvider, E as sessionIdentity, Z as Empty, it as useQuery, nt as Button, tt as useMessageLanguage, w as captureSessionIdentity } from "./shared-poc11xxo.js";
|
|
2
2
|
import { F as primaryKey, Pn as useQueryClient, at as DISPLAY_TONES, gt as defineMessages, m as initialsOf, p as hueOf, rn as shell, ut as humanName } from "./shared-DJZjSi3J.js";
|
|
3
3
|
import { t as useMutation } from "./shared-BSPDIjPQ.js";
|
|
4
|
-
import { F as useRecentChange, L as DropItem, O as liveKeyText, P as useLiveActive, a as canInsert, c as openRelatedRecord, l as countsChanged } from "./shared-
|
|
5
|
-
import { B as toast, L as state, M as saveJson, c as columnLabel, d as findTable, f as go, h as loadJson, i as api, j as rowLabel, k as registerSurfaceMutationPendingProbe, m as labelPath, s as columnDisplay, st as ownedBy, w as quote, z as tableView } from "./shared-
|
|
4
|
+
import { F as useRecentChange, L as DropItem, O as liveKeyText, P as useLiveActive, a as canInsert, c as openRelatedRecord, l as countsChanged } from "./shared-BHsjawAG.js";
|
|
5
|
+
import { B as toast, L as state, M as saveJson, c as columnLabel, d as findTable, f as go, h as loadJson, i as api, j as rowLabel, k as registerSurfaceMutationPendingProbe, m as labelPath, s as columnDisplay, st as ownedBy, w as quote, z as tableView } from "./shared-BoLbc2WD.js";
|
|
6
6
|
import { t as Modal } from "./shared-CRr4kJXB.js";
|
|
7
|
-
import { t as onDemand } from "./shared-
|
|
7
|
+
import { t as onDemand } from "./shared-B-BUF9fx.js";
|
|
8
8
|
import { t as Dropdown } from "./shared-gtzTT5Z7.js";
|
|
9
|
-
import { vt as presentationColumns } from "./shared-
|
|
9
|
+
import { vt as presentationColumns } from "./shared-XcSKDp6N.js";
|
|
10
10
|
import { a as ErrorBoundary } from "./shared-C3MTHv9P.js";
|
|
11
|
-
import { c as updateAttempts, d as RefJump, f as Value } from "./shared-
|
|
11
|
+
import { c as updateAttempts, d as RefJump, f as Value } from "./shared-Chp88all.js";
|
|
12
12
|
import { r as factWord } from "./shared-CS6uipL4.js";
|
|
13
13
|
import { n as pathEqualityFilter, r as recordKey } from "./shared-_IMKuuvy.js";
|
|
14
|
-
import { i as useAvatarPhotos } from "./shared-
|
|
14
|
+
import { i as useAvatarPhotos } from "./shared-BOe4W2FI.js";
|
|
15
15
|
import { r as useCrumbSlots } from "./shared-yOrkqLkz.js";
|
|
16
|
-
import { a as relabelFavorite, i as FavoriteStar, r as useMediaQuery, t as PHONE_QUERY } from "./shared-
|
|
17
|
-
import { c as rootLabel, d as sourceOf, o as headerOf } from "./shared-
|
|
18
|
-
import { o as headerColumns } from "./shared-
|
|
19
|
-
import { n as canEditRow } from "./shared-
|
|
20
|
-
import { E as subscribeStaged, T as stagedVersion, _ as sameRow, f as pendingCount, r as applyingStaged } from "./shared-
|
|
21
|
-
import { r as refreshRecordInPlace } from "./shared-
|
|
22
|
-
import { r as RecordPicker } from "./shared-
|
|
23
|
-
import { n as PendingBar, t as Editable } from "./shared-
|
|
24
|
-
import { a as shareRecordSource, c as spoken, i as readRecordSource, l as usePageApi, n as Sections, o as PageRenderContext, r as canDelete, s as recordReadNames } from "./shared-
|
|
25
|
-
import "./shared-
|
|
26
|
-
import { n as RecordTrailNav, t as commandOperations } from "./shared-
|
|
27
|
-
import { t as useWalk } from "./shared-
|
|
28
|
-
import { a as drawnLayout, i as useRecordSurface, o as showcaseIndex, r as RECORD_REFRESH_FAILED } from "./shared-
|
|
16
|
+
import { a as relabelFavorite, i as FavoriteStar, r as useMediaQuery, t as PHONE_QUERY } from "./shared-WhbuObEW.js";
|
|
17
|
+
import { c as rootLabel, d as sourceOf, o as headerOf } from "./shared-Bf30ZLoS.js";
|
|
18
|
+
import { o as headerColumns } from "./shared-CZJE4Bmp.js";
|
|
19
|
+
import { n as canEditRow } from "./shared-BHCQ60yN.js";
|
|
20
|
+
import { E as subscribeStaged, T as stagedVersion, _ as sameRow, f as pendingCount, r as applyingStaged } from "./shared-Z4uBJU6I.js";
|
|
21
|
+
import { r as refreshRecordInPlace } from "./shared-CdQOMD8J.js";
|
|
22
|
+
import { r as RecordPicker } from "./shared-C2RU1qjv.js";
|
|
23
|
+
import { n as PendingBar, t as Editable } from "./shared-BumxsBlA.js";
|
|
24
|
+
import { a as shareRecordSource, c as spoken, i as readRecordSource, l as usePageApi, n as Sections, o as PageRenderContext, r as canDelete, s as recordReadNames } from "./shared-B5aBCUi7.js";
|
|
25
|
+
import "./shared-DGaQZXnw.js";
|
|
26
|
+
import { n as RecordTrailNav, t as commandOperations } from "./shared-Docl_0tq.js";
|
|
27
|
+
import { t as useWalk } from "./shared-CSPhENq3.js";
|
|
28
|
+
import { a as drawnLayout, i as useRecordSurface, o as showcaseIndex, r as RECORD_REFRESH_FAILED } from "./shared-CL3RLKDA.js";
|
|
29
29
|
import { lazy, useCallback, useContext, useEffect, useLayoutEffect, useMemo, useRef, useState, useSyncExternalStore } from "react";
|
|
30
30
|
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
|
|
31
31
|
import { createPortal } from "react-dom";
|
|
@@ -590,7 +590,7 @@ var say$2 = defineMessages({
|
|
|
590
590
|
* Delete, tags and pending bar. Everything that acts on the whole record
|
|
591
591
|
* sits here, above the sections.
|
|
592
592
|
*/
|
|
593
|
-
var LiveUpdatedLine = onDemand(() => import("./shared-
|
|
593
|
+
var LiveUpdatedLine = onDemand(() => import("./shared-B07qIMlE.js"), "LiveUpdatedLine", { quiet: true });
|
|
594
594
|
function PageHead({ entry, page, base, others, onLayout, actions, host, onPending, title, gone = false, header, onSectionLabel, onTitleEditor, titleOwner }) {
|
|
595
595
|
useMessageLanguage();
|
|
596
596
|
useWalk();
|
|
@@ -1066,7 +1066,7 @@ function PageLayout({ children, aside, asideLabel = say$1("recordContext"), layo
|
|
|
1066
1066
|
* PageMetrics, PageTimeline, PageRelated) through one box (PageSectionBox),
|
|
1067
1067
|
* reading the page around it from pageContext.ts.
|
|
1068
1068
|
*/
|
|
1069
|
-
var NewRecordDialog = onDemand(() => import("./shared-
|
|
1069
|
+
var NewRecordDialog = onDemand(() => import("./shared-C4wSfz6k.js").then((n) => n.i), "NewRecordDialog", { quiet: true });
|
|
1070
1070
|
function PageView(props) {
|
|
1071
1071
|
const { entry, page, base, plans, chooser, host } = props;
|
|
1072
1072
|
const queries = useQueryClient();
|
|
@@ -1321,7 +1321,7 @@ var say = defineMessages({
|
|
|
1321
1321
|
theDeletionResultIsNotYet: "The deletion result is not yet confirmed. Keep this tab open; do not submit another deletion."
|
|
1322
1322
|
});
|
|
1323
1323
|
Object.freeze([]);
|
|
1324
|
-
lazy(() => import("./shared-
|
|
1324
|
+
lazy(() => import("./shared-DUPMRoO0.js"));
|
|
1325
1325
|
var suggestionsKey = (connection, table, key) => key === void 0 ? [
|
|
1326
1326
|
"record-decisions",
|
|
1327
1327
|
connection,
|
|
@@ -1493,4 +1493,4 @@ function RecordPageBody({ owner, tableId, recordKey, label, pageId, close, setPe
|
|
|
1493
1493
|
}
|
|
1494
1494
|
export { RecordPageBody };
|
|
1495
1495
|
|
|
1496
|
-
//# sourceMappingURL=shared-
|
|
1496
|
+
//# sourceMappingURL=shared-D66ju_Cb.js.map
|