@metabase/cli 0.3.2-alpha.fix-transform-test-ee-path.8ac2a7a → 0.4.0

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 (305) hide show
  1. package/dist/{add-collection-B_-eMU_k.mjs → add-collection-CC6KSwjX.mjs} +5 -5
  2. package/dist/{alert-Dalin_DD.mjs → alert-Dt6La9tK.mjs} +7 -7
  3. package/dist/{alerts-DpBgrjPI.mjs → alerts-ClKnJqgB.mjs} +6 -6
  4. package/dist/{append-C1JNVALm.mjs → append-pnaQWP_A.mjs} +4 -4
  5. package/dist/{archive-B51prFgS.mjs → archive-By1pLYtO.mjs} +3 -3
  6. package/dist/{archive-CwITzj_j.mjs → archive-CLu2TGW5.mjs} +5 -5
  7. package/dist/{archive-52ZHbFDm2.mjs → archive-COP9joWU.mjs} +4 -4
  8. package/dist/{archive-cAdUa1-2.mjs → archive-CSnBFcQ_.mjs} +3 -3
  9. package/dist/{archive-DA3OiLEE.mjs → archive-Ct1eyolN.mjs} +3 -3
  10. package/dist/{archive-CdKf_Eqq.mjs → archive-D7nAQcCz.mjs} +3 -3
  11. package/dist/{archive-CISXgZAI.mjs → archive-DEDA48w3.mjs} +5 -5
  12. package/dist/{archive-DVHxeDKS.mjs → archive-DJAsSzCz.mjs} +5 -5
  13. package/dist/{archive-BkITQyWW.mjs → archive-DtabbPUk.mjs} +4 -4
  14. package/dist/{archive-DckxlWBt.mjs → archive-YNpa8daf.mjs} +3 -3
  15. package/dist/{archive-CicPYX27.mjs → archive-ewitrKdx.mjs} +5 -5
  16. package/dist/{auth-A96JOCQx.mjs → auth-DdLhXCn-.mjs} +5 -5
  17. package/dist/body-Dd-TwYYL.mjs +17 -0
  18. package/dist/branch-flag-pFQPNYKr.mjs +9 -0
  19. package/dist/{branches-CbcwWYL9.mjs → branches-ZvGNhed6.mjs} +3 -3
  20. package/dist/breaking-BLswgvkA.mjs +36 -0
  21. package/dist/broken-BN0nL2hf.mjs +37 -0
  22. package/dist/bulk-discard-values-DFJUjSnE.mjs +49 -0
  23. package/dist/bulk-edit-Brqr67bu.mjs +53 -0
  24. package/dist/bulk-rescan-values-DndXXi2N.mjs +28 -0
  25. package/dist/bulk-sync-schema-mO-t2QlL.mjs +28 -0
  26. package/dist/{cancel-DpDcVY7M.mjs → cancel-DP03dXBf.mjs} +3 -3
  27. package/dist/{cancel-task-B4RDvIYb.mjs → cancel-task-CELBfBPP.mjs} +4 -4
  28. package/dist/{card-voh1k4hl.mjs → card-Bv4ZN0oV.mjs} +5 -3
  29. package/dist/card-CFd-GUEM.mjs +25 -0
  30. package/dist/{card-CEkp1mcI.mjs → card-DSrgU7lT.mjs} +1 -1
  31. package/dist/{cards-BC0JX8Yg.mjs → cards-Cn2ywFTJ.mjs} +6 -6
  32. package/dist/cli.mjs +410 -111
  33. package/dist/{client-ClL6gf7G.mjs → client-ToLiPu9q.mjs} +785 -316
  34. package/dist/{collection-DYM0p3Xl.mjs → collection-BG3Ksea-.mjs} +1 -1
  35. package/dist/collection-BKNShKcY.mjs +21 -0
  36. package/dist/{collection-BxdPxD38.mjs → collection-D3KXhvnc.mjs} +7 -5
  37. package/dist/{collection-namespace-Dv0l-V9K.mjs → collection-namespace-CWW6hZxK.mjs} +2 -2
  38. package/dist/{content-translation-BXIXL4eW.mjs → content-translation-C19SqZWp.mjs} +3 -3
  39. package/dist/copy-BGK8Wz6d.mjs +55 -0
  40. package/dist/copy-COLUuiuF.mjs +36 -0
  41. package/dist/copy-flags-eU8aa0zj.mjs +32 -0
  42. package/dist/{create-BbjSOTN-.mjs → create-B2tuInV9.mjs} +4 -4
  43. package/dist/{create-Za1EskpV.mjs → create-B3TKri1E.mjs} +4 -4
  44. package/dist/{create--fiwuTWc.mjs → create-B4gXKDRr.mjs} +3 -3
  45. package/dist/create-B63JphYe.mjs +34 -0
  46. package/dist/{create-NCKHHdov.mjs → create-BH6kLjHS.mjs} +4 -4
  47. package/dist/{create-Dhai9zAt.mjs → create-BwifyhyL.mjs} +3 -3
  48. package/dist/{create-DWFJdyIr.mjs → create-Colz5bOO.mjs} +3 -3
  49. package/dist/{create-BcsVwXgS2.mjs → create-CulUZgN1.mjs} +4 -4
  50. package/dist/{create-D--Z1S3p2.mjs → create-Cxuqr3kT.mjs} +6 -6
  51. package/dist/{create-Bryrkb9g.mjs → create-CzW_UTE7.mjs} +6 -6
  52. package/dist/{create-kZIIEN2Y.mjs → create-DNR8RMvV.mjs} +6 -6
  53. package/dist/{create-DmN2gFc4.mjs → create-DSHeoV7e.mjs} +4 -4
  54. package/dist/{create-BVNhtAgF.mjs → create-DWbW2WSc.mjs} +6 -6
  55. package/dist/{create-CHr8MPPq.mjs → create-Dx8nfjGs.mjs} +3 -3
  56. package/dist/{create-B9qXQ_wV.mjs → create-XGomrTz5.mjs} +5 -5
  57. package/dist/{create-branch-CseVn3lp.mjs → create-branch-DxL7KUZp.mjs} +4 -4
  58. package/dist/{create-YetX69Re.mjs → create-g1f2yJ4s.mjs} +3 -3
  59. package/dist/{csv-DNzesu8y.mjs → csv-C6TEfLMi.mjs} +4 -4
  60. package/dist/{current-task-DRTKZcP9.mjs → current-task-CHs0zNFM.mjs} +4 -4
  61. package/dist/dashboard-AWrXqQ7a.mjs +35 -0
  62. package/dist/{dashboard-D0hwTC-f.mjs → dashboard-Phz3XpRM.mjs} +2 -1
  63. package/dist/{dashboard-DgK81azj.mjs → dashboard-XSTr9QCr.mjs} +6 -2
  64. package/dist/database-D-CRyRIv.mjs +45 -0
  65. package/dist/{database-C3E9PZSx.mjs → database-MlUPpitM.mjs} +1 -1
  66. package/dist/dataset-p5oNPQgL.mjs +66 -0
  67. package/dist/{db-BDijt81U.mjs → db-BFSeETMO.mjs} +7 -7
  68. package/dist/{delete-Dc8E5YwZ.mjs → delete-BUKgSJhh.mjs} +4 -4
  69. package/dist/{delete-BxjJ66BS.mjs → delete-CPBByycV.mjs} +4 -4
  70. package/dist/{delete-wFsy80db.mjs → delete-Cucqn4-V.mjs} +4 -4
  71. package/dist/{delete--15it-A8.mjs → delete-D79TlpcE.mjs} +4 -4
  72. package/dist/delete-DZJxBmdU.mjs +44 -0
  73. package/dist/{delete-BudvZkvK.mjs → delete-DndykJn2.mjs} +4 -4
  74. package/dist/delete-runtime-BbmRg_in.mjs +55 -0
  75. package/dist/{delete-table-5AQpn8OB.mjs → delete-table-CbsWcjh5.mjs} +4 -4
  76. package/dist/{dependencies-C1ogC3BV.mjs → dependencies-B-880phi.mjs} +5 -5
  77. package/dist/dependency-DBUJwXqv.mjs +15 -0
  78. package/dist/dependency-DKSjKT8P.mjs +165 -0
  79. package/dist/dependency-DSxKm9oS.mjs +111 -0
  80. package/dist/dependents-C_FDnpZs.mjs +52 -0
  81. package/dist/{dirty-CSLDYO-K.mjs → dirty-B-Is68--.mjs} +5 -5
  82. package/dist/discard-values-yzH-kIsr.mjs +55 -0
  83. package/dist/document-BRaba87v.mjs +20 -0
  84. package/dist/{document-CA0Q6lqu.mjs → document-C18b5rM6.mjs} +1 -1
  85. package/dist/{document-BHpLJbKU.mjs → document-DFCj1Az_.mjs} +2 -1
  86. package/dist/{download-Ddap1OAo.mjs → download-DluF-vnU.mjs} +2 -2
  87. package/dist/{eid-HnrWhPoe.mjs → eid-Dz-mP40j.mjs} +11 -10
  88. package/dist/entity-CA4zfRt4.mjs +20 -0
  89. package/dist/entry-flags-7x7bIyOQ.mjs +42 -0
  90. package/dist/{events-CXqetjcS.mjs → events-2sOk6H09.mjs} +4 -4
  91. package/dist/export-BKkAJOFb.mjs +74 -0
  92. package/dist/export-flags-NiZ7C3Gm.mjs +81 -0
  93. package/dist/export-preflight-CwJ_3-iX.mjs +35 -0
  94. package/dist/{field-CcN4oZy6.mjs → field-5nivEfd6.mjs} +33 -3
  95. package/dist/field-BARgq5I9.mjs +21 -0
  96. package/dist/field-wmN6raOG.mjs +128 -0
  97. package/dist/{fields-DxHxuxwO.mjs → fields-Bod0s_uV.mjs} +6 -6
  98. package/dist/filter-flags-BYcbB85j.mjs +71 -0
  99. package/dist/fks-IUw66K_Q.mjs +36 -0
  100. package/dist/{get-eJilYnHk.mjs → get-B8DUMrCw.mjs} +5 -5
  101. package/dist/{get-C3cuZNeW.mjs → get-BGqvoGQM.mjs} +3 -3
  102. package/dist/{get-DmKtPNOy.mjs → get-BSUsfysk.mjs} +3 -3
  103. package/dist/{get-DW7mCaGe.mjs → get-BXsLkoit.mjs} +5 -5
  104. package/dist/{get-Dtre5jzh.mjs → get-BXssHyJ1.mjs} +5 -5
  105. package/dist/get-Bct52yPw.mjs +36 -0
  106. package/dist/{get-BiPclcIP.mjs → get-Besqwy32.mjs} +3 -3
  107. package/dist/{get-BcoJ9Aha.mjs → get-BfSX-OeS.mjs} +3 -3
  108. package/dist/{get-BF2vdF3W.mjs → get-Biy4gOzu2.mjs} +3 -3
  109. package/dist/{get-C_tdSMwW2.mjs → get-CYIeiTZ9.mjs} +4 -4
  110. package/dist/{get-b0CoPz5B.mjs → get-CaEiQnSw.mjs} +4 -4
  111. package/dist/{get-CxUQyhte.mjs → get-Cl81y0Md.mjs} +5 -5
  112. package/dist/{get-B2pj2q3X.mjs → get-D1NjMXAH.mjs} +4 -4
  113. package/dist/{get-D_x-ENFe.mjs → get-D2cPuOPR.mjs} +5 -5
  114. package/dist/{get-DjlQhgD4.mjs → get-DITlshJH.mjs} +3 -3
  115. package/dist/{get-CE9_4Q7E.mjs → get-DLyg6Al9.mjs} +3 -3
  116. package/dist/{get-CDnmpfHQ.mjs → get-DQZfaVNq.mjs} +4 -4
  117. package/dist/{get-BGLvyOO3.mjs → get-DtBqoGTa.mjs} +5 -5
  118. package/dist/{get-H6kInHIx.mjs → get-_ik_5_lQ.mjs} +5 -5
  119. package/dist/{get-run-BE1HtJDW.mjs → get-run-CEc_tr5b.mjs} +4 -4
  120. package/dist/{git-sync-BwBRmEhE.mjs → git-sync-COokpYgc.mjs} +12 -3
  121. package/dist/git-sync-DKcaddkV.mjs +29 -0
  122. package/dist/git-sync-DspFahwV.mjs +165 -0
  123. package/dist/glossary-BlNCrYbw.mjs +30 -0
  124. package/dist/glossary-CWIX8Zh6.mjs +14 -0
  125. package/dist/glossary-LmZWwCNP.mjs +21 -0
  126. package/dist/graph-f6Bp1e8U.mjs +34 -0
  127. package/dist/{group-YQQ5GIcP.mjs → group-bpD_KcjA.mjs} +1 -1
  128. package/dist/{has-remote-changes-Cj1KhBOT.mjs → has-remote-changes-B8MmN6yh.mjs} +4 -4
  129. package/dist/{import-DLb9VN4l.mjs → import-Bhq15KgP.mjs} +19 -8
  130. package/dist/{input-D5tQEfqN.mjs → input-D8qW-KtR.mjs} +6 -2
  131. package/dist/{is-dirty-BxtgV2xF.mjs → is-dirty-CAsVuVx8.mjs} +2 -2
  132. package/dist/{items-DLUYc5-z.mjs → items-BZJomiDE.mjs} +8 -8
  133. package/dist/{key-PYetuQ13.mjs → key-BynJSK9u.mjs} +1 -1
  134. package/dist/{library-BNSxXOpc.mjs → library-B7wDH-Nc.mjs} +5 -5
  135. package/dist/{library-PGCfm0UA.mjs → library-BOv5SY24.mjs} +1 -1
  136. package/dist/{library-BPIzb3K_.mjs → library-Ck0EK5bi.mjs} +4 -2
  137. package/dist/{list-BUz6KOfw.mjs → list-B2uUl26x.mjs} +6 -6
  138. package/dist/{list-CERbeLbQ.mjs → list-B4luDSYj.mjs} +6 -6
  139. package/dist/{list-jhQSgh6i.mjs → list-B8ND9t2h.mjs} +3 -3
  140. package/dist/{list-M8J10Ozk.mjs → list-BT5t8ZOl.mjs} +4 -4
  141. package/dist/{list-Dat8QNcf.mjs → list-BT7xiUQe.mjs} +3 -3
  142. package/dist/{list-cIMww2Me.mjs → list-BWFCv_zk.mjs} +5 -5
  143. package/dist/{list-B1soS8QW.mjs → list-BtZVe1Nq.mjs} +6 -6
  144. package/dist/{list-C5mS_ehX.mjs → list-BwdSG-P5.mjs} +5 -5
  145. package/dist/{list-BQnOEB3W.mjs → list-C-A-2HFq.mjs} +3 -3
  146. package/dist/list-C9x--9Jq.mjs +101 -0
  147. package/dist/{list-CX9qZ-bx.mjs → list-CCdXig7b.mjs} +4 -4
  148. package/dist/{list-Sd7jGZoX.mjs → list-CJDFoOHb.mjs} +3 -3
  149. package/dist/{list-CzRzCbCY.mjs → list-CLFu3mQB.mjs} +3 -3
  150. package/dist/{list-CBLxhaNZ.mjs → list-Cd40Kr0R.mjs} +3 -3
  151. package/dist/{list-COLpwXW4.mjs → list-Cj_mTxbY.mjs} +4 -4
  152. package/dist/{list-CQbiSx26.mjs → list-CtS50R7m.mjs} +5 -5
  153. package/dist/{list-CehE6KBV.mjs → list-CvZyTwmV.mjs} +5 -5
  154. package/dist/list-DcnNlYQA.mjs +35 -0
  155. package/dist/{list-BcP1DTJH.mjs → list-DtgbtE3_.mjs} +3 -3
  156. package/dist/{login-BfLqBfCd.mjs → login-Bi_nGMJ9.mjs} +6 -6
  157. package/dist/{logout-BpRXB3Ze.mjs → logout-CiHQJWTu.mjs} +2 -2
  158. package/dist/{measure-Ds8O5Evr.mjs → measure-D2qq5e8f.mjs} +6 -6
  159. package/dist/moderation-review-BdqEH6N1.mjs +31 -0
  160. package/dist/{notification-DVrLkjFT.mjs → notification-DOYdl0ao.mjs} +1 -1
  161. package/dist/{parameter-values-DhrkLXoN.mjs → parameter-values-CZow98nb.mjs} +3 -3
  162. package/dist/{parse-enum-Dc0dMZ3P.mjs → parse-enum-CLIXMsd8.mjs} +1 -1
  163. package/dist/parse-id-BW09NysN.mjs +13 -0
  164. package/dist/{parse-ref-DTDld_LJ.mjs → parse-ref-Cw5fa4FI.mjs} +1 -1
  165. package/dist/parse-text-T0lTXzTZ.mjs +11 -0
  166. package/dist/{path-_GHFrTLx.mjs → path-K6LPLYPb.mjs} +4 -4
  167. package/dist/{poll-KLl4Eq8Y.mjs → poll-Dz4tUm2f.mjs} +2 -2
  168. package/dist/{preflight-BpYtF0IU.mjs → preflight-CX6cqB90.mjs} +3 -3
  169. package/dist/{process-CLtOWKBn.mjs → process-D0HdqZ3r.mjs} +1 -1
  170. package/dist/{publish-D-7Zlmuk.mjs → publish-COatW4Un.mjs} +4 -4
  171. package/dist/{pulse-x0gFxWfG.mjs → pulse-D1uh8UIU.mjs} +1 -1
  172. package/dist/query-BJXTIDhy.mjs +328 -0
  173. package/dist/{query-B1CZztxs.mjs → query-DmvkyDfo.mjs} +14 -33
  174. package/dist/remapping-CPAvDKHV.mjs +53 -0
  175. package/dist/{remove-collection-C4saCFxz.mjs → remove-collection-Bg-sNX3U.mjs} +5 -5
  176. package/dist/{render-6O_eF-P1.mjs → render-BSfDD6ip.mjs} +2 -2
  177. package/dist/{replace-BuR4f2Ai.mjs → replace-RCHeZLUT.mjs} +4 -4
  178. package/dist/{rescan-values-CNOiiWQ5.mjs → rescan-values-CpDGYZvf.mjs} +5 -5
  179. package/dist/rescan-values-PeMnpaFY.mjs +32 -0
  180. package/dist/{run-DijA_BXt.mjs → run-CaQ7kubO.mjs} +3 -3
  181. package/dist/{run-QEUbWNm7.mjs → run-DkRkZRgf.mjs} +7 -7
  182. package/dist/{runs-BSlhVeDO.mjs → runs-BDjoVJ0P.mjs} +5 -5
  183. package/dist/{runtime-Dtb93zKy.mjs → runtime-CZ5zh32z.mjs} +21 -82
  184. package/dist/{schema-tables-BE3rEb6I.mjs → schema-tables-C2qjLcPq.mjs} +6 -6
  185. package/dist/{schemas-yDjBiwlH.mjs → schemas-D8hfNduk.mjs} +4 -4
  186. package/dist/search-BrQQuNmh.mjs +131 -0
  187. package/dist/search-CnTXKJgx.mjs +85 -0
  188. package/dist/{segment-Cm6zQjJW.mjs → segment-Bi6eqj3e.mjs} +6 -6
  189. package/dist/{send-kC8oerkT.mjs → send-CAjgVNlA.mjs} +3 -3
  190. package/dist/{set-tFhPkxrL.mjs → set-BXTkYWid.mjs} +4 -4
  191. package/dist/{set-active-lDKhAlij.mjs → set-active-CBQVCePU.mjs} +3 -3
  192. package/dist/set-sensitivity-D39kGTob.mjs +57 -0
  193. package/dist/{setting-DrJXCaFE.mjs → setting-CPkvkc4H.mjs} +4 -4
  194. package/dist/{setup-BWY9M0iR.mjs → setup-Be3xDXHi.mjs} +3 -3
  195. package/dist/{signal-Csom0mt5.mjs → signal-CxWeLszu.mjs} +1 -1
  196. package/dist/{skill-list-CCes8pKe.mjs → skill-list-CBGq30sI.mjs} +2 -2
  197. package/dist/{skills-DE9ej5Rg.mjs → skills-CJ9eXouJ.mjs} +2 -2
  198. package/dist/{skills-DPRN2384.mjs → skills-DyiLycMY.mjs} +3 -3
  199. package/dist/snippet-QirK70R_.mjs +19 -0
  200. package/dist/{stash-C9oDvQ9P.mjs → stash-BVN3s5N_.mjs} +6 -6
  201. package/dist/{status-CkpujA26.mjs → status-BtbMmIWo.mjs} +7 -7
  202. package/dist/{status-DSdXmNC3.mjs → status-CxP6w3aL.mjs} +3 -3
  203. package/dist/{subscription-DKOKoHRG.mjs → subscription-Dr-YHARg.mjs} +6 -6
  204. package/dist/{subscriptions-C5SyJL4B.mjs → subscriptions-8tM8TTeQ.mjs} +6 -6
  205. package/dist/{summary-DTPgXsc0.mjs → summary-DKx6ptQe.mjs} +5 -5
  206. package/dist/sync-schema-B8RY0Ra4.mjs +32 -0
  207. package/dist/{sync-schema-DKKkNSR7.mjs → sync-schema-kNriXZjG.mjs} +6 -6
  208. package/dist/sync-task-CXFoqlpF.mjs +53 -0
  209. package/dist/table-CZnT6d9x.mjs +26 -0
  210. package/dist/{table-DfuY0N8e.mjs → table-Ci6bhZkb.mjs} +35 -12
  211. package/dist/table-CxvaDiIZ.mjs +155 -0
  212. package/dist/table-selector-flags-1bYkAKld.mjs +42 -0
  213. package/dist/text-DaNkPRwt.mjs +6 -0
  214. package/dist/timeline-CUzx6uXi.mjs +21 -0
  215. package/dist/{timeline-event-n4Lzet7l.mjs → timeline-event-DpNm4dkn.mjs} +6 -6
  216. package/dist/{transform-CtqB1WYo.mjs → transform-CNBIV7No.mjs} +1 -1
  217. package/dist/transform-g4-HHzDp.mjs +28 -0
  218. package/dist/transform-job-DqBtnTrG.mjs +22 -0
  219. package/dist/{transform-tag-D6NXqWaX.mjs → transform-tag-nTb0Ivpj.mjs} +5 -5
  220. package/dist/{transforms-O4NtXqFz.mjs → transforms-BSsAfwAg.mjs} +5 -5
  221. package/dist/tree-lMvw1jnZ.mjs +34 -0
  222. package/dist/{unpublish-DvWefKJi.mjs → unpublish-CYFDd828.mjs} +3 -3
  223. package/dist/unreferenced-8Xdq76Kw.mjs +36 -0
  224. package/dist/{update-AJ2JmwDl.mjs → update-6P_GYCLT.mjs} +5 -5
  225. package/dist/{update-76nzOc71.mjs → update-B28EJzrx.mjs} +13 -8
  226. package/dist/{update-To6A1Ugu.mjs → update-BDunZa7G.mjs} +4 -4
  227. package/dist/{update-2KIpYgyj.mjs → update-BT2yNB_g.mjs} +6 -6
  228. package/dist/{update-DmgRIp7o.mjs → update-BnMUSFYZ.mjs} +4 -4
  229. package/dist/update-BwrYeKso.mjs +41 -0
  230. package/dist/{update-DOdcflLH.mjs → update-C7DEMiu-.mjs} +7 -7
  231. package/dist/{update-CGJvIS-l.mjs → update-CITzAFG8.mjs} +4 -4
  232. package/dist/update-CLl8tE20.mjs +181 -0
  233. package/dist/{update-BB6Go_RX.mjs → update-CM5uuhjB.mjs} +4 -4
  234. package/dist/{update-xEegxIyH.mjs → update-CQXcsvaa.mjs} +5 -5
  235. package/dist/{update-DV54H3L5.mjs → update-Cs2zv_L2.mjs} +7 -7
  236. package/dist/{update-Bah7N8QX.mjs → update-D--Fw7-_.mjs} +5 -5
  237. package/dist/{update-H_fdjugs.mjs → update-D9p0N8ky.mjs} +4 -4
  238. package/dist/{update-7oKvP1HC.mjs → update-DAzRx0of.mjs} +5 -5
  239. package/dist/{update-DXmZuJho.mjs → update-D_DCOOAB.mjs} +6 -6
  240. package/dist/{update-D7dG7H-z.mjs → update-_sYM1GuU.mjs} +7 -7
  241. package/dist/{update-dashcard-DjT5QOkL.mjs → update-dashcard-VNnIqHDI.mjs} +6 -6
  242. package/dist/{upgrade-CuJx9fX4.mjs → upgrade-Tj_reACv.mjs} +4 -4
  243. package/dist/upload-BKxOpSz3.mjs +13 -0
  244. package/dist/{upload-DOO94rCQ.mjs → upload-C2fhpKkP.mjs} +2 -2
  245. package/dist/{upload-CboARPZm.mjs → upload-Dg91ldGg.mjs} +3 -3
  246. package/dist/{uuid-InwZlrpQ.mjs → uuid-Blpv_e0S.mjs} +2 -2
  247. package/dist/{validate-D6-Vg_kn.mjs → validate-D7e110oU.mjs} +1 -1
  248. package/dist/{validate-query-B90KYPQr.mjs → validate-query-C7LuKiUT.mjs} +2 -2
  249. package/dist/{values-CsZLk1Ls.mjs → values-PonkbYAK.mjs} +5 -5
  250. package/dist/verify-DixUBbd2.mjs +38 -0
  251. package/dist/verify-Dv7ER11c.mjs +38 -0
  252. package/dist/{verify-DrGjZwBM.mjs → verify-Mpb65a5v.mjs} +3 -3
  253. package/dist/verify-flags-CMpRkMPa.mjs +58 -0
  254. package/dist/{wait-BmzdarP9.mjs → wait-CaH6XHQV.mjs} +6 -6
  255. package/dist/{wait-flags-CiJGrTCT.mjs → wait-flags-rUU4NUrv.mjs} +2 -2
  256. package/dist/{window-DSb1tqSe.mjs → window-CI_QD04s.mjs} +1 -1
  257. package/package.json +1 -1
  258. package/skill-data/core/SKILL.md +24 -23
  259. package/skill-data/dashboard/SKILL.md +1 -1
  260. package/skill-data/document/SKILL.md +12 -1
  261. package/skill-data/git-sync/SKILL.md +61 -9
  262. package/skill-data/mbql/SKILL.md +5 -0
  263. package/skill-data/metadata/SKILL.md +36 -6
  264. package/skill-data/transform/SKILL.md +1 -63
  265. package/dist/body-CshgcV6U.mjs +0 -17
  266. package/dist/card-CefVYtF7.mjs +0 -24
  267. package/dist/collection-Be5AHVWP.mjs +0 -20
  268. package/dist/create-DiJ8bUb-.mjs +0 -34
  269. package/dist/dashboard-CMw13KXM.mjs +0 -33
  270. package/dist/database-JtHTqSpq.mjs +0 -26
  271. package/dist/delete-Bsdwqh7H.mjs +0 -44
  272. package/dist/delete-runtime-BKEzJn22.mjs +0 -49
  273. package/dist/document-BGzVip5_.mjs +0 -19
  274. package/dist/export-IFZdgYZ2.mjs +0 -63
  275. package/dist/field-BJ6HoLRd.mjs +0 -18
  276. package/dist/field-fDtIrY6D.mjs +0 -80
  277. package/dist/get-i0KInCw9.mjs +0 -32
  278. package/dist/get-jofVjU6e.mjs +0 -31
  279. package/dist/git-sync-TjX1r_wF.mjs +0 -136
  280. package/dist/git-sync-xKC1sqC4.mjs +0 -28
  281. package/dist/list-Cuhf2lKL.mjs +0 -35
  282. package/dist/list-D-SyhKFw.mjs +0 -34
  283. package/dist/parse-id-DtM6q9HU.mjs +0 -10
  284. package/dist/query-CxESKMve.mjs +0 -114
  285. package/dist/query-result-E4Q-Gra6.mjs +0 -15
  286. package/dist/run-FmRruANb.mjs +0 -64
  287. package/dist/search-CR_xNArA.mjs +0 -97
  288. package/dist/selectors-C-vgMcGK.mjs +0 -35
  289. package/dist/snippet-DWHTSo9c.mjs +0 -19
  290. package/dist/sync-task-BtDnTXCP.mjs +0 -38
  291. package/dist/table-C6h4tIRw.mjs +0 -37
  292. package/dist/table-I8NXSdUC.mjs +0 -18
  293. package/dist/timeline-B_ESH-6W.mjs +0 -21
  294. package/dist/transform-BNuNiH9d.mjs +0 -28
  295. package/dist/transform-job-B7yc6dfH.mjs +0 -22
  296. package/dist/transform-test-BjjCQ2xm.mjs +0 -169
  297. package/dist/transform-test-C1Oqtfb-.mjs +0 -16
  298. package/dist/transform-test-gzDcbypy.mjs +0 -25
  299. package/dist/transport-CyVo29u7.mjs +0 -313
  300. package/dist/tree-CuyF116R.mjs +0 -26
  301. package/dist/update-l3PyNQKG.mjs +0 -41
  302. package/dist/upload-2YFFBSln.mjs +0 -13
  303. package/skill-data/transform-test-plan/SKILL.md +0 -171
  304. package/skill-data/transform-test-plan/references/checklist.md +0 -81
  305. package/skill-data/transform-test-plan/references/checks.md +0 -263
@@ -1,22 +1,26 @@
1
- import { Q as ConfigError, et as InternalError, it as TimeoutError, rt as ResponseShapeError, st as errorMessage } from "./cli.mjs";
1
+ import { at as ConfigError, ct as NetworkError, ft as ValidationError, lt as ResponseShapeError, mt as formatZodIssue, n as methodRequirements, ot as InternalError, pt as errorMessage, ut as TimeoutError } from "./cli.mjs";
2
2
  import { n as Notification, r as NotificationCardPayload, t as CARD_PAYLOAD_TYPE } from "./notification-DaA4bBHW.mjs";
3
- import { H as parseJsonOrPlain, L as HttpError } from "./runtime-Dtb93zKy.mjs";
4
- import { n as createTransport } from "./transport-CyVo29u7.mjs";
5
- import { a as FieldSearchMatches, i as FieldRemappedValue, l as FieldValues, n as FieldBaseType, o as FieldSemanticType, t as Field } from "./field-CcN4oZy6.mjs";
3
+ import { $ as CapabilityError, B as assertCredentialHeaderSafe, G as normalizeUrl, H as credentialSecrets, I as isRetryableStatus, J as checkFeatures, L as JSON_CONTENT_TYPE, M as buildNetworkError, N as isConnectionClosed, P as HttpError, Q as probeServer, R as parseJson, V as credentialAuthHeader, X as createServerProfile, Z as PROBE_PATH, z as parseJsonOrPlain } from "./runtime-CZ5zh32z.mjs";
4
+ import { n as throwIfAborted, r as untilAborted, t as combineAborts } from "./signal-CxWeLszu.mjs";
5
+ import { f as FieldWithDataSensitivity, h as fieldRemappedValueSchema, m as fieldDetailSchema, n as FieldBaseType, o as FieldSearchMatches, s as FieldSemanticType, u as FieldValues } from "./field-5nivEfd6.mjs";
6
6
  import { a as TemporalUnit, r as ParameterValues } from "./parameter-Celg0wZa.mjs";
7
- import { a as CardQueryResult, l as DatasetQuery, s as CardType, t as Card } from "./card-voh1k4hl.mjs";
8
- import { c as TableVisibilityType, i as TableForeignKey, o as TableQueryMetadata, r as TableDataLayerTier, t as Table } from "./table-DfuY0N8e.mjs";
9
- import { t as Database } from "./database-JtHTqSpq.mjs";
7
+ import { a as CardQueryResult, d as PivotExportFormat, l as DatasetQuery, t as Card } from "./card-Bv4ZN0oV.mjs";
8
+ import { b as TableVisibilityType, p as TableQueryMetadata, s as TableDataLayerTier, t as Table, u as TableForeignKey, v as TableSelectors } from "./table-Ci6bhZkb.mjs";
9
+ import { t as Database } from "./database-D-CRyRIv.mjs";
10
10
  import { t as Snippet } from "./snippet-CyKAgIZl.mjs";
11
- import { c as CollectionItem, i as CollectionAuthorityLevel, m as CollectionTreeNode, r as Collection, s as CollectionId } from "./collection-BxdPxD38.mjs";
11
+ import { o as compiledQuerySchema, r as QueryMetadata } from "./dataset-p5oNPQgL.mjs";
12
+ import { c as CollectionItem, m as CollectionTreeNode, r as Collection } from "./collection-D3KXhvnc.mjs";
12
13
  import { t as ContentTranslationUploadResult } from "./content-translation-BrHOrmj9.mjs";
13
- import { a as DashboardDetail, c as Dashcard, r as DashboardCopy, t as Dashboard } from "./dashboard-D0hwTC-f.mjs";
14
- import { r as pollUntil } from "./poll-KLl4Eq8Y.mjs";
15
- import { t as Document } from "./document-BHpLJbKU.mjs";
14
+ import { l as Dashcard, o as DashboardDetail, r as DashboardCopy, t as Dashboard } from "./dashboard-Phz3XpRM.mjs";
15
+ import { r as pollUntil } from "./poll-Dz4tUm2f.mjs";
16
+ import { i as DependencyEntity, s as DependencyGraph, t as BreakingSource, u as DependencyNode } from "./dependency-DKSjKT8P.mjs";
17
+ import { t as Document } from "./document-DFCj1Az_.mjs";
16
18
  import { i as EidTranslateResult } from "./eid-translation-zEHtr5Oc.mjs";
17
- import { c as SyncSettingsUpdateResult, i as SyncExportPreflight, n as SyncDirtyItem, p as isSyncTaskTerminal, s as SyncRemoteChanges, t as SyncBranchCreated, u as SyncTask } from "./git-sync-BwBRmEhE.mjs";
18
- import { a as toLibrary, i as libraryWireSchema, n as LibraryCollectionInfo } from "./library-BPIzb3K_.mjs";
19
+ import { c as SyncRemoteChanges, d as SyncTask, i as SyncExportPreflight, l as SyncSettingsUpdateResult, m as isSyncTaskTerminal, n as SyncDirtyItem, t as SyncBranchCreated } from "./git-sync-COokpYgc.mjs";
20
+ import { t as Glossary } from "./glossary-BlNCrYbw.mjs";
21
+ import { a as libraryWireSchema, i as LibraryPublishTablesInput, n as LibraryCollectionInfo, o as toLibrary } from "./library-Ck0EK5bi.mjs";
19
22
  import { t as Measure } from "./measure-CtfjqJFP.mjs";
23
+ import { r as ModerationReviewCreateInput, t as ModerationReview } from "./moderation-review-BdqEH6N1.mjs";
20
24
  import { t as Pulse } from "./pulse-Dz0ocv0l.mjs";
21
25
  import { a as TransformDagTransform, d as TransformTarget, g as transformRowSchema, h as transformDetailSchema, i as TransformDagRunResult, l as TransformRunSummary, m as isTransformRunTerminal, o as TransformRun, p as isTransformRunFailed, u as TransformSourceTableEntry } from "./transform-DiW7bREn.mjs";
22
26
  import { r as SearchResult } from "./search-BAXg-EJw.mjs";
@@ -26,9 +30,9 @@ import { n as SetupResult } from "./setup-CO7QV-ao.mjs";
26
30
  import { i as TimelineEvent, t as Timeline } from "./timeline-CCSU2qOS.mjs";
27
31
  import { c as transformJobSchema, n as TransformJobActiveResult, s as transformJobRunResultSchema } from "./transform-job-CCguL6LP.mjs";
28
32
  import { t as TransformTag } from "./transform-tag-CcElGp3C.mjs";
29
- import { i as TransformTestRunResult, t as TransformTest } from "./transform-test-BjjCQ2xm.mjs";
30
33
  import { t as UploadResult } from "./upload-DAtxBBms.mjs";
31
34
  import { z } from "zod";
35
+ import { setTimeout } from "node:timers/promises";
32
36
  //#region \0rolldown/runtime.js
33
37
  var __defProp = Object.defineProperty;
34
38
  var __exportAll = (all, no_symbols) => {
@@ -41,43 +45,324 @@ var __exportAll = (all, no_symbols) => {
41
45
  return target;
42
46
  };
43
47
  //#endregion
44
- //#region ../client/src/domain/dataset.ts
45
- const CompiledQuery = z.object({
46
- query: z.union([z.string(), z.array(z.unknown())]),
47
- params: z.array(z.unknown()).nullable().optional(),
48
- collection: z.string().optional()
49
- }).loose();
50
- const FieldRef = z.tuple([
51
- z.literal("field"),
52
- z.string(),
53
- z.object({ "base-type": FieldBaseType }).loose()
48
+ //#region ../client/src/http/response-shape.ts
49
+ async function parseJsonResponse(text, schema, context) {
50
+ try {
51
+ return parseJson(text, schema, { source: context.url });
52
+ } catch (error) {
53
+ if (error instanceof ValidationError) throw ResponseShapeError.fromZodIssues({
54
+ kind: "zod",
55
+ method: context.method,
56
+ url: context.url,
57
+ status: context.status,
58
+ zodIssues: error.developerDetail.zodIssues,
59
+ serverTag: await context.getServerTag(),
60
+ serverSkew: context.serverSkew
61
+ });
62
+ throw error;
63
+ }
64
+ }
65
+ //#endregion
66
+ //#region ../client/src/http/retry.ts
67
+ const BASE_DELAY_MS = 250;
68
+ const MAX_DELAY_MS = 8e3;
69
+ const MS_PER_SECOND = 1e3;
70
+ function backoffDelay({ attempt, retryAfterHeader }) {
71
+ const fromHeader = parseRetryAfter(retryAfterHeader);
72
+ if (fromHeader !== null) return fromHeader;
73
+ return Math.min(MAX_DELAY_MS, BASE_DELAY_MS * 2 ** attempt);
74
+ }
75
+ function parseRetryAfter(header) {
76
+ if (!header) return null;
77
+ const numeric = Number(header);
78
+ if (Number.isFinite(numeric) && numeric >= 0) return Math.round(numeric * MS_PER_SECOND);
79
+ const dateMs = Date.parse(header);
80
+ if (Number.isFinite(dateMs)) return Math.max(0, dateMs - Date.now());
81
+ return null;
82
+ }
83
+ function sleep(ms, signal) {
84
+ return setTimeout(ms, void 0, { signal });
85
+ }
86
+ async function runWithRetries(attempt, signal) {
87
+ let attemptIndex = 0;
88
+ while (true) {
89
+ const outcome = await attempt(attemptIndex);
90
+ if (outcome.kind === "success") return outcome.response;
91
+ await sleep(outcome.delayMs, signal);
92
+ attemptIndex += 1;
93
+ }
94
+ }
95
+ //#endregion
96
+ //#region ../client/src/http/transport.ts
97
+ const UNAUTHORIZED_STATUS = 401;
98
+ const DEFAULT_TIMEOUT_MS = 3e4;
99
+ const OCTET_STREAM_CONTENT_TYPE = "application/octet-stream";
100
+ const TEXT_CONTENT_TYPE_PREFIX = "text/";
101
+ const ERROR_BODY_BYTE_CAP = 64 * 1024;
102
+ const IDEMPOTENT_METHODS = /* @__PURE__ */ new Set([
103
+ "GET",
104
+ "HEAD",
105
+ "OPTIONS"
54
106
  ]);
55
- const VirtualField = z.object({
56
- id: z.union([z.number().int(), FieldRef]),
57
- table_id: z.string(),
58
- name: z.string(),
59
- display_name: z.string(),
60
- base_type: FieldBaseType,
61
- semantic_type: FieldSemanticType.nullable(),
62
- fk_target_field_id: z.number().int().nullable().optional()
63
- }).loose();
64
- const VirtualTable = z.object({
65
- id: z.string(),
66
- db_id: z.number().int(),
67
- display_name: z.string(),
68
- schema: z.string(),
69
- description: z.string().nullable(),
70
- type: CardType,
71
- moderated_status: z.string().nullable(),
72
- entity_id: z.string().nullable(),
73
- fields: z.array(VirtualField)
74
- }).loose();
75
- const QueryMetadata = z.object({
76
- databases: z.array(Database),
77
- tables: z.array(z.union([TableQueryMetadata, VirtualTable])),
78
- fields: z.array(Field),
79
- snippets: z.array(Snippet)
80
- }).loose();
107
+ function createTransport(config, options) {
108
+ const baseUrl = normalizeUrl(config.url);
109
+ assertCredentialHeaderSafe(config.credential);
110
+ const fetchImpl = options.fetchImpl ?? globalThis.fetch.bind(globalThis);
111
+ let settledProfile = options.server ?? null;
112
+ const getServerTag = options.getServerTag ?? (async () => tagOf(settledProfile));
113
+ const serverSkew = () => settledProfile === null ? null : settledProfile.skew;
114
+ const refreshCredential = options.refreshCredential;
115
+ let credential = config.credential;
116
+ const knownSecrets = new Set(credentialSecrets(credential));
117
+ const redactionContext = { knownSecrets };
118
+ let refreshInFlight = null;
119
+ function tryRefreshCredential() {
120
+ const refresh = refreshCredential;
121
+ if (credential.kind !== "oauth" || refresh === void 0) return Promise.resolve(false);
122
+ refreshInFlight ??= refreshOnce(refresh).finally(() => {
123
+ refreshInFlight = null;
124
+ });
125
+ return refreshInFlight;
126
+ }
127
+ async function refreshOnce(refresh) {
128
+ const next = await refresh();
129
+ if (next === null) return false;
130
+ credential = next;
131
+ for (const secret of credentialSecrets(next)) knownSecrets.add(secret);
132
+ return true;
133
+ }
134
+ async function attemptOnce(prepared, attempt) {
135
+ const hasRetriesLeft = attempt < prepared.retries;
136
+ const timeoutSignal = AbortSignal.timeout(prepared.timeoutMs);
137
+ const combined = combineAborts(timeoutSignal, prepared.cancelSignal);
138
+ let response;
139
+ try {
140
+ response = await fetchImpl(prepared.url, {
141
+ method: prepared.method,
142
+ headers: prepared.headers,
143
+ body: prepared.body,
144
+ signal: combined
145
+ });
146
+ } catch (error) {
147
+ throwIfAborted(prepared.cancelSignal);
148
+ const isStaleSocketFirstTry = attempt === 0 && isConnectionClosed(error);
149
+ if (prepared.idempotent && (hasRetriesLeft || isStaleSocketFirstTry)) return {
150
+ kind: "retry",
151
+ delayMs: backoffDelay({ attempt })
152
+ };
153
+ if (timeoutSignal.aborted) throw new TimeoutError(`Request timed out after ${prepared.timeoutMs}ms`, {
154
+ kind: "http",
155
+ method: prepared.method,
156
+ url: prepared.url,
157
+ timeoutMs: prepared.timeoutMs
158
+ });
159
+ throw buildNetworkError(error, prepared.method, prepared.url);
160
+ }
161
+ const canRetryStatus = hasRetriesLeft && prepared.idempotent;
162
+ if (!response.ok && isRetryableStatus(response.status) && canRetryStatus) {
163
+ const retryAfter = response.headers.get("Retry-After");
164
+ response.body?.cancel().catch(() => void 0);
165
+ return {
166
+ kind: "retry",
167
+ delayMs: backoffDelay({
168
+ attempt,
169
+ retryAfterHeader: retryAfter
170
+ })
171
+ };
172
+ }
173
+ if (!response.ok) {
174
+ const rawBody = await readBodyForError(response);
175
+ const serverTag = await getServerTag();
176
+ throw new HttpError({
177
+ status: response.status,
178
+ statusText: response.statusText,
179
+ method: prepared.method,
180
+ url: prepared.url,
181
+ responseHeaders: response.headers,
182
+ rawBody,
183
+ serverTag,
184
+ redactionContext
185
+ });
186
+ }
187
+ assertContentType(response, prepared);
188
+ return {
189
+ kind: "success",
190
+ response
191
+ };
192
+ }
193
+ async function executeRaw(prepared) {
194
+ try {
195
+ return await runWithRetries((attempt) => attemptOnce(prepared, attempt), prepared.cancelSignal);
196
+ } catch (error) {
197
+ throwIfAborted(prepared.cancelSignal);
198
+ throw error;
199
+ }
200
+ }
201
+ async function executeWithAuthRefresh(path, opts) {
202
+ const prepared = prepare(path, opts);
203
+ try {
204
+ return {
205
+ response: await executeRaw(prepared),
206
+ prepared
207
+ };
208
+ } catch (error) {
209
+ if (error instanceof HttpError && error.status === UNAUTHORIZED_STATUS) {
210
+ if (await tryRefreshCredential()) {
211
+ const retried = prepare(path, opts);
212
+ return {
213
+ response: await executeRaw(retried),
214
+ prepared: retried
215
+ };
216
+ }
217
+ }
218
+ throw error;
219
+ }
220
+ }
221
+ function prepare(path, opts = {}) {
222
+ const method = opts.method ?? "GET";
223
+ const expectContentType = opts.expectContentType ?? "json";
224
+ const url = buildUrl(baseUrl, path, opts.query);
225
+ const headers = new Headers();
226
+ const auth = credentialAuthHeader(credential);
227
+ headers.set(auth.name, auth.value);
228
+ headers.set("accept", acceptHeader(expectContentType));
229
+ headers.set("user-agent", options.userAgent);
230
+ let body = null;
231
+ if (opts.body !== void 0 && opts.body !== null) if (typeof opts.body === "string" || opts.body instanceof URLSearchParams) body = opts.body;
232
+ else if (opts.body instanceof FormData || opts.body instanceof ReadableStream) body = opts.body;
233
+ else if (opts.body instanceof Uint8Array) {
234
+ body = opts.body;
235
+ headers.set("content-type", OCTET_STREAM_CONTENT_TYPE);
236
+ } else {
237
+ body = JSON.stringify(opts.body);
238
+ headers.set("content-type", JSON_CONTENT_TYPE);
239
+ }
240
+ return {
241
+ url,
242
+ method,
243
+ headers,
244
+ body,
245
+ expectContentType,
246
+ retries: opts.retries ?? 3,
247
+ idempotent: opts.idempotent ?? IDEMPOTENT_METHODS.has(method),
248
+ timeoutMs: opts.timeoutMs ?? DEFAULT_TIMEOUT_MS,
249
+ cancelSignal: combineAborts(opts.signal, options.signal)
250
+ };
251
+ }
252
+ let serverProfile = options.server === void 0 ? null : Promise.resolve(options.server);
253
+ async function server(wait = {}) {
254
+ throwIfAborted(wait.signal);
255
+ if (serverProfile === null) {
256
+ const probe = probeServer(transport).then((info) => {
257
+ settledProfile = createServerProfile(info);
258
+ return settledProfile;
259
+ });
260
+ probe.catch(() => {
261
+ serverProfile = null;
262
+ });
263
+ serverProfile = probe;
264
+ }
265
+ return untilAborted(serverProfile, wait.signal);
266
+ }
267
+ const enforceRequirements = options.enforceRequirements ?? true;
268
+ async function requireFeatures(features, wait = {}) {
269
+ if (!enforceRequirements || features.length === 0) return;
270
+ const failure = checkFeatures(features, await server(wait));
271
+ if (failure !== null) throw new CapabilityError(failure);
272
+ }
273
+ async function requireMethod(key, wait = {}) {
274
+ return requireFeatures(methodRequirements(key), wait);
275
+ }
276
+ const transport = {
277
+ server,
278
+ require: requireMethod,
279
+ requireFeatures,
280
+ async requestRaw(path, opts) {
281
+ return (await executeWithAuthRefresh(path, opts ?? {})).response;
282
+ },
283
+ async requestParsed(schema, path, opts) {
284
+ const { response, prepared } = await executeWithAuthRefresh(path, {
285
+ ...opts,
286
+ expectContentType: "json"
287
+ });
288
+ return parseJsonResponse(await response.text(), schema, {
289
+ method: prepared.method,
290
+ url: prepared.url,
291
+ status: response.status,
292
+ getServerTag,
293
+ serverSkew: serverSkew()
294
+ });
295
+ },
296
+ async requestStream(path, opts) {
297
+ const { response, prepared } = await executeWithAuthRefresh(path, {
298
+ ...opts,
299
+ expectContentType: opts?.expectContentType ?? "binary"
300
+ });
301
+ if (!response.body) throw new NetworkError("Response had no body to stream", {
302
+ method: prepared.method,
303
+ url: prepared.url,
304
+ cause: "missing body"
305
+ });
306
+ return response.body;
307
+ }
308
+ };
309
+ return transport;
310
+ }
311
+ function tagOf(profile) {
312
+ return profile === null ? null : profile.version.tag;
313
+ }
314
+ function buildUrl(baseUrl, path, query) {
315
+ const normalizedPath = path.startsWith("/") ? path : `/${path}`;
316
+ const target = new URL(baseUrl + normalizedPath);
317
+ if (query) for (const [key, value] of Object.entries(query)) {
318
+ if (value === void 0) continue;
319
+ if (Array.isArray(value)) for (const entry of value) target.searchParams.append(key, String(entry));
320
+ else target.searchParams.append(key, String(value));
321
+ }
322
+ return target.toString();
323
+ }
324
+ function acceptHeader(expected) {
325
+ if (expected === "json") return JSON_CONTENT_TYPE;
326
+ if (expected === "text") return "text/*";
327
+ return "*/*";
328
+ }
329
+ function assertContentType(response, prepared) {
330
+ if (prepared.expectContentType === "binary") return;
331
+ const contentType = response.headers.get("content-type");
332
+ if (contentType === null) throwContentTypeMismatch(response, prepared, prepared.expectContentType);
333
+ if (prepared.expectContentType === "json" && !contentType.includes("application/json")) throwContentTypeMismatch(response, prepared, "json");
334
+ if (prepared.expectContentType === "text" && !contentType.startsWith(TEXT_CONTENT_TYPE_PREFIX)) throwContentTypeMismatch(response, prepared, "text");
335
+ }
336
+ function throwContentTypeMismatch(response, prepared, expected) {
337
+ const actual = response.headers.get("content-type") ?? "no content-type";
338
+ throw new HttpError({
339
+ status: response.status,
340
+ statusText: response.statusText,
341
+ method: prepared.method,
342
+ url: prepared.url,
343
+ responseHeaders: response.headers,
344
+ rawBody: null,
345
+ overrideUserMessage: `Expected ${expected} response but got ${actual}`
346
+ });
347
+ }
348
+ async function readBodyForError(response) {
349
+ try {
350
+ return Buffer.from(await response.arrayBuffer()).subarray(0, ERROR_BODY_BYTE_CAP).toString("utf8");
351
+ } catch (error) {
352
+ return `[body read failed: ${errorMessage(error)}]`;
353
+ }
354
+ }
355
+ //#endregion
356
+ //#region ../client/src/resources/pivot-export.ts
357
+ const PivotedExportsSetting = z.object({ "enable-pivoted-exports": z.boolean() });
358
+ /**
359
+ * Refuse a pivoted export the server would answer with plain rows: a JSON export keeps only the
360
+ * ungrouped rows, and an admin can turn pivoted CSV and XLSX exports off.
361
+ */
362
+ async function assertPivotedExport(transport, format, options) {
363
+ if (!PivotExportFormat.safeParse(format).success) throw new ConfigError(`a ${format} export cannot be pivoted; only ${PivotExportFormat.options.join(" and ")} can`);
364
+ if (!(await transport.requestParsed(PivotedExportsSetting, "/api/session/properties", { ...options }))["enable-pivoted-exports"]) throw new ConfigError("the server has pivoted exports turned off (the enable-pivoted-exports setting), so it would export the plain rows");
365
+ }
81
366
  //#endregion
82
367
  //#region ../client/src/resources/card.ts
83
368
  const CardApiList = z.array(Card);
@@ -134,15 +419,22 @@ function cardResource(transport) {
134
419
  });
135
420
  }
136
421
  /**
137
- * Run a saved card and stream its result as a download. Unlike `query`, this endpoint takes a
138
- * form-encoded body and answers bytes, so a caller consumes the stream rather than a value.
422
+ * Run the query associated with a Card, and return its results as a file in the specified
423
+ * format. Unlike `query`, this endpoint takes a form-encoded body and answers bytes, so a caller
424
+ * consumes the stream rather than a value. A pivot the server would answer with plain rows (a
425
+ * JSON export, or pivoted exports turned off) is refused. `csv_include_bom` opens a CSV with a
426
+ * UTF-8 byte order mark; a server without it drops the key silently, so asking for one is refused
427
+ * there before the wire.
139
428
  */
140
429
  async function exportQuery(id, format, params, options = {}) {
141
430
  await transport.require("card.exportQuery", options);
431
+ await transport.requireFeatures(params.csv_include_bom ? ["exportCsvByteOrderMark"] : [], options);
432
+ if (params.pivot_results) await assertPivotedExport(transport, format, options);
142
433
  const body = new URLSearchParams({
143
434
  parameters: JSON.stringify(params.parameters),
144
435
  format_rows: String(params.format_rows),
145
- pivot_results: String(params.pivot_results)
436
+ pivot_results: String(params.pivot_results),
437
+ csv_include_bom: String(params.csv_include_bom)
146
438
  });
147
439
  return transport.requestStream(`/api/card/${id}/query/${format}`, {
148
440
  ...options,
@@ -226,20 +518,20 @@ function refPath(ref) {
226
518
  return encodeURIComponent(ref);
227
519
  }
228
520
  /**
229
- * List collections including the Library and its children, parsing each through the caller's own
230
- * projection. `Collection` pins `type`, `namespace` and `authority_level` to closed enums, so a
231
- * consumer reading a few fields off every collection on the instance narrows here: one collection
232
- * carrying a server value outside those sets then costs nothing to a caller that never reads the
233
- * field.
521
+ * List every collection the caller can read, the Library and its children among them, parsing each
522
+ * through the caller's own projection. `Collection` pins `type`, `namespace` and `authority_level`
523
+ * to closed enums, so a consumer reading a few fields off every collection on the instance narrows
524
+ * here: one collection carrying a server value outside those sets then costs nothing to a caller
525
+ * that never reads the field.
234
526
  */
235
- async function listCollectionsWithLibrary(transport, schema, options = {}) {
236
- return transport.requestParsed(z.array(schema), "/api/collection", {
237
- ...options,
238
- query: { "include-library": true }
239
- });
527
+ async function listCollectionsAs(transport, schema, options = {}) {
528
+ return transport.requestParsed(z.array(schema), "/api/collection", { ...options });
240
529
  }
241
530
  function collectionResource(transport) {
242
- /** List collections. `filter` picks a server-side preset: everything, archived, or personal. */
531
+ /**
532
+ * List collections. `filter` picks a server-side preset: everything, archived, or personal. Every
533
+ * preset includes the Library collections that match it.
534
+ */
243
535
  async function list(params = {}, options = {}) {
244
536
  await transport.require("collection.list", options);
245
537
  return {
@@ -250,18 +542,6 @@ function collectionResource(transport) {
250
542
  total: null
251
543
  };
252
544
  }
253
- /**
254
- * List collections including the Library and its children, which the plain listing omits.
255
- * The Library's own children carry neither `type` nor `is_remote_synced`, so this is where a
256
- * caller resolves both.
257
- */
258
- async function listWithLibrary(options = {}) {
259
- await transport.require("collection.listWithLibrary", options);
260
- return {
261
- data: await listCollectionsWithLibrary(transport, Collection, options),
262
- total: null
263
- };
264
- }
265
545
  /** Get one collection by id, entity id, or the `root`/`trash` alias. */
266
546
  async function get(ref, options = {}) {
267
547
  await transport.require("collection.get", options);
@@ -276,7 +556,11 @@ function collectionResource(transport) {
276
556
  body: params
277
557
  });
278
558
  }
279
- /** Update a collection, patching only the fields the body carries. */
559
+ /**
560
+ * Update a collection, patching the fields the body carries. The server reads an absent
561
+ * `archived` as `false`, so a patch without it restores an archived collection, and a patch that
562
+ * moves a collection into the trash ignores `parent_id`.
563
+ */
280
564
  async function update(ref, params, options = {}) {
281
565
  await transport.require("collection.update", options);
282
566
  return transport.requestParsed(Collection, `/api/collection/${refPath(ref)}`, {
@@ -309,16 +593,18 @@ function collectionResource(transport) {
309
593
  });
310
594
  }
311
595
  /** Fetch the collection hierarchy as a forest of nested nodes. */
312
- async function tree(options = {}) {
596
+ async function tree(params = {}, options = {}) {
313
597
  await transport.require("collection.tree", options);
314
598
  return {
315
- data: await transport.requestParsed(CollectionTreeApiList, "/api/collection/tree", { ...options }),
599
+ data: await transport.requestParsed(CollectionTreeApiList, "/api/collection/tree", {
600
+ ...options,
601
+ query: { "include-library": params["include-library"] }
602
+ }),
316
603
  total: null
317
604
  };
318
605
  }
319
606
  return {
320
607
  list,
321
- listWithLibrary,
322
608
  get,
323
609
  create,
324
610
  update,
@@ -407,9 +693,13 @@ function dashboardResource(transport) {
407
693
  }
408
694
  /**
409
695
  * Copy a dashboard, with its tabs and dashcards, into `collection_id` (root when absent). A deep
410
- * copy duplicates the cards it can; otherwise the copy references them, except dashboard
411
- * questions, which are always duplicated. Cards the caller cannot read are left behind and
412
- * reported as `uncopied`.
696
+ * copy duplicates its questions and metrics and references its models. With `is_deep_copy`
697
+ * false or absent the copy references every card, and a dashboard holding unarchived dashboard
698
+ * questions is refused. Archived cards, cards the caller cannot read, and every card on a
699
+ * dashcard whose main card the caller cannot read are left out and reported as `uncopied`, once
700
+ * per dashcard they sat on. A left-out main card takes its dashcard with it; a left-out series
701
+ * card stays on a dashcard whose main card is referenced and is dropped from one whose main card
702
+ * is duplicated. Action, link and placeholder dashcards are not copied.
413
703
  */
414
704
  async function copy(id, params = {}, options = {}) {
415
705
  await transport.require("dashboard.copy", options);
@@ -663,7 +953,8 @@ function datasetResource(transport) {
663
953
  */
664
954
  async function native(datasetQuery, params = {}, options = {}) {
665
955
  await transport.require("dataset.native", options);
666
- return transport.requestParsed(CompiledQuery, "/api/dataset/native", {
956
+ const { features } = await transport.server(options);
957
+ return transport.requestParsed(compiledQuerySchema(features), "/api/dataset/native", {
667
958
  ...options,
668
959
  method: "POST",
669
960
  body: {
@@ -686,18 +977,33 @@ function datasetResource(transport) {
686
977
  });
687
978
  }
688
979
  /**
689
- * Run an ad-hoc query and stream its result as a download. Unlike `query`, this endpoint answers
690
- * bytes, so a caller consumes the stream rather than a value.
980
+ * Execute a query and download the result data as a file in the specified format. Unlike
981
+ * `query`, this endpoint answers bytes, so a caller consumes the stream rather than a value.
982
+ * `visualization_settings` drive `format_rows` column formatting and, through
983
+ * `pivot_table.column_split`, the layout `pivot_results` lays the rows out in. The server only
984
+ * computes that layout for a query it runs as a pivot, which it reads from the query's own
985
+ * `was-pivot`, so `pivot_results` sets it. A pivot the server would answer with plain rows (a
986
+ * JSON export, or pivoted exports turned off) is refused. `csv_include_bom` opens a CSV with a
987
+ * UTF-8 byte order mark; a server without it drops the key silently, so asking for one is refused
988
+ * there before the wire.
691
989
  */
692
990
  async function exportQuery(format, params, options = {}) {
693
991
  await transport.require("dataset.exportQuery", options);
992
+ await transport.requireFeatures(params.csv_include_bom ? ["exportCsvByteOrderMark"] : [], options);
993
+ if (params.pivot_results) await assertPivotedExport(transport, format, options);
994
+ const exported = params.pivot_results ? {
995
+ ...params.query,
996
+ "was-pivot": true
997
+ } : params.query;
694
998
  return transport.requestStream(`/api/dataset/${format}`, {
695
999
  ...options,
696
1000
  method: "POST",
697
1001
  body: {
698
- query: params.query,
1002
+ query: exported,
1003
+ visualization_settings: params.visualization_settings,
699
1004
  format_rows: params.format_rows,
700
- pivot_results: params.pivot_results
1005
+ pivot_results: params.pivot_results,
1006
+ csv_include_bom: params.csv_include_bom
701
1007
  }
702
1008
  });
703
1009
  }
@@ -709,133 +1015,18 @@ function datasetResource(transport) {
709
1015
  };
710
1016
  }
711
1017
  //#endregion
712
- //#region ../client/src/domain/dependency.ts
713
- const DependencyType = z.enum([
714
- "table",
715
- "card",
716
- "snippet",
717
- "transform",
718
- "dashboard",
719
- "document",
720
- "sandbox",
721
- "segment",
722
- "measure"
723
- ]);
724
- const DependencyUsageType = z.enum([
725
- "table",
726
- "snippet",
727
- "transform",
728
- "dashboard",
729
- "document",
730
- "sandbox",
731
- "segment",
732
- "question",
733
- "model",
734
- "metric",
735
- "measure"
736
- ]);
737
- const DependencyFindingErrorType = z.enum([
738
- "missing-column",
739
- "missing-table-alias",
740
- "missing-table",
741
- "missing-card",
742
- "duplicate-column",
743
- "syntax-error",
744
- "validation-exception-error"
745
- ]);
746
- const DependencyErrorSourceType = z.enum([
747
- "table",
748
- "card",
749
- "transform"
750
- ]);
751
- z.enum([
752
- "name",
753
- "location",
754
- "view-count"
755
- ]);
756
- z.enum([
757
- "name",
758
- "location",
759
- "dependents-with-errors",
760
- "dependents-errors"
761
- ]);
762
- const DependencyCollectionRef = z.object({
763
- id: CollectionId,
764
- name: z.string(),
765
- authority_level: CollectionAuthorityLevel.nullable(),
766
- is_personal: z.boolean().optional()
767
- }).loose();
768
- const DependencyContainerRef = z.object({
769
- id: z.number().int(),
770
- name: z.string()
771
- }).loose();
772
- const DependencyEntityData = z.object({
773
- name: z.string().nullable().optional(),
774
- display_name: z.string().nullable().optional(),
775
- description: z.string().nullable().optional(),
776
- type: CardType.nullable().optional(),
777
- display: z.string().nullable().optional(),
778
- database_id: z.number().int().nullable().optional(),
779
- db_id: z.number().int().nullable().optional(),
780
- schema: z.string().nullable().optional(),
781
- collection_id: CollectionId.nullable().optional(),
782
- collection: DependencyCollectionRef.nullable().optional(),
783
- dashboard_id: z.number().int().nullable().optional(),
784
- dashboard: DependencyContainerRef.nullable().optional(),
785
- document_id: z.number().int().nullable().optional(),
786
- document: DependencyContainerRef.nullable().optional(),
787
- table_id: z.number().int().nullable().optional(),
788
- view_count: z.number().int().nullable().optional()
789
- }).loose();
790
- const DependencyEntity = z.object({
791
- id: z.number().int(),
792
- type: DependencyType,
793
- data: DependencyEntityData
794
- }).loose();
795
- const DependencyNode = DependencyEntity.extend({ dependents_count: z.partialRecord(DependencyUsageType, z.number().int()).nullable() });
796
- const DependencyFindingError = z.object({
797
- id: z.number().int(),
798
- analyzed_entity_type: DependencyType,
799
- analyzed_entity_id: z.number().int(),
800
- error_type: DependencyFindingErrorType,
801
- error_detail: z.string().nullable().optional(),
802
- source_entity_type: DependencyErrorSourceType.nullable().optional(),
803
- source_entity_id: z.number().int().nullable().optional()
804
- }).loose();
805
- const BreakingSource = DependencyNode.extend({ dependents_errors: z.array(DependencyFindingError).nullable().optional() });
806
- const DependencyEdge = z.object({
807
- from_entity_type: DependencyType,
808
- from_entity_id: z.number().int(),
809
- to_entity_type: DependencyType,
810
- to_entity_id: z.number().int()
811
- }).loose();
812
- const DependencyGraph = z.object({
813
- nodes: z.array(DependencyNode),
814
- edges: z.array(DependencyEdge)
815
- }).loose();
816
- //#endregion
817
1018
  //#region ../client/src/resources/dependency.ts
818
1019
  const DependencyNodeApiList = z.array(DependencyNode);
819
1020
  const DependencyEntityApiList = z.array(DependencyEntity);
820
- const RENAMED_FILTERS = [
821
- "dependent-types",
822
- "dependent-card-types",
823
- "card-types",
824
- "include-personal-collections",
825
- "sort-column",
826
- "sort-direction"
827
- ];
828
- function filterFeatures(params) {
829
- return RENAMED_FILTERS.some((key) => params[key] !== void 0) ? ["dependencyKebabCaseFilters"] : [];
830
- }
831
1021
  function dependencyResource(transport) {
832
1022
  /**
833
1023
  * The upstream dependency graph of one entity. `nodes` holds the starting entity plus every
834
1024
  * entity it depends on, directly or transitively; each edge runs from the dependent to what it
835
- * depends on.
1025
+ * depends on. A measure starts a graph only on a server with `measureDependencyGraph`.
836
1026
  */
837
1027
  async function graph(type, id, options = {}) {
838
1028
  await transport.require("dependency.graph", options);
1029
+ if (type === "measure") await transport.requireFeatures(["measureDependencyGraph"], options);
839
1030
  return transport.requestParsed(DependencyGraph, "/api/ee/dependencies/graph", {
840
1031
  ...options,
841
1032
  query: {
@@ -852,7 +1043,6 @@ function dependencyResource(transport) {
852
1043
  */
853
1044
  async function dependents(type, id, params = {}, options = {}) {
854
1045
  await transport.require("dependency.dependents", options);
855
- await transport.requireFeatures(filterFeatures(params), options);
856
1046
  return {
857
1047
  data: await transport.requestParsed(DependencyNodeApiList, "/api/ee/dependencies/graph/dependents", {
858
1048
  ...options,
@@ -879,7 +1069,6 @@ function dependencyResource(transport) {
879
1069
  */
880
1070
  async function broken(type, id, params = {}, options = {}) {
881
1071
  await transport.require("dependency.broken", options);
882
- await transport.requireFeatures(filterFeatures(params), options);
883
1072
  return {
884
1073
  data: await transport.requestParsed(DependencyEntityApiList, "/api/ee/dependencies/graph/broken", {
885
1074
  ...options,
@@ -897,15 +1086,23 @@ function dependencyResource(transport) {
897
1086
  };
898
1087
  }
899
1088
  /**
900
- * Walk the entities nothing depends on, one page at a time. `types` and `card-types` narrow
901
- * which kinds are listed, `query` matches against names and locations,
1089
+ * Walk the entities that no readable, unarchived dependent depends on, one page at a time: an
1090
+ * entity used only by archived content, or by content the caller cannot read, is listed. `types`
1091
+ * and `card-types` narrow which kinds are listed, `query` matches against names and locations,
902
1092
  * `include-personal-collections` admits content in personal collections, and `sort-column` /
903
- * `sort-direction` order the result. This endpoint pages on the server, so the caller consumes
904
- * pages and decides how far to pull.
1093
+ * `sort-direction` order the result. A `query` leaves sandboxes out, since they have no name or
1094
+ * location to match, so sandboxes alone with a `query` answer one empty page without a request.
1095
+ * This endpoint pages on the server, so the caller consumes pages and decides how far to pull.
905
1096
  */
906
1097
  async function* unreferencedPages(params = {}, options = {}) {
907
1098
  await transport.require("dependency.unreferencedPages", options);
908
- await transport.requireFeatures(filterFeatures(params), options);
1099
+ if (queryLeavesNoKind(params)) {
1100
+ yield {
1101
+ items: [],
1102
+ total: 0
1103
+ };
1104
+ return;
1105
+ }
909
1106
  yield* paginatePages(transport, "/api/ee/dependencies/graph/unreferenced", DependencyNode, {
910
1107
  query: itemListQuery(params),
911
1108
  ...options.offset !== void 0 && { offset: options.offset },
@@ -923,7 +1120,13 @@ function dependencyResource(transport) {
923
1120
  */
924
1121
  async function* breakingPages(params = {}, options = {}) {
925
1122
  await transport.require("dependency.breakingPages", options);
926
- await transport.requireFeatures(filterFeatures(params), options);
1123
+ if (queryLeavesNoKind(params)) {
1124
+ yield {
1125
+ items: [],
1126
+ total: 0
1127
+ };
1128
+ return;
1129
+ }
927
1130
  yield* paginatePages(transport, "/api/ee/dependencies/graph/breaking", BreakingSource, {
928
1131
  query: itemListQuery(params),
929
1132
  ...options.offset !== void 0 && { offset: options.offset },
@@ -940,9 +1143,14 @@ function dependencyResource(transport) {
940
1143
  breakingPages
941
1144
  };
942
1145
  }
1146
+ function queryLeavesNoKind(params) {
1147
+ const { query, types } = params;
1148
+ if (query === void 0 || types === void 0 || types.length === 0) return false;
1149
+ return types.every((type) => type === "sandbox");
1150
+ }
943
1151
  function itemListQuery(params) {
944
1152
  return {
945
- types: params.types,
1153
+ types: params.types === void 0 ? void 0 : [...new Set(params.types)],
946
1154
  "card-types": params["card-types"],
947
1155
  query: params.query,
948
1156
  "include-personal-collections": params["include-personal-collections"],
@@ -1109,21 +1317,39 @@ async function fetchOptionalParsed(client, path, schema, options = {}) {
1109
1317
  //#region ../client/src/resources/field.ts
1110
1318
  const FieldApiSummary = z.tuple([z.tuple([z.literal("count"), z.number().int()]), z.tuple([z.literal("distincts"), z.number().int()])]);
1111
1319
  function fieldResource(transport) {
1112
- /** Get one field by id. */
1320
+ /**
1321
+ * Get one field by id. A server that labels data sensitivity answers `data_sensitivity`, `null`
1322
+ * for an unlabelled field; any other answers the field without the key (`hasDataSensitivity`).
1323
+ */
1113
1324
  async function get(id, options = {}) {
1114
1325
  await transport.require("field.get", options);
1115
- return transport.requestParsed(Field, `/api/field/${id}`, { ...options });
1326
+ const { features } = await transport.server(options);
1327
+ return transport.requestParsed(fieldDetailSchema(features), `/api/field/${id}`, { ...options });
1116
1328
  }
1117
1329
  /**
1118
1330
  * Update a field by id, patching only the fields the body carries. A `data_sensitivity` label is
1119
1331
  * a person's call the server's classifier never overwrites, and `null` withdraws it so the
1120
1332
  * classifier's own applies again; a server without the column would drop the key silently, so
1121
- * the label is refused there before the wire.
1333
+ * the label is refused there before the wire. Answers the field the way `get` does.
1122
1334
  */
1123
1335
  async function update(id, params, options = {}) {
1124
1336
  await transport.require("field.update", options);
1125
1337
  await transport.requireFeatures(params.data_sensitivity === void 0 ? [] : ["fieldDataSensitivity"], options);
1126
- return transport.requestParsed(Field, `/api/field/${id}`, {
1338
+ const { features } = await transport.server(options);
1339
+ return transport.requestParsed(fieldDetailSchema(features), `/api/field/${id}`, {
1340
+ ...options,
1341
+ method: "PUT",
1342
+ body: params
1343
+ });
1344
+ }
1345
+ /**
1346
+ * Label a field's data sensitivity by hand. A person's label is never overwritten by the server's
1347
+ * classifier; `null` withdraws it, so whatever label the classifier wrote shows again. Answers
1348
+ * the field with the label it now carries.
1349
+ */
1350
+ async function setDataSensitivity(id, params, options = {}) {
1351
+ await transport.require("field.setDataSensitivity", options);
1352
+ return transport.requestParsed(FieldWithDataSensitivity, `/api/field/${id}`, {
1127
1353
  ...options,
1128
1354
  method: "PUT",
1129
1355
  body: params
@@ -1131,8 +1357,11 @@ function fieldResource(transport) {
1131
1357
  }
1132
1358
  /**
1133
1359
  * Search the values of `searchId` that contain `value`, case-insensitively, answering the
1134
- * matching values of `id` paired with them. An FK on either side is followed to the PK it
1135
- * points at. Without `value`, the first `limit` values.
1360
+ * matching values of `id` paired with them, ordered by value, at most `limit` of them. An FK on
1361
+ * either side is followed to the PK it points at, and a field that resolves to the same field as
1362
+ * `searchId` answers each value alone. Without `value`, the first `limit` values. A field with
1363
+ * custom display values answers every mapped value with its display value instead, matching
1364
+ * `value` against the display value, ignoring both `searchId` and `limit`.
1136
1365
  */
1137
1366
  async function search(id, searchId, params, options = {}) {
1138
1367
  await transport.require("field.search", options);
@@ -1146,11 +1375,13 @@ function fieldResource(transport) {
1146
1375
  }
1147
1376
  /**
1148
1377
  * The value of `remappedId` on the one row where `id` equals `value`, as `[value, remapped]`,
1149
- * or `null` when no row matches. `value` is parsed as a number for a numeric field.
1378
+ * or `null` when no row matches. For a numeric field the server reads the leading number of
1379
+ * `value` and ignores any text after it, refusing only a `value` that has none.
1150
1380
  */
1151
1381
  async function remapping(id, remappedId, params, options = {}) {
1152
1382
  await transport.require("field.remapping", options);
1153
- return fetchOptionalParsed(transport, `/api/field/${id}/remapping/${remappedId}`, FieldRemappedValue, {
1383
+ const { features } = await transport.server(options);
1384
+ return fetchOptionalParsed(transport, `/api/field/${id}/remapping/${remappedId}`, fieldRemappedValueSchema(features, id === remappedId), {
1154
1385
  ...options,
1155
1386
  query: { value: params.value }
1156
1387
  });
@@ -1173,6 +1404,7 @@ function fieldResource(transport) {
1173
1404
  return {
1174
1405
  get,
1175
1406
  update,
1407
+ setDataSensitivity,
1176
1408
  search,
1177
1409
  remapping,
1178
1410
  summary,
@@ -1204,6 +1436,7 @@ const SyncStashStarted = z.object({
1204
1436
  task_id: z.number().int().positive()
1205
1437
  });
1206
1438
  const RemoteSyncSetting = z.string().nullable();
1439
+ const RemoteSyncBranchProperty = z.object({ "remote-sync-branch": z.string().nullable().optional() });
1207
1440
  const FORBIDDEN_STATUS = 403;
1208
1441
  const UNREGISTERED_STATUS = 404;
1209
1442
  function isRemoteUnreadable(error) {
@@ -1251,16 +1484,24 @@ function gitSyncResource(transport) {
1251
1484
  /**
1252
1485
  * Import content from the remote into Metabase. The endpoint queues a task and returns at once;
1253
1486
  * pass `wait` to poll that task until it reaches a terminal status. A server already up to date
1254
- * answers no task id, and there is then nothing to poll.
1487
+ * answers no task id, and there is then nothing to poll. A server that guards the tracked branch
1488
+ * refuses with 409 when `expected_branch` disagrees with the setting; left out, it is the tracked
1489
+ * branch as read just before the request. `merge` folds the remote's changes into local content
1490
+ * by a three-way merge and keeps un-pushed local changes, where a plain import refuses on a dirty
1491
+ * instance.
1255
1492
  */
1256
1493
  async function importFromRemote(params = {}, options = {}) {
1257
1494
  await transport.require("gitSync.import", options);
1495
+ await requireMerge(params.merge, options);
1496
+ const expectedBranch = await guardedBranch(params.expected_branch, options);
1258
1497
  const started = await transport.requestParsed(SyncImportStarted, "/api/ee/remote-sync/import", {
1259
1498
  ...options,
1260
1499
  method: "POST",
1261
1500
  body: {
1262
1501
  branch: params.branch,
1263
- force: params.force
1502
+ force: params.force,
1503
+ merge: params.merge,
1504
+ expected_branch: expectedBranch
1264
1505
  }
1265
1506
  });
1266
1507
  const message = started.message ?? null;
@@ -1274,19 +1515,36 @@ function gitSyncResource(transport) {
1274
1515
  final: await settle(params.wait, options)
1275
1516
  };
1276
1517
  }
1518
+ async function requireMerge(merge, options) {
1519
+ if (merge === true) await transport.requireFeatures(["remoteSyncMerge"], options);
1520
+ }
1521
+ async function guardedBranch(given, options) {
1522
+ if (given !== void 0) return given;
1523
+ const { features } = await transport.server(options);
1524
+ if (!features.remoteSyncBranchGuard) return;
1525
+ return trackedBranch(options);
1526
+ }
1277
1527
  /**
1278
1528
  * Export Metabase's content to the remote. The endpoint queues a task and returns at once; pass
1279
- * `wait` to poll that task until it reaches a terminal status.
1529
+ * `wait` to poll that task until it reaches a terminal status. A server that guards the tracked
1530
+ * branch refuses with 409 when `branch` is not the tracked one; left out, it is the tracked branch
1531
+ * as read just before the request there, and the server's own default elsewhere. When the remote
1532
+ * has moved past the last sync, a plain export ends in a `conflict` task where `merge` is
1533
+ * available, and is refused with 400 before any task elsewhere; `merge` folds the remote's changes
1534
+ * in by a three-way merge instead, and `force` overwrites them.
1280
1535
  */
1281
1536
  async function exportToRemote(params = {}, options = {}) {
1282
1537
  await transport.require("gitSync.export", options);
1538
+ await requireMerge(params.merge, options);
1539
+ const branchName = await guardedBranch(params.branch, options);
1283
1540
  const started = await transport.requestParsed(SyncExportStarted, "/api/ee/remote-sync/export", {
1284
1541
  ...options,
1285
1542
  method: "POST",
1286
1543
  body: {
1287
- branch: params.branch,
1544
+ branch: branchName,
1288
1545
  message: params.message,
1289
- force: params.force
1546
+ force: params.force,
1547
+ merge: params.merge
1290
1548
  }
1291
1549
  });
1292
1550
  if (params.wait === void 0) return {
@@ -1371,7 +1629,7 @@ function gitSyncResource(transport) {
1371
1629
  async function syncedCollections(options = {}) {
1372
1630
  await transport.require("gitSync.syncedCollections", options);
1373
1631
  return {
1374
- data: (await listCollectionsWithLibrary(transport, SyncScopeCollection, options)).filter((entry) => entry.is_remote_synced === true),
1632
+ data: (await listCollectionsAs(transport, SyncScopeCollection, options)).filter((entry) => entry.is_remote_synced === true),
1375
1633
  total: null
1376
1634
  };
1377
1635
  }
@@ -1387,17 +1645,22 @@ function gitSyncResource(transport) {
1387
1645
  }
1388
1646
  }
1389
1647
  /**
1390
- * The branch git-sync tracks, or null when none is configured, the caller may not read it, or
1391
- * the server has no remote-sync module.
1648
+ * The branch git-sync tracks, or null when none is configured. Refuses when the caller may not
1649
+ * read the setting (it is admin-only) or the server has no remote-sync module, rather than
1650
+ * reading either as unset.
1392
1651
  */
1393
1652
  async function branch(options = {}) {
1394
1653
  await transport.require("gitSync.branch", options);
1395
- try {
1396
- return await fetchOptionalParsed(transport, "/api/setting/remote-sync-branch", RemoteSyncSetting, options);
1397
- } catch (error) {
1398
- if (isRemoteUnreadable(error)) return null;
1399
- throw error;
1400
- }
1654
+ const tracked = (await transport.requestParsed(RemoteSyncBranchProperty, PROBE_PATH, { ...options }))["remote-sync-branch"];
1655
+ if (tracked === void 0) throw new ConfigError("the remote-sync-branch setting is not readable: it is visible to admins only, and absent on a server without the remote-sync module");
1656
+ return tracked;
1657
+ }
1658
+ /** The branch git-sync tracks, refused when none is configured or the caller may not read it. */
1659
+ async function trackedBranch(options = {}) {
1660
+ await transport.require("gitSync.trackedBranch", options);
1661
+ const tracked = await branch(options);
1662
+ if (tracked === null) throw new ConfigError("git-sync tracks no branch: the remote-sync-branch setting is unset");
1663
+ return tracked;
1401
1664
  }
1402
1665
  /**
1403
1666
  * Poll the current task until it reaches a terminal status. A server with no task at all
@@ -1429,36 +1692,11 @@ function gitSyncResource(transport) {
1429
1692
  syncedCollections,
1430
1693
  remoteUrl,
1431
1694
  branch,
1695
+ trackedBranch,
1432
1696
  waitForTask
1433
1697
  };
1434
1698
  }
1435
1699
  //#endregion
1436
- //#region ../client/src/domain/glossary.ts
1437
- const GlossaryCreator = z.object({
1438
- id: z.number().int(),
1439
- email: z.string(),
1440
- first_name: z.string().nullable(),
1441
- last_name: z.string().nullable()
1442
- }).loose();
1443
- const Glossary = z.object({
1444
- id: z.number().int(),
1445
- term: z.string(),
1446
- definition: z.string(),
1447
- creator_id: z.number().int(),
1448
- creator: GlossaryCreator,
1449
- created_at: z.string(),
1450
- updated_at: z.string()
1451
- }).loose();
1452
- Glossary.pick({
1453
- id: true,
1454
- term: true,
1455
- definition: true
1456
- }).strip();
1457
- z.object({
1458
- term: z.string().min(1),
1459
- definition: z.string().min(1)
1460
- }).strict();
1461
- //#endregion
1462
1700
  //#region ../client/src/resources/glossary.ts
1463
1701
  const GlossaryApiList = z.object({ data: z.array(Glossary) }).loose();
1464
1702
  function glossaryResource(transport) {
@@ -1511,6 +1749,17 @@ function glossaryResource(transport) {
1511
1749
  };
1512
1750
  }
1513
1751
  //#endregion
1752
+ //#region ../client/src/resources/request-body.ts
1753
+ /**
1754
+ * Parse the body a caller hands a method, refusing one that does not match `schema` before any
1755
+ * request. `what` names the body in the refusal.
1756
+ */
1757
+ function parseRequestBody(schema, value, what) {
1758
+ const parsed = schema.safeParse(value);
1759
+ if (!parsed.success) throw new ConfigError(`invalid ${what}: ${parsed.error.issues.map(formatZodIssue).join("; ")}`);
1760
+ return parsed.data;
1761
+ }
1762
+ //#endregion
1514
1763
  //#region ../client/src/resources/library.ts
1515
1764
  const LIBRARY_ROOT_PATH = "/api/ee/library/";
1516
1765
  const PUBLISH_TABLES_PATH = "/api/ee/data-studio/table/publish-tables";
@@ -1527,7 +1776,7 @@ function libraryResource(transport) {
1527
1776
  return toLibrary(wire, await libraryListing(options));
1528
1777
  }
1529
1778
  async function libraryListing(options) {
1530
- const data = await listCollectionsWithLibrary(transport, LibraryCollectionInfo, options);
1779
+ const data = await listCollectionsAs(transport, LibraryCollectionInfo, options);
1531
1780
  const byId = /* @__PURE__ */ new Map();
1532
1781
  for (const collection of data) if (typeof collection.id === "number") byId.set(collection.id, collection);
1533
1782
  return byId;
@@ -1560,26 +1809,31 @@ function libraryResource(transport) {
1560
1809
  }
1561
1810
  /**
1562
1811
  * Publish tables — and every upstream table they depend on — into a collection, so they lead the
1563
- * data pickers and rank up in search. Answers the collection they landed in.
1812
+ * data pickers and rank up in search. Answers the collection they landed in. The endpoint
1813
+ * answers the same whether or not the selectors matched a table, so a body that does not match
1814
+ * `LibraryPublishTablesInput` is refused before any request.
1564
1815
  */
1565
1816
  async function publishTables(params, options = {}) {
1566
1817
  await transport.require("library.publishTables", options);
1818
+ const body = parseRequestBody(LibraryPublishTablesInput, params, "tables to publish");
1567
1819
  return (await transport.requestParsed(PublishTablesResponse, PUBLISH_TABLES_PATH, {
1568
1820
  ...options,
1569
1821
  method: "POST",
1570
- body: params
1822
+ body
1571
1823
  })).target_collection;
1572
1824
  }
1573
1825
  /**
1574
1826
  * Clear the Library collection from tables, and recursively from every downstream table that
1575
- * depends on them. The endpoint answers no JSON body.
1827
+ * depends on them. The endpoint answers no JSON body, whether or not the selectors matched a
1828
+ * table, so selectors that do not match `TableSelectors` are refused before any request.
1576
1829
  */
1577
1830
  async function unpublishTables(params, options = {}) {
1578
1831
  await transport.require("library.unpublishTables", options);
1832
+ const body = parseRequestBody(TableSelectors, params, "table selectors");
1579
1833
  await transport.requestRaw(UNPUBLISH_TABLES_PATH, {
1580
1834
  ...options,
1581
1835
  method: "POST",
1582
- body: params,
1836
+ body,
1583
1837
  expectContentType: "binary"
1584
1838
  });
1585
1839
  }
@@ -1832,48 +2086,21 @@ function metricResource(transport) {
1832
2086
  };
1833
2087
  }
1834
2088
  //#endregion
1835
- //#region ../client/src/domain/moderation-review.ts
1836
- const ModeratedItemType = z.enum(["card", "dashboard"]);
1837
- const ModerationStatus = z.enum(["verified"]);
1838
- const ModerationReview = z.object({
1839
- id: z.number().int(),
1840
- moderated_item_id: z.number().int(),
1841
- moderated_item_type: ModeratedItemType,
1842
- moderator_id: z.number().int(),
1843
- status: ModerationStatus.nullable(),
1844
- text: z.string().nullable(),
1845
- most_recent: z.boolean(),
1846
- created_at: z.string(),
1847
- updated_at: z.string()
1848
- }).loose();
1849
- ModerationReview.pick({
1850
- id: true,
1851
- moderated_item_id: true,
1852
- moderated_item_type: true,
1853
- status: true,
1854
- text: true,
1855
- most_recent: true
1856
- }).strip();
1857
- z.object({
1858
- moderated_item_id: z.number().int().positive(),
1859
- moderated_item_type: ModeratedItemType,
1860
- status: ModerationStatus.nullable().optional(),
1861
- text: z.string().nullable().optional()
1862
- }).strict();
1863
- //#endregion
1864
2089
  //#region ../client/src/resources/moderation-review.ts
1865
2090
  function moderationReviewResource(transport) {
1866
2091
  /**
1867
2092
  * Create a moderation review on a card or dashboard. `status: "verified"` marks the item
1868
2093
  * verified, `null` or an absent status records a note that leaves it unverified. The new review
1869
2094
  * becomes the item's most recent one; the server keeps the ten newest per item. Admins only.
2095
+ * A body that does not match `ModerationReviewCreateInput` is refused before any request.
1870
2096
  */
1871
2097
  async function create(params, options = {}) {
1872
2098
  await transport.require("moderationReview.create", options);
2099
+ const body = parseRequestBody(ModerationReviewCreateInput, params, "moderation review");
1873
2100
  return transport.requestParsed(ModerationReview, "/api/moderation-review", {
1874
2101
  ...options,
1875
2102
  method: "POST",
1876
- body: params
2103
+ body
1877
2104
  });
1878
2105
  }
1879
2106
  return { create };
@@ -2394,8 +2621,10 @@ function searchResource(transport) {
2394
2621
  * may match, `archived` swaps the active set for the archived one, `table_db_id` restricts to
2395
2622
  * items on one database, `verified` to verified content, `collection` to one collection and its
2396
2623
  * descendants, `created_by` to items created by any of those users, `search_native_query` also
2397
- * matches the text of native queries, `include_metadata` attaches each card's `result_metadata`,
2398
- * and `limit`/`offset` are the window the server applies before ranking hydration.
2624
+ * matches native query text but narrows to the models that carry one (cards, models, metrics,
2625
+ * actions, transforms), `include_metadata` attaches each card's `result_metadata`,
2626
+ * `include_dashboard_questions` also matches questions saved into a dashboard (excluded by
2627
+ * default), and `limit`/`offset` are the window the server applies before ranking hydration.
2399
2628
  */
2400
2629
  async function query(params = {}, options = {}) {
2401
2630
  await transport.require("search.query", options);
@@ -2412,7 +2641,8 @@ function searchResource(transport) {
2412
2641
  collection: params.collection,
2413
2642
  created_by: params.created_by,
2414
2643
  search_native_query: params.search_native_query,
2415
- include_metadata: params.include_metadata
2644
+ include_metadata: params.include_metadata,
2645
+ include_dashboard_questions: params.include_dashboard_questions
2416
2646
  }
2417
2647
  });
2418
2648
  return {
@@ -2596,14 +2826,18 @@ function snippetResource(transport) {
2596
2826
  const TableApiList = z.array(Table);
2597
2827
  const TableApiFks = z.array(TableForeignKey);
2598
2828
  const SyncSchemaResponse = z.object({ status: z.literal("ok") });
2599
- const RescanValuesResponse = z.object({ status: z.literal("success") });
2829
+ const FieldValuesResponse = z.object({ status: z.literal("success") });
2600
2830
  const BulkEditResponse = z.object({});
2601
2831
  const BULK_EDIT_PATH = "/api/data-studio/table/edit";
2832
+ const BULK_SYNC_SCHEMA_PATH = "/api/data-studio/table/sync-schema";
2833
+ const BULK_RESCAN_VALUES_PATH = "/api/data-studio/table/rescan-values";
2834
+ const BULK_DISCARD_VALUES_PATH = "/api/data-studio/table/discard-values";
2602
2835
  const LIST_PARAM_FEATURES = [
2603
2836
  ["can-query", "tableListAccessFilters"],
2604
2837
  ["can-write", "tableListAccessFilters"],
2605
2838
  ["include-transform-targets", "tableListTransformTargets"],
2606
- ["unused-only", "tableUnusedFilter"]
2839
+ ["unused-only", "tableUnusedFilter"],
2840
+ ["published-only", "tableListPublishedFilter"]
2607
2841
  ];
2608
2842
  function listParamFeatures(params) {
2609
2843
  return LIST_PARAM_FEATURES.filter(([param]) => params[param] !== void 0).map(([, feature]) => feature);
@@ -2617,7 +2851,7 @@ function tableResource(transport) {
2617
2851
  * List every table the caller can see, across all databases. `term` matches names and display
2618
2852
  * names; `can-query` and `can-write` keep only the tables the caller may query or edit the
2619
2853
  * metadata of; `include-transform-targets` adds tables a transform writes to; `unused-only` keeps
2620
- * tables nothing depends on.
2854
+ * tables nothing depends on; `published-only` keeps tables published to the library.
2621
2855
  */
2622
2856
  async function list(params = {}, options = {}) {
2623
2857
  await transport.require("table.list", options);
@@ -2635,6 +2869,7 @@ function tableResource(transport) {
2635
2869
  "owner-email": params["owner-email"],
2636
2870
  "orphan-only": params["orphan-only"],
2637
2871
  "unused-only": params["unused-only"],
2872
+ "published-only": params["published-only"],
2638
2873
  "can-query": params["can-query"],
2639
2874
  "can-write": params["can-write"],
2640
2875
  "include-transform-targets": params["include-transform-targets"]
@@ -2684,38 +2919,107 @@ function tableResource(transport) {
2684
2919
  };
2685
2920
  }
2686
2921
  /**
2687
- * Trigger a manual update of this table's schema metadata. The sync runs after the call returns;
2688
- * a warehouse the server cannot connect to is a 422.
2922
+ * Trigger a sync of this table: its columns, their fingerprints and its cached field values. It
2923
+ * never discovers new tables. The sync runs after the call returns; a warehouse the server cannot
2924
+ * connect to is a 422.
2689
2925
  */
2690
2926
  async function syncSchema(id, options = {}) {
2691
2927
  await transport.require("table.syncSchema", options);
2692
- await transport.requestParsed(SyncSchemaResponse, `/api/table/${id}/sync_schema`, {
2693
- ...options,
2694
- method: "POST"
2695
- });
2928
+ return {
2929
+ id,
2930
+ status: (await transport.requestParsed(SyncSchemaResponse, `/api/table/${id}/sync_schema`, {
2931
+ ...options,
2932
+ method: "POST"
2933
+ })).status
2934
+ };
2696
2935
  }
2697
2936
  /**
2698
- * Trigger an update of the field values of every eligible field of this table. The scan runs
2699
- * after the call returns.
2937
+ * Trigger an update of the field values of every eligible field of this table that already has a
2938
+ * cached set. The scan runs after the call returns.
2700
2939
  */
2701
2940
  async function rescanValues(id, options = {}) {
2702
2941
  await transport.require("table.rescanValues", options);
2703
- await transport.requestParsed(RescanValuesResponse, `/api/table/${id}/rescan_values`, {
2704
- ...options,
2705
- method: "POST"
2706
- });
2942
+ return {
2943
+ id,
2944
+ status: (await transport.requestParsed(FieldValuesResponse, `/api/table/${id}/rescan_values`, {
2945
+ ...options,
2946
+ method: "POST"
2947
+ })).status
2948
+ };
2949
+ }
2950
+ /**
2951
+ * Discard the cached field values of every field of this table, custom display values included.
2952
+ * No scan recreates a discarded set; the server rebuilds it, without the display values, the next
2953
+ * time the field's values are read.
2954
+ */
2955
+ async function discardValues(id, options = {}) {
2956
+ await transport.require("table.discardValues", options);
2957
+ return {
2958
+ id,
2959
+ status: (await transport.requestParsed(FieldValuesResponse, `/api/table/${id}/discard_values`, {
2960
+ ...options,
2961
+ method: "POST"
2962
+ })).status
2963
+ };
2707
2964
  }
2708
2965
  /**
2709
2966
  * Set the same metadata on every table the selectors pick out. A table leaving the `hidden` data
2710
- * layer is re-synced after the call returns.
2967
+ * layer is re-synced after the call returns. The server answers the same whether or not the
2968
+ * selectors matched a table.
2711
2969
  */
2712
2970
  async function bulkEdit(params, options = {}) {
2713
2971
  await transport.require("table.bulkEdit", options);
2972
+ await requireDataAuthorityNull(params.data_authority, options);
2714
2973
  await transport.requestParsed(BulkEditResponse, BULK_EDIT_PATH, {
2715
2974
  ...options,
2716
2975
  method: "POST",
2717
2976
  body: params
2718
2977
  });
2978
+ return {
2979
+ accepted: true,
2980
+ ...params
2981
+ };
2982
+ }
2983
+ async function requireDataAuthorityNull(value, options) {
2984
+ if (value === null) await transport.requireFeatures(["tableUserValueWithdrawal"], options);
2985
+ }
2986
+ async function postSelection(path, selectors, options) {
2987
+ const body = parseRequestBody(TableSelectors, selectors, "table selectors");
2988
+ await transport.requestRaw(path, {
2989
+ ...options,
2990
+ method: "POST",
2991
+ body,
2992
+ expectContentType: "binary"
2993
+ });
2994
+ return {
2995
+ accepted: true,
2996
+ ...body
2997
+ };
2998
+ }
2999
+ /**
3000
+ * Trigger a sync of every table the selectors pick out: its columns, their fingerprints and its
3001
+ * cached field values. Every database behind them must answer a connection test first, or the
3002
+ * call is a 422; the syncs run after it returns.
3003
+ */
3004
+ async function bulkSyncSchema(selectors, options = {}) {
3005
+ await transport.require("table.bulkSyncSchema", options);
3006
+ return postSelection(BULK_SYNC_SCHEMA_PATH, selectors, options);
3007
+ }
3008
+ /**
3009
+ * Trigger a field-values rescan of every table the selectors pick out, refreshing the sets that
3010
+ * are already cached. The scans run after the call returns.
3011
+ */
3012
+ async function bulkRescanValues(selectors, options = {}) {
3013
+ await transport.require("table.bulkRescanValues", options);
3014
+ return postSelection(BULK_RESCAN_VALUES_PATH, selectors, options);
3015
+ }
3016
+ /**
3017
+ * Discard the cached field values of every table the selectors pick out, custom display values
3018
+ * included. No scan recreates a discarded set.
3019
+ */
3020
+ async function bulkDiscardValues(selectors, options = {}) {
3021
+ await transport.require("table.bulkDiscardValues", options);
3022
+ return postSelection(BULK_DISCARD_VALUES_PATH, selectors, options);
2719
3023
  }
2720
3024
  async function updateFromCsv(id, action, file, options) {
2721
3025
  await transport.requestRaw(`/api/table/${id}/${UPLOAD_UPDATE_PATHS[action]}`, {
@@ -2757,7 +3061,11 @@ function tableResource(transport) {
2757
3061
  fks,
2758
3062
  syncSchema,
2759
3063
  rescanValues,
3064
+ discardValues,
2760
3065
  bulkEdit,
3066
+ bulkSyncSchema,
3067
+ bulkRescanValues,
3068
+ bulkDiscardValues,
2761
3069
  appendCsv,
2762
3070
  replaceCsv
2763
3071
  };
@@ -3584,6 +3892,167 @@ function transformTagResource(transport) {
3584
3892
  };
3585
3893
  }
3586
3894
  //#endregion
3895
+ //#region ../client/src/domain/transform-test.ts
3896
+ const TransformTestTable = z.object({
3897
+ schema: z.string().min(1).nullable().optional(),
3898
+ name: z.string().min(1)
3899
+ }).loose();
3900
+ const TransformTestColumn = z.object({
3901
+ name: z.string().min(1),
3902
+ cast_type: z.string().min(1)
3903
+ }).loose();
3904
+ const TransformTestCell = z.union([
3905
+ z.boolean(),
3906
+ z.number(),
3907
+ z.string(),
3908
+ z.null()
3909
+ ]);
3910
+ const TransformTestRow = z.record(z.string(), TransformTestCell);
3911
+ const TransformTestSqlInput = z.object({
3912
+ table: TransformTestTable,
3913
+ format: z.literal("sql"),
3914
+ sql: z.string().min(1)
3915
+ }).loose();
3916
+ const TransformTestRowsInput = z.object({
3917
+ table: TransformTestTable,
3918
+ format: z.literal("rows"),
3919
+ columns: z.array(TransformTestColumn).min(1),
3920
+ rows: z.array(TransformTestRow)
3921
+ }).loose();
3922
+ const TransformTestInput = z.discriminatedUnion("format", [TransformTestSqlInput, TransformTestRowsInput]);
3923
+ const TransformTestEqualsSqlExpectation = z.object({
3924
+ type: z.literal("equals"),
3925
+ name: z.string().min(1),
3926
+ format: z.literal("sql"),
3927
+ sql: z.string().min(1)
3928
+ }).loose();
3929
+ const TransformTestEqualsRowsExpectation = z.object({
3930
+ type: z.literal("equals"),
3931
+ name: z.string().min(1),
3932
+ format: z.literal("rows"),
3933
+ columns: z.array(TransformTestColumn).min(1),
3934
+ rows: z.array(TransformTestRow)
3935
+ }).loose();
3936
+ const TransformTestEqualsExpectation = z.discriminatedUnion("format", [TransformTestEqualsSqlExpectation, TransformTestEqualsRowsExpectation]);
3937
+ const TransformTestEmptyExpectation = z.object({
3938
+ type: z.literal("empty"),
3939
+ name: z.string().min(1),
3940
+ sql: z.string().min(1)
3941
+ }).loose();
3942
+ const TransformTestExpectation = z.discriminatedUnion("type", [TransformTestEqualsExpectation, TransformTestEmptyExpectation]);
3943
+ const TransformTest = z.object({
3944
+ id: z.number().int(),
3945
+ entity_id: z.string(),
3946
+ transform_id: z.number().int(),
3947
+ creator_id: z.number().int(),
3948
+ name: z.string(),
3949
+ description: z.string().nullable(),
3950
+ inputs: z.array(TransformTestInput),
3951
+ expectations: z.array(TransformTestExpectation),
3952
+ created_at: z.string(),
3953
+ updated_at: z.string()
3954
+ }).loose();
3955
+ TransformTest.pick({
3956
+ id: true,
3957
+ transform_id: true,
3958
+ name: true,
3959
+ description: true
3960
+ }).strip();
3961
+ z.object({
3962
+ transform_id: z.number().int().positive(),
3963
+ name: z.string().min(1),
3964
+ description: z.string().nullable().optional(),
3965
+ inputs: z.array(TransformTestInput),
3966
+ expectations: z.array(TransformTestExpectation)
3967
+ }).loose();
3968
+ z.object({
3969
+ transform_id: z.number().int().positive().optional(),
3970
+ name: z.string().min(1).optional(),
3971
+ description: z.string().nullable().optional(),
3972
+ inputs: z.array(TransformTestInput).optional(),
3973
+ expectations: z.array(TransformTestExpectation).optional()
3974
+ }).loose();
3975
+ const TransformTestResultColumn = z.object({
3976
+ name: z.string(),
3977
+ database_type: z.string()
3978
+ }).loose();
3979
+ const TransformTestExpectationError = z.object({
3980
+ type: z.string(),
3981
+ message: z.string()
3982
+ }).loose();
3983
+ const TransformTestCellMismatch = z.object({
3984
+ column: z.string(),
3985
+ expected: TransformTestCell,
3986
+ actual: TransformTestCell
3987
+ }).loose();
3988
+ const TransformTestRowCounts = z.object({
3989
+ actual: z.number().int(),
3990
+ expected: z.number().int()
3991
+ }).loose();
3992
+ const TransformTestEqualsFindings = z.object({
3993
+ name: z.string(),
3994
+ type: z.literal("equals"),
3995
+ status: z.enum(["passed", "failed"]),
3996
+ columns: z.array(TransformTestResultColumn),
3997
+ "row-counts": TransformTestRowCounts,
3998
+ "extra-rows": z.array(TransformTestRow),
3999
+ "missing-rows": z.array(TransformTestRow),
4000
+ "cell-mismatches": z.array(TransformTestCellMismatch),
4001
+ truncated: z.number().int()
4002
+ }).loose();
4003
+ const TransformTestEqualsError = z.object({
4004
+ name: z.string(),
4005
+ type: z.literal("equals"),
4006
+ status: z.literal("error"),
4007
+ error: TransformTestExpectationError
4008
+ }).loose();
4009
+ const TransformTestEqualsResult = z.discriminatedUnion("status", [TransformTestEqualsFindings, TransformTestEqualsError]);
4010
+ const TransformTestEmptyPassed = z.object({
4011
+ name: z.string(),
4012
+ type: z.literal("empty"),
4013
+ status: z.literal("passed")
4014
+ }).loose();
4015
+ const TransformTestEmptyFailed = z.object({
4016
+ name: z.string(),
4017
+ type: z.literal("empty"),
4018
+ status: z.literal("failed"),
4019
+ columns: z.array(TransformTestResultColumn),
4020
+ sample: z.array(TransformTestRow),
4021
+ truncated: z.number().int()
4022
+ }).loose();
4023
+ const TransformTestEmptyError = z.object({
4024
+ name: z.string(),
4025
+ type: z.literal("empty"),
4026
+ status: z.literal("error"),
4027
+ error: TransformTestExpectationError
4028
+ }).loose();
4029
+ const TransformTestEmptyResult = z.discriminatedUnion("status", [
4030
+ TransformTestEmptyPassed,
4031
+ TransformTestEmptyFailed,
4032
+ TransformTestEmptyError
4033
+ ]);
4034
+ const TransformTestExpectationResult = z.discriminatedUnion("type", [TransformTestEqualsResult, TransformTestEmptyResult]);
4035
+ const TransformTestRunResult = z.object({
4036
+ status: z.enum(["passed", "failed"]),
4037
+ expectations: z.array(TransformTestExpectationResult),
4038
+ tables: z.record(z.string(), z.string())
4039
+ }).loose();
4040
+ z.enum([
4041
+ "transform-test.unknown-column",
4042
+ "transform-test.ambiguous-column",
4043
+ "transform-test.missing-inputs",
4044
+ "transform-test.unused-inputs",
4045
+ "transform-test.duplicate-input-table",
4046
+ "transform-test.unparseable-source",
4047
+ "transform-test.unremapped-reference",
4048
+ "transform-test.unsupported-transform",
4049
+ "transform-test.unsupported-driver",
4050
+ "transform-test.transform-failed",
4051
+ "transform-test.setup-failed",
4052
+ "transform-test.expectation-failed",
4053
+ "transform-test.unsupported-format"
4054
+ ]);
4055
+ //#endregion
3587
4056
  //#region ../client/src/resources/transform-test.ts
3588
4057
  const TransformTestApiList = z.array(TransformTest);
3589
4058
  function transformTestResource(transport) {