@metabase/cli 0.3.1-alpha.transform-tests.3fbcf8b → 0.3.1-alpha.transform-tests.d9ed765

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 (266) hide show
  1. package/dist/{add-collection-C-XJPp3F.mjs → add-collection-v_uw_8VC.mjs} +6 -9
  2. package/dist/{alert-Klz8Bhst.mjs → alert-2MDhiuxT.mjs} +7 -7
  3. package/dist/{alerts-Bp2vByJf.mjs → alerts-BDoIryWj.mjs} +7 -7
  4. package/dist/{append-D16_s1HW.mjs → append-CeHVEN3m.mjs} +5 -5
  5. package/dist/{archive-RzzXt2V0.mjs → archive-B9DiDia8.mjs} +6 -6
  6. package/dist/{archive-nDvHMzTv.mjs → archive-BMQBzQMw.mjs} +4 -4
  7. package/dist/{archive-C9iNjXcI.mjs → archive-BU3VZ1An.mjs} +5 -5
  8. package/dist/{archive-CA-HIfQq.mjs → archive-BopUoNoz.mjs} +4 -4
  9. package/dist/{archive-BOJUGwyL.mjs → archive-BuHy5_kr.mjs} +4 -4
  10. package/dist/{archive-Q_qUuYh8.mjs → archive-CVTpSQ0H.mjs} +6 -6
  11. package/dist/{archive-Dd7ZTibw.mjs → archive-CYaJZhBs.mjs} +4 -4
  12. package/dist/{archive-vzu8ghZZ.mjs → archive-CxzoUCE_.mjs} +6 -6
  13. package/dist/{archive-D4nGMs8A.mjs → archive-D5QNFMmn.mjs} +4 -4
  14. package/dist/{archive-Bj4MjbJY.mjs → archive-IBEbIm_S2.mjs} +6 -6
  15. package/dist/{archive-lDnTIypd.mjs → archive-M2_D7zAj.mjs} +6 -6
  16. package/dist/{auth-kyPQfiND.mjs → auth-DuGPC1Q0.mjs} +5 -5
  17. package/dist/{body-DxRSAMNC.mjs → body-hAwPMqBg.mjs} +3 -3
  18. package/dist/{branches-QixvzIpl.mjs → branches-CIP60haa.mjs} +4 -7
  19. package/dist/{cancel-CPStS4zJ.mjs → cancel-C9hrQ1yg.mjs} +4 -4
  20. package/dist/{cancel-task--cuSISnl.mjs → cancel-task-BeviniVd.mjs} +5 -8
  21. package/dist/{card-zyUkr2nS.mjs → card-CEkp1mcI.mjs} +1 -1
  22. package/dist/card-DqPrL79i.mjs +24 -0
  23. package/dist/{card-DZxRmver.mjs → card-voh1k4hl.mjs} +14 -11
  24. package/dist/{cards-CNbV8aGO.mjs → cards-CvWT-tKQ.mjs} +7 -7
  25. package/dist/cli.mjs +567 -70
  26. package/dist/client-yPhazV6T.mjs +4093 -0
  27. package/dist/collection-BsXk1V41.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-C5SNf6Yw.mjs} +2 -2
  31. package/dist/{content-translation-CxTabpLF.mjs → content-translation-BNYQ8fJ3.mjs} +3 -3
  32. package/dist/{create-CEP4Jsrd.mjs → create-BVd4Y4py2.mjs} +6 -6
  33. package/dist/{create-ku05K1Oj.mjs → create-BZyLtvg5.mjs} +6 -6
  34. package/dist/{create-UxWtLwXT.mjs → create-BsiUuwSb.mjs} +5 -5
  35. package/dist/{create-WIIp7MVV.mjs → create-C1fVgFBd.mjs} +4 -4
  36. package/dist/{create-M8qXs24L.mjs → create-C4U9DGDG.mjs} +7 -7
  37. package/dist/{create-BTvSwLws.mjs → create-CHn7P-Bz.mjs} +5 -5
  38. package/dist/{create-BikaTHCw.mjs → create-CL4xkZ4j.mjs} +6 -6
  39. package/dist/{create-CYhsYOOJ.mjs → create-CcOTodqT.mjs} +4 -4
  40. package/dist/{create-BGV7ejai.mjs → create-Cmgq35ZB.mjs} +4 -4
  41. package/dist/{create-U15wd8_9.mjs → create-DPb3b69Y.mjs} +4 -4
  42. package/dist/{create-DMLjSEkF.mjs → create-DRyA-nuP.mjs} +5 -5
  43. package/dist/{create-CtDaASGO.mjs → create-DTfaHMNw.mjs} +6 -6
  44. package/dist/{create-BGy4L_yh.mjs → create-Db3QVXRi.mjs} +7 -7
  45. package/dist/{create-BsvpUxJq.mjs → create-DqKDw2zq.mjs} +5 -8
  46. package/dist/{create-CsABLrSI.mjs → create-S0jXAtl2.mjs} +11 -7
  47. package/dist/{create-BMokmmLp2.mjs → create-Z_gzD_p-2.mjs} +8 -8
  48. package/dist/{create-branch-Bkq9rtf7.mjs → create-branch-hYwnfY8X.mjs} +5 -9
  49. package/dist/{csv-GincCch9.mjs → csv-DOEqRG95.mjs} +5 -5
  50. package/dist/{current-task-CbnNWQ7H.mjs → current-task-DVo5aDfA.mjs} +5 -8
  51. package/dist/{dashboard-CKUR8ZpQ.mjs → dashboard-D0hwTC-f.mjs} +11 -2
  52. package/dist/{dashboard-ReNaou5J.mjs → dashboard-D8Yjjwfr.mjs} +10 -10
  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-2hSYsqHk.mjs → db-ntq1NYVT.mjs} +7 -7
  57. package/dist/{delete-Bv3_SIqh.mjs → delete-BQWk6Ogb.mjs} +5 -5
  58. package/dist/{delete-CZqleA9Q.mjs → delete-C2iVm203.mjs} +5 -5
  59. package/dist/{delete-C1YmyeVy.mjs → delete-CPzdQGKf.mjs} +5 -5
  60. package/dist/{delete-DNsY94Ok.mjs → delete-CW8xJwDm.mjs} +5 -5
  61. package/dist/{delete-BEPw7WRT.mjs → delete-CZqaDxkf.mjs} +5 -5
  62. package/dist/{delete-B2wmUpj_.mjs → delete-Qsf-OKkl.mjs} +5 -5
  63. package/dist/{delete-runtime-D74s6vhu.mjs → delete-runtime-BKEzJn22.mjs} +1 -2
  64. package/dist/{delete-table-DySwoEaq.mjs → delete-table-DLufNvzW.mjs} +5 -5
  65. package/dist/{dependencies-ygT6uMu4.mjs → dependencies-BGtd-eIR.mjs} +7 -7
  66. package/dist/{dirty-BkiHZ8gb.mjs → dirty-BiiJ5Ngh.mjs} +6 -9
  67. package/dist/{document-Cd2mmqCp.mjs → document-BHpLJbKU.mjs} +5 -0
  68. package/dist/document-BiS-U56S.mjs +19 -0
  69. package/dist/{document-D6OybtP2.mjs → document-CA0Q6lqu.mjs} +1 -1
  70. package/dist/{download-Chr-YNTG.mjs → download-DrcL0yRr.mjs} +3 -6
  71. package/dist/{eid-BvY-YGpN.mjs → eid-Bn3Impnq.mjs} +4 -5
  72. package/dist/{events-B01P0G7C.mjs → events-CfnrXbim.mjs} +5 -5
  73. package/dist/{export-CG23iezf.mjs → export-CFK8cMvK.mjs} +7 -10
  74. package/dist/{field-Cr2DPUG9.mjs → field-CcN4oZy6.mjs} +16 -1
  75. package/dist/{field-DikmNcAt.mjs → field-CeP-41qf.mjs} +5 -5
  76. package/dist/{field-BPsNa-TO.mjs → field-fDtIrY6D.mjs} +1 -1
  77. package/dist/{fields-C9BF3jHL.mjs → fields-B3tJI4X2.mjs} +7 -7
  78. package/dist/{get-B3jvGI0b.mjs → get-3ymehUjQ.mjs} +6 -6
  79. package/dist/{get-gFM8-HHP.mjs → get-B9fPTBEQ.mjs} +5 -8
  80. package/dist/{get-PKhv8WUf.mjs → get-BFh5ctuV.mjs} +6 -6
  81. package/dist/{get-N5EUCDL0.mjs → get-BMZ3UoJz.mjs} +6 -6
  82. package/dist/{get-DZpRq_Fw.mjs → get-Be9oShms.mjs} +4 -4
  83. package/dist/{get-DvqYIBp5.mjs → get-BkTiIo_7.mjs} +4 -4
  84. package/dist/{get-Blbcl76m.mjs → get-C-E-I10i.mjs} +6 -6
  85. package/dist/{get-FJofgEPB.mjs → get-CIlXE4zy.mjs} +6 -6
  86. package/dist/{get-UW0DOjH5.mjs → get-Cqfb4zZM.mjs} +4 -4
  87. package/dist/{get-BtauixMx.mjs → get-Cxvi9pSj.mjs} +6 -6
  88. package/dist/{get-Buxkx-RX.mjs → get-D2Bt3r3M.mjs} +4 -4
  89. package/dist/{get-DdSB-fpR.mjs → get-DJDV3NMU.mjs} +5 -5
  90. package/dist/{get-DY-e5oP7.mjs → get-D_f0INnl.mjs} +6 -6
  91. package/dist/{get-BHpVRSbm.mjs → get-Diozf-D0.mjs} +6 -6
  92. package/dist/{get-C1V7vZse.mjs → get-Dl9WoeCd.mjs} +4 -4
  93. package/dist/{get-C99cjjD0.mjs → get-DlPhNHPX.mjs} +6 -6
  94. package/dist/{get-BYSFFlsd.mjs → get-DnVGJfW42.mjs} +6 -6
  95. package/dist/get-Dx4k6_Qt.mjs +93 -0
  96. package/dist/{get-CkMLxzVy.mjs → get-lRUl1Dnb.mjs} +4 -4
  97. package/dist/{get-CMMXBVff.mjs → get-pGqPQ0Of.mjs} +6 -6
  98. package/dist/{get-run-F7ARJeAD.mjs → get-run-DmtNpSbG.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-jvNlPu2I.mjs +28 -0
  102. package/dist/{group-DBM87IgC.mjs → group-YQQ5GIcP.mjs} +2 -2
  103. package/dist/{has-remote-changes-Bwyp8mc-.mjs → has-remote-changes-BS6jOb2-.mjs} +5 -8
  104. package/dist/{import-CPY8aM8d.mjs → import-Cur2I6Yc.mjs} +7 -10
  105. package/dist/{input-DH9i67x_.mjs → input-DEvkIjGr.mjs} +1 -1
  106. package/dist/{is-dirty-0F_UJY7Q.mjs → is-dirty-7Jo0tglq.mjs} +3 -6
  107. package/dist/{items-FUop0zGR.mjs → items-BBJSvqWt.mjs} +7 -7
  108. package/dist/{key-BEhqIzIQ.mjs → key-PYetuQ13.mjs} +1 -1
  109. package/dist/library-BPIzb3K_.mjs +81 -0
  110. package/dist/{library-DpOtb0E0.mjs → library-CpDosMc5.mjs} +5 -5
  111. package/dist/{library-DfYAT2Ep.mjs → library-PGCfm0UA.mjs} +1 -1
  112. package/dist/{list-B-74c1BD.mjs → list--Frwwg4i.mjs} +7 -7
  113. package/dist/{list-BASNYNJr.mjs → list-40V_8T3H.mjs} +4 -4
  114. package/dist/{list-xC99-2X0.mjs → list-BAO7rPNU.mjs} +4 -4
  115. package/dist/{list--B2EUWJg.mjs → list-BAaBsdMk.mjs} +6 -6
  116. package/dist/{list-rQ-6XSua.mjs → list-BCD9lkxc.mjs} +4 -4
  117. package/dist/{list-BQaXU1bp.mjs → list-BuZaFlV-.mjs} +4 -4
  118. package/dist/{list-Beoh2AYD.mjs → list-C7kqJAc8.mjs} +4 -4
  119. package/dist/{list-CGkgypYz.mjs → list-CBGsfTib.mjs} +7 -7
  120. package/dist/{list-Uc1OxV36.mjs → list-CFJyXUsF.mjs} +14 -13
  121. package/dist/{list-DfbsmsHv.mjs → list-CQJoLqy0.mjs} +7 -7
  122. package/dist/{list-DdFViPYS.mjs → list-CVs3TyU7.mjs} +6 -6
  123. package/dist/{list-DMlFbccD.mjs → list-CX2668xz.mjs} +6 -6
  124. package/dist/{list-ba7lI44w.mjs → list-CcyZu5Jp.mjs} +6 -6
  125. package/dist/{list-C2qxVTu7.mjs → list-DPvJihmj.mjs} +7 -7
  126. package/dist/{list-BQrk4Ua4.mjs → list-D_Kv8Ezq.mjs} +7 -7
  127. package/dist/{list-GyP4b_tU.mjs → list-DuZlYCTl.mjs} +5 -5
  128. package/dist/{list-Bqm0F1Y-.mjs → list-_6JwpPXA.mjs} +6 -6
  129. package/dist/{list-lzIKVtE9.mjs → list-bCtszwHJ.mjs} +4 -4
  130. package/dist/list-rojRNBu5.mjs +60 -0
  131. package/dist/{login-D5jt0q9K.mjs → login-BCxYB6ii.mjs} +15 -12
  132. package/dist/{logout-DViy0VzV.mjs → logout-BVEYg9pV.mjs} +3 -4
  133. package/dist/{measure-IPlonpqU.mjs → measure-DYmGuTVW.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-CHyOCxmR.mjs → parameter-values-D4qte8qc.mjs} +5 -6
  137. package/dist/{parse-enum-D0Jfm_Bz.mjs → parse-enum-Dc0dMZ3P.mjs} +1 -1
  138. package/dist/{parse-id-CPINxy7h.mjs → parse-id-BSdAXN-r.mjs} +1 -1
  139. package/dist/{parse-ref-ibKVB0J4.mjs → parse-ref-DTDld_LJ.mjs} +1 -1
  140. package/dist/{path-bMZzUOVo.mjs → path-BNZf4ETt.mjs} +5 -5
  141. package/dist/{poll-75SvT7Zv.mjs → poll-CZeXepUQ.mjs} +2 -2
  142. package/dist/{preflight-CoF1Em99.mjs → preflight-BsT-Ik4Z.mjs} +3 -4
  143. package/dist/{process-DBOOrmET.mjs → process-CTrfxxaC.mjs} +1 -1
  144. package/dist/{publish-Cs-OUG6n.mjs → publish-3Qlrs4CC.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-CEdmSEq8.mjs → query-B8MCziCM.mjs} +9 -10
  148. package/dist/{query-CpD46hL6.mjs → query-DxjE4Hq2.mjs} +10 -12
  149. package/dist/{query-result-DBDwk8TS.mjs → query-result-E4Q-Gra6.mjs} +1 -1
  150. package/dist/{remove-collection-DynsqkwG.mjs → remove-collection-CNWmp8C-.mjs} +6 -9
  151. package/dist/{render-CI93iP0I.mjs → render-MoT089RO.mjs} +13 -2
  152. package/dist/{replace-C6YqqCG9.mjs → replace-DOmUXCyk.mjs} +5 -5
  153. package/dist/{rescan-values-C6PB02uT.mjs → rescan-values-DpU_Ex0F.mjs} +6 -6
  154. package/dist/{run-C7PXBBEl.mjs → run-B8Vys-6V.mjs} +5 -5
  155. package/dist/{run-Cb86sH_c.mjs → run-CCPUWI0V.mjs} +6 -6
  156. package/dist/{run-CpmWoOGp.mjs → run-cyUFpMX3.mjs} +26 -14
  157. package/dist/{runs-CCRszsbB.mjs → runs-92XSK8ij.mjs} +7 -7
  158. package/dist/{runtime-BMJv4VOi.mjs → runtime-DzVkvFHY.mjs} +946 -246
  159. package/dist/{schema-tables-BQdFNy1B.mjs → schema-tables-lMGk2fyi.mjs} +7 -7
  160. package/dist/{schemas-CNAPFh4n.mjs → schemas-C83Q8dYY.mjs} +5 -5
  161. package/dist/{search-DFBwUc6d.mjs → search-BAXg-EJw.mjs} +2 -1
  162. package/dist/{search-BKVV6YtB.mjs → search-D6qBaNsw.mjs} +6 -6
  163. package/dist/{segment-CDoZHSYX.mjs → segment-BFJd2-ck.mjs} +6 -6
  164. package/dist/{selectors-BXbjj36S.mjs → selectors-Dcp25rNo.mjs} +3 -3
  165. package/dist/{send-D2eXL9lt.mjs → send-Be-_KmWr.mjs} +4 -4
  166. package/dist/{set-sHBtSGLi.mjs → set-Bg_4elCb.mjs} +5 -5
  167. package/dist/{set-active-DT61WwV0.mjs → set-active-CtQiMzt7.mjs} +5 -5
  168. package/dist/{setting-dkfKvCxc.mjs → setting-BNEblMco.mjs} +4 -4
  169. package/dist/{setup-TOwWatgm.mjs → setup-DFnxwJGX.mjs} +4 -4
  170. package/dist/{signal-CMd0EFUa.mjs → signal-k7cm5N6h.mjs} +11 -2
  171. package/dist/skill-list-Ro6J0pyV.mjs +76 -0
  172. package/dist/skills-BdrMrbXh.mjs +351 -0
  173. package/dist/{skills-BcOjZldN.mjs → skills-CGYk6b2r.mjs} +3 -3
  174. package/dist/snippet-vMnFtNwi.mjs +19 -0
  175. package/dist/{stash-BgWw2lyu.mjs → stash-C9SZwusp.mjs} +7 -11
  176. package/dist/{status-B14FO8n7.mjs → status-D0n7AuQU.mjs} +12 -11
  177. package/dist/{status-J4pEIm-c.mjs → status-Dj04FCCv.mjs} +11 -9
  178. package/dist/{subscription-B1uuKxM7.mjs → subscription-B5Iax7Ci.mjs} +6 -6
  179. package/dist/{subscriptions-BHIATSN6.mjs → subscriptions-DwvHRO1v.mjs} +7 -7
  180. package/dist/{summary-B1V5TXaZ.mjs → summary-DaA6Twxk.mjs} +6 -6
  181. package/dist/{sync-schema-D1vX-rpv.mjs → sync-schema-BFWKEC3r.mjs} +7 -7
  182. package/dist/{sync-task-BACcrs0i.mjs → sync-task-BXeWuARG.mjs} +1 -1
  183. package/dist/{table-CsIJNPFf.mjs → table-C6h4tIRw.mjs} +1 -1
  184. package/dist/{table-CDeO1WbH.mjs → table-DW1dG3Rl.mjs} +5 -5
  185. package/dist/{table-CeeTJgQb.mjs → table-DfuY0N8e.mjs} +51 -4
  186. package/dist/timeline-C0rqHF4p.mjs +21 -0
  187. package/dist/{timeline-event-oGmne082.mjs → timeline-event-D1MUnexK.mjs} +6 -6
  188. package/dist/{transform-DoTyyXAu.mjs → transform-CtqB1WYo.mjs} +2 -2
  189. package/dist/transform-D08iA4H_.mjs +28 -0
  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-DRrK28IH.mjs → transform-job-CCguL6LP.mjs} +41 -4
  193. package/dist/transform-job-Me5CeV2z.mjs +22 -0
  194. package/dist/{transform-tag-Bpj8l5Ci.mjs → transform-tag-CbgjSy76.mjs} +5 -5
  195. package/dist/{transform-test-BJOPAwKl.mjs → transform-test-B-gVzODx.mjs} +1 -1
  196. package/dist/transform-test-BB_IFtZS.mjs +163 -0
  197. package/dist/transform-test-CwonhnyQ.mjs +16 -0
  198. package/dist/{transforms-K7Y4ON_q.mjs → transforms-Bhtk_Gil.mjs} +7 -7
  199. package/dist/{tree-CtFtroe4.mjs → tree-DLorrdEm.mjs} +4 -5
  200. package/dist/{unpublish-D7UaaIWA.mjs → unpublish-DOQhmLAx.mjs} +4 -7
  201. package/dist/{update-BvbPpgOL.mjs → update-BF4DWRT5.mjs} +6 -6
  202. package/dist/{update-dRAPKE3c.mjs → update-BeU02D8b.mjs} +6 -6
  203. package/dist/{update-C_wTtrtX.mjs → update-Bpb2V8Gm.mjs} +9 -9
  204. package/dist/{update-DUNJEk8m.mjs → update-CHNSRFKO.mjs} +7 -7
  205. package/dist/{update-BpuZsX9z.mjs → update-CSqPKfTk.mjs} +8 -8
  206. package/dist/{update-bix8NoKq.mjs → update-CTCcgeaY.mjs} +7 -7
  207. package/dist/{update-BlBEKrNE.mjs → update-Ch43eYU-.mjs} +5 -5
  208. package/dist/{update-MWaDj2VX.mjs → update-D2dis8s_.mjs} +8 -8
  209. package/dist/{update-YkB3xWUh.mjs → update-DEULsCgK.mjs} +6 -6
  210. package/dist/{update-B7veBLhx.mjs → update-DTZ07XFM.mjs} +5 -5
  211. package/dist/{update-CGJXd_E3.mjs → update-DWhC3xYc.mjs} +5 -5
  212. package/dist/{update-HqUKBeM2.mjs → update-DeA4gyTG.mjs} +5 -5
  213. package/dist/{update-BicO3Lio.mjs → update-Dq-KEeyS.mjs} +7 -7
  214. package/dist/{update-dashcard-BGqKMqQb.mjs → update-dashcard-CfDqxOlj.mjs} +7 -7
  215. package/dist/{update-3ksm443P.mjs → update-ezD5XTpy.mjs} +7 -7
  216. package/dist/{update-e4ufwrkF.mjs → update-mmeImeUo.mjs} +7 -7
  217. package/dist/{update-D9Nfv864.mjs → update-xjuN7bdu.mjs} +7 -7
  218. package/dist/{upgrade-DkQ1wk4z.mjs → upgrade-DgmbeOoJ.mjs} +6 -8
  219. package/dist/upload-BsPrAjN-.mjs +13 -0
  220. package/dist/{upload-CD555ui1.mjs → upload-Do2PBSeH.mjs} +2 -2
  221. package/dist/{upload-BfGc-L4t.mjs → upload-DzFBdNxM.mjs} +4 -7
  222. package/dist/{uuid-BLBLkWAF.mjs → uuid-DYYGRv9y.mjs} +3 -4
  223. package/dist/{validate-BWchyW0V.mjs → validate-EAB-1EkK.mjs} +1 -1
  224. package/dist/{validate-query-DaGYSmpQ.mjs → validate-query-CQG86147.mjs} +2 -3
  225. package/dist/{values-8CrXBkyg.mjs → values-Dk2CAR4T.mjs} +6 -6
  226. package/dist/{verify-nNVN-0CR.mjs → verify-8TnYrSNm.mjs} +3 -18
  227. package/dist/{wait-YrD7UYFF.mjs → wait-Oz6xFpyA.mjs} +7 -10
  228. package/dist/{wait-flags-CDtMS8FP.mjs → wait-flags-ClJx9LJ9.mjs} +2 -2
  229. package/dist/{window-BkvrP0gB.mjs → window-DSb1tqSe.mjs} +1 -1
  230. package/package.json +1 -1
  231. package/skill-data/core/SKILL.md +29 -13
  232. package/skill-data/data-workflow/references/building-clean-tables.md +6 -2
  233. package/skill-data/data-workflow/references/reusable-definitions.md +11 -3
  234. package/skill-data/document/SKILL.md +4 -1
  235. package/skill-data/git-sync/SKILL.md +5 -0
  236. package/skill-data/mbql/SKILL.md +1 -1
  237. package/skill-data/mbql/references/operators.md +20 -15
  238. package/skill-data/metadata/SKILL.md +1 -1
  239. package/skill-data/metadata/references/semantic-types.md +7 -1
  240. package/skill-data/native-sql/references/template-tags.md +6 -2
  241. package/skill-data/notification/SKILL.md +7 -1
  242. package/skill-data/transform/SKILL.md +25 -7
  243. package/skill-data/transform-test-plan/SKILL.md +171 -0
  244. package/skill-data/transform-test-plan/references/checklist.md +81 -0
  245. package/skill-data/transform-test-plan/references/checks.md +259 -0
  246. package/skill-data/visualization/SKILL.md +11 -3
  247. package/skill-data/visualization/references/settings.md +6 -4
  248. package/skills/metabase-cli/SKILL.md +1 -1
  249. package/dist/card-p2r_szeS.mjs +0 -24
  250. package/dist/client-DynvZqa0.mjs +0 -2282
  251. package/dist/collection-CAM47Der.mjs +0 -20
  252. package/dist/document-DGbDloCb.mjs +0 -19
  253. package/dist/get-B4GltkXP.mjs +0 -80
  254. package/dist/git-sync-IW4T2sKq.mjs +0 -28
  255. package/dist/library-ClLgrAXy.mjs +0 -19
  256. package/dist/list-CvzWE6CS.mjs +0 -98
  257. package/dist/network-error-D6CiOEBw.mjs +0 -431
  258. package/dist/predicates-Bkm2IoeX.mjs +0 -170
  259. package/dist/skills-DTCrMcix.mjs +0 -216
  260. package/dist/snippet-DMdFqvNq.mjs +0 -19
  261. package/dist/timeline-MQFX3Fla.mjs +0 -21
  262. package/dist/transform-CWIqW64R.mjs +0 -28
  263. package/dist/transform-job-DpF2MARE.mjs +0 -22
  264. package/dist/transform-test-BhkpwFqD.mjs +0 -16
  265. package/dist/transform-test-Dhcj7u-U.mjs +0 -142
  266. package/dist/upload-JN6EK96c.mjs +0 -13
@@ -1,2282 +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 { i as TransformTestRunResult, t as TransformTest } from "./transform-test-Dhcj7u-U.mjs";
30
- import { t as UploadResult } from "./upload-DAtxBBms.mjs";
31
- import { z } from "zod";
32
- import { setTimeout } from "node:timers/promises";
33
- //#region \0rolldown/runtime.js
34
- var __defProp = Object.defineProperty;
35
- var __exportAll = (all, no_symbols) => {
36
- let target = {};
37
- for (var name in all) __defProp(target, name, {
38
- get: all[name],
39
- enumerable: true
40
- });
41
- if (!no_symbols) __defProp(target, Symbol.toStringTag, { value: "Module" });
42
- return target;
43
- };
44
- //#endregion
45
- //#region ../client/src/http/response-shape.ts
46
- const NO_SERVER_TAG = async () => null;
47
- async function parseJsonResponse(text, schema, context) {
48
- try {
49
- return parseJson(text, schema, { source: context.url });
50
- } catch (error) {
51
- if (error instanceof ValidationError) throw ResponseShapeError.fromZodIssues({
52
- kind: "zod",
53
- method: context.method,
54
- url: context.url,
55
- status: context.status,
56
- zodIssues: error.developerDetail.zodIssues,
57
- serverTag: await context.getServerTag()
58
- });
59
- throw error;
60
- }
61
- }
62
- //#endregion
63
- //#region ../client/src/http/retry.ts
64
- const BASE_DELAY_MS = 250;
65
- const MAX_DELAY_MS = 8e3;
66
- const MS_PER_SECOND = 1e3;
67
- function backoffDelay({ attempt, retryAfterHeader }) {
68
- const fromHeader = parseRetryAfter(retryAfterHeader);
69
- if (fromHeader !== null) return fromHeader;
70
- return Math.min(MAX_DELAY_MS, BASE_DELAY_MS * 2 ** attempt);
71
- }
72
- function parseRetryAfter(header) {
73
- if (!header) return null;
74
- const numeric = Number(header);
75
- if (Number.isFinite(numeric) && numeric >= 0) return Math.round(numeric * MS_PER_SECOND);
76
- const dateMs = Date.parse(header);
77
- if (Number.isFinite(dateMs)) return Math.max(0, dateMs - Date.now());
78
- return null;
79
- }
80
- function sleep(ms, signal) {
81
- return setTimeout(ms, void 0, { signal });
82
- }
83
- async function runWithRetries(attempt, signal) {
84
- let attemptIndex = 0;
85
- while (true) {
86
- const outcome = await attempt(attemptIndex);
87
- if (outcome.kind === "success") return outcome.response;
88
- await sleep(outcome.delayMs, signal);
89
- attemptIndex += 1;
90
- }
91
- }
92
- //#endregion
93
- //#region ../client/src/http/transport.ts
94
- const UNAUTHORIZED_STATUS = 401;
95
- const DEFAULT_TIMEOUT_MS = 3e4;
96
- const OCTET_STREAM_CONTENT_TYPE = "application/octet-stream";
97
- const TEXT_CONTENT_TYPE_PREFIX = "text/";
98
- const ERROR_BODY_BYTE_CAP = 64 * 1024;
99
- const IDEMPOTENT_METHODS = /* @__PURE__ */ new Set([
100
- "GET",
101
- "HEAD",
102
- "OPTIONS"
103
- ]);
104
- function createTransport(config, options) {
105
- const baseUrl = normalizeUrl(config.url);
106
- assertCredentialHeaderSafe(config.credential);
107
- const fetchImpl = options.fetchImpl ?? globalThis.fetch.bind(globalThis);
108
- const getServerTag = options.getServerTag ?? NO_SERVER_TAG;
109
- const refreshCredential = options.refreshCredential;
110
- let credential = config.credential;
111
- const knownSecrets = new Set(credentialSecrets(credential));
112
- const redactionContext = { knownSecrets };
113
- let refreshInFlight = null;
114
- function tryRefreshCredential() {
115
- const refresh = refreshCredential;
116
- if (credential.kind !== "oauth" || refresh === void 0) return Promise.resolve(false);
117
- refreshInFlight ??= refreshOnce(refresh).finally(() => {
118
- refreshInFlight = null;
119
- });
120
- return refreshInFlight;
121
- }
122
- async function refreshOnce(refresh) {
123
- const next = await refresh();
124
- if (next === null) return false;
125
- credential = next;
126
- for (const secret of credentialSecrets(next)) knownSecrets.add(secret);
127
- return true;
128
- }
129
- async function attemptOnce(prepared, attempt) {
130
- const hasRetriesLeft = attempt < prepared.retries;
131
- const timeoutSignal = AbortSignal.timeout(prepared.timeoutMs);
132
- const combined = combineAborts(timeoutSignal, prepared.cancelSignal);
133
- let response;
134
- try {
135
- response = await fetchImpl(prepared.url, {
136
- method: prepared.method,
137
- headers: prepared.headers,
138
- body: prepared.body,
139
- signal: combined
140
- });
141
- } catch (error) {
142
- throwIfAborted(prepared.cancelSignal);
143
- const isStaleSocketFirstTry = attempt === 0 && isConnectionClosed(error);
144
- if (prepared.idempotent && (hasRetriesLeft || isStaleSocketFirstTry)) return {
145
- kind: "retry",
146
- delayMs: backoffDelay({ attempt })
147
- };
148
- if (timeoutSignal.aborted) throw new TimeoutError(`Request timed out after ${prepared.timeoutMs}ms`, {
149
- kind: "http",
150
- method: prepared.method,
151
- url: prepared.url,
152
- timeoutMs: prepared.timeoutMs
153
- });
154
- throw buildNetworkError(error, prepared.method, prepared.url);
155
- }
156
- const canRetryStatus = hasRetriesLeft && prepared.idempotent;
157
- if (!response.ok && isRetryableStatus(response.status) && canRetryStatus) {
158
- const retryAfter = response.headers.get("Retry-After");
159
- response.body?.cancel().catch(() => void 0);
160
- return {
161
- kind: "retry",
162
- delayMs: backoffDelay({
163
- attempt,
164
- retryAfterHeader: retryAfter
165
- })
166
- };
167
- }
168
- if (!response.ok) {
169
- const rawBody = await readBodyForError(response);
170
- const serverTag = await getServerTag();
171
- throw new HttpError({
172
- status: response.status,
173
- statusText: response.statusText,
174
- method: prepared.method,
175
- url: prepared.url,
176
- responseHeaders: response.headers,
177
- rawBody,
178
- serverTag,
179
- redactionContext
180
- });
181
- }
182
- assertContentType(response, prepared);
183
- return {
184
- kind: "success",
185
- response
186
- };
187
- }
188
- async function executeRaw(prepared) {
189
- try {
190
- return await runWithRetries((attempt) => attemptOnce(prepared, attempt), prepared.cancelSignal);
191
- } catch (error) {
192
- throwIfAborted(prepared.cancelSignal);
193
- throw error;
194
- }
195
- }
196
- async function executeWithAuthRefresh(path, opts) {
197
- const prepared = prepare(path, opts);
198
- try {
199
- return {
200
- response: await executeRaw(prepared),
201
- prepared
202
- };
203
- } catch (error) {
204
- if (error instanceof HttpError && error.status === UNAUTHORIZED_STATUS) {
205
- if (await tryRefreshCredential()) {
206
- const retried = prepare(path, opts);
207
- return {
208
- response: await executeRaw(retried),
209
- prepared: retried
210
- };
211
- }
212
- }
213
- throw error;
214
- }
215
- }
216
- function prepare(path, opts = {}) {
217
- const method = opts.method ?? "GET";
218
- const expectContentType = opts.expectContentType ?? "json";
219
- const url = buildUrl(baseUrl, path, opts.query);
220
- const headers = new Headers();
221
- const auth = credentialAuthHeader(credential);
222
- headers.set(auth.name, auth.value);
223
- headers.set("accept", acceptHeader(expectContentType));
224
- headers.set("user-agent", options.userAgent);
225
- let body = null;
226
- if (opts.body !== void 0 && opts.body !== null) if (typeof opts.body === "string" || opts.body instanceof URLSearchParams) body = opts.body;
227
- else if (opts.body instanceof FormData || opts.body instanceof ReadableStream) body = opts.body;
228
- else if (opts.body instanceof Uint8Array) {
229
- body = opts.body;
230
- headers.set("content-type", OCTET_STREAM_CONTENT_TYPE);
231
- } else {
232
- body = JSON.stringify(opts.body);
233
- headers.set("content-type", JSON_CONTENT_TYPE);
234
- }
235
- return {
236
- url,
237
- method,
238
- headers,
239
- body,
240
- expectContentType,
241
- retries: opts.retries ?? 3,
242
- idempotent: opts.idempotent ?? IDEMPOTENT_METHODS.has(method),
243
- timeoutMs: opts.timeoutMs ?? DEFAULT_TIMEOUT_MS,
244
- cancelSignal: combineAborts(opts.signal, options.signal)
245
- };
246
- }
247
- return {
248
- async requestRaw(path, opts) {
249
- return (await executeWithAuthRefresh(path, opts ?? {})).response;
250
- },
251
- async requestParsed(schema, path, opts) {
252
- const { response, prepared } = await executeWithAuthRefresh(path, {
253
- ...opts,
254
- expectContentType: "json"
255
- });
256
- return parseJsonResponse(await response.text(), schema, {
257
- method: prepared.method,
258
- url: prepared.url,
259
- status: response.status,
260
- getServerTag
261
- });
262
- },
263
- async requestStream(path, opts) {
264
- const { response, prepared } = await executeWithAuthRefresh(path, {
265
- ...opts,
266
- expectContentType: opts?.expectContentType ?? "binary"
267
- });
268
- if (!response.body) throw new NetworkError("Response had no body to stream", {
269
- method: prepared.method,
270
- url: prepared.url,
271
- cause: "missing body"
272
- });
273
- return response.body;
274
- }
275
- };
276
- }
277
- function buildUrl(baseUrl, path, query) {
278
- const normalizedPath = path.startsWith("/") ? path : `/${path}`;
279
- const target = new URL(baseUrl + normalizedPath);
280
- if (query) for (const [key, value] of Object.entries(query)) {
281
- if (value === void 0) continue;
282
- if (Array.isArray(value)) for (const entry of value) target.searchParams.append(key, String(entry));
283
- else target.searchParams.append(key, String(value));
284
- }
285
- return target.toString();
286
- }
287
- function acceptHeader(expected) {
288
- if (expected === "json") return JSON_CONTENT_TYPE;
289
- if (expected === "text") return "text/*";
290
- return "*/*";
291
- }
292
- function assertContentType(response, prepared) {
293
- if (prepared.expectContentType === "binary") return;
294
- const contentType = response.headers.get("content-type");
295
- if (contentType === null) throwContentTypeMismatch(response, prepared, prepared.expectContentType);
296
- if (prepared.expectContentType === "json" && !contentType.includes("application/json")) throwContentTypeMismatch(response, prepared, "json");
297
- if (prepared.expectContentType === "text" && !contentType.startsWith(TEXT_CONTENT_TYPE_PREFIX)) throwContentTypeMismatch(response, prepared, "text");
298
- }
299
- function throwContentTypeMismatch(response, prepared, expected) {
300
- const actual = response.headers.get("content-type") ?? "no content-type";
301
- throw new HttpError({
302
- status: response.status,
303
- statusText: response.statusText,
304
- method: prepared.method,
305
- url: prepared.url,
306
- responseHeaders: response.headers,
307
- rawBody: null,
308
- overrideUserMessage: `Expected ${expected} response but got ${actual}`
309
- });
310
- }
311
- async function readBodyForError(response) {
312
- try {
313
- return Buffer.from(await response.arrayBuffer()).subarray(0, ERROR_BODY_BYTE_CAP).toString("utf8");
314
- } catch (error) {
315
- return `[body read failed: ${errorMessage(error)}]`;
316
- }
317
- }
318
- //#endregion
319
- //#region ../client/src/resources/card.ts
320
- const CardApiList = z.array(Card);
321
- function cardResource(transport) {
322
- /** List cards. `f` picks a server-side preset; `model_id` scopes the presets that need an id. */
323
- async function list(params = {}, options = {}) {
324
- return {
325
- data: await transport.requestParsed(CardApiList, "/api/card", {
326
- ...options,
327
- query: {
328
- f: params.f,
329
- model_id: params.model_id
330
- }
331
- }),
332
- total: null
333
- };
334
- }
335
- /** Get one card by id. */
336
- async function get(id, options = {}) {
337
- return transport.requestParsed(Card, `/api/card/${id}`, { ...options });
338
- }
339
- /** Create a card — a question, a model, or a metric — from a full card body. */
340
- async function create(params, options = {}) {
341
- return transport.requestParsed(Card, "/api/card", {
342
- ...options,
343
- method: "POST",
344
- body: params
345
- });
346
- }
347
- /** Update a card by id, patching only the fields the body carries. */
348
- async function update(id, params, options = {}) {
349
- return transport.requestParsed(Card, `/api/card/${id}`, {
350
- ...options,
351
- method: "PUT",
352
- body: params
353
- });
354
- }
355
- /** Archive (soft-delete) a card by id. Metabase models this as an update, not its own endpoint. */
356
- async function archive(id, options = {}) {
357
- return update(id, { archived: true }, options);
358
- }
359
- /** Run a saved card and return the query result envelope. */
360
- async function query(id, params, options = {}) {
361
- return transport.requestParsed(CardQueryResult, `/api/card/${id}/query`, {
362
- ...options,
363
- method: "POST",
364
- body: { parameters: params.parameters }
365
- });
366
- }
367
- /**
368
- * Run a saved card and stream its result as a download. Unlike `query`, this endpoint takes a
369
- * form-encoded body and answers bytes, so a caller consumes the stream rather than a value.
370
- */
371
- async function exportQuery(id, format, params, options = {}) {
372
- const body = new URLSearchParams({
373
- parameters: JSON.stringify(params.parameters),
374
- format_rows: String(params.format_rows),
375
- pivot_results: String(params.pivot_results)
376
- });
377
- return transport.requestStream(`/api/card/${id}/query/${format}`, {
378
- ...options,
379
- method: "POST",
380
- body
381
- });
382
- }
383
- return {
384
- list,
385
- get,
386
- create,
387
- update,
388
- archive,
389
- query,
390
- exportQuery
391
- };
392
- }
393
- async function* paginatePages(client, path, itemSchema, opts = {}) {
394
- const envelopeSchema = paginatedEnvelopeSchema(itemSchema);
395
- const pageSize = opts.pageSize ?? 50;
396
- if (!Number.isInteger(pageSize) || pageSize < 1) throw new InternalError(`pageSize must be an integer of at least 1, got ${pageSize}`);
397
- const start = opts.offset ?? 0;
398
- const max = opts.max ?? Number.POSITIVE_INFINITY;
399
- let taken = 0;
400
- let previousHead = null;
401
- while (taken < max) {
402
- const remaining = max - taken;
403
- const limit = Math.min(pageSize, remaining);
404
- const offset = start + taken;
405
- const envelope = await client.requestParsed(envelopeSchema, path, {
406
- query: {
407
- ...opts.query,
408
- limit,
409
- offset
410
- },
411
- ...opts.signal !== void 0 && { signal: opts.signal }
412
- });
413
- const items = envelope.data.length > remaining ? envelope.data.slice(0, remaining) : envelope.data;
414
- const total = envelope.total ?? null;
415
- const head = items.length === 0 ? null : JSON.stringify(items[0]);
416
- 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`);
417
- previousHead = head;
418
- yield {
419
- items,
420
- total
421
- };
422
- if (items.length === 0) return;
423
- const consumed = taken + items.length;
424
- if (total !== null && start + consumed === total) return;
425
- taken = consumed;
426
- }
427
- }
428
- function paginatedEnvelopeSchema(itemSchema) {
429
- return z.object({
430
- data: z.array(itemSchema),
431
- total: z.number().int().nonnegative().nullable().optional(),
432
- limit: z.number().int().nonnegative().optional(),
433
- offset: z.number().int().nonnegative().optional()
434
- }).loose();
435
- }
436
- //#endregion
437
- //#region ../client/src/resources/collection.ts
438
- const CollectionApiList = z.array(Collection);
439
- const CollectionTreeApiList = z.array(CollectionTreeNode);
440
- const COLLECTION_LIST_QUERY = {
441
- all: {},
442
- archived: { archived: true },
443
- personal: { "personal-only": true }
444
- };
445
- const DEFAULT_LIST_FILTER = "all";
446
- function refPath(ref) {
447
- return encodeURIComponent(ref);
448
- }
449
- /**
450
- * List collections including the Library and its children, parsing each through the caller's own
451
- * projection. `Collection` pins `type`, `namespace` and `authority_level` to closed enums, so a
452
- * consumer reading a few fields off every collection on the instance narrows here: one collection
453
- * carrying a server value outside those sets then costs nothing to a caller that never reads the
454
- * field.
455
- */
456
- async function listCollectionsWithLibrary(transport, schema, options = {}) {
457
- return transport.requestParsed(z.array(schema), "/api/collection", {
458
- ...options,
459
- query: { "include-library": true }
460
- });
461
- }
462
- function collectionResource(transport) {
463
- /** List collections. `filter` picks a server-side preset: everything, archived, or personal. */
464
- async function list(params = {}, options = {}) {
465
- return {
466
- data: await transport.requestParsed(CollectionApiList, "/api/collection", {
467
- ...options,
468
- query: COLLECTION_LIST_QUERY[params.filter ?? DEFAULT_LIST_FILTER]
469
- }),
470
- total: null
471
- };
472
- }
473
- /**
474
- * List collections including the Library and its children, which the plain listing omits.
475
- * The Library's own children carry neither `type` nor `is_remote_synced`, so this is where a
476
- * caller resolves both.
477
- */
478
- async function listWithLibrary(options = {}) {
479
- return {
480
- data: await listCollectionsWithLibrary(transport, Collection, options),
481
- total: null
482
- };
483
- }
484
- /** Get one collection by id, entity id, or the `root`/`trash` alias. */
485
- async function get(ref, options = {}) {
486
- return transport.requestParsed(Collection, `/api/collection/${refPath(ref)}`, { ...options });
487
- }
488
- /** Create a new collection. */
489
- async function create(params, options = {}) {
490
- return transport.requestParsed(Collection, "/api/collection", {
491
- ...options,
492
- method: "POST",
493
- body: params
494
- });
495
- }
496
- /** Update a collection, patching only the fields the body carries. */
497
- async function update(ref, params, options = {}) {
498
- return transport.requestParsed(Collection, `/api/collection/${refPath(ref)}`, {
499
- ...options,
500
- method: "PUT",
501
- body: params
502
- });
503
- }
504
- /** Archive (soft-delete) a collection. Metabase models this as an update, not its own endpoint. */
505
- async function archive(ref, options = {}) {
506
- return update(ref, { archived: true }, options);
507
- }
508
- /**
509
- * Walk the items inside a collection one page at a time. This endpoint pages on the server, so
510
- * the caller consumes pages rather than a single list and decides how far to pull.
511
- */
512
- function itemPages(ref, params = {}, options = {}) {
513
- return paginatePages(transport, `/api/collection/${refPath(ref)}/items`, CollectionItem, {
514
- query: {
515
- models: params.models,
516
- archived: params.archived,
517
- pinned_state: params.pinned_state
518
- },
519
- ...options.offset !== void 0 && { offset: options.offset },
520
- ...options.max !== void 0 && { max: options.max },
521
- ...options.pageSize !== void 0 && { pageSize: options.pageSize },
522
- ...options.signal !== void 0 && { signal: options.signal }
523
- });
524
- }
525
- /** Fetch the collection hierarchy as a forest of nested nodes. */
526
- async function tree(options = {}) {
527
- return {
528
- data: await transport.requestParsed(CollectionTreeApiList, "/api/collection/tree", { ...options }),
529
- total: null
530
- };
531
- }
532
- return {
533
- list,
534
- listWithLibrary,
535
- get,
536
- create,
537
- update,
538
- archive,
539
- itemPages,
540
- tree
541
- };
542
- }
543
- //#endregion
544
- //#region ../client/src/resources/csv-upload.ts
545
- const CSV_CONTENT_TYPE = "text/csv";
546
- function buildCsvFormData(file) {
547
- const form = new FormData();
548
- form.append("file", new Blob([file.bytes], { type: CSV_CONTENT_TYPE }), file.filename);
549
- return form;
550
- }
551
- //#endregion
552
- //#region ../client/src/resources/content-translation.ts
553
- const CONTENT_TRANSLATION_PATH = "/api/ee/content-translation";
554
- function contentTranslationResource(transport) {
555
- /** Download the complete content translation dictionary as CSV. */
556
- async function download(options = {}) {
557
- return transport.requestStream(`${CONTENT_TRANSLATION_PATH}/csv`, options);
558
- }
559
- /** Replace the complete content translation dictionary with the attached CSV. */
560
- async function upload(file, options = {}) {
561
- const form = buildCsvFormData(file);
562
- return transport.requestParsed(ContentTranslationUploadResult, `${CONTENT_TRANSLATION_PATH}/upload-dictionary`, {
563
- ...options,
564
- method: "POST",
565
- body: form
566
- });
567
- }
568
- return {
569
- download,
570
- upload
571
- };
572
- }
573
- //#endregion
574
- //#region ../client/src/resources/dashboard.ts
575
- const DashboardApiList = z.array(Dashboard);
576
- const PreflightDashcard = z.looseObject({ card_id: z.number().int().nullable().optional() });
577
- function dashboardResource(transport) {
578
- const card = cardResource(transport);
579
- /** List dashboards. `f` picks a server-side preset. */
580
- async function list(params = {}, options = {}) {
581
- return {
582
- data: await transport.requestParsed(DashboardApiList, "/api/dashboard", {
583
- ...options,
584
- query: { f: params.f }
585
- }),
586
- total: null
587
- };
588
- }
589
- /** Get one dashboard by id, with its dashcards, tabs and parameters. */
590
- async function get(id, options = {}) {
591
- return transport.requestParsed(DashboardDetail, `/api/dashboard/${id}`, { ...options });
592
- }
593
- /**
594
- * Create a dashboard. The endpoint accepts no dashcards or tabs — a follow-up `update` is what
595
- * puts content on a fresh dashboard.
596
- */
597
- async function create(params, options = {}) {
598
- return transport.requestParsed(Dashboard, "/api/dashboard", {
599
- ...options,
600
- method: "POST",
601
- body: params
602
- });
603
- }
604
- /**
605
- * Update a dashboard by id, patching only the fields the body carries. `dashcards` and `tabs` are
606
- * full replacements: whatever the body omits is deleted from the dashboard.
607
- */
608
- async function update(id, params, options = {}) {
609
- return transport.requestParsed(DashboardDetail, `/api/dashboard/${id}`, {
610
- ...options,
611
- method: "PUT",
612
- body: params
613
- });
614
- }
615
- /**
616
- * Archive (soft-delete) a dashboard by id. Metabase models this as an update, not its own
617
- * endpoint. The answer is read as `Dashboard` rather than the `DashboardDetail` `update` returns:
618
- * an archive is a state change on the dashboard itself, and its dashcards are not part of it.
619
- */
620
- async function archive(id, options = {}) {
621
- return transport.requestParsed(Dashboard, `/api/dashboard/${id}`, {
622
- ...options,
623
- method: "PUT",
624
- body: { archived: true }
625
- });
626
- }
627
- /**
628
- * Patch one dashcard on a dashboard. Metabase exposes no dashcard endpoint and its dashboard PUT
629
- * is a full replace of `dashcards`, so the patch is read-modify-written over the dashboard as it
630
- * currently stands.
631
- */
632
- async function updateDashcard(dashboardId, dashcardId, params, options = {}) {
633
- const dashboard = await get(dashboardId, options);
634
- const target = dashboard.dashcards.find((dashcard) => dashcard.id === dashcardId);
635
- if (target === void 0) throw new ConfigError(`dashcard ${dashcardId} not found on dashboard ${dashboardId}`);
636
- const patched = Dashcard.parse({
637
- ...target,
638
- ...params
639
- });
640
- const refreshed = (await update(dashboardId, { dashcards: dashboard.dashcards.map((dashcard) => stripEntityId(dashcard.id === dashcardId ? patched : dashcard)) }, options)).dashcards.find((dashcard) => dashcard.id === dashcardId);
641
- if (refreshed === void 0) throw new Error(`PUT /api/dashboard/${dashboardId}: dashcard ${dashcardId} missing from response`);
642
- return refreshed;
643
- }
644
- /**
645
- * Check every card a `dashcards` body references before writing it, through `GET /api/card/{id}`
646
- * once per distinct id. Reports one issue per reference whose card is missing, archived, or
647
- * unreadable, so an empty result means the body is safe to send; an id the server answers for in
648
- * any other way propagates as the failure it was.
649
- */
650
- async function checkCardReferences(dashcards, options = {}) {
651
- const grouped = groupByCardId(collectCardReferences(dashcards));
652
- return (await Promise.all(Array.from(grouped.entries()).map(async ([cardId, references]) => ({
653
- references,
654
- problem: await inspectCard(cardId, options)
655
- })))).flatMap((check) => {
656
- const problem = check.problem;
657
- if (problem === null) return [];
658
- return check.references.map((reference) => ({
659
- ...reference,
660
- problem
661
- }));
662
- });
663
- }
664
- async function inspectCard(cardId, options) {
665
- try {
666
- return (await card.get(cardId, options)).archived ? { reason: "archived" } : null;
667
- } catch (error) {
668
- if (!(error instanceof HttpError)) throw error;
669
- if (error.kind === "resource-missing") return { reason: "missing" };
670
- if (error.kind === "auth") return {
671
- reason: "unreadable",
672
- detail: error.userMessage
673
- };
674
- throw error;
675
- }
676
- }
677
- /**
678
- * Fetch the selectable values for a dashboard parameter, through the chain-filter value endpoint.
679
- */
680
- async function parameterValues(dashboardId, parameterId, options = {}) {
681
- return transport.requestParsed(ParameterValues, `/api/dashboard/${dashboardId}/params/${encodeURIComponent(parameterId)}/values`, { ...options });
682
- }
683
- /**
684
- * Search a dashboard parameter's selectable values: the server returns only values containing the
685
- * substring, capped at the first 1000 matches.
686
- */
687
- async function searchParameterValues(dashboardId, parameterId, query, options = {}) {
688
- const parameter = encodeURIComponent(parameterId);
689
- return transport.requestParsed(ParameterValues, `/api/dashboard/${dashboardId}/params/${parameter}/search/${encodeURIComponent(query)}`, { ...options });
690
- }
691
- return {
692
- list,
693
- get,
694
- create,
695
- update,
696
- archive,
697
- updateDashcard,
698
- checkCardReferences,
699
- parameterValues,
700
- searchParameterValues
701
- };
702
- }
703
- function collectCardReferences(dashcards) {
704
- if (dashcards === void 0 || dashcards === null) return [];
705
- const references = [];
706
- dashcards.forEach((dashcard, index) => {
707
- const parsed = PreflightDashcard.safeParse(dashcard);
708
- if (!parsed.success) return;
709
- const cardId = parsed.data.card_id;
710
- if (typeof cardId === "number" && cardId > 0) references.push({
711
- cardId,
712
- path: `/dashcards/${index}/card_id`
713
- });
714
- });
715
- return references;
716
- }
717
- function groupByCardId(references) {
718
- const grouped = /* @__PURE__ */ new Map();
719
- for (const reference of references) {
720
- const existing = grouped.get(reference.cardId);
721
- if (existing === void 0) grouped.set(reference.cardId, [reference]);
722
- else existing.push(reference);
723
- }
724
- return grouped;
725
- }
726
- function stripEntityId(dashcard) {
727
- const { entity_id: _entity_id, id, size_x, size_y, row, col, ...rest } = dashcard;
728
- return {
729
- ...rest,
730
- id,
731
- size_x,
732
- size_y,
733
- row,
734
- col
735
- };
736
- }
737
- //#endregion
738
- //#region ../client/src/resources/database.ts
739
- const DatabaseApiList = z.object({
740
- data: z.array(Database),
741
- total: z.number().int().nonnegative()
742
- }).loose();
743
- const DatabaseTaskAck = z.object({ status: z.literal("ok") });
744
- const DatabaseApiSchemaList = z.array(z.string());
745
- const DatabaseApiSchemaTableList = z.array(Table);
746
- const SYNC_COMPLETE = "complete";
747
- function databaseResource(transport) {
748
- /** List databases. `include` hydrates each database's tables; `saved` adds the Saved Questions virtual database. */
749
- async function list(params = {}, options = {}) {
750
- const response = await transport.requestParsed(DatabaseApiList, "/api/database", {
751
- ...options,
752
- query: {
753
- include: params.include,
754
- saved: params.saved
755
- }
756
- });
757
- return {
758
- data: response.data,
759
- total: response.total
760
- };
761
- }
762
- /** Get one database by id. `include` hydrates its tables, and `tables.fields` their fields too. */
763
- async function get(id, params = {}, options = {}) {
764
- return transport.requestParsed(Database, `/api/database/${id}`, {
765
- ...options,
766
- query: { include: params.include }
767
- });
768
- }
769
- /** List the schema names in a database. */
770
- async function schemas(id, options = {}) {
771
- return {
772
- data: await transport.requestParsed(DatabaseApiSchemaList, `/api/database/${id}/schemas`, { ...options }),
773
- total: null
774
- };
775
- }
776
- /** List the tables one schema of a database holds. */
777
- async function schemaTables(id, schema, options = {}) {
778
- return {
779
- data: await transport.requestParsed(DatabaseApiSchemaTableList, `/api/database/${id}/schema/${encodeURIComponent(schema)}`, { ...options }),
780
- total: null
781
- };
782
- }
783
- /**
784
- * Trigger a manual schema sync for a database. The endpoint queues the sync and returns at once;
785
- * pass `wait` to poll the database until it reports its initial sync complete.
786
- */
787
- async function syncSchema(id, params = {}, options = {}) {
788
- const ack = await transport.requestParsed(DatabaseTaskAck, `/api/database/${id}/sync_schema`, {
789
- ...options,
790
- method: "POST"
791
- });
792
- const wait = params.wait;
793
- if (wait === void 0) return {
794
- id,
795
- status: ack.status
796
- };
797
- const database = await pollUntil(async (signal) => transport.requestParsed(Database, `/api/database/${id}`, {
798
- ...options,
799
- signal
800
- }), (candidate) => candidate.initial_sync_status === SYNC_COMPLETE, wait);
801
- return {
802
- id,
803
- status: ack.status,
804
- initial_sync_status: database.initial_sync_status ?? null
805
- };
806
- }
807
- /** Trigger a rescan of the cached field values across a database. */
808
- async function rescanValues(id, options = {}) {
809
- return {
810
- id,
811
- status: (await transport.requestParsed(DatabaseTaskAck, `/api/database/${id}/rescan_values`, {
812
- ...options,
813
- method: "POST"
814
- })).status
815
- };
816
- }
817
- return {
818
- list,
819
- get,
820
- schemas,
821
- schemaTables,
822
- syncSchema,
823
- rescanValues
824
- };
825
- }
826
- //#endregion
827
- //#region ../client/src/resources/dataset.ts
828
- function datasetResource(transport) {
829
- /**
830
- * Run an ad-hoc query and return its result envelope. The body is a whole query — MBQL 5, legacy
831
- * MBQL, or native — rather than a reference to a saved one, so nothing here is a card.
832
- */
833
- async function query(body, options = {}) {
834
- return transport.requestParsed(CardQueryResult, "/api/dataset", {
835
- ...options,
836
- method: "POST",
837
- body
838
- });
839
- }
840
- return { query };
841
- }
842
- //#endregion
843
- //#region ../client/src/resources/document.ts
844
- const DocumentApiList = z.object({ items: z.array(Document) }).loose();
845
- function documentResource(transport) {
846
- /** Get existing documents. */
847
- async function list(options = {}) {
848
- return {
849
- data: (await transport.requestParsed(DocumentApiList, "/api/document", { ...options })).items,
850
- total: null
851
- };
852
- }
853
- /** Return an existing document by id. */
854
- async function get(id, options = {}) {
855
- return transport.requestParsed(Document, `/api/document/${id}`, { ...options });
856
- }
857
- /** Create a new document. */
858
- async function create(params, options = {}) {
859
- return transport.requestParsed(Document, "/api/document", {
860
- ...options,
861
- method: "POST",
862
- body: params
863
- });
864
- }
865
- /** Update an existing document by id. */
866
- async function update(id, params, options = {}) {
867
- return transport.requestParsed(Document, `/api/document/${id}`, {
868
- ...options,
869
- method: "PUT",
870
- body: params
871
- });
872
- }
873
- /** Archive (soft-delete) a document by id. Metabase models this as an update, not its own endpoint. */
874
- async function archive(id, options = {}) {
875
- return update(id, { archived: true }, options);
876
- }
877
- return {
878
- list,
879
- get,
880
- create,
881
- update,
882
- archive
883
- };
884
- }
885
- //#endregion
886
- //#region ../client/src/resources/eid-translation.ts
887
- function eidTranslationResource(transport) {
888
- /**
889
- * Translate entity ids to the numeric ids of the rows they name. The request groups the entity
890
- * ids by model; the response is keyed by entity id, each entry carrying its model and — when the
891
- * lookup succeeded — the numeric id.
892
- */
893
- async function translate(params, options = {}) {
894
- return transport.requestParsed(EidTranslateResult, "/api/eid-translation/translate", {
895
- ...options,
896
- method: "POST",
897
- body: params
898
- });
899
- }
900
- return { translate };
901
- }
902
- //#endregion
903
- //#region ../client/src/resources/field.ts
904
- const FieldApiSummary = z.tuple([z.tuple([z.literal("count"), z.number().int()]), z.tuple([z.literal("distincts"), z.number().int()])]);
905
- function fieldResource(transport) {
906
- /** Get one field by id. */
907
- async function get(id, options = {}) {
908
- return transport.requestParsed(Field, `/api/field/${id}`, { ...options });
909
- }
910
- /** Update a field by id, patching only the fields the body carries. */
911
- async function update(id, params, options = {}) {
912
- return transport.requestParsed(Field, `/api/field/${id}`, {
913
- ...options,
914
- method: "PUT",
915
- body: params
916
- });
917
- }
918
- /** Get the row count and the distinct-value count for a field. */
919
- async function summary(id, options = {}) {
920
- const [[, count], [, distincts]] = await transport.requestParsed(FieldApiSummary, `/api/field/${id}/summary`, { ...options });
921
- return {
922
- field_id: id,
923
- count,
924
- distincts
925
- };
926
- }
927
- /** Get the cached distinct values Metabase holds for a field. */
928
- async function values(id, options = {}) {
929
- return transport.requestParsed(FieldValues, `/api/field/${id}/values`, { ...options });
930
- }
931
- return {
932
- get,
933
- update,
934
- summary,
935
- values
936
- };
937
- }
938
- //#endregion
939
- //#region ../client/src/resources/optional-parsed.ts
940
- const NO_CONTENT_STATUS = 204;
941
- async function fetchOptionalParsed(client, path, schema, options = {}) {
942
- const response = await client.requestRaw(path, {
943
- ...options,
944
- method: "GET",
945
- expectContentType: "binary"
946
- });
947
- if (response.status === NO_CONTENT_STATUS) return null;
948
- return parseJsonOrPlain(await response.text(), response.headers.get("content-type"), schema, { source: response.url });
949
- }
950
- //#endregion
951
- //#region ../client/src/resources/git-sync.ts
952
- const SyncScopeCollection = Collection.pick({
953
- id: true,
954
- name: true,
955
- is_remote_synced: true
956
- }).strip();
957
- const SyncDirtyFlag = z.object({ is_dirty: z.boolean() });
958
- const SyncDirtyList = z.object({ dirty: z.array(SyncDirtyItem) });
959
- const SyncBranchList = z.object({ items: z.array(z.string()) });
960
- const SyncImportStarted = z.object({
961
- status: z.literal("success"),
962
- task_id: z.number().int().positive().nullable(),
963
- message: z.string().nullable().optional()
964
- });
965
- const SyncExportStarted = z.object({
966
- message: z.string(),
967
- task_id: z.number().int().positive()
968
- });
969
- const SyncStashStarted = z.object({
970
- status: z.literal("success"),
971
- message: z.string(),
972
- task_id: z.number().int().positive()
973
- });
974
- const RemoteSyncSetting = z.string().nullable();
975
- const FORBIDDEN_STATUS = 403;
976
- const UNREGISTERED_STATUS = 404;
977
- function isRemoteUnreadable(error) {
978
- if (!(error instanceof HttpError)) return false;
979
- return error.status === FORBIDDEN_STATUS || error.status === UNREGISTERED_STATUS;
980
- }
981
- function gitSyncResource(transport) {
982
- /** Get the running or most recently finished sync task, or null when the server has none. */
983
- async function currentTask(options = {}) {
984
- return fetchOptionalParsed(transport, "/api/ee/remote-sync/current-task", SyncTask, options);
985
- }
986
- /** Request cancellation of the running sync task, and answer it in the state that left it. */
987
- async function cancelTask(options = {}) {
988
- return transport.requestParsed(SyncTask, "/api/ee/remote-sync/current-task/cancel", {
989
- ...options,
990
- method: "POST"
991
- });
992
- }
993
- /** Whether Metabase holds content changes the remote has not been told about. */
994
- async function isDirty(options = {}) {
995
- return (await transport.requestParsed(SyncDirtyFlag, "/api/ee/remote-sync/is-dirty", { ...options })).is_dirty;
996
- }
997
- /** List the objects whose local state differs from the remote. */
998
- async function dirty(options = {}) {
999
- return {
1000
- data: (await transport.requestParsed(SyncDirtyList, "/api/ee/remote-sync/dirty", { ...options })).dirty,
1001
- total: null
1002
- };
1003
- }
1004
- /**
1005
- * Compare the tracked remote branch against what Metabase last imported. The server caches the
1006
- * comparison; `force-refresh` re-reads the remote instead.
1007
- */
1008
- async function hasRemoteChanges(params = {}, options = {}) {
1009
- return transport.requestParsed(SyncRemoteChanges, "/api/ee/remote-sync/has-remote-changes", {
1010
- ...options,
1011
- query: { "force-refresh": params["force-refresh"] }
1012
- });
1013
- }
1014
- /**
1015
- * Import content from the remote into Metabase. The endpoint queues a task and returns at once;
1016
- * pass `wait` to poll that task until it reaches a terminal status. A server already up to date
1017
- * answers no task id, and there is then nothing to poll.
1018
- */
1019
- async function importFromRemote(params = {}, options = {}) {
1020
- const started = await transport.requestParsed(SyncImportStarted, "/api/ee/remote-sync/import", {
1021
- ...options,
1022
- method: "POST",
1023
- body: {
1024
- branch: params.branch,
1025
- force: params.force
1026
- }
1027
- });
1028
- const message = started.message ?? null;
1029
- if (params.wait === void 0 || started.task_id === null) return {
1030
- message,
1031
- task_id: started.task_id
1032
- };
1033
- return {
1034
- message,
1035
- task_id: started.task_id,
1036
- final: await settle(params.wait, options)
1037
- };
1038
- }
1039
- /**
1040
- * Export Metabase's content to the remote. The endpoint queues a task and returns at once; pass
1041
- * `wait` to poll that task until it reaches a terminal status.
1042
- */
1043
- async function exportToRemote(params = {}, options = {}) {
1044
- const started = await transport.requestParsed(SyncExportStarted, "/api/ee/remote-sync/export", {
1045
- ...options,
1046
- method: "POST",
1047
- body: {
1048
- branch: params.branch,
1049
- message: params.message,
1050
- force: params.force
1051
- }
1052
- });
1053
- if (params.wait === void 0) return {
1054
- message: started.message,
1055
- task_id: started.task_id
1056
- };
1057
- return {
1058
- message: started.message,
1059
- task_id: started.task_id,
1060
- final: await settle(params.wait, options)
1061
- };
1062
- }
1063
- /**
1064
- * Export Metabase's current content to a branch the remote does not have yet. The endpoint
1065
- * queues a task and returns at once; pass `wait` to poll that task to a terminal status.
1066
- */
1067
- async function stash(params, options = {}) {
1068
- const started = await transport.requestParsed(SyncStashStarted, "/api/ee/remote-sync/stash", {
1069
- ...options,
1070
- method: "POST",
1071
- body: {
1072
- new_branch: params.new_branch,
1073
- message: params.message
1074
- }
1075
- });
1076
- if (params.wait === void 0) return {
1077
- status: started.status,
1078
- message: started.message,
1079
- task_id: started.task_id
1080
- };
1081
- return {
1082
- status: started.status,
1083
- message: started.message,
1084
- task_id: started.task_id,
1085
- final: await settle(params.wait, options)
1086
- };
1087
- }
1088
- /** List the branches the configured remote carries. */
1089
- async function branches(options = {}) {
1090
- return {
1091
- data: (await transport.requestParsed(SyncBranchList, "/api/ee/remote-sync/branches", { ...options })).items,
1092
- total: null
1093
- };
1094
- }
1095
- /** Create a branch on the remote and point git-sync at it. */
1096
- async function createBranch(params, options = {}) {
1097
- return transport.requestParsed(SyncBranchCreated, "/api/ee/remote-sync/create-branch", {
1098
- ...options,
1099
- method: "POST",
1100
- body: { name: params.name }
1101
- });
1102
- }
1103
- /**
1104
- * Mark one collection as git-synced, or unmark it. The server cascades the flag to descendants
1105
- * by location prefix, and may queue an export task to carry the change to the remote.
1106
- */
1107
- async function setCollectionSynced(collectionId, synced, options = {}) {
1108
- return transport.requestParsed(SyncSettingsUpdateResult, "/api/ee/remote-sync/settings", {
1109
- ...options,
1110
- method: "PUT",
1111
- body: { collections: { [collectionId]: synced } }
1112
- });
1113
- }
1114
- /** The collections currently in git-sync's scope. */
1115
- async function syncedCollections(options = {}) {
1116
- return {
1117
- data: (await listCollectionsWithLibrary(transport, SyncScopeCollection, options)).filter((entry) => entry.is_remote_synced === true),
1118
- total: null
1119
- };
1120
- }
1121
- /** The remote's URL, or null when none is configured or the caller may not read it. */
1122
- async function remoteUrl(options = {}) {
1123
- try {
1124
- const url = await fetchOptionalParsed(transport, "/api/setting/remote-sync-url", RemoteSyncSetting, options);
1125
- return url === "" ? null : url;
1126
- } catch (error) {
1127
- if (isRemoteUnreadable(error)) return null;
1128
- throw error;
1129
- }
1130
- }
1131
- /** The branch git-sync tracks, or null when none is configured or the caller may not read it. */
1132
- async function branch(options = {}) {
1133
- return fetchOptionalParsed(transport, "/api/setting/remote-sync-branch", RemoteSyncSetting, options);
1134
- }
1135
- /**
1136
- * Poll the current task until it reaches a terminal status. A server with no task at all
1137
- * answers null, which is terminal in the same sense: nothing further will happen.
1138
- */
1139
- async function waitForTask(wait, options = {}) {
1140
- return settle(wait, options);
1141
- }
1142
- async function settle(wait, options) {
1143
- return pollUntil(async (signal) => currentTask({
1144
- ...options,
1145
- signal
1146
- }), (task) => task === null || isSyncTaskTerminal(task.status), wait);
1147
- }
1148
- return {
1149
- currentTask,
1150
- cancelTask,
1151
- isDirty,
1152
- dirty,
1153
- hasRemoteChanges,
1154
- import: importFromRemote,
1155
- export: exportToRemote,
1156
- stash,
1157
- branches,
1158
- createBranch,
1159
- setCollectionSynced,
1160
- syncedCollections,
1161
- remoteUrl,
1162
- branch,
1163
- waitForTask
1164
- };
1165
- }
1166
- //#endregion
1167
- //#region ../client/src/resources/library.ts
1168
- const LIBRARY_ROOT_PATH = "/api/ee/library/";
1169
- const PUBLISH_TABLES_PATH = "/api/ee/data-studio/table/publish-tables";
1170
- const UNPUBLISH_TABLES_PATH = "/api/ee/data-studio/table/unpublish-tables";
1171
- const LIBRARY_DATA_TYPE = "library-data";
1172
- const AbsentLibrary = z.object({ data: z.null() });
1173
- const LibraryOrAbsent = z.union([Library, AbsentLibrary]);
1174
- const PublishTablesResponse = z.object({ target_collection: Collection.nullable() });
1175
- const LibraryCollectionInfo = Collection.pick({
1176
- id: true,
1177
- type: true,
1178
- is_remote_synced: true
1179
- }).strip();
1180
- function libraryResource(transport) {
1181
- /** Get the Library root and its child collections, or `null` on an instance that has none. */
1182
- async function get(options = {}) {
1183
- const result = await transport.requestParsed(LibraryOrAbsent, LIBRARY_ROOT_PATH, { ...options });
1184
- if (!("effective_children" in result)) return null;
1185
- const infoById = await libraryCollectionsById(options);
1186
- const effective_children = result.effective_children.map((child) => {
1187
- if (typeof child.id !== "number") return child;
1188
- const info = infoById.get(child.id);
1189
- if (info === void 0) return child;
1190
- return {
1191
- ...child,
1192
- type: info.type ?? child.type,
1193
- is_remote_synced: info.is_remote_synced ?? child.is_remote_synced
1194
- };
1195
- });
1196
- return {
1197
- ...result,
1198
- effective_children
1199
- };
1200
- }
1201
- async function libraryCollectionsById(options) {
1202
- const data = await listCollectionsWithLibrary(transport, LibraryCollectionInfo, options);
1203
- const byId = /* @__PURE__ */ new Map();
1204
- for (const collection of data) if (typeof collection.id === "number") byId.set(collection.id, collection);
1205
- return byId;
1206
- }
1207
- /**
1208
- * Create the Library subtree (its Data and Metrics collections). Metabase takes no body, rejects
1209
- * a second create with a 400, and answers the bare root collection without its
1210
- * `effective_children` — so an existing Library short-circuits the call and a fresh one comes
1211
- * back from a refetch, which together make this idempotent.
1212
- */
1213
- async function create(options = {}) {
1214
- const existing = await get(options);
1215
- if (existing !== null) return existing;
1216
- await transport.requestRaw(LIBRARY_ROOT_PATH, {
1217
- ...options,
1218
- method: "POST"
1219
- });
1220
- const created = await get(options);
1221
- if (created === null) throw new Error(`Library was not created after POST ${LIBRARY_ROOT_PATH}`);
1222
- return created;
1223
- }
1224
- /** The id of the Library's Data collection, creating the Library first when it does not exist. */
1225
- async function ensureDataCollectionId(options = {}) {
1226
- const data = (await create(options)).effective_children.find((child) => child.type === LIBRARY_DATA_TYPE);
1227
- if (data === void 0) throw new Error("Library has no Data collection to publish into");
1228
- if (typeof data.id !== "number") throw new Error(`Library Data collection has a non-numeric id ${String(data.id)}`);
1229
- return data.id;
1230
- }
1231
- /**
1232
- * Publish tables — and every upstream table they depend on — into a collection, so they lead the
1233
- * data pickers and rank up in search. Answers the collection they landed in.
1234
- */
1235
- async function publishTables(params, options = {}) {
1236
- return (await transport.requestParsed(PublishTablesResponse, PUBLISH_TABLES_PATH, {
1237
- ...options,
1238
- method: "POST",
1239
- body: params
1240
- })).target_collection;
1241
- }
1242
- /**
1243
- * Clear the Library collection from tables, and recursively from every downstream table that
1244
- * depends on them. The endpoint answers no JSON body.
1245
- */
1246
- async function unpublishTables(params, options = {}) {
1247
- await transport.requestRaw(UNPUBLISH_TABLES_PATH, {
1248
- ...options,
1249
- method: "POST",
1250
- body: params,
1251
- expectContentType: "binary"
1252
- });
1253
- }
1254
- return {
1255
- get,
1256
- create,
1257
- ensureDataCollectionId,
1258
- publishTables,
1259
- unpublishTables
1260
- };
1261
- }
1262
- //#endregion
1263
- //#region ../client/src/resources/measure.ts
1264
- const MeasureApiList = z.array(Measure);
1265
- function measureResource(transport) {
1266
- /** List measures. */
1267
- async function list(options = {}) {
1268
- return {
1269
- data: await transport.requestParsed(MeasureApiList, "/api/measure", { ...options }),
1270
- total: null
1271
- };
1272
- }
1273
- /** Get one measure by id. */
1274
- async function get(id, options = {}) {
1275
- return transport.requestParsed(Measure, `/api/measure/${id}`, { ...options });
1276
- }
1277
- /** Create a measure — a saved aggregation tied to a table — from a full measure body. */
1278
- async function create(params, options = {}) {
1279
- return transport.requestParsed(Measure, "/api/measure", {
1280
- ...options,
1281
- method: "POST",
1282
- body: params
1283
- });
1284
- }
1285
- /**
1286
- * Update a measure by id, patching only the fields the body carries. `revision_message` is
1287
- * required and lands in the audit log.
1288
- */
1289
- async function update(id, params, options = {}) {
1290
- return transport.requestParsed(Measure, `/api/measure/${id}`, {
1291
- ...options,
1292
- method: "PUT",
1293
- body: params
1294
- });
1295
- }
1296
- /**
1297
- * Archive (soft-delete) a measure by id. Metabase models this as an update, not its own endpoint,
1298
- * so it carries the same required `revision_message`.
1299
- */
1300
- async function archive(id, params, options = {}) {
1301
- return update(id, {
1302
- archived: true,
1303
- revision_message: params.revision_message
1304
- }, options);
1305
- }
1306
- return {
1307
- list,
1308
- get,
1309
- create,
1310
- update,
1311
- archive
1312
- };
1313
- }
1314
- //#endregion
1315
- //#region ../client/src/resources/notification.ts
1316
- const NotificationApiList = z.array(Notification);
1317
- function assertCardAlert(notification) {
1318
- 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`);
1319
- return notification;
1320
- }
1321
- function mergeAlertUpdate(current, patch) {
1322
- return Notification.parse({
1323
- ...current,
1324
- ...patch,
1325
- id: current.id,
1326
- payload: patch.payload === void 0 ? current.payload : mergePayload(current, patch.payload)
1327
- });
1328
- }
1329
- function mergePayload(current, patch) {
1330
- if (current.payload === null) throw new ConfigError(`alert ${current.id} has lost its card payload — it can be archived, but not patched`);
1331
- return NotificationCardPayload.parse({
1332
- ...current.payload,
1333
- ...patch
1334
- });
1335
- }
1336
- function notificationResource(transport) {
1337
- /**
1338
- * List question alerts, optionally narrowed by the card they watch, their creator, or a
1339
- * recipient. `/api/notification` also serves Metabase's internal system-event notifications, so
1340
- * the request pins the card payload type.
1341
- */
1342
- async function list(params = {}, options = {}) {
1343
- return {
1344
- data: await transport.requestParsed(NotificationApiList, "/api/notification", {
1345
- ...options,
1346
- query: {
1347
- payload_type: CARD_PAYLOAD_TYPE,
1348
- card_id: params.card_id,
1349
- creator_id: params.creator_id,
1350
- recipient_id: params.recipient_id,
1351
- include_inactive: params.include_inactive
1352
- }
1353
- }),
1354
- total: null
1355
- };
1356
- }
1357
- /** Get one question alert by id, refusing an id that names a system-event notification. */
1358
- async function get(id, options = {}) {
1359
- return assertCardAlert(await transport.requestParsed(Notification, `/api/notification/${id}`, { ...options }));
1360
- }
1361
- /** Create a question alert — its card payload, schedules and handlers — from a full body. */
1362
- async function create(params, options = {}) {
1363
- return transport.requestParsed(Notification, "/api/notification", {
1364
- ...options,
1365
- method: "POST",
1366
- body: params
1367
- });
1368
- }
1369
- /** Update a question alert by id, merging the patch over the stored notification. */
1370
- async function update(id, params, options = {}) {
1371
- const current = await get(id, options);
1372
- return transport.requestParsed(Notification, `/api/notification/${id}`, {
1373
- ...options,
1374
- method: "PUT",
1375
- body: mergeAlertUpdate(current, params)
1376
- });
1377
- }
1378
- /** Archive a question alert by id, stopping every delivery. Metabase models this as an update. */
1379
- async function archive(id, options = {}) {
1380
- return update(id, { active: false }, options);
1381
- }
1382
- /**
1383
- * Send a question alert now, off-schedule, to every handler on it. The server answers with no
1384
- * body.
1385
- */
1386
- async function send(id, options = {}) {
1387
- await get(id, options);
1388
- await transport.requestRaw(`/api/notification/${id}/send`, {
1389
- ...options,
1390
- method: "POST",
1391
- expectContentType: "binary"
1392
- });
1393
- }
1394
- return {
1395
- list,
1396
- get,
1397
- create,
1398
- update,
1399
- archive,
1400
- send
1401
- };
1402
- }
1403
- //#endregion
1404
- //#region ../client/src/resources/pulse.ts
1405
- const PulseApiList = z.array(Pulse);
1406
- function mergePulseUpdate(current, patch) {
1407
- return {
1408
- ...patch,
1409
- archived: patch.archived ?? current.archived,
1410
- skip_if_empty: patch.skip_if_empty ?? current.skip_if_empty
1411
- };
1412
- }
1413
- function pulseResource(transport) {
1414
- /** List dashboard subscriptions, optionally narrowed to one dashboard or to the archived ones. */
1415
- async function list(params = {}, options = {}) {
1416
- return {
1417
- data: await transport.requestParsed(PulseApiList, "/api/pulse", {
1418
- ...options,
1419
- query: {
1420
- dashboard_id: params.dashboard_id,
1421
- archived: params.archived
1422
- }
1423
- }),
1424
- total: null
1425
- };
1426
- }
1427
- /** Get one dashboard subscription by id. */
1428
- async function get(id, options = {}) {
1429
- return transport.requestParsed(Pulse, `/api/pulse/${id}`, { ...options });
1430
- }
1431
- /** Create a dashboard subscription — its cards and its delivery channels — from a full body. */
1432
- async function create(params, options = {}) {
1433
- return transport.requestParsed(Pulse, "/api/pulse", {
1434
- ...options,
1435
- method: "POST",
1436
- body: params
1437
- });
1438
- }
1439
- /** Update a dashboard subscription by id, carrying the server-defaulted flags forward. */
1440
- async function update(id, params, options = {}) {
1441
- const current = await get(id, options);
1442
- return transport.requestParsed(Pulse, `/api/pulse/${id}`, {
1443
- ...options,
1444
- method: "PUT",
1445
- body: mergePulseUpdate(current, params)
1446
- });
1447
- }
1448
- /**
1449
- * Archive a dashboard subscription by id, stopping every delivery. Metabase models this as an
1450
- * update, and disables each of the subscription's channels as a side effect.
1451
- */
1452
- async function archive(id, options = {}) {
1453
- return update(id, { archived: true }, options);
1454
- }
1455
- return {
1456
- list,
1457
- get,
1458
- create,
1459
- update,
1460
- archive
1461
- };
1462
- }
1463
- //#endregion
1464
- //#region ../client/src/resources/search.ts
1465
- const SearchApiResponse = z.object({
1466
- data: z.array(SearchResult),
1467
- total: z.number().int().nonnegative()
1468
- }).loose();
1469
- function searchResource(transport) {
1470
- /**
1471
- * Search over the instance's content, ranked against `q`. `models` narrows which kinds of entity
1472
- * may match, `archived` swaps the active set for the archived one, `table_db_id` restricts to
1473
- * items on one database, `verified` to verified content, and `limit`/`offset` are the window the
1474
- * server applies before ranking hydration.
1475
- */
1476
- async function query(params = {}, options = {}) {
1477
- const response = await transport.requestParsed(SearchApiResponse, "/api/search", {
1478
- ...options,
1479
- query: {
1480
- q: params.q,
1481
- models: params.models,
1482
- archived: params.archived,
1483
- limit: params.limit,
1484
- offset: params.offset,
1485
- table_db_id: params.table_db_id,
1486
- verified: params.verified
1487
- }
1488
- });
1489
- return {
1490
- data: response.data,
1491
- total: response.total
1492
- };
1493
- }
1494
- return { query };
1495
- }
1496
- //#endregion
1497
- //#region ../client/src/resources/segment.ts
1498
- const SegmentApiList = z.array(Segment);
1499
- function segmentResource(transport) {
1500
- /** List every segment the caller can see. */
1501
- async function list(options = {}) {
1502
- return {
1503
- data: await transport.requestParsed(SegmentApiList, "/api/segment", { ...options }),
1504
- total: null
1505
- };
1506
- }
1507
- /** Get one segment by id. */
1508
- async function get(id, options = {}) {
1509
- return transport.requestParsed(Segment, `/api/segment/${id}`, { ...options });
1510
- }
1511
- /** Create a segment — a reusable row filter over one table — from a full segment body. */
1512
- async function create(params, options = {}) {
1513
- return transport.requestParsed(Segment, "/api/segment", {
1514
- ...options,
1515
- method: "POST",
1516
- body: params
1517
- });
1518
- }
1519
- /**
1520
- * Update a segment by id, patching only the fields the body carries. `revision_message` is
1521
- * required: Metabase records every segment change in its revision history.
1522
- */
1523
- async function update(id, params, options = {}) {
1524
- return transport.requestParsed(Segment, `/api/segment/${id}`, {
1525
- ...options,
1526
- method: "PUT",
1527
- body: params
1528
- });
1529
- }
1530
- /**
1531
- * Archive (soft-delete) a segment by id. Metabase models this as an update, so it carries the
1532
- * same required `revision_message`.
1533
- */
1534
- async function archive(id, params, options = {}) {
1535
- return update(id, {
1536
- archived: true,
1537
- revision_message: params.revision_message
1538
- }, options);
1539
- }
1540
- return {
1541
- list,
1542
- get,
1543
- create,
1544
- update,
1545
- archive
1546
- };
1547
- }
1548
- //#endregion
1549
- //#region ../client/src/resources/setting.ts
1550
- const SettingApiList = z.array(Setting);
1551
- const UNKNOWN_SETTING_PREFIX = "Unknown setting:";
1552
- function rethrowSettingError(error, key) {
1553
- if (errorMessage(error).startsWith(UNKNOWN_SETTING_PREFIX)) throw new ConfigError(`unknown setting: ${key}`);
1554
- throw error;
1555
- }
1556
- function settingResource(transport) {
1557
- /** Get all settings and their values, with descriptions and environment-variable names. */
1558
- async function list(options = {}) {
1559
- return {
1560
- data: await transport.requestParsed(SettingApiList, "/api/setting", { ...options }),
1561
- total: null
1562
- };
1563
- }
1564
- /**
1565
- * Fetch a single setting's value by key. An unset setting answers 204 rather than 404, which
1566
- * reaches the caller as `null`; older servers answer the value as bare text rather than JSON.
1567
- */
1568
- async function get(key, options = {}) {
1569
- return fetchOptionalParsed(transport, `/api/setting/${encodeURIComponent(key)}`, z.unknown(), options).catch((error) => rethrowSettingError(error, key));
1570
- }
1571
- /** Set a single setting's value by key. The endpoint answers 204 with no body. */
1572
- async function set(key, value, options = {}) {
1573
- await transport.requestRaw(`/api/setting/${encodeURIComponent(key)}`, {
1574
- ...options,
1575
- method: "PUT",
1576
- body: { value },
1577
- expectContentType: "binary"
1578
- }).catch((error) => rethrowSettingError(error, key));
1579
- }
1580
- return {
1581
- list,
1582
- get,
1583
- set
1584
- };
1585
- }
1586
- //#endregion
1587
- //#region ../client/src/resources/setup.ts
1588
- function setupResource(transport) {
1589
- /**
1590
- * Complete the initial setup wizard on a fresh instance, creating its first admin user and
1591
- * applying the instance preferences. The setup token is single-use.
1592
- */
1593
- async function create(params, options = {}) {
1594
- return transport.requestParsed(SetupResult, "/api/setup", {
1595
- ...options,
1596
- method: "POST",
1597
- body: params
1598
- });
1599
- }
1600
- return { create };
1601
- }
1602
- //#endregion
1603
- //#region ../client/src/resources/snippet.ts
1604
- const SnippetApiList = z.array(Snippet);
1605
- function snippetResource(transport) {
1606
- /** List native query snippets. `archived` swaps the listing to archived snippets. */
1607
- async function list(params = {}, options = {}) {
1608
- return {
1609
- data: await transport.requestParsed(SnippetApiList, "/api/native-query-snippet", {
1610
- ...options,
1611
- query: { archived: params.archived }
1612
- }),
1613
- total: null
1614
- };
1615
- }
1616
- /** Get one native query snippet by id. */
1617
- async function get(id, options = {}) {
1618
- return transport.requestParsed(Snippet, `/api/native-query-snippet/${id}`, { ...options });
1619
- }
1620
- /** Create a native query snippet from a name, its SQL fragment, and an optional collection. */
1621
- async function create(params, options = {}) {
1622
- return transport.requestParsed(Snippet, "/api/native-query-snippet", {
1623
- ...options,
1624
- method: "POST",
1625
- body: params
1626
- });
1627
- }
1628
- /** Update a native query snippet by id, patching only the fields the body carries. */
1629
- async function update(id, params, options = {}) {
1630
- return transport.requestParsed(Snippet, `/api/native-query-snippet/${id}`, {
1631
- ...options,
1632
- method: "PUT",
1633
- body: params
1634
- });
1635
- }
1636
- /**
1637
- * Archive (soft-delete) a native query snippet by id. Metabase models this as an update, not its
1638
- * own endpoint.
1639
- */
1640
- async function archive(id, options = {}) {
1641
- return update(id, { archived: true }, options);
1642
- }
1643
- return {
1644
- list,
1645
- get,
1646
- create,
1647
- update,
1648
- archive
1649
- };
1650
- }
1651
- //#endregion
1652
- //#region ../client/src/resources/table.ts
1653
- const TableApiList = z.array(Table);
1654
- const UPLOAD_UPDATE_PATHS = {
1655
- append: "append-csv",
1656
- replace: "replace-csv"
1657
- };
1658
- function tableResource(transport) {
1659
- /** List every table the caller can see, across all databases. */
1660
- async function list(options = {}) {
1661
- return {
1662
- data: await transport.requestParsed(TableApiList, "/api/table", { ...options }),
1663
- total: null
1664
- };
1665
- }
1666
- /** Get one table by id, without its fields. */
1667
- async function get(id, options = {}) {
1668
- return transport.requestParsed(Table, `/api/table/${id}`, { ...options });
1669
- }
1670
- /** Update a table by id, patching only the fields the body carries. */
1671
- async function update(id, params, options = {}) {
1672
- return transport.requestParsed(Table, `/api/table/${id}`, {
1673
- ...options,
1674
- method: "PUT",
1675
- body: params
1676
- });
1677
- }
1678
- /** Get a table by id with its fields hydrated — the metadata the query builder runs on. */
1679
- async function queryMetadata(id, options = {}) {
1680
- return transport.requestParsed(TableQueryMetadata, `/api/table/${id}/query_metadata`, { ...options });
1681
- }
1682
- async function updateFromCsv(id, action, file, options) {
1683
- await transport.requestRaw(`/api/table/${id}/${UPLOAD_UPDATE_PATHS[action]}`, {
1684
- ...options,
1685
- method: "POST",
1686
- body: buildCsvFormData(file),
1687
- expectContentType: "binary"
1688
- });
1689
- return {
1690
- table_id: id,
1691
- action
1692
- };
1693
- }
1694
- /**
1695
- * Inserts the rows of an uploaded CSV file into the table identified by `id`. The table must have
1696
- * been created by uploading a CSV file.
1697
- *
1698
- * The file may be at most 50 MB; larger uploads are rejected with a 413 response.
1699
- */
1700
- async function appendCsv(id, file, options = {}) {
1701
- return updateFromCsv(id, "append", file, options);
1702
- }
1703
- /**
1704
- * Replaces the contents of the table identified by `id` with the rows of an uploaded CSV file.
1705
- * The table must have been created by uploading a CSV file.
1706
- *
1707
- * The file may be at most 50 MB; larger uploads are rejected with a 413 response.
1708
- */
1709
- async function replaceCsv(id, file, options = {}) {
1710
- return updateFromCsv(id, "replace", file, options);
1711
- }
1712
- return {
1713
- list,
1714
- get,
1715
- update,
1716
- queryMetadata,
1717
- appendCsv,
1718
- replaceCsv
1719
- };
1720
- }
1721
- //#endregion
1722
- //#region ../client/src/resources/timeline-event.ts
1723
- function timelineEventResource(transport) {
1724
- /** Get one timeline event by id. */
1725
- async function get(id, options = {}) {
1726
- return transport.requestParsed(TimelineEvent, `/api/timeline-event/${id}`, { ...options });
1727
- }
1728
- /** Create a timeline event on an existing timeline. */
1729
- async function create(params, options = {}) {
1730
- return transport.requestParsed(TimelineEvent, "/api/timeline-event", {
1731
- ...options,
1732
- method: "POST",
1733
- body: params
1734
- });
1735
- }
1736
- /**
1737
- * Update a timeline event by id, patching only the fields the body carries. `timeline_id` moves
1738
- * the event to another timeline.
1739
- */
1740
- async function update(id, params, options = {}) {
1741
- return transport.requestParsed(TimelineEvent, `/api/timeline-event/${id}`, {
1742
- ...options,
1743
- method: "PUT",
1744
- body: params
1745
- });
1746
- }
1747
- /**
1748
- * Archive (soft-delete) a timeline event by id. Metabase models this as an update, not its own
1749
- * endpoint.
1750
- */
1751
- async function archive(id, options = {}) {
1752
- return update(id, { archived: true }, options);
1753
- }
1754
- /** Permanently delete a timeline event by id. The server answers with no body. */
1755
- async function remove(id, options = {}) {
1756
- await transport.requestRaw(`/api/timeline-event/${id}`, {
1757
- ...options,
1758
- method: "DELETE",
1759
- expectContentType: "binary"
1760
- });
1761
- }
1762
- return {
1763
- get,
1764
- create,
1765
- update,
1766
- archive,
1767
- delete: remove
1768
- };
1769
- }
1770
- //#endregion
1771
- //#region ../client/src/resources/timeline.ts
1772
- const TimelineApiList = z.array(Timeline);
1773
- const TimelineWithEvents = Timeline.required({ events: true });
1774
- function timelineResource(transport) {
1775
- /** List timelines. `archived` swaps the active listing for the archived one. */
1776
- async function list(params = {}, options = {}) {
1777
- return {
1778
- data: await transport.requestParsed(TimelineApiList, "/api/timeline", {
1779
- ...options,
1780
- query: { archived: params.archived }
1781
- }),
1782
- total: null
1783
- };
1784
- }
1785
- /** Get one timeline by id, without its events. */
1786
- async function get(id, options = {}) {
1787
- return transport.requestParsed(Timeline, `/api/timeline/${id}`, { ...options });
1788
- }
1789
- /**
1790
- * List the events on one timeline. Metabase has no endpoint of its own for these: the same
1791
- * timeline read hydrates them on request, and `archived` chooses which of them come back.
1792
- */
1793
- async function events(id, params = {}, options = {}) {
1794
- return {
1795
- data: (await transport.requestParsed(TimelineWithEvents, `/api/timeline/${id}`, {
1796
- ...options,
1797
- query: {
1798
- include: "events",
1799
- archived: params.archived
1800
- }
1801
- })).events,
1802
- total: null
1803
- };
1804
- }
1805
- /** Create a timeline from a full timeline body. */
1806
- async function create(params, options = {}) {
1807
- return transport.requestParsed(Timeline, "/api/timeline", {
1808
- ...options,
1809
- method: "POST",
1810
- body: params
1811
- });
1812
- }
1813
- /**
1814
- * Update a timeline by id, patching only the fields the body carries. Changing `archived`
1815
- * cascades to every event on the timeline.
1816
- */
1817
- async function update(id, params, options = {}) {
1818
- return transport.requestParsed(Timeline, `/api/timeline/${id}`, {
1819
- ...options,
1820
- method: "PUT",
1821
- body: params
1822
- });
1823
- }
1824
- /**
1825
- * Archive (soft-delete) a timeline and all its events by id. Metabase models this as an update,
1826
- * not its own endpoint.
1827
- */
1828
- async function archive(id, options = {}) {
1829
- return update(id, { archived: true }, options);
1830
- }
1831
- /** Permanently delete a timeline and all its events by id. The server answers with no body. */
1832
- async function remove(id, options = {}) {
1833
- await transport.requestRaw(`/api/timeline/${id}`, {
1834
- ...options,
1835
- method: "DELETE",
1836
- expectContentType: "binary"
1837
- });
1838
- }
1839
- return {
1840
- list,
1841
- get,
1842
- events,
1843
- create,
1844
- update,
1845
- archive,
1846
- delete: remove
1847
- };
1848
- }
1849
- //#endregion
1850
- //#region ../client/src/resources/transform-job.ts
1851
- const TransformJobApiList = z.array(TransformJob);
1852
- const TransformApiList$1 = z.array(Transform);
1853
- function transformJobResource(transport) {
1854
- /** List every transform job the caller can see. */
1855
- async function list(options = {}) {
1856
- return {
1857
- data: await transport.requestParsed(TransformJobApiList, "/api/transform-job", { ...options }),
1858
- total: null
1859
- };
1860
- }
1861
- /** Get one transform job by id. */
1862
- async function get(id, options = {}) {
1863
- return transport.requestParsed(TransformJob, `/api/transform-job/${id}`, { ...options });
1864
- }
1865
- /** Create a transform job — a schedule plus the tags it runs — from a full body. */
1866
- async function create(params, options = {}) {
1867
- return transport.requestParsed(TransformJob, "/api/transform-job", {
1868
- ...options,
1869
- method: "POST",
1870
- body: params
1871
- });
1872
- }
1873
- /** Update a transform job by id, patching only the fields the body carries. */
1874
- async function update(id, params, options = {}) {
1875
- return transport.requestParsed(TransformJob, `/api/transform-job/${id}`, {
1876
- ...options,
1877
- method: "PUT",
1878
- body: params
1879
- });
1880
- }
1881
- /** Delete a transform job by id, leaving the transforms it ran untouched. */
1882
- async function remove(id, options = {}) {
1883
- await transport.requestRaw(`/api/transform-job/${id}`, {
1884
- ...options,
1885
- method: "DELETE",
1886
- expectContentType: "binary"
1887
- });
1888
- }
1889
- /**
1890
- * Start a run of a transform job by id. The job runs every transform carrying one of its tags,
1891
- * plus those transforms' dependencies; `run_all` re-runs dependencies that are already fresh.
1892
- */
1893
- async function run(id, params = {}, options = {}) {
1894
- return transport.requestParsed(TransformJobRunResult, `/api/transform-job/${id}/run`, {
1895
- ...options,
1896
- method: "POST",
1897
- body: { run_all: params.run_all }
1898
- });
1899
- }
1900
- /** List the transforms a job would execute, resolved from the job's tags. */
1901
- async function transforms(id, options = {}) {
1902
- return {
1903
- data: await transport.requestParsed(TransformApiList$1, `/api/transform-job/${id}/transforms`, { ...options }),
1904
- total: null
1905
- };
1906
- }
1907
- /**
1908
- * Flip the active flag on every transform job at once. Inactive jobs do not run on schedule;
1909
- * manual runs ignore the flag. The path carries no id and is a different endpoint from `update`.
1910
- */
1911
- async function setActive(active, options = {}) {
1912
- return transport.requestParsed(TransformJobActiveResult, "/api/transform-job/active", {
1913
- ...options,
1914
- method: "PUT",
1915
- body: { active }
1916
- });
1917
- }
1918
- return {
1919
- list,
1920
- get,
1921
- create,
1922
- update,
1923
- delete: remove,
1924
- run,
1925
- transforms,
1926
- setActive
1927
- };
1928
- }
1929
- //#endregion
1930
- //#region ../client/src/resources/transform.ts
1931
- const TransformApiList = z.array(Transform);
1932
- const TransformRunKickoff = z.object({
1933
- message: z.string(),
1934
- run_id: z.number().int().positive().nullable()
1935
- });
1936
- function transformResource(transport) {
1937
- /** List every transform the caller can see. */
1938
- async function list(options = {}) {
1939
- return {
1940
- data: await transport.requestParsed(TransformApiList, "/api/transform", { ...options }),
1941
- total: null
1942
- };
1943
- }
1944
- /** Get one transform by id. */
1945
- async function get(id, options = {}) {
1946
- return transport.requestParsed(Transform, `/api/transform/${id}`, { ...options });
1947
- }
1948
- /** Create a transform — a query plus the warehouse table it writes — from a full body. */
1949
- async function create(params, options = {}) {
1950
- return transport.requestParsed(Transform, "/api/transform", {
1951
- ...options,
1952
- method: "POST",
1953
- body: params
1954
- });
1955
- }
1956
- /** Update a transform by id, patching only the fields the body carries. */
1957
- async function update(id, params, options = {}) {
1958
- return transport.requestParsed(Transform, `/api/transform/${id}`, {
1959
- ...options,
1960
- method: "PUT",
1961
- body: params
1962
- });
1963
- }
1964
- /** Delete a transform by id, leaving any table it already materialized in place. */
1965
- async function remove(id, options = {}) {
1966
- await transport.requestRaw(`/api/transform/${id}`, {
1967
- ...options,
1968
- method: "DELETE",
1969
- expectContentType: "binary"
1970
- });
1971
- }
1972
- /** Drop a transform's materialized output table, keeping the transform definition. */
1973
- async function deleteTable(id, options = {}) {
1974
- await transport.requestRaw(`/api/transform/${id}/table`, {
1975
- ...options,
1976
- method: "DELETE",
1977
- expectContentType: "binary"
1978
- });
1979
- }
1980
- /** List the upstream transforms a transform depends on. */
1981
- async function dependencies(id, options = {}) {
1982
- return {
1983
- data: await transport.requestParsed(TransformApiList, `/api/transform/${id}/dependencies`, { ...options }),
1984
- total: null
1985
- };
1986
- }
1987
- /** Request cancellation of a transform's current run. */
1988
- async function cancel(id, options = {}) {
1989
- await transport.requestRaw(`/api/transform/${id}/cancel`, {
1990
- ...options,
1991
- method: "POST",
1992
- expectContentType: "binary"
1993
- });
1994
- }
1995
- /** Get one transform run by run id — not by the id of the transform that produced it. */
1996
- async function getRun(runId, options = {}) {
1997
- return transport.requestParsed(TransformRun, `/api/transform/run/${runId}`, { ...options });
1998
- }
1999
- /** Walk the run history, newest first, optionally narrowed to a single transform. */
2000
- function runPages(params = {}, options = {}) {
2001
- return paginatePages(transport, "/api/transform/run", TransformRun, {
2002
- query: { "transform-ids": params["transform-ids"] },
2003
- ...options.offset !== void 0 && { offset: options.offset },
2004
- ...options.max !== void 0 && { max: options.max },
2005
- ...options.pageSize !== void 0 && { pageSize: options.pageSize },
2006
- ...options.signal !== void 0 && { signal: options.signal }
2007
- });
2008
- }
2009
- /**
2010
- * Start a run of a transform by id. The server queues the run and answers at once; `wait` polls
2011
- * it to a terminal status, and `syncTarget` follows that with the output table's registration.
2012
- * A server that answers no run id started nothing, and there is then nothing to poll.
2013
- */
2014
- async function run(id, params = {}, options = {}) {
2015
- const kickoff = await transport.requestParsed(TransformRunKickoff, `/api/transform/${id}/run`, {
2016
- ...options,
2017
- method: "POST"
2018
- });
2019
- const schedule = params.syncTarget === true ? params.wait ?? {} : params.wait;
2020
- if (schedule === void 0 || kickoff.run_id === null) return {
2021
- message: kickoff.message,
2022
- run_id: kickoff.run_id,
2023
- final: null
2024
- };
2025
- const runId = kickoff.run_id;
2026
- const final = await pollUntil(async (signal) => getRun(runId, {
2027
- ...options,
2028
- signal
2029
- }), (candidate) => isTransformRunTerminal(candidate.status), schedule);
2030
- if (params.syncTarget !== true) return {
2031
- message: kickoff.message,
2032
- run_id: runId,
2033
- final
2034
- };
2035
- const targetTableId = isTransformRunFailed(final.status) ? null : await awaitTargetTableId(id, schedule, options);
2036
- return {
2037
- message: kickoff.message,
2038
- run_id: runId,
2039
- final,
2040
- target_table_id: targetTableId
2041
- };
2042
- }
2043
- async function awaitTargetTableId(id, wait, options) {
2044
- try {
2045
- return linkedTableId(await pollUntil(async (signal) => get(id, {
2046
- ...options,
2047
- signal
2048
- }), (transform) => linkedTableId(transform) !== null, wait));
2049
- } catch (error) {
2050
- if (error instanceof TimeoutError) return null;
2051
- throw error;
2052
- }
2053
- }
2054
- return {
2055
- list,
2056
- get,
2057
- create,
2058
- update,
2059
- delete: remove,
2060
- deleteTable,
2061
- dependencies,
2062
- cancel,
2063
- getRun,
2064
- runPages,
2065
- run
2066
- };
2067
- }
2068
- function linkedTableId(transform) {
2069
- return transform.target_table_id ?? transform.table?.id ?? null;
2070
- }
2071
- //#endregion
2072
- //#region ../client/src/resources/transform-tag.ts
2073
- const TransformTagApiList = z.array(TransformTag);
2074
- function transformTagResource(transport) {
2075
- /** List every transform tag the caller can see, built-in tags included. */
2076
- async function list(options = {}) {
2077
- return {
2078
- data: await transport.requestParsed(TransformTagApiList, "/api/transform-tag", { ...options }),
2079
- total: null
2080
- };
2081
- }
2082
- /** Create a transform tag, the label a transform job matches transforms on. */
2083
- async function create(params, options = {}) {
2084
- return transport.requestParsed(TransformTag, "/api/transform-tag", {
2085
- ...options,
2086
- method: "POST",
2087
- body: params
2088
- });
2089
- }
2090
- /** Rename a transform tag by id. */
2091
- async function update(id, params, options = {}) {
2092
- return transport.requestParsed(TransformTag, `/api/transform-tag/${id}`, {
2093
- ...options,
2094
- method: "PUT",
2095
- body: params
2096
- });
2097
- }
2098
- /** Delete a transform tag by id, detaching it from every transform and job carrying it. */
2099
- async function remove(id, options = {}) {
2100
- await transport.requestRaw(`/api/transform-tag/${id}`, {
2101
- ...options,
2102
- method: "DELETE",
2103
- expectContentType: "binary"
2104
- });
2105
- }
2106
- return {
2107
- list,
2108
- create,
2109
- update,
2110
- delete: remove
2111
- };
2112
- }
2113
- //#endregion
2114
- //#region ../client/src/resources/transform-test.ts
2115
- const TransformTestApiList = z.array(TransformTest);
2116
- function transformTestResource(transport) {
2117
- /** List the transform tests the caller can see, optionally only those of one transform. */
2118
- async function list(params = {}, options = {}) {
2119
- return {
2120
- data: await transport.requestParsed(TransformTestApiList, "/api/transform-test", {
2121
- ...options,
2122
- query: { "transform-id": params["transform-id"] }
2123
- }),
2124
- total: null
2125
- };
2126
- }
2127
- /** Get one transform test by id. */
2128
- async function get(id, options = {}) {
2129
- return transport.requestParsed(TransformTest, `/api/transform-test/${id}`, { ...options });
2130
- }
2131
- /** Create a transform test — the inputs standing in for the transform's source tables, and the expectations checked against its output. */
2132
- async function create(params, options = {}) {
2133
- return transport.requestParsed(TransformTest, "/api/transform-test", {
2134
- ...options,
2135
- method: "POST",
2136
- body: params
2137
- });
2138
- }
2139
- /** Update a transform test by id, patching only the fields the body carries. */
2140
- async function update(id, params, options = {}) {
2141
- return transport.requestParsed(TransformTest, `/api/transform-test/${id}`, {
2142
- ...options,
2143
- method: "PUT",
2144
- body: params
2145
- });
2146
- }
2147
- /** Delete a transform test by id. */
2148
- async function remove(id, options = {}) {
2149
- await transport.requestRaw(`/api/transform-test/${id}`, {
2150
- ...options,
2151
- method: "DELETE",
2152
- expectContentType: "binary"
2153
- });
2154
- }
2155
- /**
2156
- * Run a transform test against temp tables and report what each expectation found. The transform
2157
- * itself never runs against real tables, and a failing expectation is a result rather than an
2158
- * error.
2159
- */
2160
- async function run(id, options = {}) {
2161
- return transport.requestParsed(TransformTestRunResult, `/api/transform-test/${id}/run`, {
2162
- ...options,
2163
- method: "POST"
2164
- });
2165
- }
2166
- return {
2167
- list,
2168
- get,
2169
- create,
2170
- update,
2171
- delete: remove,
2172
- run
2173
- };
2174
- }
2175
- //#endregion
2176
- //#region ../client/src/resources/upload.ts
2177
- const UPLOAD_TABLE_ID_HEADER = "metabase-table-id";
2178
- function uploadResource(transport) {
2179
- /**
2180
- * Create a table and model populated with the values from the attached CSV. Returns the model ID
2181
- * if successful.
2182
- *
2183
- * The file may be at most 50 MB; larger uploads are rejected with a 413 response.
2184
- */
2185
- async function createFromCsv(file, params, options = {}) {
2186
- const form = buildCsvFormData(file);
2187
- form.append("collection_id", params.collection_id);
2188
- const response = await transport.requestRaw("/api/upload/csv", {
2189
- ...options,
2190
- method: "POST",
2191
- body: form,
2192
- expectContentType: "binary"
2193
- });
2194
- return parseCreateUploadResult(await response.text(), response.headers);
2195
- }
2196
- return { createFromCsv };
2197
- }
2198
- function parseCreateUploadResult(bodyText, headers) {
2199
- return UploadResult.parse({
2200
- model_id: parseResponseInteger(bodyText, "response body"),
2201
- table_id: parseResponseInteger(headers.get(UPLOAD_TABLE_ID_HEADER), `${UPLOAD_TABLE_ID_HEADER} header`)
2202
- });
2203
- }
2204
- function parseResponseInteger(value, source) {
2205
- const trimmed = value?.trim() ?? "";
2206
- if (trimmed === "") throw new ResponseShapeError(`upload succeeded but the ${source} was empty`, {
2207
- kind: "decoded",
2208
- source,
2209
- value
2210
- });
2211
- const parsed = Number(trimmed);
2212
- if (!Number.isInteger(parsed)) throw new ResponseShapeError(`upload succeeded but the ${source} was not an integer: ${JSON.stringify(trimmed)}`, {
2213
- kind: "decoded",
2214
- source,
2215
- value
2216
- });
2217
- return parsed;
2218
- }
2219
- //#endregion
2220
- //#region ../client/src/domain/user.ts
2221
- const CurrentUser = z.object({
2222
- id: z.number().int(),
2223
- email: z.email(),
2224
- common_name: z.string(),
2225
- is_superuser: z.boolean()
2226
- }).loose();
2227
- CurrentUser.pick({
2228
- id: true,
2229
- email: true,
2230
- common_name: true,
2231
- is_superuser: true
2232
- }).strip();
2233
- //#endregion
2234
- //#region ../client/src/resources/user.ts
2235
- function userResource(transport) {
2236
- /** Get the user the request's credentials authenticate as. */
2237
- async function current(options = {}) {
2238
- return transport.requestParsed(CurrentUser, "/api/user/current", { ...options });
2239
- }
2240
- return { current };
2241
- }
2242
- //#endregion
2243
- //#region ../client/src/client.ts
2244
- var client_exports = /* @__PURE__ */ __exportAll({ createClient: () => createClient });
2245
- function createClient(config, options) {
2246
- const transport = createTransport(config, options);
2247
- return {
2248
- card: cardResource(transport),
2249
- collection: collectionResource(transport),
2250
- contentTranslation: contentTranslationResource(transport),
2251
- dashboard: dashboardResource(transport),
2252
- database: databaseResource(transport),
2253
- dataset: datasetResource(transport),
2254
- document: documentResource(transport),
2255
- eidTranslation: eidTranslationResource(transport),
2256
- field: fieldResource(transport),
2257
- gitSync: gitSyncResource(transport),
2258
- library: libraryResource(transport),
2259
- measure: measureResource(transport),
2260
- notification: notificationResource(transport),
2261
- pulse: pulseResource(transport),
2262
- search: searchResource(transport),
2263
- segment: segmentResource(transport),
2264
- setting: settingResource(transport),
2265
- setup: setupResource(transport),
2266
- snippet: snippetResource(transport),
2267
- table: tableResource(transport),
2268
- timeline: timelineResource(transport),
2269
- timelineEvent: timelineEventResource(transport),
2270
- transform: transformResource(transport),
2271
- transformJob: transformJobResource(transport),
2272
- transformTag: transformTagResource(transport),
2273
- transformTest: transformTestResource(transport),
2274
- upload: uploadResource(transport),
2275
- user: userResource(transport),
2276
- requestParsed: transport.requestParsed,
2277
- requestRaw: transport.requestRaw,
2278
- requestStream: transport.requestStream
2279
- };
2280
- }
2281
- //#endregion
2282
- export { createClient as n, client_exports as t };