@metabase/cli 0.3.2-alpha.fix-transform-test-ee-path.8ac2a7a → 0.4.0-alpha.release-65-integration-branch.31ca6bb

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 (318) hide show
  1. package/dist/{add-collection-B_-eMU_k.mjs → add-collection-B-Kczwcj.mjs} +5 -5
  2. package/dist/{alert-Dalin_DD.mjs → alert-Ne0ivd5m.mjs} +7 -7
  3. package/dist/{alerts-DpBgrjPI.mjs → alerts-Fakzg9iP.mjs} +6 -6
  4. package/dist/{append-C1JNVALm.mjs → append-DCDVqPmR.mjs} +4 -4
  5. package/dist/archive-55sDfnHf.mjs +32 -0
  6. package/dist/{archive-CdKf_Eqq.mjs → archive-BNJit8eD.mjs} +3 -3
  7. package/dist/{archive-DckxlWBt.mjs → archive-BbNqts-V.mjs} +3 -3
  8. package/dist/{archive-B51prFgS.mjs → archive-C93UR4Uc.mjs} +3 -3
  9. package/dist/{archive-CISXgZAI.mjs → archive-CGmvQht4.mjs} +5 -5
  10. package/dist/{archive-cAdUa1-2.mjs → archive-CL8wqAzm.mjs} +3 -3
  11. package/dist/{archive-DVHxeDKS.mjs → archive-CSdktxvW.mjs} +5 -5
  12. package/dist/{archive-CicPYX27.mjs → archive-CpCSY4RT.mjs} +5 -5
  13. package/dist/{archive-CwITzj_j.mjs → archive-DCCkQTjQ.mjs} +5 -5
  14. package/dist/{archive-BkITQyWW.mjs → archive-DCE087yD.mjs} +4 -4
  15. package/dist/{archive-DA3OiLEE.mjs → archive-DEef7eB8.mjs} +3 -3
  16. package/dist/{archive-52ZHbFDm2.mjs → archive-DIZu7o4C.mjs} +4 -4
  17. package/dist/{auth-A96JOCQx.mjs → auth-Bx4QQhqt.mjs} +5 -5
  18. package/dist/body-CB2eDFFb.mjs +17 -0
  19. package/dist/branch-flag-pFQPNYKr.mjs +9 -0
  20. package/dist/{branches-CbcwWYL9.mjs → branches-B6ilUG-7.mjs} +3 -3
  21. package/dist/breaking-Dg3-8yDF.mjs +36 -0
  22. package/dist/broken-BNBD4Eo3.mjs +37 -0
  23. package/dist/bulk-discard-values-DfKXuZpR.mjs +49 -0
  24. package/dist/bulk-edit-oUCfDQ_M.mjs +53 -0
  25. package/dist/bulk-rescan-values-B8pNlXUH.mjs +28 -0
  26. package/dist/bulk-sync-schema-tRp7jBJt.mjs +28 -0
  27. package/dist/{cancel-DpDcVY7M.mjs → cancel-Bl4BMkwI.mjs} +3 -3
  28. package/dist/{cancel-task-B4RDvIYb.mjs → cancel-task-CWWo7vLf.mjs} +4 -4
  29. package/dist/card-CQD4D8mw.mjs +25 -0
  30. package/dist/{card-CEkp1mcI.mjs → card-CQNUT9pm.mjs} +1 -1
  31. package/dist/{card-voh1k4hl.mjs → card-P5mBknsl.mjs} +3 -11
  32. package/dist/{cards-BC0JX8Yg.mjs → cards-BIUYdSIR.mjs} +6 -6
  33. package/dist/cli.mjs +420 -111
  34. package/dist/{client-ClL6gf7G.mjs → client-BHIFvEg2.mjs} +863 -316
  35. package/dist/{collection-DYM0p3Xl.mjs → collection-BG3Ksea-.mjs} +1 -1
  36. package/dist/collection-CuaTd10G.mjs +21 -0
  37. package/dist/{collection-BxdPxD38.mjs → collection-D3KXhvnc.mjs} +7 -5
  38. package/dist/{collection-namespace-Dv0l-V9K.mjs → collection-namespace-ZQePD67z.mjs} +2 -2
  39. package/dist/{content-translation-BXIXL4eW.mjs → content-translation-BRdNdAmn.mjs} +3 -3
  40. package/dist/copy-BMEaYmTb.mjs +55 -0
  41. package/dist/copy-CbDfVZRC.mjs +36 -0
  42. package/dist/copy-flags-anRhAvB5.mjs +32 -0
  43. package/dist/{create-Dhai9zAt.mjs → create-5cDaZcRL.mjs} +3 -3
  44. package/dist/{create-DWFJdyIr.mjs → create-BEN-2XFK.mjs} +3 -3
  45. package/dist/create-BJG630xB.mjs +48 -0
  46. package/dist/{create-NCKHHdov.mjs → create-BTQB1lqX.mjs} +4 -4
  47. package/dist/{create-kZIIEN2Y.mjs → create-C3TmU1Bi.mjs} +6 -6
  48. package/dist/create-C7O9tPL2.mjs +34 -0
  49. package/dist/{create-BVNhtAgF.mjs → create-C8hsOv_D.mjs} +6 -6
  50. package/dist/{create-D--Z1S3p2.mjs → create-CBSsW8Hm.mjs} +6 -6
  51. package/dist/{create-BcsVwXgS2.mjs → create-CG6WWY6k.mjs} +4 -4
  52. package/dist/{create--fiwuTWc.mjs → create-D2Shlb7t.mjs} +3 -3
  53. package/dist/{create-DmN2gFc4.mjs → create-DVEqry26.mjs} +4 -4
  54. package/dist/{create-YetX69Re.mjs → create-D_pNX7d0.mjs} +3 -3
  55. package/dist/{create-Za1EskpV.mjs → create-R0Q-nRlq.mjs} +4 -4
  56. package/dist/{create-Bryrkb9g.mjs → create-SqmOf6WQ.mjs} +6 -6
  57. package/dist/{create-branch-CseVn3lp.mjs → create-branch-Cb3CWojg.mjs} +4 -4
  58. package/dist/{create-BbjSOTN-.mjs → create-c2zR9y4J.mjs} +4 -4
  59. package/dist/{create-CHr8MPPq.mjs → create-xt4ff6fP.mjs} +3 -3
  60. package/dist/{create-B9qXQ_wV.mjs → create-zpJIRn9j.mjs} +5 -5
  61. package/dist/{csv-DNzesu8y.mjs → csv-CRNOhy4X.mjs} +4 -4
  62. package/dist/{current-task-DRTKZcP9.mjs → current-task-DFo1ZJ51.mjs} +4 -4
  63. package/dist/dashboard-D11YAa7I.mjs +35 -0
  64. package/dist/{dashboard-D0hwTC-f.mjs → dashboard-Phz3XpRM.mjs} +2 -1
  65. package/dist/{dashboard-DgK81azj.mjs → dashboard-XSTr9QCr.mjs} +6 -2
  66. package/dist/data-action-BiHjjVjc.mjs +24 -0
  67. package/dist/data-action-DZxVB_hD.mjs +85 -0
  68. package/dist/data-action-R9qxJDPA.mjs +40 -0
  69. package/dist/database-BT7DVgSr.mjs +45 -0
  70. package/dist/{database-C3E9PZSx.mjs → database-Kq2AL5jH.mjs} +1 -1
  71. package/dist/dataset-BmvCxGoE.mjs +66 -0
  72. package/dist/{db-BDijt81U.mjs → db-C8lj73Dz.mjs} +7 -7
  73. package/dist/delete-09O7BTNw.mjs +44 -0
  74. package/dist/{delete-wFsy80db.mjs → delete-CYgNpHl7.mjs} +4 -4
  75. package/dist/{delete-BudvZkvK.mjs → delete-D_ZNoYVv.mjs} +4 -4
  76. package/dist/{delete--15it-A8.mjs → delete-HWeQtc4M.mjs} +4 -4
  77. package/dist/delete-I4eFpsed.mjs +44 -0
  78. package/dist/{delete-Dc8E5YwZ.mjs → delete-My8TX-B2.mjs} +4 -4
  79. package/dist/{delete-BxjJ66BS.mjs → delete-qwdN0N7e.mjs} +4 -4
  80. package/dist/delete-runtime-BbmRg_in.mjs +55 -0
  81. package/dist/{delete-table-5AQpn8OB.mjs → delete-table-BCvjX7bh.mjs} +4 -4
  82. package/dist/{dependencies-C1ogC3BV.mjs → dependencies-BAE4YPXX.mjs} +5 -5
  83. package/dist/dependency-CIam7zmr.mjs +15 -0
  84. package/dist/dependency-DzLH3J8P.mjs +165 -0
  85. package/dist/dependency-zElFM-os.mjs +111 -0
  86. package/dist/dependents-Dv6tLdSs.mjs +52 -0
  87. package/dist/{dirty-CSLDYO-K.mjs → dirty-CZORg0i0.mjs} +5 -5
  88. package/dist/discard-values-DKnP-JHr.mjs +55 -0
  89. package/dist/{document-CA0Q6lqu.mjs → document-C18b5rM6.mjs} +1 -1
  90. package/dist/{document-BHpLJbKU.mjs → document-DFCj1Az_.mjs} +2 -1
  91. package/dist/document-uxz96Lah.mjs +20 -0
  92. package/dist/{download-Ddap1OAo.mjs → download-BImtTll0.mjs} +2 -2
  93. package/dist/{eid-HnrWhPoe.mjs → eid-D0FxhT9H.mjs} +11 -10
  94. package/dist/entity-DWp9WJbU.mjs +20 -0
  95. package/dist/entry-flags-3sDWwa90.mjs +42 -0
  96. package/dist/{events-CXqetjcS.mjs → events-BzCjVA3-.mjs} +4 -4
  97. package/dist/execute-BhHbkBqf.mjs +45 -0
  98. package/dist/export-CjqjDnaZ.mjs +74 -0
  99. package/dist/export-flags-BETJHNcw.mjs +81 -0
  100. package/dist/export-preflight-DzvIP6TB.mjs +35 -0
  101. package/dist/{field-CcN4oZy6.mjs → field-5nivEfd6.mjs} +33 -3
  102. package/dist/field-fBpiGiqr.mjs +21 -0
  103. package/dist/field-wmN6raOG.mjs +128 -0
  104. package/dist/{fields-DxHxuxwO.mjs → fields-C-au1eLO.mjs} +6 -6
  105. package/dist/filter-flags-BIFcA2TT.mjs +72 -0
  106. package/dist/fks-83QIm8xb.mjs +36 -0
  107. package/dist/{get-CDnmpfHQ.mjs → get-BMHbEGbr.mjs} +4 -4
  108. package/dist/{get-BiPclcIP.mjs → get-BTCOzSkl.mjs} +3 -3
  109. package/dist/{get-DmKtPNOy.mjs → get-BawLhSwW.mjs} +3 -3
  110. package/dist/{get-BcoJ9Aha.mjs → get-BjqqFG2m.mjs} +3 -3
  111. package/dist/{get-C3cuZNeW.mjs → get-C-R_Fdsi.mjs} +3 -3
  112. package/dist/{get-H6kInHIx.mjs → get-C73V2KsB.mjs} +5 -5
  113. package/dist/{get-BGLvyOO3.mjs → get-C9sq2boy.mjs} +5 -5
  114. package/dist/{get-B2pj2q3X.mjs → get-Cggv6yLC.mjs} +4 -4
  115. package/dist/{get-CxUQyhte.mjs → get-CkXc0Xld.mjs} +5 -5
  116. package/dist/{get-BF2vdF3W.mjs → get-CqNEVAX_2.mjs} +3 -3
  117. package/dist/{get-Dtre5jzh.mjs → get-D7h7uH4k.mjs} +5 -5
  118. package/dist/get-DGmE5fmp.mjs +31 -0
  119. package/dist/{get-D_x-ENFe.mjs → get-DTTsPd-c.mjs} +5 -5
  120. package/dist/{get-DW7mCaGe.mjs → get-DXBXhPrU.mjs} +5 -5
  121. package/dist/{get-CE9_4Q7E.mjs → get-D_v1IAL1.mjs} +3 -3
  122. package/dist/{get-eJilYnHk.mjs → get-DkzO3G5p.mjs} +5 -5
  123. package/dist/{get-DjlQhgD4.mjs → get-Dvr_69L7.mjs} +3 -3
  124. package/dist/get-NOMvMvYJ.mjs +36 -0
  125. package/dist/{get-C_tdSMwW2.mjs → get-YPDWhgm_2.mjs} +4 -4
  126. package/dist/{get-b0CoPz5B.mjs → get-Z36_0HX_.mjs} +4 -4
  127. package/dist/{get-run-BE1HtJDW.mjs → get-run-v1QHn-Mx.mjs} +4 -4
  128. package/dist/{git-sync-BwBRmEhE.mjs → git-sync-COokpYgc.mjs} +12 -3
  129. package/dist/git-sync-DspFahwV.mjs +165 -0
  130. package/dist/git-sync-VAqASCQ5.mjs +29 -0
  131. package/dist/glossary-BlNCrYbw.mjs +30 -0
  132. package/dist/glossary-Brnk2PBi.mjs +14 -0
  133. package/dist/glossary-LmZWwCNP.mjs +21 -0
  134. package/dist/graph-B6OliqnW.mjs +34 -0
  135. package/dist/{group-YQQ5GIcP.mjs → group-bpD_KcjA.mjs} +1 -1
  136. package/dist/{has-remote-changes-Cj1KhBOT.mjs → has-remote-changes-iTRCU9j0.mjs} +4 -4
  137. package/dist/{import-DLb9VN4l.mjs → import-CdSs5CtT.mjs} +19 -8
  138. package/dist/{input-D5tQEfqN.mjs → input-D8qW-KtR.mjs} +6 -2
  139. package/dist/{is-dirty-BxtgV2xF.mjs → is-dirty-B5fj9NeS.mjs} +2 -2
  140. package/dist/{items-DLUYc5-z.mjs → items-BxWnNEh7.mjs} +8 -8
  141. package/dist/{key-PYetuQ13.mjs → key-BynJSK9u.mjs} +1 -1
  142. package/dist/{library-BNSxXOpc.mjs → library-BHHgurW0.mjs} +5 -5
  143. package/dist/{library-PGCfm0UA.mjs → library-BOv5SY24.mjs} +1 -1
  144. package/dist/{library-BPIzb3K_.mjs → library-Ck0EK5bi.mjs} +4 -2
  145. package/dist/{list-cIMww2Me.mjs → list-BPMOLrwn.mjs} +5 -5
  146. package/dist/{list-jhQSgh6i.mjs → list-BTcEm4td.mjs} +3 -3
  147. package/dist/{list-M8J10Ozk.mjs → list-BTgAbqeS.mjs} +4 -4
  148. package/dist/{list-CERbeLbQ.mjs → list-Bop1NTbU.mjs} +6 -6
  149. package/dist/{list-BQnOEB3W.mjs → list-By9XJRiv.mjs} +3 -3
  150. package/dist/list-CNC-XHbN.mjs +35 -0
  151. package/dist/{list-CX9qZ-bx.mjs → list-CPWgBkPa.mjs} +4 -4
  152. package/dist/{list-C5mS_ehX.mjs → list-Cpa0Se7M.mjs} +5 -5
  153. package/dist/list-DA9KsA0o.mjs +101 -0
  154. package/dist/{list-Dat8QNcf.mjs → list-DE9gYY3I.mjs} +3 -3
  155. package/dist/{list-COLpwXW4.mjs → list-DFJt2-fY.mjs} +4 -4
  156. package/dist/{list-CBLxhaNZ.mjs → list-DUcnAb1h.mjs} +3 -3
  157. package/dist/{list-CehE6KBV.mjs → list-DW4-u7eO.mjs} +5 -5
  158. package/dist/{list-CQbiSx26.mjs → list-DbXnSL2x.mjs} +5 -5
  159. package/dist/list-DgsM9YQX.mjs +28 -0
  160. package/dist/{list-Sd7jGZoX.mjs → list-Dzzt6Yee.mjs} +3 -3
  161. package/dist/{list-BUz6KOfw.mjs → list-ZHLsjxXg.mjs} +6 -6
  162. package/dist/{list-CzRzCbCY.mjs → list-e7yvJYMw.mjs} +3 -3
  163. package/dist/{list-B1soS8QW.mjs → list-hN_Tu2T6.mjs} +6 -6
  164. package/dist/{list-BcP1DTJH.mjs → list-zyKxxNvn.mjs} +3 -3
  165. package/dist/{login-BfLqBfCd.mjs → login-B7nGQDZK.mjs} +6 -6
  166. package/dist/{logout-BpRXB3Ze.mjs → logout-pZffAh1G.mjs} +2 -2
  167. package/dist/{measure-Ds8O5Evr.mjs → measure-AtnrCTCC.mjs} +6 -6
  168. package/dist/moderation-review-BdqEH6N1.mjs +31 -0
  169. package/dist/{notification-DVrLkjFT.mjs → notification-DOYdl0ao.mjs} +1 -1
  170. package/dist/{parameter-values-DhrkLXoN.mjs → parameter-values-CxTkEjCs.mjs} +3 -3
  171. package/dist/{parse-enum-Dc0dMZ3P.mjs → parse-enum-CLIXMsd8.mjs} +1 -1
  172. package/dist/parse-id-7ja3HUdB.mjs +13 -0
  173. package/dist/{parse-ref-DTDld_LJ.mjs → parse-ref-Cw5fa4FI.mjs} +1 -1
  174. package/dist/parse-text-T0lTXzTZ.mjs +11 -0
  175. package/dist/{path-_GHFrTLx.mjs → path-DM4vyihl.mjs} +4 -4
  176. package/dist/{poll-KLl4Eq8Y.mjs → poll-Dz4tUm2f.mjs} +2 -2
  177. package/dist/{preflight-BpYtF0IU.mjs → preflight-DaZ2z2C1.mjs} +3 -3
  178. package/dist/{process-CLtOWKBn.mjs → process-D0HdqZ3r.mjs} +1 -1
  179. package/dist/{publish-D-7Zlmuk.mjs → publish-C0HCL04a.mjs} +4 -4
  180. package/dist/{pulse-x0gFxWfG.mjs → pulse-D1uh8UIU.mjs} +1 -1
  181. package/dist/{query-B1CZztxs.mjs → query-BC-C6efK.mjs} +14 -33
  182. package/dist/query-BKtMP5eH.mjs +13 -0
  183. package/dist/query-CAFPlqfi.mjs +329 -0
  184. package/dist/remapping-CgA6UJGU.mjs +53 -0
  185. package/dist/{remove-collection-C4saCFxz.mjs → remove-collection-DoctJa9g.mjs} +5 -5
  186. package/dist/{render-6O_eF-P1.mjs → render-Bvm9mta6.mjs} +2 -2
  187. package/dist/{replace-BuR4f2Ai.mjs → replace-CaFJd9fO.mjs} +4 -4
  188. package/dist/rescan-values-7VOGCLMe.mjs +32 -0
  189. package/dist/{rescan-values-CNOiiWQ5.mjs → rescan-values-sJRwcHsk.mjs} +5 -5
  190. package/dist/{run-DijA_BXt.mjs → run-COHDQ5J4.mjs} +3 -3
  191. package/dist/{run-QEUbWNm7.mjs → run-RXpFlDAB.mjs} +7 -7
  192. package/dist/{runs-BSlhVeDO.mjs → runs-CUYdCKiE.mjs} +5 -5
  193. package/dist/{runtime-Dtb93zKy.mjs → runtime-B8RtMb4B.mjs} +21 -82
  194. package/dist/{schema-tables-BE3rEb6I.mjs → schema-tables-CO5qyZBe.mjs} +6 -6
  195. package/dist/{schemas-yDjBiwlH.mjs → schemas-CzHHgDdF.mjs} +4 -4
  196. package/dist/search-BWb052_b.mjs +131 -0
  197. package/dist/search-Cc9vHNae.mjs +85 -0
  198. package/dist/{segment-Cm6zQjJW.mjs → segment-C_rsUkHK.mjs} +6 -6
  199. package/dist/{send-kC8oerkT.mjs → send-C-3bkpni.mjs} +3 -3
  200. package/dist/{set-tFhPkxrL.mjs → set-BDkT37OT.mjs} +4 -4
  201. package/dist/{set-active-lDKhAlij.mjs → set-active-CDJTfQEc.mjs} +3 -3
  202. package/dist/set-sensitivity-DVrINHde.mjs +57 -0
  203. package/dist/{setting-DrJXCaFE.mjs → setting-CoLzd08x.mjs} +4 -4
  204. package/dist/{setup-BWY9M0iR.mjs → setup-C4F4XYbU.mjs} +3 -3
  205. package/dist/{signal-Csom0mt5.mjs → signal-CxWeLszu.mjs} +1 -1
  206. package/dist/{skill-list-CCes8pKe.mjs → skill-list-BgihWuPf.mjs} +2 -2
  207. package/dist/{skills-DE9ej5Rg.mjs → skills-4qDjKRSk.mjs} +2 -2
  208. package/dist/{skills-DPRN2384.mjs → skills-BWEFRpUj.mjs} +3 -3
  209. package/dist/snippet-CYd8D9SK.mjs +19 -0
  210. package/dist/{stash-C9oDvQ9P.mjs → stash-CZ1x0rox.mjs} +6 -6
  211. package/dist/{status-DSdXmNC3.mjs → status-BM6eYW7I.mjs} +3 -3
  212. package/dist/{status-CkpujA26.mjs → status-gqpPZvue.mjs} +7 -7
  213. package/dist/{subscription-DKOKoHRG.mjs → subscription-pSuO241O.mjs} +6 -6
  214. package/dist/{subscriptions-C5SyJL4B.mjs → subscriptions-n5zJ9rYZ.mjs} +6 -6
  215. package/dist/{summary-DTPgXsc0.mjs → summary-DvIf2EiO.mjs} +5 -5
  216. package/dist/sync-schema-Cc21crxQ.mjs +32 -0
  217. package/dist/{sync-schema-DKKkNSR7.mjs → sync-schema-D1t8rhdQ.mjs} +6 -6
  218. package/dist/sync-task-CXFoqlpF.mjs +53 -0
  219. package/dist/{table-DfuY0N8e.mjs → table-Ci6bhZkb.mjs} +35 -12
  220. package/dist/table-CxvaDiIZ.mjs +155 -0
  221. package/dist/table-Dc0dLfyg.mjs +26 -0
  222. package/dist/table-selector-flags-BVZvnhUa.mjs +42 -0
  223. package/dist/text-DaNkPRwt.mjs +6 -0
  224. package/dist/timeline-BqU5sOb6.mjs +21 -0
  225. package/dist/{timeline-event-n4Lzet7l.mjs → timeline-event-jn1SOKd4.mjs} +6 -6
  226. package/dist/transform-BUIlFqpv.mjs +28 -0
  227. package/dist/{transform-CtqB1WYo.mjs → transform-CNBIV7No.mjs} +1 -1
  228. package/dist/transform-job-DsbY9mme.mjs +22 -0
  229. package/dist/{transform-tag-D6NXqWaX.mjs → transform-tag-C0jzV6Dk.mjs} +5 -5
  230. package/dist/{transforms-O4NtXqFz.mjs → transforms-DwTy_Quh.mjs} +5 -5
  231. package/dist/tree-p2j6IVy-.mjs +34 -0
  232. package/dist/{unpublish-DvWefKJi.mjs → unpublish-B-961jX1.mjs} +3 -3
  233. package/dist/unreferenced-Dxy-aYI7.mjs +36 -0
  234. package/dist/{update-DXmZuJho.mjs → update-BFYRBbRu.mjs} +6 -6
  235. package/dist/{update-xEegxIyH.mjs → update-BGeaPntx.mjs} +5 -5
  236. package/dist/{update-Bah7N8QX.mjs → update-BnIEN390.mjs} +5 -5
  237. package/dist/{update-To6A1Ugu.mjs → update-CALlEgIC.mjs} +4 -4
  238. package/dist/{update-76nzOc71.mjs → update-CHkVN69L.mjs} +13 -8
  239. package/dist/{update-AJ2JmwDl.mjs → update-CKqL9PmU.mjs} +5 -5
  240. package/dist/{update-DmgRIp7o.mjs → update-CYGYUCFQ.mjs} +4 -4
  241. package/dist/update-CuQy2g51.mjs +52 -0
  242. package/dist/{update-DOdcflLH.mjs → update-D4TGE6FS.mjs} +7 -7
  243. package/dist/{update-H_fdjugs.mjs → update-D7xi-0bU.mjs} +4 -4
  244. package/dist/{update-2KIpYgyj.mjs → update-DK77vtFF.mjs} +6 -6
  245. package/dist/{update-7oKvP1HC.mjs → update-DKDQTlnV.mjs} +5 -5
  246. package/dist/update-DXxJHC8y.mjs +41 -0
  247. package/dist/update-DiJK0uRG.mjs +181 -0
  248. package/dist/{update-CGJvIS-l.mjs → update-MD1Kwq1P.mjs} +4 -4
  249. package/dist/{update-dashcard-DjT5QOkL.mjs → update-dashcard-DuTjOh14.mjs} +6 -6
  250. package/dist/{update-D7dG7H-z.mjs → update-hvO4VpfZ.mjs} +7 -7
  251. package/dist/{update-DV54H3L5.mjs → update-qDZvnwvf.mjs} +7 -7
  252. package/dist/{update-BB6Go_RX.mjs → update-tltXCUwR.mjs} +4 -4
  253. package/dist/{upgrade-CuJx9fX4.mjs → upgrade-Ca-Ss5jb.mjs} +4 -4
  254. package/dist/{upload-DOO94rCQ.mjs → upload-C2fhpKkP.mjs} +2 -2
  255. package/dist/upload-Dw7mVr9u.mjs +13 -0
  256. package/dist/{upload-CboARPZm.mjs → upload-t6dkccqn.mjs} +3 -3
  257. package/dist/{uuid-InwZlrpQ.mjs → uuid-BMlJZT8z.mjs} +2 -2
  258. package/dist/{validate-D6-Vg_kn.mjs → validate-D7e110oU.mjs} +1 -1
  259. package/dist/{validate-query-B90KYPQr.mjs → validate-query-BzbZmenf.mjs} +7 -3
  260. package/dist/{values-CsZLk1Ls.mjs → values-CXN4xTTh.mjs} +5 -5
  261. package/dist/verify-CPVfwKSu.mjs +38 -0
  262. package/dist/verify-flags-CMpRkMPa.mjs +58 -0
  263. package/dist/verify-k-JB-k3D.mjs +38 -0
  264. package/dist/{verify-DrGjZwBM.mjs → verify-t-CEmvoG.mjs} +3 -3
  265. package/dist/{wait-BmzdarP9.mjs → wait-KSkq7kKW.mjs} +6 -6
  266. package/dist/{wait-flags-CiJGrTCT.mjs → wait-flags-KX7NHdj4.mjs} +2 -2
  267. package/dist/{window-DSb1tqSe.mjs → window-CI_QD04s.mjs} +1 -1
  268. package/package.json +1 -1
  269. package/skill-data/core/SKILL.md +24 -23
  270. package/skill-data/dashboard/SKILL.md +1 -1
  271. package/skill-data/data-action/SKILL.md +125 -0
  272. package/skill-data/document/SKILL.md +12 -1
  273. package/skill-data/git-sync/SKILL.md +61 -9
  274. package/skill-data/mbql/SKILL.md +5 -0
  275. package/skill-data/metadata/SKILL.md +36 -6
  276. package/skill-data/native-sql/SKILL.md +1 -1
  277. package/skill-data/transform/SKILL.md +1 -63
  278. package/dist/body-CshgcV6U.mjs +0 -17
  279. package/dist/card-CefVYtF7.mjs +0 -24
  280. package/dist/collection-Be5AHVWP.mjs +0 -20
  281. package/dist/create-DiJ8bUb-.mjs +0 -34
  282. package/dist/dashboard-CMw13KXM.mjs +0 -33
  283. package/dist/database-JtHTqSpq.mjs +0 -26
  284. package/dist/delete-Bsdwqh7H.mjs +0 -44
  285. package/dist/delete-runtime-BKEzJn22.mjs +0 -49
  286. package/dist/document-BGzVip5_.mjs +0 -19
  287. package/dist/export-IFZdgYZ2.mjs +0 -63
  288. package/dist/field-BJ6HoLRd.mjs +0 -18
  289. package/dist/field-fDtIrY6D.mjs +0 -80
  290. package/dist/get-i0KInCw9.mjs +0 -32
  291. package/dist/get-jofVjU6e.mjs +0 -31
  292. package/dist/git-sync-TjX1r_wF.mjs +0 -136
  293. package/dist/git-sync-xKC1sqC4.mjs +0 -28
  294. package/dist/list-Cuhf2lKL.mjs +0 -35
  295. package/dist/list-D-SyhKFw.mjs +0 -34
  296. package/dist/parse-id-DtM6q9HU.mjs +0 -10
  297. package/dist/query-CxESKMve.mjs +0 -114
  298. package/dist/query-result-E4Q-Gra6.mjs +0 -15
  299. package/dist/run-FmRruANb.mjs +0 -64
  300. package/dist/search-CR_xNArA.mjs +0 -97
  301. package/dist/selectors-C-vgMcGK.mjs +0 -35
  302. package/dist/snippet-DWHTSo9c.mjs +0 -19
  303. package/dist/sync-task-BtDnTXCP.mjs +0 -38
  304. package/dist/table-C6h4tIRw.mjs +0 -37
  305. package/dist/table-I8NXSdUC.mjs +0 -18
  306. package/dist/timeline-B_ESH-6W.mjs +0 -21
  307. package/dist/transform-BNuNiH9d.mjs +0 -28
  308. package/dist/transform-job-B7yc6dfH.mjs +0 -22
  309. package/dist/transform-test-BjjCQ2xm.mjs +0 -169
  310. package/dist/transform-test-C1Oqtfb-.mjs +0 -16
  311. package/dist/transform-test-gzDcbypy.mjs +0 -25
  312. package/dist/transport-CyVo29u7.mjs +0 -313
  313. package/dist/tree-CuyF116R.mjs +0 -26
  314. package/dist/update-l3PyNQKG.mjs +0 -41
  315. package/dist/upload-2YFFBSln.mjs +0 -13
  316. package/skill-data/transform-test-plan/SKILL.md +0 -171
  317. package/skill-data/transform-test-plan/references/checklist.md +0 -81
  318. package/skill-data/transform-test-plan/references/checks.md +0 -263
@@ -1,22 +1,28 @@
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-B8RtMb4B.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 { r as PivotExportFormat, t as DatasetQuery } from "./query-BKtMP5eH.mjs";
8
+ import { a as CardQueryResult, t as Card } from "./card-P5mBknsl.mjs";
9
+ import { b as TableVisibilityType, p as TableQueryMetadata, s as TableDataLayerTier, t as Table, u as TableForeignKey, v as TableSelectors } from "./table-Ci6bhZkb.mjs";
10
+ import { t as Database } from "./database-BT7DVgSr.mjs";
10
11
  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";
12
+ import { o as compiledQuerySchema, r as QueryMetadata } from "./dataset-BmvCxGoE.mjs";
13
+ import { c as CollectionItem, m as CollectionTreeNode, r as Collection } from "./collection-D3KXhvnc.mjs";
12
14
  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";
15
+ import { l as Dashcard, o as DashboardDetail, r as DashboardCopy, t as Dashboard } from "./dashboard-Phz3XpRM.mjs";
16
+ import { a as DataActionExecuteResult, s as dataActionSchema } from "./data-action-DZxVB_hD.mjs";
17
+ import { r as pollUntil } from "./poll-Dz4tUm2f.mjs";
18
+ import { i as DependencyEntity, s as DependencyGraph, t as BreakingSource, u as DependencyNode } from "./dependency-DzLH3J8P.mjs";
19
+ import { t as Document } from "./document-DFCj1Az_.mjs";
16
20
  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";
21
+ 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";
22
+ import { t as Glossary } from "./glossary-BlNCrYbw.mjs";
23
+ import { a as libraryWireSchema, i as LibraryPublishTablesInput, n as LibraryCollectionInfo, o as toLibrary } from "./library-Ck0EK5bi.mjs";
19
24
  import { t as Measure } from "./measure-CtfjqJFP.mjs";
25
+ import { r as ModerationReviewCreateInput, t as ModerationReview } from "./moderation-review-BdqEH6N1.mjs";
20
26
  import { t as Pulse } from "./pulse-Dz0ocv0l.mjs";
21
27
  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
28
  import { r as SearchResult } from "./search-BAXg-EJw.mjs";
@@ -26,9 +32,9 @@ import { n as SetupResult } from "./setup-CO7QV-ao.mjs";
26
32
  import { i as TimelineEvent, t as Timeline } from "./timeline-CCSU2qOS.mjs";
27
33
  import { c as transformJobSchema, n as TransformJobActiveResult, s as transformJobRunResultSchema } from "./transform-job-CCguL6LP.mjs";
28
34
  import { t as TransformTag } from "./transform-tag-CcElGp3C.mjs";
29
- import { i as TransformTestRunResult, t as TransformTest } from "./transform-test-BjjCQ2xm.mjs";
30
35
  import { t as UploadResult } from "./upload-DAtxBBms.mjs";
31
36
  import { z } from "zod";
37
+ import { setTimeout } from "node:timers/promises";
32
38
  //#region \0rolldown/runtime.js
33
39
  var __defProp = Object.defineProperty;
34
40
  var __exportAll = (all, no_symbols) => {
@@ -41,43 +47,324 @@ var __exportAll = (all, no_symbols) => {
41
47
  return target;
42
48
  };
43
49
  //#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()
50
+ //#region ../client/src/http/response-shape.ts
51
+ async function parseJsonResponse(text, schema, context) {
52
+ try {
53
+ return parseJson(text, schema, { source: context.url });
54
+ } catch (error) {
55
+ if (error instanceof ValidationError) throw ResponseShapeError.fromZodIssues({
56
+ kind: "zod",
57
+ method: context.method,
58
+ url: context.url,
59
+ status: context.status,
60
+ zodIssues: error.developerDetail.zodIssues,
61
+ serverTag: await context.getServerTag(),
62
+ serverSkew: context.serverSkew
63
+ });
64
+ throw error;
65
+ }
66
+ }
67
+ //#endregion
68
+ //#region ../client/src/http/retry.ts
69
+ const BASE_DELAY_MS = 250;
70
+ const MAX_DELAY_MS = 8e3;
71
+ const MS_PER_SECOND = 1e3;
72
+ function backoffDelay({ attempt, retryAfterHeader }) {
73
+ const fromHeader = parseRetryAfter(retryAfterHeader);
74
+ if (fromHeader !== null) return fromHeader;
75
+ return Math.min(MAX_DELAY_MS, BASE_DELAY_MS * 2 ** attempt);
76
+ }
77
+ function parseRetryAfter(header) {
78
+ if (!header) return null;
79
+ const numeric = Number(header);
80
+ if (Number.isFinite(numeric) && numeric >= 0) return Math.round(numeric * MS_PER_SECOND);
81
+ const dateMs = Date.parse(header);
82
+ if (Number.isFinite(dateMs)) return Math.max(0, dateMs - Date.now());
83
+ return null;
84
+ }
85
+ function sleep(ms, signal) {
86
+ return setTimeout(ms, void 0, { signal });
87
+ }
88
+ async function runWithRetries(attempt, signal) {
89
+ let attemptIndex = 0;
90
+ while (true) {
91
+ const outcome = await attempt(attemptIndex);
92
+ if (outcome.kind === "success") return outcome.response;
93
+ await sleep(outcome.delayMs, signal);
94
+ attemptIndex += 1;
95
+ }
96
+ }
97
+ //#endregion
98
+ //#region ../client/src/http/transport.ts
99
+ const UNAUTHORIZED_STATUS = 401;
100
+ const DEFAULT_TIMEOUT_MS = 3e4;
101
+ const OCTET_STREAM_CONTENT_TYPE = "application/octet-stream";
102
+ const TEXT_CONTENT_TYPE_PREFIX = "text/";
103
+ const ERROR_BODY_BYTE_CAP = 64 * 1024;
104
+ const IDEMPOTENT_METHODS = /* @__PURE__ */ new Set([
105
+ "GET",
106
+ "HEAD",
107
+ "OPTIONS"
54
108
  ]);
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();
109
+ function createTransport(config, options) {
110
+ const baseUrl = normalizeUrl(config.url);
111
+ assertCredentialHeaderSafe(config.credential);
112
+ const fetchImpl = options.fetchImpl ?? globalThis.fetch.bind(globalThis);
113
+ let settledProfile = options.server ?? null;
114
+ const getServerTag = options.getServerTag ?? (async () => tagOf(settledProfile));
115
+ const serverSkew = () => settledProfile === null ? null : settledProfile.skew;
116
+ const refreshCredential = options.refreshCredential;
117
+ let credential = config.credential;
118
+ const knownSecrets = new Set(credentialSecrets(credential));
119
+ const redactionContext = { knownSecrets };
120
+ let refreshInFlight = null;
121
+ function tryRefreshCredential() {
122
+ const refresh = refreshCredential;
123
+ if (credential.kind !== "oauth" || refresh === void 0) return Promise.resolve(false);
124
+ refreshInFlight ??= refreshOnce(refresh).finally(() => {
125
+ refreshInFlight = null;
126
+ });
127
+ return refreshInFlight;
128
+ }
129
+ async function refreshOnce(refresh) {
130
+ const next = await refresh();
131
+ if (next === null) return false;
132
+ credential = next;
133
+ for (const secret of credentialSecrets(next)) knownSecrets.add(secret);
134
+ return true;
135
+ }
136
+ async function attemptOnce(prepared, attempt) {
137
+ const hasRetriesLeft = attempt < prepared.retries;
138
+ const timeoutSignal = AbortSignal.timeout(prepared.timeoutMs);
139
+ const combined = combineAborts(timeoutSignal, prepared.cancelSignal);
140
+ let response;
141
+ try {
142
+ response = await fetchImpl(prepared.url, {
143
+ method: prepared.method,
144
+ headers: prepared.headers,
145
+ body: prepared.body,
146
+ signal: combined
147
+ });
148
+ } catch (error) {
149
+ throwIfAborted(prepared.cancelSignal);
150
+ const isStaleSocketFirstTry = attempt === 0 && isConnectionClosed(error);
151
+ if (prepared.idempotent && (hasRetriesLeft || isStaleSocketFirstTry)) return {
152
+ kind: "retry",
153
+ delayMs: backoffDelay({ attempt })
154
+ };
155
+ if (timeoutSignal.aborted) throw new TimeoutError(`Request timed out after ${prepared.timeoutMs}ms`, {
156
+ kind: "http",
157
+ method: prepared.method,
158
+ url: prepared.url,
159
+ timeoutMs: prepared.timeoutMs
160
+ });
161
+ throw buildNetworkError(error, prepared.method, prepared.url);
162
+ }
163
+ const canRetryStatus = hasRetriesLeft && prepared.idempotent;
164
+ if (!response.ok && isRetryableStatus(response.status) && canRetryStatus) {
165
+ const retryAfter = response.headers.get("Retry-After");
166
+ response.body?.cancel().catch(() => void 0);
167
+ return {
168
+ kind: "retry",
169
+ delayMs: backoffDelay({
170
+ attempt,
171
+ retryAfterHeader: retryAfter
172
+ })
173
+ };
174
+ }
175
+ if (!response.ok) {
176
+ const rawBody = await readBodyForError(response);
177
+ const serverTag = await getServerTag();
178
+ throw new HttpError({
179
+ status: response.status,
180
+ statusText: response.statusText,
181
+ method: prepared.method,
182
+ url: prepared.url,
183
+ responseHeaders: response.headers,
184
+ rawBody,
185
+ serverTag,
186
+ redactionContext
187
+ });
188
+ }
189
+ assertContentType(response, prepared);
190
+ return {
191
+ kind: "success",
192
+ response
193
+ };
194
+ }
195
+ async function executeRaw(prepared) {
196
+ try {
197
+ return await runWithRetries((attempt) => attemptOnce(prepared, attempt), prepared.cancelSignal);
198
+ } catch (error) {
199
+ throwIfAborted(prepared.cancelSignal);
200
+ throw error;
201
+ }
202
+ }
203
+ async function executeWithAuthRefresh(path, opts) {
204
+ const prepared = prepare(path, opts);
205
+ try {
206
+ return {
207
+ response: await executeRaw(prepared),
208
+ prepared
209
+ };
210
+ } catch (error) {
211
+ if (error instanceof HttpError && error.status === UNAUTHORIZED_STATUS) {
212
+ if (await tryRefreshCredential()) {
213
+ const retried = prepare(path, opts);
214
+ return {
215
+ response: await executeRaw(retried),
216
+ prepared: retried
217
+ };
218
+ }
219
+ }
220
+ throw error;
221
+ }
222
+ }
223
+ function prepare(path, opts = {}) {
224
+ const method = opts.method ?? "GET";
225
+ const expectContentType = opts.expectContentType ?? "json";
226
+ const url = buildUrl(baseUrl, path, opts.query);
227
+ const headers = new Headers();
228
+ const auth = credentialAuthHeader(credential);
229
+ headers.set(auth.name, auth.value);
230
+ headers.set("accept", acceptHeader(expectContentType));
231
+ headers.set("user-agent", options.userAgent);
232
+ let body = null;
233
+ if (opts.body !== void 0 && opts.body !== null) if (typeof opts.body === "string" || opts.body instanceof URLSearchParams) body = opts.body;
234
+ else if (opts.body instanceof FormData || opts.body instanceof ReadableStream) body = opts.body;
235
+ else if (opts.body instanceof Uint8Array) {
236
+ body = opts.body;
237
+ headers.set("content-type", OCTET_STREAM_CONTENT_TYPE);
238
+ } else {
239
+ body = JSON.stringify(opts.body);
240
+ headers.set("content-type", JSON_CONTENT_TYPE);
241
+ }
242
+ return {
243
+ url,
244
+ method,
245
+ headers,
246
+ body,
247
+ expectContentType,
248
+ retries: opts.retries ?? 3,
249
+ idempotent: opts.idempotent ?? IDEMPOTENT_METHODS.has(method),
250
+ timeoutMs: opts.timeoutMs ?? DEFAULT_TIMEOUT_MS,
251
+ cancelSignal: combineAborts(opts.signal, options.signal)
252
+ };
253
+ }
254
+ let serverProfile = options.server === void 0 ? null : Promise.resolve(options.server);
255
+ async function server(wait = {}) {
256
+ throwIfAborted(wait.signal);
257
+ if (serverProfile === null) {
258
+ const probe = probeServer(transport).then((info) => {
259
+ settledProfile = createServerProfile(info);
260
+ return settledProfile;
261
+ });
262
+ probe.catch(() => {
263
+ serverProfile = null;
264
+ });
265
+ serverProfile = probe;
266
+ }
267
+ return untilAborted(serverProfile, wait.signal);
268
+ }
269
+ const enforceRequirements = options.enforceRequirements ?? true;
270
+ async function requireFeatures(features, wait = {}) {
271
+ if (!enforceRequirements || features.length === 0) return;
272
+ const failure = checkFeatures(features, await server(wait));
273
+ if (failure !== null) throw new CapabilityError(failure);
274
+ }
275
+ async function requireMethod(key, wait = {}) {
276
+ return requireFeatures(methodRequirements(key), wait);
277
+ }
278
+ const transport = {
279
+ server,
280
+ require: requireMethod,
281
+ requireFeatures,
282
+ async requestRaw(path, opts) {
283
+ return (await executeWithAuthRefresh(path, opts ?? {})).response;
284
+ },
285
+ async requestParsed(schema, path, opts) {
286
+ const { response, prepared } = await executeWithAuthRefresh(path, {
287
+ ...opts,
288
+ expectContentType: "json"
289
+ });
290
+ return parseJsonResponse(await response.text(), schema, {
291
+ method: prepared.method,
292
+ url: prepared.url,
293
+ status: response.status,
294
+ getServerTag,
295
+ serverSkew: serverSkew()
296
+ });
297
+ },
298
+ async requestStream(path, opts) {
299
+ const { response, prepared } = await executeWithAuthRefresh(path, {
300
+ ...opts,
301
+ expectContentType: opts?.expectContentType ?? "binary"
302
+ });
303
+ if (!response.body) throw new NetworkError("Response had no body to stream", {
304
+ method: prepared.method,
305
+ url: prepared.url,
306
+ cause: "missing body"
307
+ });
308
+ return response.body;
309
+ }
310
+ };
311
+ return transport;
312
+ }
313
+ function tagOf(profile) {
314
+ return profile === null ? null : profile.version.tag;
315
+ }
316
+ function buildUrl(baseUrl, path, query) {
317
+ const normalizedPath = path.startsWith("/") ? path : `/${path}`;
318
+ const target = new URL(baseUrl + normalizedPath);
319
+ if (query) for (const [key, value] of Object.entries(query)) {
320
+ if (value === void 0) continue;
321
+ if (Array.isArray(value)) for (const entry of value) target.searchParams.append(key, String(entry));
322
+ else target.searchParams.append(key, String(value));
323
+ }
324
+ return target.toString();
325
+ }
326
+ function acceptHeader(expected) {
327
+ if (expected === "json") return JSON_CONTENT_TYPE;
328
+ if (expected === "text") return "text/*";
329
+ return "*/*";
330
+ }
331
+ function assertContentType(response, prepared) {
332
+ if (prepared.expectContentType === "binary") return;
333
+ const contentType = response.headers.get("content-type");
334
+ if (contentType === null) throwContentTypeMismatch(response, prepared, prepared.expectContentType);
335
+ if (prepared.expectContentType === "json" && !contentType.includes("application/json")) throwContentTypeMismatch(response, prepared, "json");
336
+ if (prepared.expectContentType === "text" && !contentType.startsWith(TEXT_CONTENT_TYPE_PREFIX)) throwContentTypeMismatch(response, prepared, "text");
337
+ }
338
+ function throwContentTypeMismatch(response, prepared, expected) {
339
+ const actual = response.headers.get("content-type") ?? "no content-type";
340
+ throw new HttpError({
341
+ status: response.status,
342
+ statusText: response.statusText,
343
+ method: prepared.method,
344
+ url: prepared.url,
345
+ responseHeaders: response.headers,
346
+ rawBody: null,
347
+ overrideUserMessage: `Expected ${expected} response but got ${actual}`
348
+ });
349
+ }
350
+ async function readBodyForError(response) {
351
+ try {
352
+ return Buffer.from(await response.arrayBuffer()).subarray(0, ERROR_BODY_BYTE_CAP).toString("utf8");
353
+ } catch (error) {
354
+ return `[body read failed: ${errorMessage(error)}]`;
355
+ }
356
+ }
357
+ //#endregion
358
+ //#region ../client/src/resources/pivot-export.ts
359
+ const PivotedExportsSetting = z.object({ "enable-pivoted-exports": z.boolean() });
360
+ /**
361
+ * Refuse a pivoted export the server would answer with plain rows: a JSON export keeps only the
362
+ * ungrouped rows, and an admin can turn pivoted CSV and XLSX exports off.
363
+ */
364
+ async function assertPivotedExport(transport, format, options) {
365
+ if (!PivotExportFormat.safeParse(format).success) throw new ConfigError(`a ${format} export cannot be pivoted; only ${PivotExportFormat.options.join(" and ")} can`);
366
+ 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");
367
+ }
81
368
  //#endregion
82
369
  //#region ../client/src/resources/card.ts
83
370
  const CardApiList = z.array(Card);
@@ -134,15 +421,22 @@ function cardResource(transport) {
134
421
  });
135
422
  }
136
423
  /**
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.
424
+ * Run the query associated with a Card, and return its results as a file in the specified
425
+ * format. Unlike `query`, this endpoint takes a form-encoded body and answers bytes, so a caller
426
+ * consumes the stream rather than a value. A pivot the server would answer with plain rows (a
427
+ * JSON export, or pivoted exports turned off) is refused. `csv_include_bom` opens a CSV with a
428
+ * UTF-8 byte order mark; a server without it drops the key silently, so asking for one is refused
429
+ * there before the wire.
139
430
  */
140
431
  async function exportQuery(id, format, params, options = {}) {
141
432
  await transport.require("card.exportQuery", options);
433
+ await transport.requireFeatures(params.csv_include_bom ? ["exportCsvByteOrderMark"] : [], options);
434
+ if (params.pivot_results) await assertPivotedExport(transport, format, options);
142
435
  const body = new URLSearchParams({
143
436
  parameters: JSON.stringify(params.parameters),
144
437
  format_rows: String(params.format_rows),
145
- pivot_results: String(params.pivot_results)
438
+ pivot_results: String(params.pivot_results),
439
+ csv_include_bom: String(params.csv_include_bom)
146
440
  });
147
441
  return transport.requestStream(`/api/card/${id}/query/${format}`, {
148
442
  ...options,
@@ -226,20 +520,20 @@ function refPath(ref) {
226
520
  return encodeURIComponent(ref);
227
521
  }
228
522
  /**
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.
523
+ * List every collection the caller can read, the Library and its children among them, parsing each
524
+ * through the caller's own projection. `Collection` pins `type`, `namespace` and `authority_level`
525
+ * to closed enums, so a consumer reading a few fields off every collection on the instance narrows
526
+ * here: one collection carrying a server value outside those sets then costs nothing to a caller
527
+ * that never reads the field.
234
528
  */
235
- async function listCollectionsWithLibrary(transport, schema, options = {}) {
236
- return transport.requestParsed(z.array(schema), "/api/collection", {
237
- ...options,
238
- query: { "include-library": true }
239
- });
529
+ async function listCollectionsAs(transport, schema, options = {}) {
530
+ return transport.requestParsed(z.array(schema), "/api/collection", { ...options });
240
531
  }
241
532
  function collectionResource(transport) {
242
- /** List collections. `filter` picks a server-side preset: everything, archived, or personal. */
533
+ /**
534
+ * List collections. `filter` picks a server-side preset: everything, archived, or personal. Every
535
+ * preset includes the Library collections that match it.
536
+ */
243
537
  async function list(params = {}, options = {}) {
244
538
  await transport.require("collection.list", options);
245
539
  return {
@@ -250,18 +544,6 @@ function collectionResource(transport) {
250
544
  total: null
251
545
  };
252
546
  }
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
547
  /** Get one collection by id, entity id, or the `root`/`trash` alias. */
266
548
  async function get(ref, options = {}) {
267
549
  await transport.require("collection.get", options);
@@ -276,7 +558,11 @@ function collectionResource(transport) {
276
558
  body: params
277
559
  });
278
560
  }
279
- /** Update a collection, patching only the fields the body carries. */
561
+ /**
562
+ * Update a collection, patching the fields the body carries. The server reads an absent
563
+ * `archived` as `false`, so a patch without it restores an archived collection, and a patch that
564
+ * moves a collection into the trash ignores `parent_id`.
565
+ */
280
566
  async function update(ref, params, options = {}) {
281
567
  await transport.require("collection.update", options);
282
568
  return transport.requestParsed(Collection, `/api/collection/${refPath(ref)}`, {
@@ -309,16 +595,18 @@ function collectionResource(transport) {
309
595
  });
310
596
  }
311
597
  /** Fetch the collection hierarchy as a forest of nested nodes. */
312
- async function tree(options = {}) {
598
+ async function tree(params = {}, options = {}) {
313
599
  await transport.require("collection.tree", options);
314
600
  return {
315
- data: await transport.requestParsed(CollectionTreeApiList, "/api/collection/tree", { ...options }),
601
+ data: await transport.requestParsed(CollectionTreeApiList, "/api/collection/tree", {
602
+ ...options,
603
+ query: { "include-library": params["include-library"] }
604
+ }),
316
605
  total: null
317
606
  };
318
607
  }
319
608
  return {
320
609
  list,
321
- listWithLibrary,
322
610
  get,
323
611
  create,
324
612
  update,
@@ -407,9 +695,13 @@ function dashboardResource(transport) {
407
695
  }
408
696
  /**
409
697
  * 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`.
698
+ * copy duplicates its questions and metrics and references its models. With `is_deep_copy`
699
+ * false or absent the copy references every card, and a dashboard holding unarchived dashboard
700
+ * questions is refused. Archived cards, cards the caller cannot read, and every card on a
701
+ * dashcard whose main card the caller cannot read are left out and reported as `uncopied`, once
702
+ * per dashcard they sat on. A left-out main card takes its dashcard with it; a left-out series
703
+ * card stays on a dashcard whose main card is referenced and is dropped from one whose main card
704
+ * is duplicated. Action, link and placeholder dashcards are not copied.
413
705
  */
414
706
  async function copy(id, params = {}, options = {}) {
415
707
  await transport.require("dashboard.copy", options);
@@ -548,6 +840,81 @@ function stripEntityId(dashcard) {
548
840
  };
549
841
  }
550
842
  //#endregion
843
+ //#region ../client/src/resources/data-action.ts
844
+ function dataActionResource(transport) {
845
+ async function readSchema(options) {
846
+ const { features } = await transport.server(options);
847
+ return dataActionSchema(features);
848
+ }
849
+ /** List the unarchived data actions the caller can see. `GET /api/action` answers a bare array. */
850
+ async function list(options = {}) {
851
+ await transport.require("dataAction.list", options);
852
+ const schema = await readSchema(options);
853
+ return {
854
+ data: await transport.requestParsed(z.array(schema), "/api/action", { ...options }),
855
+ total: null
856
+ };
857
+ }
858
+ /** Get one unarchived data action by id. */
859
+ async function get(id, options = {}) {
860
+ await transport.require("dataAction.get", options);
861
+ const schema = await readSchema(options);
862
+ return transport.requestParsed(schema, `/api/action/${id}`, { ...options });
863
+ }
864
+ /** Create a data action — a parameterized native query that writes to a database — in a collection. */
865
+ async function create(params, options = {}) {
866
+ await transport.require("dataAction.create", options);
867
+ const schema = await readSchema(options);
868
+ return transport.requestParsed(schema, "/api/action", {
869
+ ...options,
870
+ method: "POST",
871
+ body: params
872
+ });
873
+ }
874
+ /** Update a data action by id, patching only the fields the body carries. */
875
+ async function update(id, params, options = {}) {
876
+ await transport.require("dataAction.update", options);
877
+ const schema = await readSchema(options);
878
+ return transport.requestParsed(schema, `/api/action/${id}`, {
879
+ ...options,
880
+ method: "PUT",
881
+ body: params
882
+ });
883
+ }
884
+ /** Archive (soft-delete) a data action by id. Metabase models this as an update, not its own endpoint. */
885
+ async function archive(id, options = {}) {
886
+ await transport.require("dataAction.archive", options);
887
+ return update(id, { archived: true }, options);
888
+ }
889
+ /** Delete a data action by id, removing it and the dashboard buttons that run it. */
890
+ async function remove(id, options = {}) {
891
+ await transport.require("dataAction.delete", options);
892
+ await transport.requestRaw(`/api/action/${id}`, {
893
+ ...options,
894
+ method: "DELETE",
895
+ expectContentType: "binary"
896
+ });
897
+ }
898
+ /** Execute a data action by id with parameter values keyed by parameter id. */
899
+ async function execute(id, params, options = {}) {
900
+ await transport.require("dataAction.execute", options);
901
+ return transport.requestParsed(DataActionExecuteResult, `/api/action/${id}/execute`, {
902
+ ...options,
903
+ method: "POST",
904
+ body: params
905
+ });
906
+ }
907
+ return {
908
+ list,
909
+ get,
910
+ create,
911
+ update,
912
+ archive,
913
+ delete: remove,
914
+ execute
915
+ };
916
+ }
917
+ //#endregion
551
918
  //#region ../client/src/resources/database.ts
552
919
  const DatabaseApiList = z.object({
553
920
  data: z.array(Database),
@@ -663,7 +1030,8 @@ function datasetResource(transport) {
663
1030
  */
664
1031
  async function native(datasetQuery, params = {}, options = {}) {
665
1032
  await transport.require("dataset.native", options);
666
- return transport.requestParsed(CompiledQuery, "/api/dataset/native", {
1033
+ const { features } = await transport.server(options);
1034
+ return transport.requestParsed(compiledQuerySchema(features), "/api/dataset/native", {
667
1035
  ...options,
668
1036
  method: "POST",
669
1037
  body: {
@@ -686,18 +1054,33 @@ function datasetResource(transport) {
686
1054
  });
687
1055
  }
688
1056
  /**
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.
1057
+ * Execute a query and download the result data as a file in the specified format. Unlike
1058
+ * `query`, this endpoint answers bytes, so a caller consumes the stream rather than a value.
1059
+ * `visualization_settings` drive `format_rows` column formatting and, through
1060
+ * `pivot_table.column_split`, the layout `pivot_results` lays the rows out in. The server only
1061
+ * computes that layout for a query it runs as a pivot, which it reads from the query's own
1062
+ * `was-pivot`, so `pivot_results` sets it. A pivot the server would answer with plain rows (a
1063
+ * JSON export, or pivoted exports turned off) is refused. `csv_include_bom` opens a CSV with a
1064
+ * UTF-8 byte order mark; a server without it drops the key silently, so asking for one is refused
1065
+ * there before the wire.
691
1066
  */
692
1067
  async function exportQuery(format, params, options = {}) {
693
1068
  await transport.require("dataset.exportQuery", options);
1069
+ await transport.requireFeatures(params.csv_include_bom ? ["exportCsvByteOrderMark"] : [], options);
1070
+ if (params.pivot_results) await assertPivotedExport(transport, format, options);
1071
+ const exported = params.pivot_results ? {
1072
+ ...params.query,
1073
+ "was-pivot": true
1074
+ } : params.query;
694
1075
  return transport.requestStream(`/api/dataset/${format}`, {
695
1076
  ...options,
696
1077
  method: "POST",
697
1078
  body: {
698
- query: params.query,
1079
+ query: exported,
1080
+ visualization_settings: params.visualization_settings,
699
1081
  format_rows: params.format_rows,
700
- pivot_results: params.pivot_results
1082
+ pivot_results: params.pivot_results,
1083
+ csv_include_bom: params.csv_include_bom
701
1084
  }
702
1085
  });
703
1086
  }
@@ -709,133 +1092,18 @@ function datasetResource(transport) {
709
1092
  };
710
1093
  }
711
1094
  //#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
1095
  //#region ../client/src/resources/dependency.ts
818
1096
  const DependencyNodeApiList = z.array(DependencyNode);
819
1097
  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
1098
  function dependencyResource(transport) {
832
1099
  /**
833
1100
  * The upstream dependency graph of one entity. `nodes` holds the starting entity plus every
834
1101
  * entity it depends on, directly or transitively; each edge runs from the dependent to what it
835
- * depends on.
1102
+ * depends on. A measure starts a graph only on a server with `measureDependencyGraph`.
836
1103
  */
837
1104
  async function graph(type, id, options = {}) {
838
1105
  await transport.require("dependency.graph", options);
1106
+ if (type === "measure") await transport.requireFeatures(["measureDependencyGraph"], options);
839
1107
  return transport.requestParsed(DependencyGraph, "/api/ee/dependencies/graph", {
840
1108
  ...options,
841
1109
  query: {
@@ -852,7 +1120,6 @@ function dependencyResource(transport) {
852
1120
  */
853
1121
  async function dependents(type, id, params = {}, options = {}) {
854
1122
  await transport.require("dependency.dependents", options);
855
- await transport.requireFeatures(filterFeatures(params), options);
856
1123
  return {
857
1124
  data: await transport.requestParsed(DependencyNodeApiList, "/api/ee/dependencies/graph/dependents", {
858
1125
  ...options,
@@ -879,7 +1146,6 @@ function dependencyResource(transport) {
879
1146
  */
880
1147
  async function broken(type, id, params = {}, options = {}) {
881
1148
  await transport.require("dependency.broken", options);
882
- await transport.requireFeatures(filterFeatures(params), options);
883
1149
  return {
884
1150
  data: await transport.requestParsed(DependencyEntityApiList, "/api/ee/dependencies/graph/broken", {
885
1151
  ...options,
@@ -897,15 +1163,23 @@ function dependencyResource(transport) {
897
1163
  };
898
1164
  }
899
1165
  /**
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,
1166
+ * Walk the entities that no readable, unarchived dependent depends on, one page at a time: an
1167
+ * entity used only by archived content, or by content the caller cannot read, is listed. `types`
1168
+ * and `card-types` narrow which kinds are listed, `query` matches against names and locations,
902
1169
  * `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.
1170
+ * `sort-direction` order the result. A `query` leaves sandboxes out, since they have no name or
1171
+ * location to match, so sandboxes alone with a `query` answer one empty page without a request.
1172
+ * This endpoint pages on the server, so the caller consumes pages and decides how far to pull.
905
1173
  */
906
1174
  async function* unreferencedPages(params = {}, options = {}) {
907
1175
  await transport.require("dependency.unreferencedPages", options);
908
- await transport.requireFeatures(filterFeatures(params), options);
1176
+ if (queryLeavesNoKind(params)) {
1177
+ yield {
1178
+ items: [],
1179
+ total: 0
1180
+ };
1181
+ return;
1182
+ }
909
1183
  yield* paginatePages(transport, "/api/ee/dependencies/graph/unreferenced", DependencyNode, {
910
1184
  query: itemListQuery(params),
911
1185
  ...options.offset !== void 0 && { offset: options.offset },
@@ -923,7 +1197,13 @@ function dependencyResource(transport) {
923
1197
  */
924
1198
  async function* breakingPages(params = {}, options = {}) {
925
1199
  await transport.require("dependency.breakingPages", options);
926
- await transport.requireFeatures(filterFeatures(params), options);
1200
+ if (queryLeavesNoKind(params)) {
1201
+ yield {
1202
+ items: [],
1203
+ total: 0
1204
+ };
1205
+ return;
1206
+ }
927
1207
  yield* paginatePages(transport, "/api/ee/dependencies/graph/breaking", BreakingSource, {
928
1208
  query: itemListQuery(params),
929
1209
  ...options.offset !== void 0 && { offset: options.offset },
@@ -940,9 +1220,14 @@ function dependencyResource(transport) {
940
1220
  breakingPages
941
1221
  };
942
1222
  }
1223
+ function queryLeavesNoKind(params) {
1224
+ const { query, types } = params;
1225
+ if (query === void 0 || types === void 0 || types.length === 0) return false;
1226
+ return types.every((type) => type === "sandbox");
1227
+ }
943
1228
  function itemListQuery(params) {
944
1229
  return {
945
- types: params.types,
1230
+ types: params.types === void 0 ? void 0 : [...new Set(params.types)],
946
1231
  "card-types": params["card-types"],
947
1232
  query: params.query,
948
1233
  "include-personal-collections": params["include-personal-collections"],
@@ -1109,21 +1394,39 @@ async function fetchOptionalParsed(client, path, schema, options = {}) {
1109
1394
  //#region ../client/src/resources/field.ts
1110
1395
  const FieldApiSummary = z.tuple([z.tuple([z.literal("count"), z.number().int()]), z.tuple([z.literal("distincts"), z.number().int()])]);
1111
1396
  function fieldResource(transport) {
1112
- /** Get one field by id. */
1397
+ /**
1398
+ * Get one field by id. A server that labels data sensitivity answers `data_sensitivity`, `null`
1399
+ * for an unlabelled field; any other answers the field without the key (`hasDataSensitivity`).
1400
+ */
1113
1401
  async function get(id, options = {}) {
1114
1402
  await transport.require("field.get", options);
1115
- return transport.requestParsed(Field, `/api/field/${id}`, { ...options });
1403
+ const { features } = await transport.server(options);
1404
+ return transport.requestParsed(fieldDetailSchema(features), `/api/field/${id}`, { ...options });
1116
1405
  }
1117
1406
  /**
1118
1407
  * Update a field by id, patching only the fields the body carries. A `data_sensitivity` label is
1119
1408
  * a person's call the server's classifier never overwrites, and `null` withdraws it so the
1120
1409
  * 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.
1410
+ * the label is refused there before the wire. Answers the field the way `get` does.
1122
1411
  */
1123
1412
  async function update(id, params, options = {}) {
1124
1413
  await transport.require("field.update", options);
1125
1414
  await transport.requireFeatures(params.data_sensitivity === void 0 ? [] : ["fieldDataSensitivity"], options);
1126
- return transport.requestParsed(Field, `/api/field/${id}`, {
1415
+ const { features } = await transport.server(options);
1416
+ return transport.requestParsed(fieldDetailSchema(features), `/api/field/${id}`, {
1417
+ ...options,
1418
+ method: "PUT",
1419
+ body: params
1420
+ });
1421
+ }
1422
+ /**
1423
+ * Label a field's data sensitivity by hand. A person's label is never overwritten by the server's
1424
+ * classifier; `null` withdraws it, so whatever label the classifier wrote shows again. Answers
1425
+ * the field with the label it now carries.
1426
+ */
1427
+ async function setDataSensitivity(id, params, options = {}) {
1428
+ await transport.require("field.setDataSensitivity", options);
1429
+ return transport.requestParsed(FieldWithDataSensitivity, `/api/field/${id}`, {
1127
1430
  ...options,
1128
1431
  method: "PUT",
1129
1432
  body: params
@@ -1131,8 +1434,11 @@ function fieldResource(transport) {
1131
1434
  }
1132
1435
  /**
1133
1436
  * 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.
1437
+ * matching values of `id` paired with them, ordered by value, at most `limit` of them. An FK on
1438
+ * either side is followed to the PK it points at, and a field that resolves to the same field as
1439
+ * `searchId` answers each value alone. Without `value`, the first `limit` values. A field with
1440
+ * custom display values answers every mapped value with its display value instead, matching
1441
+ * `value` against the display value, ignoring both `searchId` and `limit`.
1136
1442
  */
1137
1443
  async function search(id, searchId, params, options = {}) {
1138
1444
  await transport.require("field.search", options);
@@ -1146,11 +1452,13 @@ function fieldResource(transport) {
1146
1452
  }
1147
1453
  /**
1148
1454
  * 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.
1455
+ * or `null` when no row matches. For a numeric field the server reads the leading number of
1456
+ * `value` and ignores any text after it, refusing only a `value` that has none.
1150
1457
  */
1151
1458
  async function remapping(id, remappedId, params, options = {}) {
1152
1459
  await transport.require("field.remapping", options);
1153
- return fetchOptionalParsed(transport, `/api/field/${id}/remapping/${remappedId}`, FieldRemappedValue, {
1460
+ const { features } = await transport.server(options);
1461
+ return fetchOptionalParsed(transport, `/api/field/${id}/remapping/${remappedId}`, fieldRemappedValueSchema(features, id === remappedId), {
1154
1462
  ...options,
1155
1463
  query: { value: params.value }
1156
1464
  });
@@ -1173,6 +1481,7 @@ function fieldResource(transport) {
1173
1481
  return {
1174
1482
  get,
1175
1483
  update,
1484
+ setDataSensitivity,
1176
1485
  search,
1177
1486
  remapping,
1178
1487
  summary,
@@ -1204,6 +1513,7 @@ const SyncStashStarted = z.object({
1204
1513
  task_id: z.number().int().positive()
1205
1514
  });
1206
1515
  const RemoteSyncSetting = z.string().nullable();
1516
+ const RemoteSyncBranchProperty = z.object({ "remote-sync-branch": z.string().nullable().optional() });
1207
1517
  const FORBIDDEN_STATUS = 403;
1208
1518
  const UNREGISTERED_STATUS = 404;
1209
1519
  function isRemoteUnreadable(error) {
@@ -1251,16 +1561,24 @@ function gitSyncResource(transport) {
1251
1561
  /**
1252
1562
  * Import content from the remote into Metabase. The endpoint queues a task and returns at once;
1253
1563
  * 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.
1564
+ * answers no task id, and there is then nothing to poll. A server that guards the tracked branch
1565
+ * refuses with 409 when `expected_branch` disagrees with the setting; left out, it is the tracked
1566
+ * branch as read just before the request. `merge` folds the remote's changes into local content
1567
+ * by a three-way merge and keeps un-pushed local changes, where a plain import refuses on a dirty
1568
+ * instance.
1255
1569
  */
1256
1570
  async function importFromRemote(params = {}, options = {}) {
1257
1571
  await transport.require("gitSync.import", options);
1572
+ await requireMerge(params.merge, options);
1573
+ const expectedBranch = await guardedBranch(params.expected_branch, options);
1258
1574
  const started = await transport.requestParsed(SyncImportStarted, "/api/ee/remote-sync/import", {
1259
1575
  ...options,
1260
1576
  method: "POST",
1261
1577
  body: {
1262
1578
  branch: params.branch,
1263
- force: params.force
1579
+ force: params.force,
1580
+ merge: params.merge,
1581
+ expected_branch: expectedBranch
1264
1582
  }
1265
1583
  });
1266
1584
  const message = started.message ?? null;
@@ -1274,19 +1592,36 @@ function gitSyncResource(transport) {
1274
1592
  final: await settle(params.wait, options)
1275
1593
  };
1276
1594
  }
1595
+ async function requireMerge(merge, options) {
1596
+ if (merge === true) await transport.requireFeatures(["remoteSyncMerge"], options);
1597
+ }
1598
+ async function guardedBranch(given, options) {
1599
+ if (given !== void 0) return given;
1600
+ const { features } = await transport.server(options);
1601
+ if (!features.remoteSyncBranchGuard) return;
1602
+ return trackedBranch(options);
1603
+ }
1277
1604
  /**
1278
1605
  * 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.
1606
+ * `wait` to poll that task until it reaches a terminal status. A server that guards the tracked
1607
+ * branch refuses with 409 when `branch` is not the tracked one; left out, it is the tracked branch
1608
+ * as read just before the request there, and the server's own default elsewhere. When the remote
1609
+ * has moved past the last sync, a plain export ends in a `conflict` task where `merge` is
1610
+ * available, and is refused with 400 before any task elsewhere; `merge` folds the remote's changes
1611
+ * in by a three-way merge instead, and `force` overwrites them.
1280
1612
  */
1281
1613
  async function exportToRemote(params = {}, options = {}) {
1282
1614
  await transport.require("gitSync.export", options);
1615
+ await requireMerge(params.merge, options);
1616
+ const branchName = await guardedBranch(params.branch, options);
1283
1617
  const started = await transport.requestParsed(SyncExportStarted, "/api/ee/remote-sync/export", {
1284
1618
  ...options,
1285
1619
  method: "POST",
1286
1620
  body: {
1287
- branch: params.branch,
1621
+ branch: branchName,
1288
1622
  message: params.message,
1289
- force: params.force
1623
+ force: params.force,
1624
+ merge: params.merge
1290
1625
  }
1291
1626
  });
1292
1627
  if (params.wait === void 0) return {
@@ -1371,7 +1706,7 @@ function gitSyncResource(transport) {
1371
1706
  async function syncedCollections(options = {}) {
1372
1707
  await transport.require("gitSync.syncedCollections", options);
1373
1708
  return {
1374
- data: (await listCollectionsWithLibrary(transport, SyncScopeCollection, options)).filter((entry) => entry.is_remote_synced === true),
1709
+ data: (await listCollectionsAs(transport, SyncScopeCollection, options)).filter((entry) => entry.is_remote_synced === true),
1375
1710
  total: null
1376
1711
  };
1377
1712
  }
@@ -1387,17 +1722,22 @@ function gitSyncResource(transport) {
1387
1722
  }
1388
1723
  }
1389
1724
  /**
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.
1725
+ * The branch git-sync tracks, or null when none is configured. Refuses when the caller may not
1726
+ * read the setting (it is admin-only) or the server has no remote-sync module, rather than
1727
+ * reading either as unset.
1392
1728
  */
1393
1729
  async function branch(options = {}) {
1394
1730
  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
- }
1731
+ const tracked = (await transport.requestParsed(RemoteSyncBranchProperty, PROBE_PATH, { ...options }))["remote-sync-branch"];
1732
+ 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");
1733
+ return tracked;
1734
+ }
1735
+ /** The branch git-sync tracks, refused when none is configured or the caller may not read it. */
1736
+ async function trackedBranch(options = {}) {
1737
+ await transport.require("gitSync.trackedBranch", options);
1738
+ const tracked = await branch(options);
1739
+ if (tracked === null) throw new ConfigError("git-sync tracks no branch: the remote-sync-branch setting is unset");
1740
+ return tracked;
1401
1741
  }
1402
1742
  /**
1403
1743
  * Poll the current task until it reaches a terminal status. A server with no task at all
@@ -1429,36 +1769,11 @@ function gitSyncResource(transport) {
1429
1769
  syncedCollections,
1430
1770
  remoteUrl,
1431
1771
  branch,
1772
+ trackedBranch,
1432
1773
  waitForTask
1433
1774
  };
1434
1775
  }
1435
1776
  //#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
1777
  //#region ../client/src/resources/glossary.ts
1463
1778
  const GlossaryApiList = z.object({ data: z.array(Glossary) }).loose();
1464
1779
  function glossaryResource(transport) {
@@ -1511,6 +1826,17 @@ function glossaryResource(transport) {
1511
1826
  };
1512
1827
  }
1513
1828
  //#endregion
1829
+ //#region ../client/src/resources/request-body.ts
1830
+ /**
1831
+ * Parse the body a caller hands a method, refusing one that does not match `schema` before any
1832
+ * request. `what` names the body in the refusal.
1833
+ */
1834
+ function parseRequestBody(schema, value, what) {
1835
+ const parsed = schema.safeParse(value);
1836
+ if (!parsed.success) throw new ConfigError(`invalid ${what}: ${parsed.error.issues.map(formatZodIssue).join("; ")}`);
1837
+ return parsed.data;
1838
+ }
1839
+ //#endregion
1514
1840
  //#region ../client/src/resources/library.ts
1515
1841
  const LIBRARY_ROOT_PATH = "/api/ee/library/";
1516
1842
  const PUBLISH_TABLES_PATH = "/api/ee/data-studio/table/publish-tables";
@@ -1527,7 +1853,7 @@ function libraryResource(transport) {
1527
1853
  return toLibrary(wire, await libraryListing(options));
1528
1854
  }
1529
1855
  async function libraryListing(options) {
1530
- const data = await listCollectionsWithLibrary(transport, LibraryCollectionInfo, options);
1856
+ const data = await listCollectionsAs(transport, LibraryCollectionInfo, options);
1531
1857
  const byId = /* @__PURE__ */ new Map();
1532
1858
  for (const collection of data) if (typeof collection.id === "number") byId.set(collection.id, collection);
1533
1859
  return byId;
@@ -1560,26 +1886,31 @@ function libraryResource(transport) {
1560
1886
  }
1561
1887
  /**
1562
1888
  * 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.
1889
+ * data pickers and rank up in search. Answers the collection they landed in. The endpoint
1890
+ * answers the same whether or not the selectors matched a table, so a body that does not match
1891
+ * `LibraryPublishTablesInput` is refused before any request.
1564
1892
  */
1565
1893
  async function publishTables(params, options = {}) {
1566
1894
  await transport.require("library.publishTables", options);
1895
+ const body = parseRequestBody(LibraryPublishTablesInput, params, "tables to publish");
1567
1896
  return (await transport.requestParsed(PublishTablesResponse, PUBLISH_TABLES_PATH, {
1568
1897
  ...options,
1569
1898
  method: "POST",
1570
- body: params
1899
+ body
1571
1900
  })).target_collection;
1572
1901
  }
1573
1902
  /**
1574
1903
  * Clear the Library collection from tables, and recursively from every downstream table that
1575
- * depends on them. The endpoint answers no JSON body.
1904
+ * depends on them. The endpoint answers no JSON body, whether or not the selectors matched a
1905
+ * table, so selectors that do not match `TableSelectors` are refused before any request.
1576
1906
  */
1577
1907
  async function unpublishTables(params, options = {}) {
1578
1908
  await transport.require("library.unpublishTables", options);
1909
+ const body = parseRequestBody(TableSelectors, params, "table selectors");
1579
1910
  await transport.requestRaw(UNPUBLISH_TABLES_PATH, {
1580
1911
  ...options,
1581
1912
  method: "POST",
1582
- body: params,
1913
+ body,
1583
1914
  expectContentType: "binary"
1584
1915
  });
1585
1916
  }
@@ -1832,48 +2163,21 @@ function metricResource(transport) {
1832
2163
  };
1833
2164
  }
1834
2165
  //#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
2166
  //#region ../client/src/resources/moderation-review.ts
1865
2167
  function moderationReviewResource(transport) {
1866
2168
  /**
1867
2169
  * Create a moderation review on a card or dashboard. `status: "verified"` marks the item
1868
2170
  * verified, `null` or an absent status records a note that leaves it unverified. The new review
1869
2171
  * becomes the item's most recent one; the server keeps the ten newest per item. Admins only.
2172
+ * A body that does not match `ModerationReviewCreateInput` is refused before any request.
1870
2173
  */
1871
2174
  async function create(params, options = {}) {
1872
2175
  await transport.require("moderationReview.create", options);
2176
+ const body = parseRequestBody(ModerationReviewCreateInput, params, "moderation review");
1873
2177
  return transport.requestParsed(ModerationReview, "/api/moderation-review", {
1874
2178
  ...options,
1875
2179
  method: "POST",
1876
- body: params
2180
+ body
1877
2181
  });
1878
2182
  }
1879
2183
  return { create };
@@ -2394,8 +2698,10 @@ function searchResource(transport) {
2394
2698
  * may match, `archived` swaps the active set for the archived one, `table_db_id` restricts to
2395
2699
  * items on one database, `verified` to verified content, `collection` to one collection and its
2396
2700
  * 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.
2701
+ * matches native query text but narrows to the models that carry one (cards, models, metrics,
2702
+ * actions, transforms), `include_metadata` attaches each card's `result_metadata`,
2703
+ * `include_dashboard_questions` also matches questions saved into a dashboard (excluded by
2704
+ * default), and `limit`/`offset` are the window the server applies before ranking hydration.
2399
2705
  */
2400
2706
  async function query(params = {}, options = {}) {
2401
2707
  await transport.require("search.query", options);
@@ -2412,7 +2718,8 @@ function searchResource(transport) {
2412
2718
  collection: params.collection,
2413
2719
  created_by: params.created_by,
2414
2720
  search_native_query: params.search_native_query,
2415
- include_metadata: params.include_metadata
2721
+ include_metadata: params.include_metadata,
2722
+ include_dashboard_questions: params.include_dashboard_questions
2416
2723
  }
2417
2724
  });
2418
2725
  return {
@@ -2596,14 +2903,18 @@ function snippetResource(transport) {
2596
2903
  const TableApiList = z.array(Table);
2597
2904
  const TableApiFks = z.array(TableForeignKey);
2598
2905
  const SyncSchemaResponse = z.object({ status: z.literal("ok") });
2599
- const RescanValuesResponse = z.object({ status: z.literal("success") });
2906
+ const FieldValuesResponse = z.object({ status: z.literal("success") });
2600
2907
  const BulkEditResponse = z.object({});
2601
2908
  const BULK_EDIT_PATH = "/api/data-studio/table/edit";
2909
+ const BULK_SYNC_SCHEMA_PATH = "/api/data-studio/table/sync-schema";
2910
+ const BULK_RESCAN_VALUES_PATH = "/api/data-studio/table/rescan-values";
2911
+ const BULK_DISCARD_VALUES_PATH = "/api/data-studio/table/discard-values";
2602
2912
  const LIST_PARAM_FEATURES = [
2603
2913
  ["can-query", "tableListAccessFilters"],
2604
2914
  ["can-write", "tableListAccessFilters"],
2605
2915
  ["include-transform-targets", "tableListTransformTargets"],
2606
- ["unused-only", "tableUnusedFilter"]
2916
+ ["unused-only", "tableUnusedFilter"],
2917
+ ["published-only", "tableListPublishedFilter"]
2607
2918
  ];
2608
2919
  function listParamFeatures(params) {
2609
2920
  return LIST_PARAM_FEATURES.filter(([param]) => params[param] !== void 0).map(([, feature]) => feature);
@@ -2617,7 +2928,7 @@ function tableResource(transport) {
2617
2928
  * List every table the caller can see, across all databases. `term` matches names and display
2618
2929
  * names; `can-query` and `can-write` keep only the tables the caller may query or edit the
2619
2930
  * metadata of; `include-transform-targets` adds tables a transform writes to; `unused-only` keeps
2620
- * tables nothing depends on.
2931
+ * tables nothing depends on; `published-only` keeps tables published to the library.
2621
2932
  */
2622
2933
  async function list(params = {}, options = {}) {
2623
2934
  await transport.require("table.list", options);
@@ -2635,6 +2946,7 @@ function tableResource(transport) {
2635
2946
  "owner-email": params["owner-email"],
2636
2947
  "orphan-only": params["orphan-only"],
2637
2948
  "unused-only": params["unused-only"],
2949
+ "published-only": params["published-only"],
2638
2950
  "can-query": params["can-query"],
2639
2951
  "can-write": params["can-write"],
2640
2952
  "include-transform-targets": params["include-transform-targets"]
@@ -2684,38 +2996,107 @@ function tableResource(transport) {
2684
2996
  };
2685
2997
  }
2686
2998
  /**
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.
2999
+ * Trigger a sync of this table: its columns, their fingerprints and its cached field values. It
3000
+ * never discovers new tables. The sync runs after the call returns; a warehouse the server cannot
3001
+ * connect to is a 422.
2689
3002
  */
2690
3003
  async function syncSchema(id, options = {}) {
2691
3004
  await transport.require("table.syncSchema", options);
2692
- await transport.requestParsed(SyncSchemaResponse, `/api/table/${id}/sync_schema`, {
2693
- ...options,
2694
- method: "POST"
2695
- });
3005
+ return {
3006
+ id,
3007
+ status: (await transport.requestParsed(SyncSchemaResponse, `/api/table/${id}/sync_schema`, {
3008
+ ...options,
3009
+ method: "POST"
3010
+ })).status
3011
+ };
2696
3012
  }
2697
3013
  /**
2698
- * Trigger an update of the field values of every eligible field of this table. The scan runs
2699
- * after the call returns.
3014
+ * Trigger an update of the field values of every eligible field of this table that already has a
3015
+ * cached set. The scan runs after the call returns.
2700
3016
  */
2701
3017
  async function rescanValues(id, options = {}) {
2702
3018
  await transport.require("table.rescanValues", options);
2703
- await transport.requestParsed(RescanValuesResponse, `/api/table/${id}/rescan_values`, {
2704
- ...options,
2705
- method: "POST"
2706
- });
3019
+ return {
3020
+ id,
3021
+ status: (await transport.requestParsed(FieldValuesResponse, `/api/table/${id}/rescan_values`, {
3022
+ ...options,
3023
+ method: "POST"
3024
+ })).status
3025
+ };
3026
+ }
3027
+ /**
3028
+ * Discard the cached field values of every field of this table, custom display values included.
3029
+ * No scan recreates a discarded set; the server rebuilds it, without the display values, the next
3030
+ * time the field's values are read.
3031
+ */
3032
+ async function discardValues(id, options = {}) {
3033
+ await transport.require("table.discardValues", options);
3034
+ return {
3035
+ id,
3036
+ status: (await transport.requestParsed(FieldValuesResponse, `/api/table/${id}/discard_values`, {
3037
+ ...options,
3038
+ method: "POST"
3039
+ })).status
3040
+ };
2707
3041
  }
2708
3042
  /**
2709
3043
  * 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.
3044
+ * layer is re-synced after the call returns. The server answers the same whether or not the
3045
+ * selectors matched a table.
2711
3046
  */
2712
3047
  async function bulkEdit(params, options = {}) {
2713
3048
  await transport.require("table.bulkEdit", options);
3049
+ await requireDataAuthorityNull(params.data_authority, options);
2714
3050
  await transport.requestParsed(BulkEditResponse, BULK_EDIT_PATH, {
2715
3051
  ...options,
2716
3052
  method: "POST",
2717
3053
  body: params
2718
3054
  });
3055
+ return {
3056
+ accepted: true,
3057
+ ...params
3058
+ };
3059
+ }
3060
+ async function requireDataAuthorityNull(value, options) {
3061
+ if (value === null) await transport.requireFeatures(["tableUserValueWithdrawal"], options);
3062
+ }
3063
+ async function postSelection(path, selectors, options) {
3064
+ const body = parseRequestBody(TableSelectors, selectors, "table selectors");
3065
+ await transport.requestRaw(path, {
3066
+ ...options,
3067
+ method: "POST",
3068
+ body,
3069
+ expectContentType: "binary"
3070
+ });
3071
+ return {
3072
+ accepted: true,
3073
+ ...body
3074
+ };
3075
+ }
3076
+ /**
3077
+ * Trigger a sync of every table the selectors pick out: its columns, their fingerprints and its
3078
+ * cached field values. Every database behind them must answer a connection test first, or the
3079
+ * call is a 422; the syncs run after it returns.
3080
+ */
3081
+ async function bulkSyncSchema(selectors, options = {}) {
3082
+ await transport.require("table.bulkSyncSchema", options);
3083
+ return postSelection(BULK_SYNC_SCHEMA_PATH, selectors, options);
3084
+ }
3085
+ /**
3086
+ * Trigger a field-values rescan of every table the selectors pick out, refreshing the sets that
3087
+ * are already cached. The scans run after the call returns.
3088
+ */
3089
+ async function bulkRescanValues(selectors, options = {}) {
3090
+ await transport.require("table.bulkRescanValues", options);
3091
+ return postSelection(BULK_RESCAN_VALUES_PATH, selectors, options);
3092
+ }
3093
+ /**
3094
+ * Discard the cached field values of every table the selectors pick out, custom display values
3095
+ * included. No scan recreates a discarded set.
3096
+ */
3097
+ async function bulkDiscardValues(selectors, options = {}) {
3098
+ await transport.require("table.bulkDiscardValues", options);
3099
+ return postSelection(BULK_DISCARD_VALUES_PATH, selectors, options);
2719
3100
  }
2720
3101
  async function updateFromCsv(id, action, file, options) {
2721
3102
  await transport.requestRaw(`/api/table/${id}/${UPLOAD_UPDATE_PATHS[action]}`, {
@@ -2757,7 +3138,11 @@ function tableResource(transport) {
2757
3138
  fks,
2758
3139
  syncSchema,
2759
3140
  rescanValues,
3141
+ discardValues,
2760
3142
  bulkEdit,
3143
+ bulkSyncSchema,
3144
+ bulkRescanValues,
3145
+ bulkDiscardValues,
2761
3146
  appendCsv,
2762
3147
  replaceCsv
2763
3148
  };
@@ -3584,6 +3969,167 @@ function transformTagResource(transport) {
3584
3969
  };
3585
3970
  }
3586
3971
  //#endregion
3972
+ //#region ../client/src/domain/transform-test.ts
3973
+ const TransformTestTable = z.object({
3974
+ schema: z.string().min(1).nullable().optional(),
3975
+ name: z.string().min(1)
3976
+ }).loose();
3977
+ const TransformTestColumn = z.object({
3978
+ name: z.string().min(1),
3979
+ cast_type: z.string().min(1)
3980
+ }).loose();
3981
+ const TransformTestCell = z.union([
3982
+ z.boolean(),
3983
+ z.number(),
3984
+ z.string(),
3985
+ z.null()
3986
+ ]);
3987
+ const TransformTestRow = z.record(z.string(), TransformTestCell);
3988
+ const TransformTestSqlInput = z.object({
3989
+ table: TransformTestTable,
3990
+ format: z.literal("sql"),
3991
+ sql: z.string().min(1)
3992
+ }).loose();
3993
+ const TransformTestRowsInput = z.object({
3994
+ table: TransformTestTable,
3995
+ format: z.literal("rows"),
3996
+ columns: z.array(TransformTestColumn).min(1),
3997
+ rows: z.array(TransformTestRow)
3998
+ }).loose();
3999
+ const TransformTestInput = z.discriminatedUnion("format", [TransformTestSqlInput, TransformTestRowsInput]);
4000
+ const TransformTestEqualsSqlExpectation = z.object({
4001
+ type: z.literal("equals"),
4002
+ name: z.string().min(1),
4003
+ format: z.literal("sql"),
4004
+ sql: z.string().min(1)
4005
+ }).loose();
4006
+ const TransformTestEqualsRowsExpectation = z.object({
4007
+ type: z.literal("equals"),
4008
+ name: z.string().min(1),
4009
+ format: z.literal("rows"),
4010
+ columns: z.array(TransformTestColumn).min(1),
4011
+ rows: z.array(TransformTestRow)
4012
+ }).loose();
4013
+ const TransformTestEqualsExpectation = z.discriminatedUnion("format", [TransformTestEqualsSqlExpectation, TransformTestEqualsRowsExpectation]);
4014
+ const TransformTestEmptyExpectation = z.object({
4015
+ type: z.literal("empty"),
4016
+ name: z.string().min(1),
4017
+ sql: z.string().min(1)
4018
+ }).loose();
4019
+ const TransformTestExpectation = z.discriminatedUnion("type", [TransformTestEqualsExpectation, TransformTestEmptyExpectation]);
4020
+ const TransformTest = z.object({
4021
+ id: z.number().int(),
4022
+ entity_id: z.string(),
4023
+ transform_id: z.number().int(),
4024
+ creator_id: z.number().int(),
4025
+ name: z.string(),
4026
+ description: z.string().nullable(),
4027
+ inputs: z.array(TransformTestInput),
4028
+ expectations: z.array(TransformTestExpectation),
4029
+ created_at: z.string(),
4030
+ updated_at: z.string()
4031
+ }).loose();
4032
+ TransformTest.pick({
4033
+ id: true,
4034
+ transform_id: true,
4035
+ name: true,
4036
+ description: true
4037
+ }).strip();
4038
+ z.object({
4039
+ transform_id: z.number().int().positive(),
4040
+ name: z.string().min(1),
4041
+ description: z.string().nullable().optional(),
4042
+ inputs: z.array(TransformTestInput),
4043
+ expectations: z.array(TransformTestExpectation)
4044
+ }).loose();
4045
+ z.object({
4046
+ transform_id: z.number().int().positive().optional(),
4047
+ name: z.string().min(1).optional(),
4048
+ description: z.string().nullable().optional(),
4049
+ inputs: z.array(TransformTestInput).optional(),
4050
+ expectations: z.array(TransformTestExpectation).optional()
4051
+ }).loose();
4052
+ const TransformTestResultColumn = z.object({
4053
+ name: z.string(),
4054
+ database_type: z.string()
4055
+ }).loose();
4056
+ const TransformTestExpectationError = z.object({
4057
+ type: z.string(),
4058
+ message: z.string()
4059
+ }).loose();
4060
+ const TransformTestCellMismatch = z.object({
4061
+ column: z.string(),
4062
+ expected: TransformTestCell,
4063
+ actual: TransformTestCell
4064
+ }).loose();
4065
+ const TransformTestRowCounts = z.object({
4066
+ actual: z.number().int(),
4067
+ expected: z.number().int()
4068
+ }).loose();
4069
+ const TransformTestEqualsFindings = z.object({
4070
+ name: z.string(),
4071
+ type: z.literal("equals"),
4072
+ status: z.enum(["passed", "failed"]),
4073
+ columns: z.array(TransformTestResultColumn),
4074
+ "row-counts": TransformTestRowCounts,
4075
+ "extra-rows": z.array(TransformTestRow),
4076
+ "missing-rows": z.array(TransformTestRow),
4077
+ "cell-mismatches": z.array(TransformTestCellMismatch),
4078
+ truncated: z.number().int()
4079
+ }).loose();
4080
+ const TransformTestEqualsError = z.object({
4081
+ name: z.string(),
4082
+ type: z.literal("equals"),
4083
+ status: z.literal("error"),
4084
+ error: TransformTestExpectationError
4085
+ }).loose();
4086
+ const TransformTestEqualsResult = z.discriminatedUnion("status", [TransformTestEqualsFindings, TransformTestEqualsError]);
4087
+ const TransformTestEmptyPassed = z.object({
4088
+ name: z.string(),
4089
+ type: z.literal("empty"),
4090
+ status: z.literal("passed")
4091
+ }).loose();
4092
+ const TransformTestEmptyFailed = z.object({
4093
+ name: z.string(),
4094
+ type: z.literal("empty"),
4095
+ status: z.literal("failed"),
4096
+ columns: z.array(TransformTestResultColumn),
4097
+ sample: z.array(TransformTestRow),
4098
+ truncated: z.number().int()
4099
+ }).loose();
4100
+ const TransformTestEmptyError = z.object({
4101
+ name: z.string(),
4102
+ type: z.literal("empty"),
4103
+ status: z.literal("error"),
4104
+ error: TransformTestExpectationError
4105
+ }).loose();
4106
+ const TransformTestEmptyResult = z.discriminatedUnion("status", [
4107
+ TransformTestEmptyPassed,
4108
+ TransformTestEmptyFailed,
4109
+ TransformTestEmptyError
4110
+ ]);
4111
+ const TransformTestExpectationResult = z.discriminatedUnion("type", [TransformTestEqualsResult, TransformTestEmptyResult]);
4112
+ const TransformTestRunResult = z.object({
4113
+ status: z.enum(["passed", "failed"]),
4114
+ expectations: z.array(TransformTestExpectationResult),
4115
+ tables: z.record(z.string(), z.string())
4116
+ }).loose();
4117
+ z.enum([
4118
+ "transform-test.unknown-column",
4119
+ "transform-test.ambiguous-column",
4120
+ "transform-test.missing-inputs",
4121
+ "transform-test.unused-inputs",
4122
+ "transform-test.duplicate-input-table",
4123
+ "transform-test.unparseable-source",
4124
+ "transform-test.unremapped-reference",
4125
+ "transform-test.unsupported-transform",
4126
+ "transform-test.unsupported-driver",
4127
+ "transform-test.transform-failed",
4128
+ "transform-test.setup-failed",
4129
+ "transform-test.expectation-failed",
4130
+ "transform-test.unsupported-format"
4131
+ ]);
4132
+ //#endregion
3587
4133
  //#region ../client/src/resources/transform-test.ts
3588
4134
  const TransformTestApiList = z.array(TransformTest);
3589
4135
  function transformTestResource(transport) {
@@ -3738,6 +4284,7 @@ function createClient(config, options) {
3738
4284
  collection: collectionResource(transport),
3739
4285
  contentTranslation: contentTranslationResource(transport),
3740
4286
  dashboard: dashboardResource(transport),
4287
+ dataAction: dataActionResource(transport),
3741
4288
  database: databaseResource(transport),
3742
4289
  dataset: datasetResource(transport),
3743
4290
  dependency: dependencyResource(transport),