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

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 (268) hide show
  1. package/dist/{add-collection-CYDUm_XO.mjs → add-collection-B_-eMU_k.mjs} +6 -9
  2. package/dist/{alert-ClyhtxIz.mjs → alert-Dalin_DD.mjs} +7 -7
  3. package/dist/{alerts-Dt3D1gcz.mjs → alerts-DpBgrjPI.mjs} +7 -7
  4. package/dist/{append-Bl_Ensmr.mjs → append-C1JNVALm.mjs} +5 -5
  5. package/dist/{archive-BOyKhNOz.mjs → archive-52ZHbFDm2.mjs} +6 -6
  6. package/dist/{archive-DiGxCojL.mjs → archive-B51prFgS.mjs} +4 -4
  7. package/dist/{archive-CWceyy8x.mjs → archive-BkITQyWW.mjs} +5 -5
  8. package/dist/{archive-BJZ7Dace.mjs → archive-CISXgZAI.mjs} +6 -6
  9. package/dist/{archive-D3a3Wgz0.mjs → archive-CdKf_Eqq.mjs} +4 -4
  10. package/dist/{archive-DVGDg8mP.mjs → archive-CicPYX27.mjs} +6 -6
  11. package/dist/{archive-CNblz55j.mjs → archive-CwITzj_j.mjs} +6 -6
  12. package/dist/{archive-DSMqHRr1.mjs → archive-DA3OiLEE.mjs} +4 -4
  13. package/dist/{archive-nKD3mOB8.mjs → archive-DVHxeDKS.mjs} +6 -6
  14. package/dist/{archive-BdHXQg4I.mjs → archive-DckxlWBt.mjs} +4 -4
  15. package/dist/{archive-DDru3vdy.mjs → archive-cAdUa1-2.mjs} +4 -4
  16. package/dist/{auth-aCksg8q2.mjs → auth-A96JOCQx.mjs} +5 -5
  17. package/dist/{body-DxRSAMNC.mjs → body-CshgcV6U.mjs} +3 -3
  18. package/dist/{branches-_0VWR2Zm.mjs → branches-CbcwWYL9.mjs} +4 -7
  19. package/dist/{cancel-ctpVE8uC.mjs → cancel-DpDcVY7M.mjs} +4 -4
  20. package/dist/{cancel-task-FtxBka-M.mjs → cancel-task-B4RDvIYb.mjs} +5 -8
  21. package/dist/{card-zyUkr2nS.mjs → card-CEkp1mcI.mjs} +1 -1
  22. package/dist/card-CefVYtF7.mjs +24 -0
  23. package/dist/{card-DZxRmver.mjs → card-voh1k4hl.mjs} +14 -11
  24. package/dist/{cards-DHOWAvfv.mjs → cards-BC0JX8Yg.mjs} +7 -7
  25. package/dist/cli.mjs +582 -69
  26. package/dist/client-ClL6gf7G.mjs +3783 -0
  27. package/dist/collection-Be5AHVWP.mjs +20 -0
  28. package/dist/{collection-CfulNRBG.mjs → collection-BxdPxD38.mjs} +1 -1
  29. package/dist/{collection-CGoVLvcD.mjs → collection-DYM0p3Xl.mjs} +1 -1
  30. package/dist/{collection-namespace-CEoQ7G08.mjs → collection-namespace-Dv0l-V9K.mjs} +2 -2
  31. package/dist/{content-translation-DNKerjS3.mjs → content-translation-BXIXL4eW.mjs} +3 -3
  32. package/dist/{create-DmvoibX8.mjs → create--fiwuTWc.mjs} +4 -4
  33. package/dist/{create-CLG2-bso.mjs → create-B9qXQ_wV.mjs} +6 -6
  34. package/dist/{create-CEydRMWS.mjs → create-BVNhtAgF.mjs} +7 -7
  35. package/dist/{create-C9vy4ZG6.mjs → create-BbjSOTN-.mjs} +5 -5
  36. package/dist/{create-BdPVWYSi.mjs → create-BcsVwXgS2.mjs} +6 -6
  37. package/dist/{create-CcLchJAN.mjs → create-Bryrkb9g.mjs} +7 -7
  38. package/dist/{create-7ddYK4TA.mjs → create-CHr8MPPq.mjs} +6 -6
  39. package/dist/{create-DaYRnK5P.mjs → create-D--Z1S3p2.mjs} +8 -8
  40. package/dist/{create-F4Lf09xq.mjs → create-DWFJdyIr.mjs} +4 -4
  41. package/dist/{create-vlrlY-2E.mjs → create-Dhai9zAt.mjs} +4 -4
  42. package/dist/create-DiJ8bUb-.mjs +34 -0
  43. package/dist/{create-C78g8Crb.mjs → create-DmN2gFc4.mjs} +5 -5
  44. package/dist/{create-wJR4CxHA.mjs → create-NCKHHdov.mjs} +5 -8
  45. package/dist/{create-C3IaXXty.mjs → create-YetX69Re.mjs} +4 -4
  46. package/dist/{create-e650zxzX.mjs → create-Za1EskpV.mjs} +5 -5
  47. package/dist/{create-branch-B8C7jl-J.mjs → create-branch-CseVn3lp.mjs} +5 -9
  48. package/dist/{create-DIVhBIyE.mjs → create-kZIIEN2Y.mjs} +11 -7
  49. package/dist/{csv-BLPJtlSC.mjs → csv-DNzesu8y.mjs} +5 -5
  50. package/dist/{current-task-C-ldJbWE.mjs → current-task-DRTKZcP9.mjs} +5 -8
  51. package/dist/{dashboard-CtO_3EfC.mjs → dashboard-CMw13KXM.mjs} +10 -10
  52. package/dist/{dashboard-CKUR8ZpQ.mjs → dashboard-D0hwTC-f.mjs} +11 -2
  53. package/dist/{dashboard-BlbNszi8.mjs → dashboard-DgK81azj.mjs} +1 -1
  54. package/dist/{database-B19qlLKZ.mjs → database-C3E9PZSx.mjs} +1 -1
  55. package/dist/{database-C8G6ZKG0.mjs → database-JtHTqSpq.mjs} +1 -1
  56. package/dist/{db-xXselnBq.mjs → db-BDijt81U.mjs} +7 -7
  57. package/dist/{delete-BZZHw6pm.mjs → delete--15it-A8.mjs} +5 -5
  58. package/dist/delete-Bsdwqh7H.mjs +44 -0
  59. package/dist/{delete-ZJJyqsRh.mjs → delete-BudvZkvK.mjs} +5 -5
  60. package/dist/{delete-BwSPQy7m.mjs → delete-BxjJ66BS.mjs} +5 -5
  61. package/dist/{delete-BZwAOQxG.mjs → delete-Dc8E5YwZ.mjs} +5 -5
  62. package/dist/{delete-runtime-D74s6vhu.mjs → delete-runtime-BKEzJn22.mjs} +1 -2
  63. package/dist/{delete-table-CJktZE3w.mjs → delete-table-5AQpn8OB.mjs} +5 -5
  64. package/dist/{delete-D6WxgWRp.mjs → delete-wFsy80db.mjs} +5 -5
  65. package/dist/{dependencies-BdqIqEIy.mjs → dependencies-C1ogC3BV.mjs} +7 -7
  66. package/dist/{dirty-BW2As2wS.mjs → dirty-CSLDYO-K.mjs} +6 -9
  67. package/dist/document-BGzVip5_.mjs +19 -0
  68. package/dist/{document-Cd2mmqCp.mjs → document-BHpLJbKU.mjs} +5 -0
  69. package/dist/{document-D6OybtP2.mjs → document-CA0Q6lqu.mjs} +1 -1
  70. package/dist/{download-mfFJ9oRS.mjs → download-Ddap1OAo.mjs} +3 -6
  71. package/dist/{eid-DZ-4t2xe.mjs → eid-HnrWhPoe.mjs} +4 -5
  72. package/dist/{events-D6yFmXP1.mjs → events-CXqetjcS.mjs} +5 -5
  73. package/dist/{export-DYZjz1WP.mjs → export-IFZdgYZ2.mjs} +7 -10
  74. package/dist/{field-BJ54wmIX.mjs → field-BJ6HoLRd.mjs} +5 -5
  75. package/dist/{field-Cr2DPUG9.mjs → field-CcN4oZy6.mjs} +16 -1
  76. package/dist/{field-BPsNa-TO.mjs → field-fDtIrY6D.mjs} +1 -1
  77. package/dist/{fields-FUWCgPOa.mjs → fields-DxHxuxwO.mjs} +7 -7
  78. package/dist/{get-ByZJf9nO.mjs → get-B2pj2q3X.mjs} +5 -5
  79. package/dist/{get-C_5AbfpO.mjs → get-BF2vdF3W.mjs} +4 -4
  80. package/dist/{get-DAOSGt5Z.mjs → get-BGLvyOO3.mjs} +6 -6
  81. package/dist/{get-DMECsioX.mjs → get-BcoJ9Aha.mjs} +4 -4
  82. package/dist/{get-CsN7NBI0.mjs → get-BiPclcIP.mjs} +4 -4
  83. package/dist/{get-DCutQeiV.mjs → get-C3cuZNeW.mjs} +4 -4
  84. package/dist/{get-CQ0-fFWP.mjs → get-CDnmpfHQ.mjs} +5 -8
  85. package/dist/{get-DRJtsS1_.mjs → get-CE9_4Q7E.mjs} +4 -4
  86. package/dist/{get-C5q49Dgx.mjs → get-C_tdSMwW2.mjs} +6 -6
  87. package/dist/{get-CWnriw33.mjs → get-CxUQyhte.mjs} +6 -6
  88. package/dist/{get-DVyesErX.mjs → get-DW7mCaGe.mjs} +6 -6
  89. package/dist/{get-DYaQpixt.mjs → get-D_x-ENFe.mjs} +6 -6
  90. package/dist/{get-Ba2HRdrx.mjs → get-DjlQhgD4.mjs} +6 -6
  91. package/dist/{get-DhkltKIV.mjs → get-DmKtPNOy.mjs} +4 -4
  92. package/dist/{get-BWl3vzsf.mjs → get-Dtre5jzh.mjs} +6 -6
  93. package/dist/get-H6kInHIx.mjs +93 -0
  94. package/dist/{get-BraVQ1FJ.mjs → get-b0CoPz5B.mjs} +6 -6
  95. package/dist/{get-LAew34ID.mjs → get-eJilYnHk.mjs} +6 -6
  96. package/dist/get-i0KInCw9.mjs +32 -0
  97. package/dist/{get-_ggLr1tY.mjs → get-jofVjU6e.mjs} +6 -6
  98. package/dist/{get-run-oH4dRCBx.mjs → get-run-BE1HtJDW.mjs} +6 -6
  99. package/dist/{git-sync-BDnxPrqU.mjs → git-sync-BwBRmEhE.mjs} +18 -1
  100. package/dist/{git-sync-DxD_ng48.mjs → git-sync-TjX1r_wF.mjs} +1 -1
  101. package/dist/git-sync-xKC1sqC4.mjs +28 -0
  102. package/dist/{group-DBM87IgC.mjs → group-YQQ5GIcP.mjs} +2 -2
  103. package/dist/{has-remote-changes-CnmyIw_7.mjs → has-remote-changes-Cj1KhBOT.mjs} +5 -8
  104. package/dist/{import-B7Si-bSI.mjs → import-DLb9VN4l.mjs} +7 -10
  105. package/dist/{input-DH9i67x_.mjs → input-D5tQEfqN.mjs} +1 -1
  106. package/dist/{is-dirty-BOH_VEA8.mjs → is-dirty-BxtgV2xF.mjs} +3 -6
  107. package/dist/{items-DouHkWev.mjs → items-DLUYc5-z.mjs} +7 -7
  108. package/dist/{key-BEhqIzIQ.mjs → key-PYetuQ13.mjs} +1 -1
  109. package/dist/{library-1J_4Dicw.mjs → library-BNSxXOpc.mjs} +5 -5
  110. package/dist/library-BPIzb3K_.mjs +81 -0
  111. package/dist/{library-DfYAT2Ep.mjs → library-PGCfm0UA.mjs} +1 -1
  112. package/dist/{list-D25ofn4v.mjs → list-B1soS8QW.mjs} +7 -7
  113. package/dist/{list-Cy0w4Fap.mjs → list-BQnOEB3W.mjs} +4 -4
  114. package/dist/{list-BeMYIeiI.mjs → list-BUz6KOfw.mjs} +7 -7
  115. package/dist/{list-C1bAtgO1.mjs → list-BcP1DTJH.mjs} +4 -4
  116. package/dist/{list-DJK9_BEF.mjs → list-C5mS_ehX.mjs} +14 -13
  117. package/dist/{list-qs9wAtC3.mjs → list-CBLxhaNZ.mjs} +4 -4
  118. package/dist/{list-aKUk-a1Y.mjs → list-CERbeLbQ.mjs} +7 -7
  119. package/dist/{list-B2Ddf4W0.mjs → list-COLpwXW4.mjs} +5 -5
  120. package/dist/{list-sDpy4nDU.mjs → list-CQbiSx26.mjs} +6 -6
  121. package/dist/{list-C0zJ2ehz.mjs → list-CX9qZ-bx.mjs} +6 -6
  122. package/dist/{list-DhViDVx_.mjs → list-CehE6KBV.mjs} +6 -6
  123. package/dist/list-Cuhf2lKL.mjs +35 -0
  124. package/dist/{list-D2IYZ6lk.mjs → list-CzRzCbCY.mjs} +6 -6
  125. package/dist/{list-DWLGpMvr.mjs → list-D-SyhKFw.mjs} +7 -7
  126. package/dist/{list-DptEWB5Y.mjs → list-Dat8QNcf.mjs} +4 -4
  127. package/dist/{list-C7UvO3Uw.mjs → list-M8J10Ozk.mjs} +6 -6
  128. package/dist/{list-BXlTYsYA.mjs → list-Sd7jGZoX.mjs} +4 -4
  129. package/dist/list-cIMww2Me.mjs +60 -0
  130. package/dist/{list-BK_6VNm_.mjs → list-jhQSgh6i.mjs} +4 -4
  131. package/dist/{login-BmyCAfRV.mjs → login-BfLqBfCd.mjs} +18 -15
  132. package/dist/{logout-DUR32q0V.mjs → logout-BpRXB3Ze.mjs} +3 -4
  133. package/dist/{measure-DdVp-8jw.mjs → measure-Ds8O5Evr.mjs} +6 -6
  134. package/dist/{notification-Fcq1fIPw.mjs → notification-DVrLkjFT.mjs} +1 -1
  135. package/dist/{parameter-DUKR8NXo.mjs → parameter-Celg0wZa.mjs} +1 -1
  136. package/dist/{parameter-values-CBR-cBev.mjs → parameter-values-DhrkLXoN.mjs} +5 -6
  137. package/dist/{parse-enum-D0Jfm_Bz.mjs → parse-enum-Dc0dMZ3P.mjs} +1 -1
  138. package/dist/{parse-id-B3YwNojT.mjs → parse-id-DtM6q9HU.mjs} +1 -1
  139. package/dist/{parse-ref-ibKVB0J4.mjs → parse-ref-DTDld_LJ.mjs} +1 -1
  140. package/dist/{path-D8BQmEhL.mjs → path-_GHFrTLx.mjs} +5 -5
  141. package/dist/{poll-75SvT7Zv.mjs → poll-KLl4Eq8Y.mjs} +2 -2
  142. package/dist/{preflight-CoF1Em99.mjs → preflight-BpYtF0IU.mjs} +3 -4
  143. package/dist/{process-DBOOrmET.mjs → process-CLtOWKBn.mjs} +1 -1
  144. package/dist/{publish-Cb7XrQ3X.mjs → publish-D-7Zlmuk.mjs} +9 -9
  145. package/dist/{pulse-BmsDenXm.mjs → pulse-Dz0ocv0l.mjs} +1 -1
  146. package/dist/{pulse-DhG6I9mI.mjs → pulse-x0gFxWfG.mjs} +2 -2
  147. package/dist/{query-D35B588l.mjs → query-B1CZztxs.mjs} +10 -12
  148. package/dist/query-CxESKMve.mjs +114 -0
  149. package/dist/{query-result-DBDwk8TS.mjs → query-result-E4Q-Gra6.mjs} +1 -1
  150. package/dist/{remove-collection-DJem6V26.mjs → remove-collection-C4saCFxz.mjs} +6 -9
  151. package/dist/{render-CI93iP0I.mjs → render-6O_eF-P1.mjs} +13 -2
  152. package/dist/{replace-CtsWICrD.mjs → replace-BuR4f2Ai.mjs} +5 -5
  153. package/dist/{rescan-values-CaXUL6z5.mjs → rescan-values-CNOiiWQ5.mjs} +6 -6
  154. package/dist/{run-CM-Amtbf.mjs → run-DijA_BXt.mjs} +26 -14
  155. package/dist/run-FmRruANb.mjs +64 -0
  156. package/dist/{run-BeLm17F4.mjs → run-QEUbWNm7.mjs} +9 -9
  157. package/dist/{runs-DFG63zgr.mjs → runs-BSlhVeDO.mjs} +7 -7
  158. package/dist/{runtime-z8rra6-I.mjs → runtime-Dtb93zKy.mjs} +994 -252
  159. package/dist/{schema-tables-COAHkIcy.mjs → schema-tables-BE3rEb6I.mjs} +7 -7
  160. package/dist/{schemas-BX5BATiV.mjs → schemas-yDjBiwlH.mjs} +5 -5
  161. package/dist/{search-DFBwUc6d.mjs → search-BAXg-EJw.mjs} +2 -1
  162. package/dist/{search-CPvvmhdt.mjs → search-CR_xNArA.mjs} +6 -6
  163. package/dist/{segment-C62L6BI3.mjs → segment-Cm6zQjJW.mjs} +6 -6
  164. package/dist/{selectors-P4QnrORk.mjs → selectors-C-vgMcGK.mjs} +3 -3
  165. package/dist/{send-PZh5IKF8.mjs → send-kC8oerkT.mjs} +4 -4
  166. package/dist/{set-active-DL4QzWDO.mjs → set-active-lDKhAlij.mjs} +5 -5
  167. package/dist/{set-DbCtUoFd.mjs → set-tFhPkxrL.mjs} +5 -5
  168. package/dist/{setting-BlRcZbhC.mjs → setting-DrJXCaFE.mjs} +4 -4
  169. package/dist/{setup-D_SLaC-3.mjs → setup-BWY9M0iR.mjs} +4 -4
  170. package/dist/{signal-CMd0EFUa.mjs → signal-Csom0mt5.mjs} +11 -2
  171. package/dist/skill-list-CCes8pKe.mjs +76 -0
  172. package/dist/skills-DE9ej5Rg.mjs +351 -0
  173. package/dist/{skills-D991LB1M.mjs → skills-DPRN2384.mjs} +3 -3
  174. package/dist/snippet-DWHTSo9c.mjs +19 -0
  175. package/dist/{stash-DyBxFoP6.mjs → stash-C9oDvQ9P.mjs} +7 -11
  176. package/dist/{status-DUsiogz5.mjs → status-CkpujA26.mjs} +11 -9
  177. package/dist/{status-cfDHqK2Q.mjs → status-DSdXmNC3.mjs} +12 -11
  178. package/dist/{subscription-Bn0AU7GN.mjs → subscription-DKOKoHRG.mjs} +6 -6
  179. package/dist/{subscriptions-DwqjCVlc.mjs → subscriptions-C5SyJL4B.mjs} +7 -7
  180. package/dist/{summary-BGwSNzf4.mjs → summary-DTPgXsc0.mjs} +6 -6
  181. package/dist/{sync-schema-dtkDOAKe.mjs → sync-schema-DKKkNSR7.mjs} +7 -7
  182. package/dist/{sync-task-BACcrs0i.mjs → sync-task-BtDnTXCP.mjs} +3 -2
  183. package/dist/{table-CsIJNPFf.mjs → table-C6h4tIRw.mjs} +1 -1
  184. package/dist/{table-CeeTJgQb.mjs → table-DfuY0N8e.mjs} +51 -4
  185. package/dist/{table-BJoEAoCU.mjs → table-I8NXSdUC.mjs} +5 -5
  186. package/dist/timeline-B_ESH-6W.mjs +21 -0
  187. package/dist/{timeline-event-BsF7YqzZ.mjs → timeline-event-n4Lzet7l.mjs} +6 -6
  188. package/dist/transform-BNuNiH9d.mjs +28 -0
  189. package/dist/{transform-DoTyyXAu.mjs → transform-CtqB1WYo.mjs} +2 -2
  190. package/dist/{transform-D3QX0jxA.mjs → transform-DiW7bREn.mjs} +68 -5
  191. package/dist/{transform-job-50GZHhKH.mjs → transform-job-AaMZRxAq.mjs} +1 -1
  192. package/dist/transform-job-B7yc6dfH.mjs +22 -0
  193. package/dist/{transform-job-DRrK28IH.mjs → transform-job-CCguL6LP.mjs} +41 -4
  194. package/dist/{transform-tag-VM9R7Q_M.mjs → transform-tag-D6NXqWaX.mjs} +5 -5
  195. package/dist/transform-test-BjjCQ2xm.mjs +169 -0
  196. package/dist/transform-test-C1Oqtfb-.mjs +16 -0
  197. package/dist/transform-test-gzDcbypy.mjs +25 -0
  198. package/dist/{transforms-BjACGbBp.mjs → transforms-O4NtXqFz.mjs} +7 -7
  199. package/dist/transport-CyVo29u7.mjs +313 -0
  200. package/dist/{tree-BwS6JAmk.mjs → tree-CuyF116R.mjs} +4 -5
  201. package/dist/{unpublish-DWdPnENY.mjs → unpublish-DvWefKJi.mjs} +4 -7
  202. package/dist/{update-DkviXwSg.mjs → update-2KIpYgyj.mjs} +7 -7
  203. package/dist/{update-DKEHY-gt.mjs → update-76nzOc71.mjs} +7 -7
  204. package/dist/{update-B2CF2DK4.mjs → update-7oKvP1HC.mjs} +6 -6
  205. package/dist/{update-DTmRHBik.mjs → update-AJ2JmwDl.mjs} +7 -7
  206. package/dist/{update-BR_vkkd1.mjs → update-BB6Go_RX.mjs} +5 -5
  207. package/dist/{update-DCjAjihm.mjs → update-Bah7N8QX.mjs} +6 -6
  208. package/dist/{update-cqR1U6DU.mjs → update-CGJvIS-l.mjs} +5 -5
  209. package/dist/{update-tLIhVIPp.mjs → update-D7dG7H-z.mjs} +8 -8
  210. package/dist/{update-C1FBVLfC.mjs → update-DOdcflLH.mjs} +8 -8
  211. package/dist/{update-DlTaD1x3.mjs → update-DV54H3L5.mjs} +9 -9
  212. package/dist/{update-C4y3iQsv.mjs → update-DXmZuJho.mjs} +7 -7
  213. package/dist/{update-3idz42uD.mjs → update-DmgRIp7o.mjs} +7 -7
  214. package/dist/{update-DsZttiSC.mjs → update-H_fdjugs.mjs} +5 -5
  215. package/dist/{update-BCT9qpVr.mjs → update-To6A1Ugu.mjs} +5 -5
  216. package/dist/{update-dashcard-DlE_bb2F.mjs → update-dashcard-DjT5QOkL.mjs} +7 -7
  217. package/dist/update-l3PyNQKG.mjs +41 -0
  218. package/dist/{update-BpPaacCF.mjs → update-xEegxIyH.mjs} +6 -6
  219. package/dist/{upgrade-mNV7XuJG.mjs → upgrade-CuJx9fX4.mjs} +6 -8
  220. package/dist/upload-2YFFBSln.mjs +13 -0
  221. package/dist/{upload-CEGVxmYB.mjs → upload-CboARPZm.mjs} +4 -7
  222. package/dist/{upload-CD555ui1.mjs → upload-DOO94rCQ.mjs} +2 -2
  223. package/dist/{uuid-C4hqn3kA.mjs → uuid-InwZlrpQ.mjs} +10 -7
  224. package/dist/{validate-BWchyW0V.mjs → validate-D6-Vg_kn.mjs} +69 -23
  225. package/dist/{validate-query-DaGYSmpQ.mjs → validate-query-B90KYPQr.mjs} +3 -4
  226. package/dist/{values-C0O3eNaW.mjs → values-CsZLk1Ls.mjs} +6 -6
  227. package/dist/{verify-DfTjYF7s.mjs → verify-DrGjZwBM.mjs} +3 -18
  228. package/dist/{wait-WZmFenN_.mjs → wait-BmzdarP9.mjs} +7 -10
  229. package/dist/{wait-flags-BbfDSP8R.mjs → wait-flags-CiJGrTCT.mjs} +2 -2
  230. package/dist/{window-BkvrP0gB.mjs → window-DSb1tqSe.mjs} +1 -1
  231. package/package.json +1 -1
  232. package/skill-data/core/SKILL.md +31 -15
  233. package/skill-data/dashboard/SKILL.md +1 -1
  234. package/skill-data/data-workflow/references/building-clean-tables.md +6 -2
  235. package/skill-data/data-workflow/references/reusable-definitions.md +11 -3
  236. package/skill-data/document/SKILL.md +4 -1
  237. package/skill-data/git-sync/SKILL.md +5 -0
  238. package/skill-data/mbql/SKILL.md +84 -115
  239. package/skill-data/mbql/references/operators.md +77 -231
  240. package/skill-data/metadata/SKILL.md +1 -1
  241. package/skill-data/metadata/references/semantic-types.md +7 -1
  242. package/skill-data/native-sql/SKILL.md +8 -9
  243. package/skill-data/native-sql/references/template-tags.md +27 -27
  244. package/skill-data/notification/SKILL.md +7 -1
  245. package/skill-data/transform/SKILL.md +76 -4
  246. package/skill-data/transform-test-plan/SKILL.md +171 -0
  247. package/skill-data/transform-test-plan/references/checklist.md +81 -0
  248. package/skill-data/transform-test-plan/references/checks.md +263 -0
  249. package/skill-data/visualization/SKILL.md +13 -6
  250. package/skill-data/visualization/references/settings.md +13 -11
  251. package/skills/metabase-cli/SKILL.md +1 -1
  252. package/dist/card-CGCXbdmD.mjs +0 -24
  253. package/dist/client-mKuHg_sc.mjs +0 -2218
  254. package/dist/collection-D8Tk8i3a.mjs +0 -20
  255. package/dist/document-KbcHhzFz.mjs +0 -19
  256. package/dist/get-BC8J8BXB.mjs +0 -80
  257. package/dist/git-sync-Dik8nKfw.mjs +0 -28
  258. package/dist/library-ClLgrAXy.mjs +0 -19
  259. package/dist/list-CW5PdYCX.mjs +0 -98
  260. package/dist/network-error-D6CiOEBw.mjs +0 -431
  261. package/dist/predicates-Bkm2IoeX.mjs +0 -170
  262. package/dist/query-C256WBYG.mjs +0 -87
  263. package/dist/skills-DTCrMcix.mjs +0 -216
  264. package/dist/snippet-DTDO55Cg.mjs +0 -19
  265. package/dist/timeline-DcXPshcT.mjs +0 -21
  266. package/dist/transform-Dsf_wHAj.mjs +0 -28
  267. package/dist/transform-job-B1yLv5l-.mjs +0 -22
  268. package/dist/upload-DsYCf5kB.mjs +0 -13
@@ -1,2218 +0,0 @@
1
- import { a as InternalError, c as ResponseShapeError, d as ValidationError, f as errorMessage, i as ConfigError, l as TimeoutError, s as NetworkError } from "./predicates-Bkm2IoeX.mjs";
2
- import { n as Notification, r as NotificationCardPayload, t as CARD_PAYLOAD_TYPE } from "./notification-DaA4bBHW.mjs";
3
- import { a as isRetryableStatus, c as normalizeUrl, d as credentialSecrets, g as parseJsonOrPlain, h as parseJson, l as assertCredentialHeaderSafe, m as JSON_CONTENT_TYPE, n as isConnectionClosed, r as HttpError, t as buildNetworkError, u as credentialAuthHeader } from "./network-error-D6CiOEBw.mjs";
4
- import { n as throwIfAborted, t as combineAborts } from "./signal-CMd0EFUa.mjs";
5
- import { s as FieldValues, t as Field } from "./field-Cr2DPUG9.mjs";
6
- import { r as ParameterValues } from "./parameter-DUKR8NXo.mjs";
7
- import { o as CardQueryResult, t as Card } from "./card-DZxRmver.mjs";
8
- import { f as CollectionTreeNode, o as CollectionItem, r as Collection } from "./collection-CfulNRBG.mjs";
9
- import { t as ContentTranslationUploadResult } from "./content-translation-BrHOrmj9.mjs";
10
- import { i as DashboardDetail, s as Dashcard, t as Dashboard } from "./dashboard-CKUR8ZpQ.mjs";
11
- import { i as TableQueryMetadata, t as Table } from "./table-CeeTJgQb.mjs";
12
- import { t as Database } from "./database-C8G6ZKG0.mjs";
13
- import { r as pollUntil } from "./poll-75SvT7Zv.mjs";
14
- import { t as Document } from "./document-Cd2mmqCp.mjs";
15
- import { i as EidTranslateResult } from "./eid-translation-zEHtr5Oc.mjs";
16
- import { f as isSyncTaskTerminal, l as SyncTask, n as SyncDirtyItem, o as SyncRemoteChanges, s as SyncSettingsUpdateResult, t as SyncBranchCreated } from "./git-sync-BDnxPrqU.mjs";
17
- import { t as Library } from "./library-ClLgrAXy.mjs";
18
- import { t as Measure } from "./measure-CtfjqJFP.mjs";
19
- import { t as Pulse } from "./pulse-BmsDenXm.mjs";
20
- import { r as SearchResult } from "./search-DFBwUc6d.mjs";
21
- import { t as Segment } from "./segment-OsrbUDzw.mjs";
22
- import { t as Setting } from "./setting-DTiLCW8g.mjs";
23
- import { n as SetupResult } from "./setup-CO7QV-ao.mjs";
24
- import { t as Snippet } from "./snippet-CyKAgIZl.mjs";
25
- import { i as TimelineEvent, t as Timeline } from "./timeline-CCSU2qOS.mjs";
26
- import { i as TransformRun, l as isTransformRunFailed, t as Transform, u as isTransformRunTerminal } from "./transform-D3QX0jxA.mjs";
27
- import { a as TransformJobRunResult, n as TransformJobActiveResult, t as TransformJob } from "./transform-job-DRrK28IH.mjs";
28
- import { t as TransformTag } from "./transform-tag-CcElGp3C.mjs";
29
- import { t as UploadResult } from "./upload-DAtxBBms.mjs";
30
- import { z } from "zod";
31
- import { setTimeout } from "node:timers/promises";
32
- //#region \0rolldown/runtime.js
33
- var __defProp = Object.defineProperty;
34
- var __exportAll = (all, no_symbols) => {
35
- let target = {};
36
- for (var name in all) __defProp(target, name, {
37
- get: all[name],
38
- enumerable: true
39
- });
40
- if (!no_symbols) __defProp(target, Symbol.toStringTag, { value: "Module" });
41
- return target;
42
- };
43
- //#endregion
44
- //#region ../client/src/http/response-shape.ts
45
- const NO_SERVER_TAG = async () => null;
46
- async function parseJsonResponse(text, schema, context) {
47
- try {
48
- return parseJson(text, schema, { source: context.url });
49
- } catch (error) {
50
- if (error instanceof ValidationError) throw ResponseShapeError.fromZodIssues({
51
- kind: "zod",
52
- method: context.method,
53
- url: context.url,
54
- status: context.status,
55
- zodIssues: error.developerDetail.zodIssues,
56
- serverTag: await context.getServerTag()
57
- });
58
- throw error;
59
- }
60
- }
61
- //#endregion
62
- //#region ../client/src/http/retry.ts
63
- const BASE_DELAY_MS = 250;
64
- const MAX_DELAY_MS = 8e3;
65
- const MS_PER_SECOND = 1e3;
66
- function backoffDelay({ attempt, retryAfterHeader }) {
67
- const fromHeader = parseRetryAfter(retryAfterHeader);
68
- if (fromHeader !== null) return fromHeader;
69
- return Math.min(MAX_DELAY_MS, BASE_DELAY_MS * 2 ** attempt);
70
- }
71
- function parseRetryAfter(header) {
72
- if (!header) return null;
73
- const numeric = Number(header);
74
- if (Number.isFinite(numeric) && numeric >= 0) return Math.round(numeric * MS_PER_SECOND);
75
- const dateMs = Date.parse(header);
76
- if (Number.isFinite(dateMs)) return Math.max(0, dateMs - Date.now());
77
- return null;
78
- }
79
- function sleep(ms, signal) {
80
- return setTimeout(ms, void 0, { signal });
81
- }
82
- async function runWithRetries(attempt, signal) {
83
- let attemptIndex = 0;
84
- while (true) {
85
- const outcome = await attempt(attemptIndex);
86
- if (outcome.kind === "success") return outcome.response;
87
- await sleep(outcome.delayMs, signal);
88
- attemptIndex += 1;
89
- }
90
- }
91
- //#endregion
92
- //#region ../client/src/http/transport.ts
93
- const UNAUTHORIZED_STATUS = 401;
94
- const DEFAULT_TIMEOUT_MS = 3e4;
95
- const OCTET_STREAM_CONTENT_TYPE = "application/octet-stream";
96
- const TEXT_CONTENT_TYPE_PREFIX = "text/";
97
- const ERROR_BODY_BYTE_CAP = 64 * 1024;
98
- const IDEMPOTENT_METHODS = /* @__PURE__ */ new Set([
99
- "GET",
100
- "HEAD",
101
- "OPTIONS"
102
- ]);
103
- function createTransport(config, options) {
104
- const baseUrl = normalizeUrl(config.url);
105
- assertCredentialHeaderSafe(config.credential);
106
- const fetchImpl = options.fetchImpl ?? globalThis.fetch.bind(globalThis);
107
- const getServerTag = options.getServerTag ?? NO_SERVER_TAG;
108
- const refreshCredential = options.refreshCredential;
109
- let credential = config.credential;
110
- const knownSecrets = new Set(credentialSecrets(credential));
111
- const redactionContext = { knownSecrets };
112
- let refreshInFlight = null;
113
- function tryRefreshCredential() {
114
- const refresh = refreshCredential;
115
- if (credential.kind !== "oauth" || refresh === void 0) return Promise.resolve(false);
116
- refreshInFlight ??= refreshOnce(refresh).finally(() => {
117
- refreshInFlight = null;
118
- });
119
- return refreshInFlight;
120
- }
121
- async function refreshOnce(refresh) {
122
- const next = await refresh();
123
- if (next === null) return false;
124
- credential = next;
125
- for (const secret of credentialSecrets(next)) knownSecrets.add(secret);
126
- return true;
127
- }
128
- async function attemptOnce(prepared, attempt) {
129
- const hasRetriesLeft = attempt < prepared.retries;
130
- const timeoutSignal = AbortSignal.timeout(prepared.timeoutMs);
131
- const combined = combineAborts(timeoutSignal, prepared.cancelSignal);
132
- let response;
133
- try {
134
- response = await fetchImpl(prepared.url, {
135
- method: prepared.method,
136
- headers: prepared.headers,
137
- body: prepared.body,
138
- signal: combined
139
- });
140
- } catch (error) {
141
- throwIfAborted(prepared.cancelSignal);
142
- const isStaleSocketFirstTry = attempt === 0 && isConnectionClosed(error);
143
- if (prepared.idempotent && (hasRetriesLeft || isStaleSocketFirstTry)) return {
144
- kind: "retry",
145
- delayMs: backoffDelay({ attempt })
146
- };
147
- if (timeoutSignal.aborted) throw new TimeoutError(`Request timed out after ${prepared.timeoutMs}ms`, {
148
- kind: "http",
149
- method: prepared.method,
150
- url: prepared.url,
151
- timeoutMs: prepared.timeoutMs
152
- });
153
- throw buildNetworkError(error, prepared.method, prepared.url);
154
- }
155
- const canRetryStatus = hasRetriesLeft && prepared.idempotent;
156
- if (!response.ok && isRetryableStatus(response.status) && canRetryStatus) {
157
- const retryAfter = response.headers.get("Retry-After");
158
- response.body?.cancel().catch(() => void 0);
159
- return {
160
- kind: "retry",
161
- delayMs: backoffDelay({
162
- attempt,
163
- retryAfterHeader: retryAfter
164
- })
165
- };
166
- }
167
- if (!response.ok) {
168
- const rawBody = await readBodyForError(response);
169
- const serverTag = await getServerTag();
170
- throw new HttpError({
171
- status: response.status,
172
- statusText: response.statusText,
173
- method: prepared.method,
174
- url: prepared.url,
175
- responseHeaders: response.headers,
176
- rawBody,
177
- serverTag,
178
- redactionContext
179
- });
180
- }
181
- assertContentType(response, prepared);
182
- return {
183
- kind: "success",
184
- response
185
- };
186
- }
187
- async function executeRaw(prepared) {
188
- try {
189
- return await runWithRetries((attempt) => attemptOnce(prepared, attempt), prepared.cancelSignal);
190
- } catch (error) {
191
- throwIfAborted(prepared.cancelSignal);
192
- throw error;
193
- }
194
- }
195
- async function executeWithAuthRefresh(path, opts) {
196
- const prepared = prepare(path, opts);
197
- try {
198
- return {
199
- response: await executeRaw(prepared),
200
- prepared
201
- };
202
- } catch (error) {
203
- if (error instanceof HttpError && error.status === UNAUTHORIZED_STATUS) {
204
- if (await tryRefreshCredential()) {
205
- const retried = prepare(path, opts);
206
- return {
207
- response: await executeRaw(retried),
208
- prepared: retried
209
- };
210
- }
211
- }
212
- throw error;
213
- }
214
- }
215
- function prepare(path, opts = {}) {
216
- const method = opts.method ?? "GET";
217
- const expectContentType = opts.expectContentType ?? "json";
218
- const url = buildUrl(baseUrl, path, opts.query);
219
- const headers = new Headers();
220
- const auth = credentialAuthHeader(credential);
221
- headers.set(auth.name, auth.value);
222
- headers.set("accept", acceptHeader(expectContentType));
223
- headers.set("user-agent", options.userAgent);
224
- let body = null;
225
- if (opts.body !== void 0 && opts.body !== null) if (typeof opts.body === "string" || opts.body instanceof URLSearchParams) body = opts.body;
226
- else if (opts.body instanceof FormData || opts.body instanceof ReadableStream) body = opts.body;
227
- else if (opts.body instanceof Uint8Array) {
228
- body = opts.body;
229
- headers.set("content-type", OCTET_STREAM_CONTENT_TYPE);
230
- } else {
231
- body = JSON.stringify(opts.body);
232
- headers.set("content-type", JSON_CONTENT_TYPE);
233
- }
234
- return {
235
- url,
236
- method,
237
- headers,
238
- body,
239
- expectContentType,
240
- retries: opts.retries ?? 3,
241
- idempotent: opts.idempotent ?? IDEMPOTENT_METHODS.has(method),
242
- timeoutMs: opts.timeoutMs ?? DEFAULT_TIMEOUT_MS,
243
- cancelSignal: combineAborts(opts.signal, options.signal)
244
- };
245
- }
246
- return {
247
- async requestRaw(path, opts) {
248
- return (await executeWithAuthRefresh(path, opts ?? {})).response;
249
- },
250
- async requestParsed(schema, path, opts) {
251
- const { response, prepared } = await executeWithAuthRefresh(path, {
252
- ...opts,
253
- expectContentType: "json"
254
- });
255
- return parseJsonResponse(await response.text(), schema, {
256
- method: prepared.method,
257
- url: prepared.url,
258
- status: response.status,
259
- getServerTag
260
- });
261
- },
262
- async requestStream(path, opts) {
263
- const { response, prepared } = await executeWithAuthRefresh(path, {
264
- ...opts,
265
- expectContentType: opts?.expectContentType ?? "binary"
266
- });
267
- if (!response.body) throw new NetworkError("Response had no body to stream", {
268
- method: prepared.method,
269
- url: prepared.url,
270
- cause: "missing body"
271
- });
272
- return response.body;
273
- }
274
- };
275
- }
276
- function buildUrl(baseUrl, path, query) {
277
- const normalizedPath = path.startsWith("/") ? path : `/${path}`;
278
- const target = new URL(baseUrl + normalizedPath);
279
- if (query) for (const [key, value] of Object.entries(query)) {
280
- if (value === void 0) continue;
281
- if (Array.isArray(value)) for (const entry of value) target.searchParams.append(key, String(entry));
282
- else target.searchParams.append(key, String(value));
283
- }
284
- return target.toString();
285
- }
286
- function acceptHeader(expected) {
287
- if (expected === "json") return JSON_CONTENT_TYPE;
288
- if (expected === "text") return "text/*";
289
- return "*/*";
290
- }
291
- function assertContentType(response, prepared) {
292
- if (prepared.expectContentType === "binary") return;
293
- const contentType = response.headers.get("content-type");
294
- if (contentType === null) throwContentTypeMismatch(response, prepared, prepared.expectContentType);
295
- if (prepared.expectContentType === "json" && !contentType.includes("application/json")) throwContentTypeMismatch(response, prepared, "json");
296
- if (prepared.expectContentType === "text" && !contentType.startsWith(TEXT_CONTENT_TYPE_PREFIX)) throwContentTypeMismatch(response, prepared, "text");
297
- }
298
- function throwContentTypeMismatch(response, prepared, expected) {
299
- const actual = response.headers.get("content-type") ?? "no content-type";
300
- throw new HttpError({
301
- status: response.status,
302
- statusText: response.statusText,
303
- method: prepared.method,
304
- url: prepared.url,
305
- responseHeaders: response.headers,
306
- rawBody: null,
307
- overrideUserMessage: `Expected ${expected} response but got ${actual}`
308
- });
309
- }
310
- async function readBodyForError(response) {
311
- try {
312
- return Buffer.from(await response.arrayBuffer()).subarray(0, ERROR_BODY_BYTE_CAP).toString("utf8");
313
- } catch (error) {
314
- return `[body read failed: ${errorMessage(error)}]`;
315
- }
316
- }
317
- //#endregion
318
- //#region ../client/src/resources/card.ts
319
- const CardApiList = z.array(Card);
320
- function cardResource(transport) {
321
- /** List cards. `f` picks a server-side preset; `model_id` scopes the presets that need an id. */
322
- async function list(params = {}, options = {}) {
323
- return {
324
- data: await transport.requestParsed(CardApiList, "/api/card", {
325
- ...options,
326
- query: {
327
- f: params.f,
328
- model_id: params.model_id
329
- }
330
- }),
331
- total: null
332
- };
333
- }
334
- /** Get one card by id. */
335
- async function get(id, options = {}) {
336
- return transport.requestParsed(Card, `/api/card/${id}`, { ...options });
337
- }
338
- /** Create a card — a question, a model, or a metric — from a full card body. */
339
- async function create(params, options = {}) {
340
- return transport.requestParsed(Card, "/api/card", {
341
- ...options,
342
- method: "POST",
343
- body: params
344
- });
345
- }
346
- /** Update a card by id, patching only the fields the body carries. */
347
- async function update(id, params, options = {}) {
348
- return transport.requestParsed(Card, `/api/card/${id}`, {
349
- ...options,
350
- method: "PUT",
351
- body: params
352
- });
353
- }
354
- /** Archive (soft-delete) a card by id. Metabase models this as an update, not its own endpoint. */
355
- async function archive(id, options = {}) {
356
- return update(id, { archived: true }, options);
357
- }
358
- /** Run a saved card and return the query result envelope. */
359
- async function query(id, params, options = {}) {
360
- return transport.requestParsed(CardQueryResult, `/api/card/${id}/query`, {
361
- ...options,
362
- method: "POST",
363
- body: { parameters: params.parameters }
364
- });
365
- }
366
- /**
367
- * Run a saved card and stream its result as a download. Unlike `query`, this endpoint takes a
368
- * form-encoded body and answers bytes, so a caller consumes the stream rather than a value.
369
- */
370
- async function exportQuery(id, format, params, options = {}) {
371
- const body = new URLSearchParams({
372
- parameters: JSON.stringify(params.parameters),
373
- format_rows: String(params.format_rows),
374
- pivot_results: String(params.pivot_results)
375
- });
376
- return transport.requestStream(`/api/card/${id}/query/${format}`, {
377
- ...options,
378
- method: "POST",
379
- body
380
- });
381
- }
382
- return {
383
- list,
384
- get,
385
- create,
386
- update,
387
- archive,
388
- query,
389
- exportQuery
390
- };
391
- }
392
- async function* paginatePages(client, path, itemSchema, opts = {}) {
393
- const envelopeSchema = paginatedEnvelopeSchema(itemSchema);
394
- const pageSize = opts.pageSize ?? 50;
395
- if (!Number.isInteger(pageSize) || pageSize < 1) throw new InternalError(`pageSize must be an integer of at least 1, got ${pageSize}`);
396
- const start = opts.offset ?? 0;
397
- const max = opts.max ?? Number.POSITIVE_INFINITY;
398
- let taken = 0;
399
- let previousHead = null;
400
- while (taken < max) {
401
- const remaining = max - taken;
402
- const limit = Math.min(pageSize, remaining);
403
- const offset = start + taken;
404
- const envelope = await client.requestParsed(envelopeSchema, path, {
405
- query: {
406
- ...opts.query,
407
- limit,
408
- offset
409
- },
410
- ...opts.signal !== void 0 && { signal: opts.signal }
411
- });
412
- const items = envelope.data.length > remaining ? envelope.data.slice(0, remaining) : envelope.data;
413
- const total = envelope.total ?? null;
414
- const head = items.length === 0 ? null : JSON.stringify(items[0]);
415
- if (head !== null && head === previousHead) throw new ConfigError(`the endpoint returned the same first row at offset ${offset} as at the previous offset; it is ignoring the offset parameter, so paging cannot advance`);
416
- previousHead = head;
417
- yield {
418
- items,
419
- total
420
- };
421
- if (items.length === 0) return;
422
- const consumed = taken + items.length;
423
- if (total !== null && start + consumed === total) return;
424
- taken = consumed;
425
- }
426
- }
427
- function paginatedEnvelopeSchema(itemSchema) {
428
- return z.object({
429
- data: z.array(itemSchema),
430
- total: z.number().int().nonnegative().nullable().optional(),
431
- limit: z.number().int().nonnegative().optional(),
432
- offset: z.number().int().nonnegative().optional()
433
- }).loose();
434
- }
435
- //#endregion
436
- //#region ../client/src/resources/collection.ts
437
- const CollectionApiList = z.array(Collection);
438
- const CollectionTreeApiList = z.array(CollectionTreeNode);
439
- const COLLECTION_LIST_QUERY = {
440
- all: {},
441
- archived: { archived: true },
442
- personal: { "personal-only": true }
443
- };
444
- const DEFAULT_LIST_FILTER = "all";
445
- function refPath(ref) {
446
- return encodeURIComponent(ref);
447
- }
448
- /**
449
- * List collections including the Library and its children, parsing each through the caller's own
450
- * projection. `Collection` pins `type`, `namespace` and `authority_level` to closed enums, so a
451
- * consumer reading a few fields off every collection on the instance narrows here: one collection
452
- * carrying a server value outside those sets then costs nothing to a caller that never reads the
453
- * field.
454
- */
455
- async function listCollectionsWithLibrary(transport, schema, options = {}) {
456
- return transport.requestParsed(z.array(schema), "/api/collection", {
457
- ...options,
458
- query: { "include-library": true }
459
- });
460
- }
461
- function collectionResource(transport) {
462
- /** List collections. `filter` picks a server-side preset: everything, archived, or personal. */
463
- async function list(params = {}, options = {}) {
464
- return {
465
- data: await transport.requestParsed(CollectionApiList, "/api/collection", {
466
- ...options,
467
- query: COLLECTION_LIST_QUERY[params.filter ?? DEFAULT_LIST_FILTER]
468
- }),
469
- total: null
470
- };
471
- }
472
- /**
473
- * List collections including the Library and its children, which the plain listing omits.
474
- * The Library's own children carry neither `type` nor `is_remote_synced`, so this is where a
475
- * caller resolves both.
476
- */
477
- async function listWithLibrary(options = {}) {
478
- return {
479
- data: await listCollectionsWithLibrary(transport, Collection, options),
480
- total: null
481
- };
482
- }
483
- /** Get one collection by id, entity id, or the `root`/`trash` alias. */
484
- async function get(ref, options = {}) {
485
- return transport.requestParsed(Collection, `/api/collection/${refPath(ref)}`, { ...options });
486
- }
487
- /** Create a new collection. */
488
- async function create(params, options = {}) {
489
- return transport.requestParsed(Collection, "/api/collection", {
490
- ...options,
491
- method: "POST",
492
- body: params
493
- });
494
- }
495
- /** Update a collection, patching only the fields the body carries. */
496
- async function update(ref, params, options = {}) {
497
- return transport.requestParsed(Collection, `/api/collection/${refPath(ref)}`, {
498
- ...options,
499
- method: "PUT",
500
- body: params
501
- });
502
- }
503
- /** Archive (soft-delete) a collection. Metabase models this as an update, not its own endpoint. */
504
- async function archive(ref, options = {}) {
505
- return update(ref, { archived: true }, options);
506
- }
507
- /**
508
- * Walk the items inside a collection one page at a time. This endpoint pages on the server, so
509
- * the caller consumes pages rather than a single list and decides how far to pull.
510
- */
511
- function itemPages(ref, params = {}, options = {}) {
512
- return paginatePages(transport, `/api/collection/${refPath(ref)}/items`, CollectionItem, {
513
- query: {
514
- models: params.models,
515
- archived: params.archived,
516
- pinned_state: params.pinned_state
517
- },
518
- ...options.offset !== void 0 && { offset: options.offset },
519
- ...options.max !== void 0 && { max: options.max },
520
- ...options.pageSize !== void 0 && { pageSize: options.pageSize },
521
- ...options.signal !== void 0 && { signal: options.signal }
522
- });
523
- }
524
- /** Fetch the collection hierarchy as a forest of nested nodes. */
525
- async function tree(options = {}) {
526
- return {
527
- data: await transport.requestParsed(CollectionTreeApiList, "/api/collection/tree", { ...options }),
528
- total: null
529
- };
530
- }
531
- return {
532
- list,
533
- listWithLibrary,
534
- get,
535
- create,
536
- update,
537
- archive,
538
- itemPages,
539
- tree
540
- };
541
- }
542
- //#endregion
543
- //#region ../client/src/resources/csv-upload.ts
544
- const CSV_CONTENT_TYPE = "text/csv";
545
- function buildCsvFormData(file) {
546
- const form = new FormData();
547
- form.append("file", new Blob([file.bytes], { type: CSV_CONTENT_TYPE }), file.filename);
548
- return form;
549
- }
550
- //#endregion
551
- //#region ../client/src/resources/content-translation.ts
552
- const CONTENT_TRANSLATION_PATH = "/api/ee/content-translation";
553
- function contentTranslationResource(transport) {
554
- /** Download the complete content translation dictionary as CSV. */
555
- async function download(options = {}) {
556
- return transport.requestStream(`${CONTENT_TRANSLATION_PATH}/csv`, options);
557
- }
558
- /** Replace the complete content translation dictionary with the attached CSV. */
559
- async function upload(file, options = {}) {
560
- const form = buildCsvFormData(file);
561
- return transport.requestParsed(ContentTranslationUploadResult, `${CONTENT_TRANSLATION_PATH}/upload-dictionary`, {
562
- ...options,
563
- method: "POST",
564
- body: form
565
- });
566
- }
567
- return {
568
- download,
569
- upload
570
- };
571
- }
572
- //#endregion
573
- //#region ../client/src/resources/dashboard.ts
574
- const DashboardApiList = z.array(Dashboard);
575
- const PreflightDashcard = z.looseObject({ card_id: z.number().int().nullable().optional() });
576
- function dashboardResource(transport) {
577
- const card = cardResource(transport);
578
- /** List dashboards. `f` picks a server-side preset. */
579
- async function list(params = {}, options = {}) {
580
- return {
581
- data: await transport.requestParsed(DashboardApiList, "/api/dashboard", {
582
- ...options,
583
- query: { f: params.f }
584
- }),
585
- total: null
586
- };
587
- }
588
- /** Get one dashboard by id, with its dashcards, tabs and parameters. */
589
- async function get(id, options = {}) {
590
- return transport.requestParsed(DashboardDetail, `/api/dashboard/${id}`, { ...options });
591
- }
592
- /**
593
- * Create a dashboard. The endpoint accepts no dashcards or tabs — a follow-up `update` is what
594
- * puts content on a fresh dashboard.
595
- */
596
- async function create(params, options = {}) {
597
- return transport.requestParsed(Dashboard, "/api/dashboard", {
598
- ...options,
599
- method: "POST",
600
- body: params
601
- });
602
- }
603
- /**
604
- * Update a dashboard by id, patching only the fields the body carries. `dashcards` and `tabs` are
605
- * full replacements: whatever the body omits is deleted from the dashboard.
606
- */
607
- async function update(id, params, options = {}) {
608
- return transport.requestParsed(DashboardDetail, `/api/dashboard/${id}`, {
609
- ...options,
610
- method: "PUT",
611
- body: params
612
- });
613
- }
614
- /**
615
- * Archive (soft-delete) a dashboard by id. Metabase models this as an update, not its own
616
- * endpoint. The answer is read as `Dashboard` rather than the `DashboardDetail` `update` returns:
617
- * an archive is a state change on the dashboard itself, and its dashcards are not part of it.
618
- */
619
- async function archive(id, options = {}) {
620
- return transport.requestParsed(Dashboard, `/api/dashboard/${id}`, {
621
- ...options,
622
- method: "PUT",
623
- body: { archived: true }
624
- });
625
- }
626
- /**
627
- * Patch one dashcard on a dashboard. Metabase exposes no dashcard endpoint and its dashboard PUT
628
- * is a full replace of `dashcards`, so the patch is read-modify-written over the dashboard as it
629
- * currently stands.
630
- */
631
- async function updateDashcard(dashboardId, dashcardId, params, options = {}) {
632
- const dashboard = await get(dashboardId, options);
633
- const target = dashboard.dashcards.find((dashcard) => dashcard.id === dashcardId);
634
- if (target === void 0) throw new ConfigError(`dashcard ${dashcardId} not found on dashboard ${dashboardId}`);
635
- const patched = Dashcard.parse({
636
- ...target,
637
- ...params
638
- });
639
- const refreshed = (await update(dashboardId, { dashcards: dashboard.dashcards.map((dashcard) => stripEntityId(dashcard.id === dashcardId ? patched : dashcard)) }, options)).dashcards.find((dashcard) => dashcard.id === dashcardId);
640
- if (refreshed === void 0) throw new Error(`PUT /api/dashboard/${dashboardId}: dashcard ${dashcardId} missing from response`);
641
- return refreshed;
642
- }
643
- /**
644
- * Check every card a `dashcards` body references before writing it, through `GET /api/card/{id}`
645
- * once per distinct id. Reports one issue per reference whose card is missing, archived, or
646
- * unreadable, so an empty result means the body is safe to send; an id the server answers for in
647
- * any other way propagates as the failure it was.
648
- */
649
- async function checkCardReferences(dashcards, options = {}) {
650
- const grouped = groupByCardId(collectCardReferences(dashcards));
651
- return (await Promise.all(Array.from(grouped.entries()).map(async ([cardId, references]) => ({
652
- references,
653
- problem: await inspectCard(cardId, options)
654
- })))).flatMap((check) => {
655
- const problem = check.problem;
656
- if (problem === null) return [];
657
- return check.references.map((reference) => ({
658
- ...reference,
659
- problem
660
- }));
661
- });
662
- }
663
- async function inspectCard(cardId, options) {
664
- try {
665
- return (await card.get(cardId, options)).archived ? { reason: "archived" } : null;
666
- } catch (error) {
667
- if (!(error instanceof HttpError)) throw error;
668
- if (error.kind === "resource-missing") return { reason: "missing" };
669
- if (error.kind === "auth") return {
670
- reason: "unreadable",
671
- detail: error.userMessage
672
- };
673
- throw error;
674
- }
675
- }
676
- /**
677
- * Fetch the selectable values for a dashboard parameter, through the chain-filter value endpoint.
678
- */
679
- async function parameterValues(dashboardId, parameterId, options = {}) {
680
- return transport.requestParsed(ParameterValues, `/api/dashboard/${dashboardId}/params/${encodeURIComponent(parameterId)}/values`, { ...options });
681
- }
682
- /**
683
- * Search a dashboard parameter's selectable values: the server returns only values containing the
684
- * substring, capped at the first 1000 matches.
685
- */
686
- async function searchParameterValues(dashboardId, parameterId, query, options = {}) {
687
- const parameter = encodeURIComponent(parameterId);
688
- return transport.requestParsed(ParameterValues, `/api/dashboard/${dashboardId}/params/${parameter}/search/${encodeURIComponent(query)}`, { ...options });
689
- }
690
- return {
691
- list,
692
- get,
693
- create,
694
- update,
695
- archive,
696
- updateDashcard,
697
- checkCardReferences,
698
- parameterValues,
699
- searchParameterValues
700
- };
701
- }
702
- function collectCardReferences(dashcards) {
703
- if (dashcards === void 0 || dashcards === null) return [];
704
- const references = [];
705
- dashcards.forEach((dashcard, index) => {
706
- const parsed = PreflightDashcard.safeParse(dashcard);
707
- if (!parsed.success) return;
708
- const cardId = parsed.data.card_id;
709
- if (typeof cardId === "number" && cardId > 0) references.push({
710
- cardId,
711
- path: `/dashcards/${index}/card_id`
712
- });
713
- });
714
- return references;
715
- }
716
- function groupByCardId(references) {
717
- const grouped = /* @__PURE__ */ new Map();
718
- for (const reference of references) {
719
- const existing = grouped.get(reference.cardId);
720
- if (existing === void 0) grouped.set(reference.cardId, [reference]);
721
- else existing.push(reference);
722
- }
723
- return grouped;
724
- }
725
- function stripEntityId(dashcard) {
726
- const { entity_id: _entity_id, id, size_x, size_y, row, col, ...rest } = dashcard;
727
- return {
728
- ...rest,
729
- id,
730
- size_x,
731
- size_y,
732
- row,
733
- col
734
- };
735
- }
736
- //#endregion
737
- //#region ../client/src/resources/database.ts
738
- const DatabaseApiList = z.object({
739
- data: z.array(Database),
740
- total: z.number().int().nonnegative()
741
- }).loose();
742
- const DatabaseTaskAck = z.object({ status: z.literal("ok") });
743
- const DatabaseApiSchemaList = z.array(z.string());
744
- const DatabaseApiSchemaTableList = z.array(Table);
745
- const SYNC_COMPLETE = "complete";
746
- function databaseResource(transport) {
747
- /** List databases. `include` hydrates each database's tables; `saved` adds the Saved Questions virtual database. */
748
- async function list(params = {}, options = {}) {
749
- const response = await transport.requestParsed(DatabaseApiList, "/api/database", {
750
- ...options,
751
- query: {
752
- include: params.include,
753
- saved: params.saved
754
- }
755
- });
756
- return {
757
- data: response.data,
758
- total: response.total
759
- };
760
- }
761
- /** Get one database by id. `include` hydrates its tables, and `tables.fields` their fields too. */
762
- async function get(id, params = {}, options = {}) {
763
- return transport.requestParsed(Database, `/api/database/${id}`, {
764
- ...options,
765
- query: { include: params.include }
766
- });
767
- }
768
- /** List the schema names in a database. */
769
- async function schemas(id, options = {}) {
770
- return {
771
- data: await transport.requestParsed(DatabaseApiSchemaList, `/api/database/${id}/schemas`, { ...options }),
772
- total: null
773
- };
774
- }
775
- /** List the tables one schema of a database holds. */
776
- async function schemaTables(id, schema, options = {}) {
777
- return {
778
- data: await transport.requestParsed(DatabaseApiSchemaTableList, `/api/database/${id}/schema/${encodeURIComponent(schema)}`, { ...options }),
779
- total: null
780
- };
781
- }
782
- /**
783
- * Trigger a manual schema sync for a database. The endpoint queues the sync and returns at once;
784
- * pass `wait` to poll the database until it reports its initial sync complete.
785
- */
786
- async function syncSchema(id, params = {}, options = {}) {
787
- const ack = await transport.requestParsed(DatabaseTaskAck, `/api/database/${id}/sync_schema`, {
788
- ...options,
789
- method: "POST"
790
- });
791
- const wait = params.wait;
792
- if (wait === void 0) return {
793
- id,
794
- status: ack.status
795
- };
796
- const database = await pollUntil(async (signal) => transport.requestParsed(Database, `/api/database/${id}`, {
797
- ...options,
798
- signal
799
- }), (candidate) => candidate.initial_sync_status === SYNC_COMPLETE, wait);
800
- return {
801
- id,
802
- status: ack.status,
803
- initial_sync_status: database.initial_sync_status ?? null
804
- };
805
- }
806
- /** Trigger a rescan of the cached field values across a database. */
807
- async function rescanValues(id, options = {}) {
808
- return {
809
- id,
810
- status: (await transport.requestParsed(DatabaseTaskAck, `/api/database/${id}/rescan_values`, {
811
- ...options,
812
- method: "POST"
813
- })).status
814
- };
815
- }
816
- return {
817
- list,
818
- get,
819
- schemas,
820
- schemaTables,
821
- syncSchema,
822
- rescanValues
823
- };
824
- }
825
- //#endregion
826
- //#region ../client/src/resources/dataset.ts
827
- function datasetResource(transport) {
828
- /**
829
- * Run an ad-hoc query and return its result envelope. The body is a whole query — MBQL 5, legacy
830
- * MBQL, or native — rather than a reference to a saved one, so nothing here is a card.
831
- */
832
- async function query(body, options = {}) {
833
- return transport.requestParsed(CardQueryResult, "/api/dataset", {
834
- ...options,
835
- method: "POST",
836
- body
837
- });
838
- }
839
- return { query };
840
- }
841
- //#endregion
842
- //#region ../client/src/resources/document.ts
843
- const DocumentApiList = z.object({ items: z.array(Document) }).loose();
844
- function documentResource(transport) {
845
- /** Get existing documents. */
846
- async function list(options = {}) {
847
- return {
848
- data: (await transport.requestParsed(DocumentApiList, "/api/document", { ...options })).items,
849
- total: null
850
- };
851
- }
852
- /** Return an existing document by id. */
853
- async function get(id, options = {}) {
854
- return transport.requestParsed(Document, `/api/document/${id}`, { ...options });
855
- }
856
- /** Create a new document. */
857
- async function create(params, options = {}) {
858
- return transport.requestParsed(Document, "/api/document", {
859
- ...options,
860
- method: "POST",
861
- body: params
862
- });
863
- }
864
- /** Update an existing document by id. */
865
- async function update(id, params, options = {}) {
866
- return transport.requestParsed(Document, `/api/document/${id}`, {
867
- ...options,
868
- method: "PUT",
869
- body: params
870
- });
871
- }
872
- /** Archive (soft-delete) a document by id. Metabase models this as an update, not its own endpoint. */
873
- async function archive(id, options = {}) {
874
- return update(id, { archived: true }, options);
875
- }
876
- return {
877
- list,
878
- get,
879
- create,
880
- update,
881
- archive
882
- };
883
- }
884
- //#endregion
885
- //#region ../client/src/resources/eid-translation.ts
886
- function eidTranslationResource(transport) {
887
- /**
888
- * Translate entity ids to the numeric ids of the rows they name. The request groups the entity
889
- * ids by model; the response is keyed by entity id, each entry carrying its model and — when the
890
- * lookup succeeded — the numeric id.
891
- */
892
- async function translate(params, options = {}) {
893
- return transport.requestParsed(EidTranslateResult, "/api/eid-translation/translate", {
894
- ...options,
895
- method: "POST",
896
- body: params
897
- });
898
- }
899
- return { translate };
900
- }
901
- //#endregion
902
- //#region ../client/src/resources/field.ts
903
- const FieldApiSummary = z.tuple([z.tuple([z.literal("count"), z.number().int()]), z.tuple([z.literal("distincts"), z.number().int()])]);
904
- function fieldResource(transport) {
905
- /** Get one field by id. */
906
- async function get(id, options = {}) {
907
- return transport.requestParsed(Field, `/api/field/${id}`, { ...options });
908
- }
909
- /** Update a field by id, patching only the fields the body carries. */
910
- async function update(id, params, options = {}) {
911
- return transport.requestParsed(Field, `/api/field/${id}`, {
912
- ...options,
913
- method: "PUT",
914
- body: params
915
- });
916
- }
917
- /** Get the row count and the distinct-value count for a field. */
918
- async function summary(id, options = {}) {
919
- const [[, count], [, distincts]] = await transport.requestParsed(FieldApiSummary, `/api/field/${id}/summary`, { ...options });
920
- return {
921
- field_id: id,
922
- count,
923
- distincts
924
- };
925
- }
926
- /** Get the cached distinct values Metabase holds for a field. */
927
- async function values(id, options = {}) {
928
- return transport.requestParsed(FieldValues, `/api/field/${id}/values`, { ...options });
929
- }
930
- return {
931
- get,
932
- update,
933
- summary,
934
- values
935
- };
936
- }
937
- //#endregion
938
- //#region ../client/src/resources/optional-parsed.ts
939
- const NO_CONTENT_STATUS = 204;
940
- async function fetchOptionalParsed(client, path, schema, options = {}) {
941
- const response = await client.requestRaw(path, {
942
- ...options,
943
- method: "GET",
944
- expectContentType: "binary"
945
- });
946
- if (response.status === NO_CONTENT_STATUS) return null;
947
- return parseJsonOrPlain(await response.text(), response.headers.get("content-type"), schema, { source: response.url });
948
- }
949
- //#endregion
950
- //#region ../client/src/resources/git-sync.ts
951
- const SyncScopeCollection = Collection.pick({
952
- id: true,
953
- name: true,
954
- is_remote_synced: true
955
- }).strip();
956
- const SyncDirtyFlag = z.object({ is_dirty: z.boolean() });
957
- const SyncDirtyList = z.object({ dirty: z.array(SyncDirtyItem) });
958
- const SyncBranchList = z.object({ items: z.array(z.string()) });
959
- const SyncImportStarted = z.object({
960
- status: z.literal("success"),
961
- task_id: z.number().int().positive().nullable(),
962
- message: z.string().nullable().optional()
963
- });
964
- const SyncExportStarted = z.object({
965
- message: z.string(),
966
- task_id: z.number().int().positive()
967
- });
968
- const SyncStashStarted = z.object({
969
- status: z.literal("success"),
970
- message: z.string(),
971
- task_id: z.number().int().positive()
972
- });
973
- const RemoteSyncSetting = z.string().nullable();
974
- const FORBIDDEN_STATUS = 403;
975
- const UNREGISTERED_STATUS = 404;
976
- function isRemoteUnreadable(error) {
977
- if (!(error instanceof HttpError)) return false;
978
- return error.status === FORBIDDEN_STATUS || error.status === UNREGISTERED_STATUS;
979
- }
980
- function gitSyncResource(transport) {
981
- /** Get the running or most recently finished sync task, or null when the server has none. */
982
- async function currentTask(options = {}) {
983
- return fetchOptionalParsed(transport, "/api/ee/remote-sync/current-task", SyncTask, options);
984
- }
985
- /** Request cancellation of the running sync task, and answer it in the state that left it. */
986
- async function cancelTask(options = {}) {
987
- return transport.requestParsed(SyncTask, "/api/ee/remote-sync/current-task/cancel", {
988
- ...options,
989
- method: "POST"
990
- });
991
- }
992
- /** Whether Metabase holds content changes the remote has not been told about. */
993
- async function isDirty(options = {}) {
994
- return (await transport.requestParsed(SyncDirtyFlag, "/api/ee/remote-sync/is-dirty", { ...options })).is_dirty;
995
- }
996
- /** List the objects whose local state differs from the remote. */
997
- async function dirty(options = {}) {
998
- return {
999
- data: (await transport.requestParsed(SyncDirtyList, "/api/ee/remote-sync/dirty", { ...options })).dirty,
1000
- total: null
1001
- };
1002
- }
1003
- /**
1004
- * Compare the tracked remote branch against what Metabase last imported. The server caches the
1005
- * comparison; `force-refresh` re-reads the remote instead.
1006
- */
1007
- async function hasRemoteChanges(params = {}, options = {}) {
1008
- return transport.requestParsed(SyncRemoteChanges, "/api/ee/remote-sync/has-remote-changes", {
1009
- ...options,
1010
- query: { "force-refresh": params["force-refresh"] }
1011
- });
1012
- }
1013
- /**
1014
- * Import content from the remote into Metabase. The endpoint queues a task and returns at once;
1015
- * pass `wait` to poll that task until it reaches a terminal status. A server already up to date
1016
- * answers no task id, and there is then nothing to poll.
1017
- */
1018
- async function importFromRemote(params = {}, options = {}) {
1019
- const started = await transport.requestParsed(SyncImportStarted, "/api/ee/remote-sync/import", {
1020
- ...options,
1021
- method: "POST",
1022
- body: {
1023
- branch: params.branch,
1024
- force: params.force
1025
- }
1026
- });
1027
- const message = started.message ?? null;
1028
- if (params.wait === void 0 || started.task_id === null) return {
1029
- message,
1030
- task_id: started.task_id
1031
- };
1032
- return {
1033
- message,
1034
- task_id: started.task_id,
1035
- final: await settle(params.wait, options)
1036
- };
1037
- }
1038
- /**
1039
- * Export Metabase's content to the remote. The endpoint queues a task and returns at once; pass
1040
- * `wait` to poll that task until it reaches a terminal status.
1041
- */
1042
- async function exportToRemote(params = {}, options = {}) {
1043
- const started = await transport.requestParsed(SyncExportStarted, "/api/ee/remote-sync/export", {
1044
- ...options,
1045
- method: "POST",
1046
- body: {
1047
- branch: params.branch,
1048
- message: params.message,
1049
- force: params.force
1050
- }
1051
- });
1052
- if (params.wait === void 0) return {
1053
- message: started.message,
1054
- task_id: started.task_id
1055
- };
1056
- return {
1057
- message: started.message,
1058
- task_id: started.task_id,
1059
- final: await settle(params.wait, options)
1060
- };
1061
- }
1062
- /**
1063
- * Export Metabase's current content to a branch the remote does not have yet. The endpoint
1064
- * queues a task and returns at once; pass `wait` to poll that task to a terminal status.
1065
- */
1066
- async function stash(params, options = {}) {
1067
- const started = await transport.requestParsed(SyncStashStarted, "/api/ee/remote-sync/stash", {
1068
- ...options,
1069
- method: "POST",
1070
- body: {
1071
- new_branch: params.new_branch,
1072
- message: params.message
1073
- }
1074
- });
1075
- if (params.wait === void 0) return {
1076
- status: started.status,
1077
- message: started.message,
1078
- task_id: started.task_id
1079
- };
1080
- return {
1081
- status: started.status,
1082
- message: started.message,
1083
- task_id: started.task_id,
1084
- final: await settle(params.wait, options)
1085
- };
1086
- }
1087
- /** List the branches the configured remote carries. */
1088
- async function branches(options = {}) {
1089
- return {
1090
- data: (await transport.requestParsed(SyncBranchList, "/api/ee/remote-sync/branches", { ...options })).items,
1091
- total: null
1092
- };
1093
- }
1094
- /** Create a branch on the remote and point git-sync at it. */
1095
- async function createBranch(params, options = {}) {
1096
- return transport.requestParsed(SyncBranchCreated, "/api/ee/remote-sync/create-branch", {
1097
- ...options,
1098
- method: "POST",
1099
- body: { name: params.name }
1100
- });
1101
- }
1102
- /**
1103
- * Mark one collection as git-synced, or unmark it. The server cascades the flag to descendants
1104
- * by location prefix, and may queue an export task to carry the change to the remote.
1105
- */
1106
- async function setCollectionSynced(collectionId, synced, options = {}) {
1107
- return transport.requestParsed(SyncSettingsUpdateResult, "/api/ee/remote-sync/settings", {
1108
- ...options,
1109
- method: "PUT",
1110
- body: { collections: { [collectionId]: synced } }
1111
- });
1112
- }
1113
- /** The collections currently in git-sync's scope. */
1114
- async function syncedCollections(options = {}) {
1115
- return {
1116
- data: (await listCollectionsWithLibrary(transport, SyncScopeCollection, options)).filter((entry) => entry.is_remote_synced === true),
1117
- total: null
1118
- };
1119
- }
1120
- /** The remote's URL, or null when none is configured or the caller may not read it. */
1121
- async function remoteUrl(options = {}) {
1122
- try {
1123
- const url = await fetchOptionalParsed(transport, "/api/setting/remote-sync-url", RemoteSyncSetting, options);
1124
- return url === "" ? null : url;
1125
- } catch (error) {
1126
- if (isRemoteUnreadable(error)) return null;
1127
- throw error;
1128
- }
1129
- }
1130
- /** The branch git-sync tracks, or null when none is configured or the caller may not read it. */
1131
- async function branch(options = {}) {
1132
- return fetchOptionalParsed(transport, "/api/setting/remote-sync-branch", RemoteSyncSetting, options);
1133
- }
1134
- /**
1135
- * Poll the current task until it reaches a terminal status. A server with no task at all
1136
- * answers null, which is terminal in the same sense: nothing further will happen.
1137
- */
1138
- async function waitForTask(wait, options = {}) {
1139
- return settle(wait, options);
1140
- }
1141
- async function settle(wait, options) {
1142
- return pollUntil(async (signal) => currentTask({
1143
- ...options,
1144
- signal
1145
- }), (task) => task === null || isSyncTaskTerminal(task.status), wait);
1146
- }
1147
- return {
1148
- currentTask,
1149
- cancelTask,
1150
- isDirty,
1151
- dirty,
1152
- hasRemoteChanges,
1153
- import: importFromRemote,
1154
- export: exportToRemote,
1155
- stash,
1156
- branches,
1157
- createBranch,
1158
- setCollectionSynced,
1159
- syncedCollections,
1160
- remoteUrl,
1161
- branch,
1162
- waitForTask
1163
- };
1164
- }
1165
- //#endregion
1166
- //#region ../client/src/resources/library.ts
1167
- const LIBRARY_ROOT_PATH = "/api/ee/library/";
1168
- const PUBLISH_TABLES_PATH = "/api/ee/data-studio/table/publish-tables";
1169
- const UNPUBLISH_TABLES_PATH = "/api/ee/data-studio/table/unpublish-tables";
1170
- const LIBRARY_DATA_TYPE = "library-data";
1171
- const AbsentLibrary = z.object({ data: z.null() });
1172
- const LibraryOrAbsent = z.union([Library, AbsentLibrary]);
1173
- const PublishTablesResponse = z.object({ target_collection: Collection.nullable() });
1174
- const LibraryCollectionInfo = Collection.pick({
1175
- id: true,
1176
- type: true,
1177
- is_remote_synced: true
1178
- }).strip();
1179
- function libraryResource(transport) {
1180
- /** Get the Library root and its child collections, or `null` on an instance that has none. */
1181
- async function get(options = {}) {
1182
- const result = await transport.requestParsed(LibraryOrAbsent, LIBRARY_ROOT_PATH, { ...options });
1183
- if (!("effective_children" in result)) return null;
1184
- const infoById = await libraryCollectionsById(options);
1185
- const effective_children = result.effective_children.map((child) => {
1186
- if (typeof child.id !== "number") return child;
1187
- const info = infoById.get(child.id);
1188
- if (info === void 0) return child;
1189
- return {
1190
- ...child,
1191
- type: info.type ?? child.type,
1192
- is_remote_synced: info.is_remote_synced ?? child.is_remote_synced
1193
- };
1194
- });
1195
- return {
1196
- ...result,
1197
- effective_children
1198
- };
1199
- }
1200
- async function libraryCollectionsById(options) {
1201
- const data = await listCollectionsWithLibrary(transport, LibraryCollectionInfo, options);
1202
- const byId = /* @__PURE__ */ new Map();
1203
- for (const collection of data) if (typeof collection.id === "number") byId.set(collection.id, collection);
1204
- return byId;
1205
- }
1206
- /**
1207
- * Create the Library subtree (its Data and Metrics collections). Metabase takes no body, rejects
1208
- * a second create with a 400, and answers the bare root collection without its
1209
- * `effective_children` — so an existing Library short-circuits the call and a fresh one comes
1210
- * back from a refetch, which together make this idempotent.
1211
- */
1212
- async function create(options = {}) {
1213
- const existing = await get(options);
1214
- if (existing !== null) return existing;
1215
- await transport.requestRaw(LIBRARY_ROOT_PATH, {
1216
- ...options,
1217
- method: "POST"
1218
- });
1219
- const created = await get(options);
1220
- if (created === null) throw new Error(`Library was not created after POST ${LIBRARY_ROOT_PATH}`);
1221
- return created;
1222
- }
1223
- /** The id of the Library's Data collection, creating the Library first when it does not exist. */
1224
- async function ensureDataCollectionId(options = {}) {
1225
- const data = (await create(options)).effective_children.find((child) => child.type === LIBRARY_DATA_TYPE);
1226
- if (data === void 0) throw new Error("Library has no Data collection to publish into");
1227
- if (typeof data.id !== "number") throw new Error(`Library Data collection has a non-numeric id ${String(data.id)}`);
1228
- return data.id;
1229
- }
1230
- /**
1231
- * Publish tables — and every upstream table they depend on — into a collection, so they lead the
1232
- * data pickers and rank up in search. Answers the collection they landed in.
1233
- */
1234
- async function publishTables(params, options = {}) {
1235
- return (await transport.requestParsed(PublishTablesResponse, PUBLISH_TABLES_PATH, {
1236
- ...options,
1237
- method: "POST",
1238
- body: params
1239
- })).target_collection;
1240
- }
1241
- /**
1242
- * Clear the Library collection from tables, and recursively from every downstream table that
1243
- * depends on them. The endpoint answers no JSON body.
1244
- */
1245
- async function unpublishTables(params, options = {}) {
1246
- await transport.requestRaw(UNPUBLISH_TABLES_PATH, {
1247
- ...options,
1248
- method: "POST",
1249
- body: params,
1250
- expectContentType: "binary"
1251
- });
1252
- }
1253
- return {
1254
- get,
1255
- create,
1256
- ensureDataCollectionId,
1257
- publishTables,
1258
- unpublishTables
1259
- };
1260
- }
1261
- //#endregion
1262
- //#region ../client/src/resources/measure.ts
1263
- const MeasureApiList = z.array(Measure);
1264
- function measureResource(transport) {
1265
- /** List measures. */
1266
- async function list(options = {}) {
1267
- return {
1268
- data: await transport.requestParsed(MeasureApiList, "/api/measure", { ...options }),
1269
- total: null
1270
- };
1271
- }
1272
- /** Get one measure by id. */
1273
- async function get(id, options = {}) {
1274
- return transport.requestParsed(Measure, `/api/measure/${id}`, { ...options });
1275
- }
1276
- /** Create a measure — a saved aggregation tied to a table — from a full measure body. */
1277
- async function create(params, options = {}) {
1278
- return transport.requestParsed(Measure, "/api/measure", {
1279
- ...options,
1280
- method: "POST",
1281
- body: params
1282
- });
1283
- }
1284
- /**
1285
- * Update a measure by id, patching only the fields the body carries. `revision_message` is
1286
- * required and lands in the audit log.
1287
- */
1288
- async function update(id, params, options = {}) {
1289
- return transport.requestParsed(Measure, `/api/measure/${id}`, {
1290
- ...options,
1291
- method: "PUT",
1292
- body: params
1293
- });
1294
- }
1295
- /**
1296
- * Archive (soft-delete) a measure by id. Metabase models this as an update, not its own endpoint,
1297
- * so it carries the same required `revision_message`.
1298
- */
1299
- async function archive(id, params, options = {}) {
1300
- return update(id, {
1301
- archived: true,
1302
- revision_message: params.revision_message
1303
- }, options);
1304
- }
1305
- return {
1306
- list,
1307
- get,
1308
- create,
1309
- update,
1310
- archive
1311
- };
1312
- }
1313
- //#endregion
1314
- //#region ../client/src/resources/notification.ts
1315
- const NotificationApiList = z.array(Notification);
1316
- function assertCardAlert(notification) {
1317
- if (notification.payload_type !== "notification/card") throw new ConfigError(`notification ${notification.id} is a ${notification.payload_type}, not a question alert — this operation accepts card alerts only`);
1318
- return notification;
1319
- }
1320
- function mergeAlertUpdate(current, patch) {
1321
- return Notification.parse({
1322
- ...current,
1323
- ...patch,
1324
- id: current.id,
1325
- payload: patch.payload === void 0 ? current.payload : mergePayload(current, patch.payload)
1326
- });
1327
- }
1328
- function mergePayload(current, patch) {
1329
- if (current.payload === null) throw new ConfigError(`alert ${current.id} has lost its card payload — it can be archived, but not patched`);
1330
- return NotificationCardPayload.parse({
1331
- ...current.payload,
1332
- ...patch
1333
- });
1334
- }
1335
- function notificationResource(transport) {
1336
- /**
1337
- * List question alerts, optionally narrowed by the card they watch, their creator, or a
1338
- * recipient. `/api/notification` also serves Metabase's internal system-event notifications, so
1339
- * the request pins the card payload type.
1340
- */
1341
- async function list(params = {}, options = {}) {
1342
- return {
1343
- data: await transport.requestParsed(NotificationApiList, "/api/notification", {
1344
- ...options,
1345
- query: {
1346
- payload_type: CARD_PAYLOAD_TYPE,
1347
- card_id: params.card_id,
1348
- creator_id: params.creator_id,
1349
- recipient_id: params.recipient_id,
1350
- include_inactive: params.include_inactive
1351
- }
1352
- }),
1353
- total: null
1354
- };
1355
- }
1356
- /** Get one question alert by id, refusing an id that names a system-event notification. */
1357
- async function get(id, options = {}) {
1358
- return assertCardAlert(await transport.requestParsed(Notification, `/api/notification/${id}`, { ...options }));
1359
- }
1360
- /** Create a question alert — its card payload, schedules and handlers — from a full body. */
1361
- async function create(params, options = {}) {
1362
- return transport.requestParsed(Notification, "/api/notification", {
1363
- ...options,
1364
- method: "POST",
1365
- body: params
1366
- });
1367
- }
1368
- /** Update a question alert by id, merging the patch over the stored notification. */
1369
- async function update(id, params, options = {}) {
1370
- const current = await get(id, options);
1371
- return transport.requestParsed(Notification, `/api/notification/${id}`, {
1372
- ...options,
1373
- method: "PUT",
1374
- body: mergeAlertUpdate(current, params)
1375
- });
1376
- }
1377
- /** Archive a question alert by id, stopping every delivery. Metabase models this as an update. */
1378
- async function archive(id, options = {}) {
1379
- return update(id, { active: false }, options);
1380
- }
1381
- /**
1382
- * Send a question alert now, off-schedule, to every handler on it. The server answers with no
1383
- * body.
1384
- */
1385
- async function send(id, options = {}) {
1386
- await get(id, options);
1387
- await transport.requestRaw(`/api/notification/${id}/send`, {
1388
- ...options,
1389
- method: "POST",
1390
- expectContentType: "binary"
1391
- });
1392
- }
1393
- return {
1394
- list,
1395
- get,
1396
- create,
1397
- update,
1398
- archive,
1399
- send
1400
- };
1401
- }
1402
- //#endregion
1403
- //#region ../client/src/resources/pulse.ts
1404
- const PulseApiList = z.array(Pulse);
1405
- function mergePulseUpdate(current, patch) {
1406
- return {
1407
- ...patch,
1408
- archived: patch.archived ?? current.archived,
1409
- skip_if_empty: patch.skip_if_empty ?? current.skip_if_empty
1410
- };
1411
- }
1412
- function pulseResource(transport) {
1413
- /** List dashboard subscriptions, optionally narrowed to one dashboard or to the archived ones. */
1414
- async function list(params = {}, options = {}) {
1415
- return {
1416
- data: await transport.requestParsed(PulseApiList, "/api/pulse", {
1417
- ...options,
1418
- query: {
1419
- dashboard_id: params.dashboard_id,
1420
- archived: params.archived
1421
- }
1422
- }),
1423
- total: null
1424
- };
1425
- }
1426
- /** Get one dashboard subscription by id. */
1427
- async function get(id, options = {}) {
1428
- return transport.requestParsed(Pulse, `/api/pulse/${id}`, { ...options });
1429
- }
1430
- /** Create a dashboard subscription — its cards and its delivery channels — from a full body. */
1431
- async function create(params, options = {}) {
1432
- return transport.requestParsed(Pulse, "/api/pulse", {
1433
- ...options,
1434
- method: "POST",
1435
- body: params
1436
- });
1437
- }
1438
- /** Update a dashboard subscription by id, carrying the server-defaulted flags forward. */
1439
- async function update(id, params, options = {}) {
1440
- const current = await get(id, options);
1441
- return transport.requestParsed(Pulse, `/api/pulse/${id}`, {
1442
- ...options,
1443
- method: "PUT",
1444
- body: mergePulseUpdate(current, params)
1445
- });
1446
- }
1447
- /**
1448
- * Archive a dashboard subscription by id, stopping every delivery. Metabase models this as an
1449
- * update, and disables each of the subscription's channels as a side effect.
1450
- */
1451
- async function archive(id, options = {}) {
1452
- return update(id, { archived: true }, options);
1453
- }
1454
- return {
1455
- list,
1456
- get,
1457
- create,
1458
- update,
1459
- archive
1460
- };
1461
- }
1462
- //#endregion
1463
- //#region ../client/src/resources/search.ts
1464
- const SearchApiResponse = z.object({
1465
- data: z.array(SearchResult),
1466
- total: z.number().int().nonnegative()
1467
- }).loose();
1468
- function searchResource(transport) {
1469
- /**
1470
- * Search over the instance's content, ranked against `q`. `models` narrows which kinds of entity
1471
- * may match, `archived` swaps the active set for the archived one, `table_db_id` restricts to
1472
- * items on one database, `verified` to verified content, and `limit`/`offset` are the window the
1473
- * server applies before ranking hydration.
1474
- */
1475
- async function query(params = {}, options = {}) {
1476
- const response = await transport.requestParsed(SearchApiResponse, "/api/search", {
1477
- ...options,
1478
- query: {
1479
- q: params.q,
1480
- models: params.models,
1481
- archived: params.archived,
1482
- limit: params.limit,
1483
- offset: params.offset,
1484
- table_db_id: params.table_db_id,
1485
- verified: params.verified
1486
- }
1487
- });
1488
- return {
1489
- data: response.data,
1490
- total: response.total
1491
- };
1492
- }
1493
- return { query };
1494
- }
1495
- //#endregion
1496
- //#region ../client/src/resources/segment.ts
1497
- const SegmentApiList = z.array(Segment);
1498
- function segmentResource(transport) {
1499
- /** List every segment the caller can see. */
1500
- async function list(options = {}) {
1501
- return {
1502
- data: await transport.requestParsed(SegmentApiList, "/api/segment", { ...options }),
1503
- total: null
1504
- };
1505
- }
1506
- /** Get one segment by id. */
1507
- async function get(id, options = {}) {
1508
- return transport.requestParsed(Segment, `/api/segment/${id}`, { ...options });
1509
- }
1510
- /** Create a segment — a reusable row filter over one table — from a full segment body. */
1511
- async function create(params, options = {}) {
1512
- return transport.requestParsed(Segment, "/api/segment", {
1513
- ...options,
1514
- method: "POST",
1515
- body: params
1516
- });
1517
- }
1518
- /**
1519
- * Update a segment by id, patching only the fields the body carries. `revision_message` is
1520
- * required: Metabase records every segment change in its revision history.
1521
- */
1522
- async function update(id, params, options = {}) {
1523
- return transport.requestParsed(Segment, `/api/segment/${id}`, {
1524
- ...options,
1525
- method: "PUT",
1526
- body: params
1527
- });
1528
- }
1529
- /**
1530
- * Archive (soft-delete) a segment by id. Metabase models this as an update, so it carries the
1531
- * same required `revision_message`.
1532
- */
1533
- async function archive(id, params, options = {}) {
1534
- return update(id, {
1535
- archived: true,
1536
- revision_message: params.revision_message
1537
- }, options);
1538
- }
1539
- return {
1540
- list,
1541
- get,
1542
- create,
1543
- update,
1544
- archive
1545
- };
1546
- }
1547
- //#endregion
1548
- //#region ../client/src/resources/setting.ts
1549
- const SettingApiList = z.array(Setting);
1550
- const UNKNOWN_SETTING_PREFIX = "Unknown setting:";
1551
- function rethrowSettingError(error, key) {
1552
- if (errorMessage(error).startsWith(UNKNOWN_SETTING_PREFIX)) throw new ConfigError(`unknown setting: ${key}`);
1553
- throw error;
1554
- }
1555
- function settingResource(transport) {
1556
- /** Get all settings and their values, with descriptions and environment-variable names. */
1557
- async function list(options = {}) {
1558
- return {
1559
- data: await transport.requestParsed(SettingApiList, "/api/setting", { ...options }),
1560
- total: null
1561
- };
1562
- }
1563
- /**
1564
- * Fetch a single setting's value by key. An unset setting answers 204 rather than 404, which
1565
- * reaches the caller as `null`; older servers answer the value as bare text rather than JSON.
1566
- */
1567
- async function get(key, options = {}) {
1568
- return fetchOptionalParsed(transport, `/api/setting/${encodeURIComponent(key)}`, z.unknown(), options).catch((error) => rethrowSettingError(error, key));
1569
- }
1570
- /** Set a single setting's value by key. The endpoint answers 204 with no body. */
1571
- async function set(key, value, options = {}) {
1572
- await transport.requestRaw(`/api/setting/${encodeURIComponent(key)}`, {
1573
- ...options,
1574
- method: "PUT",
1575
- body: { value },
1576
- expectContentType: "binary"
1577
- }).catch((error) => rethrowSettingError(error, key));
1578
- }
1579
- return {
1580
- list,
1581
- get,
1582
- set
1583
- };
1584
- }
1585
- //#endregion
1586
- //#region ../client/src/resources/setup.ts
1587
- function setupResource(transport) {
1588
- /**
1589
- * Complete the initial setup wizard on a fresh instance, creating its first admin user and
1590
- * applying the instance preferences. The setup token is single-use.
1591
- */
1592
- async function create(params, options = {}) {
1593
- return transport.requestParsed(SetupResult, "/api/setup", {
1594
- ...options,
1595
- method: "POST",
1596
- body: params
1597
- });
1598
- }
1599
- return { create };
1600
- }
1601
- //#endregion
1602
- //#region ../client/src/resources/snippet.ts
1603
- const SnippetApiList = z.array(Snippet);
1604
- function snippetResource(transport) {
1605
- /** List native query snippets. `archived` swaps the listing to archived snippets. */
1606
- async function list(params = {}, options = {}) {
1607
- return {
1608
- data: await transport.requestParsed(SnippetApiList, "/api/native-query-snippet", {
1609
- ...options,
1610
- query: { archived: params.archived }
1611
- }),
1612
- total: null
1613
- };
1614
- }
1615
- /** Get one native query snippet by id. */
1616
- async function get(id, options = {}) {
1617
- return transport.requestParsed(Snippet, `/api/native-query-snippet/${id}`, { ...options });
1618
- }
1619
- /** Create a native query snippet from a name, its SQL fragment, and an optional collection. */
1620
- async function create(params, options = {}) {
1621
- return transport.requestParsed(Snippet, "/api/native-query-snippet", {
1622
- ...options,
1623
- method: "POST",
1624
- body: params
1625
- });
1626
- }
1627
- /** Update a native query snippet by id, patching only the fields the body carries. */
1628
- async function update(id, params, options = {}) {
1629
- return transport.requestParsed(Snippet, `/api/native-query-snippet/${id}`, {
1630
- ...options,
1631
- method: "PUT",
1632
- body: params
1633
- });
1634
- }
1635
- /**
1636
- * Archive (soft-delete) a native query snippet by id. Metabase models this as an update, not its
1637
- * own endpoint.
1638
- */
1639
- async function archive(id, options = {}) {
1640
- return update(id, { archived: true }, options);
1641
- }
1642
- return {
1643
- list,
1644
- get,
1645
- create,
1646
- update,
1647
- archive
1648
- };
1649
- }
1650
- //#endregion
1651
- //#region ../client/src/resources/table.ts
1652
- const TableApiList = z.array(Table);
1653
- const UPLOAD_UPDATE_PATHS = {
1654
- append: "append-csv",
1655
- replace: "replace-csv"
1656
- };
1657
- function tableResource(transport) {
1658
- /** List every table the caller can see, across all databases. */
1659
- async function list(options = {}) {
1660
- return {
1661
- data: await transport.requestParsed(TableApiList, "/api/table", { ...options }),
1662
- total: null
1663
- };
1664
- }
1665
- /** Get one table by id, without its fields. */
1666
- async function get(id, options = {}) {
1667
- return transport.requestParsed(Table, `/api/table/${id}`, { ...options });
1668
- }
1669
- /** Update a table by id, patching only the fields the body carries. */
1670
- async function update(id, params, options = {}) {
1671
- return transport.requestParsed(Table, `/api/table/${id}`, {
1672
- ...options,
1673
- method: "PUT",
1674
- body: params
1675
- });
1676
- }
1677
- /** Get a table by id with its fields hydrated — the metadata the query builder runs on. */
1678
- async function queryMetadata(id, options = {}) {
1679
- return transport.requestParsed(TableQueryMetadata, `/api/table/${id}/query_metadata`, { ...options });
1680
- }
1681
- async function updateFromCsv(id, action, file, options) {
1682
- await transport.requestRaw(`/api/table/${id}/${UPLOAD_UPDATE_PATHS[action]}`, {
1683
- ...options,
1684
- method: "POST",
1685
- body: buildCsvFormData(file),
1686
- expectContentType: "binary"
1687
- });
1688
- return {
1689
- table_id: id,
1690
- action
1691
- };
1692
- }
1693
- /**
1694
- * Inserts the rows of an uploaded CSV file into the table identified by `id`. The table must have
1695
- * been created by uploading a CSV file.
1696
- *
1697
- * The file may be at most 50 MB; larger uploads are rejected with a 413 response.
1698
- */
1699
- async function appendCsv(id, file, options = {}) {
1700
- return updateFromCsv(id, "append", file, options);
1701
- }
1702
- /**
1703
- * Replaces the contents of the table identified by `id` with the rows of an uploaded CSV file.
1704
- * The table must have been created by uploading a CSV file.
1705
- *
1706
- * The file may be at most 50 MB; larger uploads are rejected with a 413 response.
1707
- */
1708
- async function replaceCsv(id, file, options = {}) {
1709
- return updateFromCsv(id, "replace", file, options);
1710
- }
1711
- return {
1712
- list,
1713
- get,
1714
- update,
1715
- queryMetadata,
1716
- appendCsv,
1717
- replaceCsv
1718
- };
1719
- }
1720
- //#endregion
1721
- //#region ../client/src/resources/timeline-event.ts
1722
- function timelineEventResource(transport) {
1723
- /** Get one timeline event by id. */
1724
- async function get(id, options = {}) {
1725
- return transport.requestParsed(TimelineEvent, `/api/timeline-event/${id}`, { ...options });
1726
- }
1727
- /** Create a timeline event on an existing timeline. */
1728
- async function create(params, options = {}) {
1729
- return transport.requestParsed(TimelineEvent, "/api/timeline-event", {
1730
- ...options,
1731
- method: "POST",
1732
- body: params
1733
- });
1734
- }
1735
- /**
1736
- * Update a timeline event by id, patching only the fields the body carries. `timeline_id` moves
1737
- * the event to another timeline.
1738
- */
1739
- async function update(id, params, options = {}) {
1740
- return transport.requestParsed(TimelineEvent, `/api/timeline-event/${id}`, {
1741
- ...options,
1742
- method: "PUT",
1743
- body: params
1744
- });
1745
- }
1746
- /**
1747
- * Archive (soft-delete) a timeline event by id. Metabase models this as an update, not its own
1748
- * endpoint.
1749
- */
1750
- async function archive(id, options = {}) {
1751
- return update(id, { archived: true }, options);
1752
- }
1753
- /** Permanently delete a timeline event by id. The server answers with no body. */
1754
- async function remove(id, options = {}) {
1755
- await transport.requestRaw(`/api/timeline-event/${id}`, {
1756
- ...options,
1757
- method: "DELETE",
1758
- expectContentType: "binary"
1759
- });
1760
- }
1761
- return {
1762
- get,
1763
- create,
1764
- update,
1765
- archive,
1766
- delete: remove
1767
- };
1768
- }
1769
- //#endregion
1770
- //#region ../client/src/resources/timeline.ts
1771
- const TimelineApiList = z.array(Timeline);
1772
- const TimelineWithEvents = Timeline.required({ events: true });
1773
- function timelineResource(transport) {
1774
- /** List timelines. `archived` swaps the active listing for the archived one. */
1775
- async function list(params = {}, options = {}) {
1776
- return {
1777
- data: await transport.requestParsed(TimelineApiList, "/api/timeline", {
1778
- ...options,
1779
- query: { archived: params.archived }
1780
- }),
1781
- total: null
1782
- };
1783
- }
1784
- /** Get one timeline by id, without its events. */
1785
- async function get(id, options = {}) {
1786
- return transport.requestParsed(Timeline, `/api/timeline/${id}`, { ...options });
1787
- }
1788
- /**
1789
- * List the events on one timeline. Metabase has no endpoint of its own for these: the same
1790
- * timeline read hydrates them on request, and `archived` chooses which of them come back.
1791
- */
1792
- async function events(id, params = {}, options = {}) {
1793
- return {
1794
- data: (await transport.requestParsed(TimelineWithEvents, `/api/timeline/${id}`, {
1795
- ...options,
1796
- query: {
1797
- include: "events",
1798
- archived: params.archived
1799
- }
1800
- })).events,
1801
- total: null
1802
- };
1803
- }
1804
- /** Create a timeline from a full timeline body. */
1805
- async function create(params, options = {}) {
1806
- return transport.requestParsed(Timeline, "/api/timeline", {
1807
- ...options,
1808
- method: "POST",
1809
- body: params
1810
- });
1811
- }
1812
- /**
1813
- * Update a timeline by id, patching only the fields the body carries. Changing `archived`
1814
- * cascades to every event on the timeline.
1815
- */
1816
- async function update(id, params, options = {}) {
1817
- return transport.requestParsed(Timeline, `/api/timeline/${id}`, {
1818
- ...options,
1819
- method: "PUT",
1820
- body: params
1821
- });
1822
- }
1823
- /**
1824
- * Archive (soft-delete) a timeline and all its events by id. Metabase models this as an update,
1825
- * not its own endpoint.
1826
- */
1827
- async function archive(id, options = {}) {
1828
- return update(id, { archived: true }, options);
1829
- }
1830
- /** Permanently delete a timeline and all its events by id. The server answers with no body. */
1831
- async function remove(id, options = {}) {
1832
- await transport.requestRaw(`/api/timeline/${id}`, {
1833
- ...options,
1834
- method: "DELETE",
1835
- expectContentType: "binary"
1836
- });
1837
- }
1838
- return {
1839
- list,
1840
- get,
1841
- events,
1842
- create,
1843
- update,
1844
- archive,
1845
- delete: remove
1846
- };
1847
- }
1848
- //#endregion
1849
- //#region ../client/src/resources/transform-job.ts
1850
- const TransformJobApiList = z.array(TransformJob);
1851
- const TransformApiList$1 = z.array(Transform);
1852
- function transformJobResource(transport) {
1853
- /** List every transform job the caller can see. */
1854
- async function list(options = {}) {
1855
- return {
1856
- data: await transport.requestParsed(TransformJobApiList, "/api/transform-job", { ...options }),
1857
- total: null
1858
- };
1859
- }
1860
- /** Get one transform job by id. */
1861
- async function get(id, options = {}) {
1862
- return transport.requestParsed(TransformJob, `/api/transform-job/${id}`, { ...options });
1863
- }
1864
- /** Create a transform job — a schedule plus the tags it runs — from a full body. */
1865
- async function create(params, options = {}) {
1866
- return transport.requestParsed(TransformJob, "/api/transform-job", {
1867
- ...options,
1868
- method: "POST",
1869
- body: params
1870
- });
1871
- }
1872
- /** Update a transform job by id, patching only the fields the body carries. */
1873
- async function update(id, params, options = {}) {
1874
- return transport.requestParsed(TransformJob, `/api/transform-job/${id}`, {
1875
- ...options,
1876
- method: "PUT",
1877
- body: params
1878
- });
1879
- }
1880
- /** Delete a transform job by id, leaving the transforms it ran untouched. */
1881
- async function remove(id, options = {}) {
1882
- await transport.requestRaw(`/api/transform-job/${id}`, {
1883
- ...options,
1884
- method: "DELETE",
1885
- expectContentType: "binary"
1886
- });
1887
- }
1888
- /**
1889
- * Start a run of a transform job by id. The job runs every transform carrying one of its tags,
1890
- * plus those transforms' dependencies; `run_all` re-runs dependencies that are already fresh.
1891
- */
1892
- async function run(id, params = {}, options = {}) {
1893
- return transport.requestParsed(TransformJobRunResult, `/api/transform-job/${id}/run`, {
1894
- ...options,
1895
- method: "POST",
1896
- body: { run_all: params.run_all }
1897
- });
1898
- }
1899
- /** List the transforms a job would execute, resolved from the job's tags. */
1900
- async function transforms(id, options = {}) {
1901
- return {
1902
- data: await transport.requestParsed(TransformApiList$1, `/api/transform-job/${id}/transforms`, { ...options }),
1903
- total: null
1904
- };
1905
- }
1906
- /**
1907
- * Flip the active flag on every transform job at once. Inactive jobs do not run on schedule;
1908
- * manual runs ignore the flag. The path carries no id and is a different endpoint from `update`.
1909
- */
1910
- async function setActive(active, options = {}) {
1911
- return transport.requestParsed(TransformJobActiveResult, "/api/transform-job/active", {
1912
- ...options,
1913
- method: "PUT",
1914
- body: { active }
1915
- });
1916
- }
1917
- return {
1918
- list,
1919
- get,
1920
- create,
1921
- update,
1922
- delete: remove,
1923
- run,
1924
- transforms,
1925
- setActive
1926
- };
1927
- }
1928
- //#endregion
1929
- //#region ../client/src/resources/transform.ts
1930
- const TransformApiList = z.array(Transform);
1931
- const TransformRunKickoff = z.object({
1932
- message: z.string(),
1933
- run_id: z.number().int().positive().nullable()
1934
- });
1935
- function transformResource(transport) {
1936
- /** List every transform the caller can see. */
1937
- async function list(options = {}) {
1938
- return {
1939
- data: await transport.requestParsed(TransformApiList, "/api/transform", { ...options }),
1940
- total: null
1941
- };
1942
- }
1943
- /** Get one transform by id. */
1944
- async function get(id, options = {}) {
1945
- return transport.requestParsed(Transform, `/api/transform/${id}`, { ...options });
1946
- }
1947
- /** Create a transform — a query plus the warehouse table it writes — from a full body. */
1948
- async function create(params, options = {}) {
1949
- return transport.requestParsed(Transform, "/api/transform", {
1950
- ...options,
1951
- method: "POST",
1952
- body: params
1953
- });
1954
- }
1955
- /** Update a transform by id, patching only the fields the body carries. */
1956
- async function update(id, params, options = {}) {
1957
- return transport.requestParsed(Transform, `/api/transform/${id}`, {
1958
- ...options,
1959
- method: "PUT",
1960
- body: params
1961
- });
1962
- }
1963
- /** Delete a transform by id, leaving any table it already materialized in place. */
1964
- async function remove(id, options = {}) {
1965
- await transport.requestRaw(`/api/transform/${id}`, {
1966
- ...options,
1967
- method: "DELETE",
1968
- expectContentType: "binary"
1969
- });
1970
- }
1971
- /** Drop a transform's materialized output table, keeping the transform definition. */
1972
- async function deleteTable(id, options = {}) {
1973
- await transport.requestRaw(`/api/transform/${id}/table`, {
1974
- ...options,
1975
- method: "DELETE",
1976
- expectContentType: "binary"
1977
- });
1978
- }
1979
- /** List the upstream transforms a transform depends on. */
1980
- async function dependencies(id, options = {}) {
1981
- return {
1982
- data: await transport.requestParsed(TransformApiList, `/api/transform/${id}/dependencies`, { ...options }),
1983
- total: null
1984
- };
1985
- }
1986
- /** Request cancellation of a transform's current run. */
1987
- async function cancel(id, options = {}) {
1988
- await transport.requestRaw(`/api/transform/${id}/cancel`, {
1989
- ...options,
1990
- method: "POST",
1991
- expectContentType: "binary"
1992
- });
1993
- }
1994
- /** Get one transform run by run id — not by the id of the transform that produced it. */
1995
- async function getRun(runId, options = {}) {
1996
- return transport.requestParsed(TransformRun, `/api/transform/run/${runId}`, { ...options });
1997
- }
1998
- /** Walk the run history, newest first, optionally narrowed to a single transform. */
1999
- function runPages(params = {}, options = {}) {
2000
- return paginatePages(transport, "/api/transform/run", TransformRun, {
2001
- query: { "transform-ids": params["transform-ids"] },
2002
- ...options.offset !== void 0 && { offset: options.offset },
2003
- ...options.max !== void 0 && { max: options.max },
2004
- ...options.pageSize !== void 0 && { pageSize: options.pageSize },
2005
- ...options.signal !== void 0 && { signal: options.signal }
2006
- });
2007
- }
2008
- /**
2009
- * Start a run of a transform by id. The server queues the run and answers at once; `wait` polls
2010
- * it to a terminal status, and `syncTarget` follows that with the output table's registration.
2011
- * A server that answers no run id started nothing, and there is then nothing to poll.
2012
- */
2013
- async function run(id, params = {}, options = {}) {
2014
- const kickoff = await transport.requestParsed(TransformRunKickoff, `/api/transform/${id}/run`, {
2015
- ...options,
2016
- method: "POST"
2017
- });
2018
- const schedule = params.syncTarget === true ? params.wait ?? {} : params.wait;
2019
- if (schedule === void 0 || kickoff.run_id === null) return {
2020
- message: kickoff.message,
2021
- run_id: kickoff.run_id,
2022
- final: null
2023
- };
2024
- const runId = kickoff.run_id;
2025
- const final = await pollUntil(async (signal) => getRun(runId, {
2026
- ...options,
2027
- signal
2028
- }), (candidate) => isTransformRunTerminal(candidate.status), schedule);
2029
- if (params.syncTarget !== true) return {
2030
- message: kickoff.message,
2031
- run_id: runId,
2032
- final
2033
- };
2034
- const targetTableId = isTransformRunFailed(final.status) ? null : await awaitTargetTableId(id, schedule, options);
2035
- return {
2036
- message: kickoff.message,
2037
- run_id: runId,
2038
- final,
2039
- target_table_id: targetTableId
2040
- };
2041
- }
2042
- async function awaitTargetTableId(id, wait, options) {
2043
- try {
2044
- return linkedTableId(await pollUntil(async (signal) => get(id, {
2045
- ...options,
2046
- signal
2047
- }), (transform) => linkedTableId(transform) !== null, wait));
2048
- } catch (error) {
2049
- if (error instanceof TimeoutError) return null;
2050
- throw error;
2051
- }
2052
- }
2053
- return {
2054
- list,
2055
- get,
2056
- create,
2057
- update,
2058
- delete: remove,
2059
- deleteTable,
2060
- dependencies,
2061
- cancel,
2062
- getRun,
2063
- runPages,
2064
- run
2065
- };
2066
- }
2067
- function linkedTableId(transform) {
2068
- return transform.target_table_id ?? transform.table?.id ?? null;
2069
- }
2070
- //#endregion
2071
- //#region ../client/src/resources/transform-tag.ts
2072
- const TransformTagApiList = z.array(TransformTag);
2073
- function transformTagResource(transport) {
2074
- /** List every transform tag the caller can see, built-in tags included. */
2075
- async function list(options = {}) {
2076
- return {
2077
- data: await transport.requestParsed(TransformTagApiList, "/api/transform-tag", { ...options }),
2078
- total: null
2079
- };
2080
- }
2081
- /** Create a transform tag, the label a transform job matches transforms on. */
2082
- async function create(params, options = {}) {
2083
- return transport.requestParsed(TransformTag, "/api/transform-tag", {
2084
- ...options,
2085
- method: "POST",
2086
- body: params
2087
- });
2088
- }
2089
- /** Rename a transform tag by id. */
2090
- async function update(id, params, options = {}) {
2091
- return transport.requestParsed(TransformTag, `/api/transform-tag/${id}`, {
2092
- ...options,
2093
- method: "PUT",
2094
- body: params
2095
- });
2096
- }
2097
- /** Delete a transform tag by id, detaching it from every transform and job carrying it. */
2098
- async function remove(id, options = {}) {
2099
- await transport.requestRaw(`/api/transform-tag/${id}`, {
2100
- ...options,
2101
- method: "DELETE",
2102
- expectContentType: "binary"
2103
- });
2104
- }
2105
- return {
2106
- list,
2107
- create,
2108
- update,
2109
- delete: remove
2110
- };
2111
- }
2112
- //#endregion
2113
- //#region ../client/src/resources/upload.ts
2114
- const UPLOAD_TABLE_ID_HEADER = "metabase-table-id";
2115
- function uploadResource(transport) {
2116
- /**
2117
- * Create a table and model populated with the values from the attached CSV. Returns the model ID
2118
- * if successful.
2119
- *
2120
- * The file may be at most 50 MB; larger uploads are rejected with a 413 response.
2121
- */
2122
- async function createFromCsv(file, params, options = {}) {
2123
- const form = buildCsvFormData(file);
2124
- form.append("collection_id", params.collection_id);
2125
- const response = await transport.requestRaw("/api/upload/csv", {
2126
- ...options,
2127
- method: "POST",
2128
- body: form,
2129
- expectContentType: "binary"
2130
- });
2131
- return parseCreateUploadResult(await response.text(), response.headers);
2132
- }
2133
- return { createFromCsv };
2134
- }
2135
- function parseCreateUploadResult(bodyText, headers) {
2136
- return UploadResult.parse({
2137
- model_id: parseResponseInteger(bodyText, "response body"),
2138
- table_id: parseResponseInteger(headers.get(UPLOAD_TABLE_ID_HEADER), `${UPLOAD_TABLE_ID_HEADER} header`)
2139
- });
2140
- }
2141
- function parseResponseInteger(value, source) {
2142
- const trimmed = value?.trim() ?? "";
2143
- if (trimmed === "") throw new ResponseShapeError(`upload succeeded but the ${source} was empty`, {
2144
- kind: "decoded",
2145
- source,
2146
- value
2147
- });
2148
- const parsed = Number(trimmed);
2149
- if (!Number.isInteger(parsed)) throw new ResponseShapeError(`upload succeeded but the ${source} was not an integer: ${JSON.stringify(trimmed)}`, {
2150
- kind: "decoded",
2151
- source,
2152
- value
2153
- });
2154
- return parsed;
2155
- }
2156
- //#endregion
2157
- //#region ../client/src/domain/user.ts
2158
- const CurrentUser = z.object({
2159
- id: z.number().int(),
2160
- email: z.email(),
2161
- common_name: z.string(),
2162
- is_superuser: z.boolean()
2163
- }).loose();
2164
- CurrentUser.pick({
2165
- id: true,
2166
- email: true,
2167
- common_name: true,
2168
- is_superuser: true
2169
- }).strip();
2170
- //#endregion
2171
- //#region ../client/src/resources/user.ts
2172
- function userResource(transport) {
2173
- /** Get the user the request's credentials authenticate as. */
2174
- async function current(options = {}) {
2175
- return transport.requestParsed(CurrentUser, "/api/user/current", { ...options });
2176
- }
2177
- return { current };
2178
- }
2179
- //#endregion
2180
- //#region ../client/src/client.ts
2181
- var client_exports = /* @__PURE__ */ __exportAll({ createClient: () => createClient });
2182
- function createClient(config, options) {
2183
- const transport = createTransport(config, options);
2184
- return {
2185
- card: cardResource(transport),
2186
- collection: collectionResource(transport),
2187
- contentTranslation: contentTranslationResource(transport),
2188
- dashboard: dashboardResource(transport),
2189
- database: databaseResource(transport),
2190
- dataset: datasetResource(transport),
2191
- document: documentResource(transport),
2192
- eidTranslation: eidTranslationResource(transport),
2193
- field: fieldResource(transport),
2194
- gitSync: gitSyncResource(transport),
2195
- library: libraryResource(transport),
2196
- measure: measureResource(transport),
2197
- notification: notificationResource(transport),
2198
- pulse: pulseResource(transport),
2199
- search: searchResource(transport),
2200
- segment: segmentResource(transport),
2201
- setting: settingResource(transport),
2202
- setup: setupResource(transport),
2203
- snippet: snippetResource(transport),
2204
- table: tableResource(transport),
2205
- timeline: timelineResource(transport),
2206
- timelineEvent: timelineEventResource(transport),
2207
- transform: transformResource(transport),
2208
- transformJob: transformJobResource(transport),
2209
- transformTag: transformTagResource(transport),
2210
- upload: uploadResource(transport),
2211
- user: userResource(transport),
2212
- requestParsed: transport.requestParsed,
2213
- requestRaw: transport.requestRaw,
2214
- requestStream: transport.requestStream
2215
- };
2216
- }
2217
- //#endregion
2218
- export { createClient as n, client_exports as t };