@metabase/cli 0.3.1-alpha.transform-tests.c0bc2d1 → 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 (264) hide show
  1. package/dist/{add-collection-CVDgC7C6.mjs → add-collection-v_uw_8VC.mjs} +6 -9
  2. package/dist/{alert-Co9m8k5l.mjs → alert-2MDhiuxT.mjs} +7 -7
  3. package/dist/{alerts-DjZGGxOy.mjs → alerts-BDoIryWj.mjs} +7 -7
  4. package/dist/{append-BXqeNFzW.mjs → append-CeHVEN3m.mjs} +5 -5
  5. package/dist/{archive-D1xZRRRA.mjs → archive-B9DiDia8.mjs} +6 -6
  6. package/dist/{archive-I61vFPxv.mjs → archive-BMQBzQMw.mjs} +4 -4
  7. package/dist/{archive-CXYUkzZo.mjs → archive-BU3VZ1An.mjs} +5 -5
  8. package/dist/{archive-Csku9zDp.mjs → archive-BopUoNoz.mjs} +4 -4
  9. package/dist/{archive-CH9osnGq.mjs → archive-BuHy5_kr.mjs} +4 -4
  10. package/dist/{archive-Bhk1IqGH.mjs → archive-CVTpSQ0H.mjs} +6 -6
  11. package/dist/{archive-pA5UZn1f.mjs → archive-CYaJZhBs.mjs} +4 -4
  12. package/dist/{archive-CUGpIXDT.mjs → archive-CxzoUCE_.mjs} +6 -6
  13. package/dist/{archive-DvV3oLCg.mjs → archive-D5QNFMmn.mjs} +4 -4
  14. package/dist/{archive-Cchi-tqq.mjs → archive-IBEbIm_S2.mjs} +6 -6
  15. package/dist/{archive-CzcjKpUC.mjs → archive-M2_D7zAj.mjs} +6 -6
  16. package/dist/{auth-BKgMIAKH.mjs → auth-DuGPC1Q0.mjs} +5 -5
  17. package/dist/{body-DxRSAMNC.mjs → body-hAwPMqBg.mjs} +3 -3
  18. package/dist/{branches-B96keFsO.mjs → branches-CIP60haa.mjs} +4 -7
  19. package/dist/{cancel-6GPBlUkr.mjs → cancel-C9hrQ1yg.mjs} +4 -4
  20. package/dist/{cancel-task-BIGAgcKk.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-DY6Togtl.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-Cg_VW3kW.mjs → content-translation-BNYQ8fJ3.mjs} +3 -3
  32. package/dist/{create-DqCdW3tt.mjs → create-BVd4Y4py2.mjs} +6 -6
  33. package/dist/{create-BsDJATJM.mjs → create-BZyLtvg5.mjs} +6 -6
  34. package/dist/{create-BkIoWkzP.mjs → create-BsiUuwSb.mjs} +5 -5
  35. package/dist/{create-cHltWf0e.mjs → create-C1fVgFBd.mjs} +4 -4
  36. package/dist/{create-BxWMTy6i.mjs → create-C4U9DGDG.mjs} +7 -7
  37. package/dist/{create-BpjBffBq.mjs → create-CHn7P-Bz.mjs} +5 -5
  38. package/dist/{create-mzHtey5k.mjs → create-CL4xkZ4j.mjs} +6 -6
  39. package/dist/{create-V2Bdeu8p.mjs → create-CcOTodqT.mjs} +4 -4
  40. package/dist/{create-BeNQQTPt.mjs → create-Cmgq35ZB.mjs} +4 -4
  41. package/dist/{create-JZevXtCI.mjs → create-DPb3b69Y.mjs} +4 -4
  42. package/dist/{create-cSpqEzKH.mjs → create-DRyA-nuP.mjs} +5 -5
  43. package/dist/{create-CK5MABYu.mjs → create-DTfaHMNw.mjs} +6 -6
  44. package/dist/{create-CaDAT54M.mjs → create-Db3QVXRi.mjs} +7 -7
  45. package/dist/{create-D_pNL2X9.mjs → create-DqKDw2zq.mjs} +5 -8
  46. package/dist/{create-bH-qAv03.mjs → create-S0jXAtl2.mjs} +11 -7
  47. package/dist/{create-BuWV1GpI2.mjs → create-Z_gzD_p-2.mjs} +8 -8
  48. package/dist/{create-branch-DN9PrlRR.mjs → create-branch-hYwnfY8X.mjs} +5 -9
  49. package/dist/{csv-CVKLuIuS.mjs → csv-DOEqRG95.mjs} +5 -5
  50. package/dist/{current-task-Dnm3JaWg.mjs → current-task-DVo5aDfA.mjs} +5 -8
  51. package/dist/{dashboard-CKUR8ZpQ.mjs → dashboard-D0hwTC-f.mjs} +11 -2
  52. package/dist/{dashboard-SxUrG3Cg.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-BnhuXAP9.mjs → db-ntq1NYVT.mjs} +7 -7
  57. package/dist/{delete-CH0FsDBg.mjs → delete-BQWk6Ogb.mjs} +5 -5
  58. package/dist/{delete-C3xeqTzS.mjs → delete-C2iVm203.mjs} +5 -5
  59. package/dist/{delete-BClvnlBc.mjs → delete-CPzdQGKf.mjs} +5 -5
  60. package/dist/{delete-Dn6VJuyR.mjs → delete-CW8xJwDm.mjs} +5 -5
  61. package/dist/{delete-DDVNawxh.mjs → delete-CZqaDxkf.mjs} +5 -5
  62. package/dist/{delete-6lroLZIE.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-C6LPzUDg.mjs → delete-table-DLufNvzW.mjs} +5 -5
  65. package/dist/{dependencies-vr51EFIu.mjs → dependencies-BGtd-eIR.mjs} +7 -7
  66. package/dist/{dirty-W0PzG3Yt.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-B-l6ajeo.mjs → download-DrcL0yRr.mjs} +3 -6
  71. package/dist/{eid-BGl_X67N.mjs → eid-Bn3Impnq.mjs} +4 -5
  72. package/dist/{events-BRRnroJb.mjs → events-CfnrXbim.mjs} +5 -5
  73. package/dist/{export-DEPLFq_E.mjs → export-CFK8cMvK.mjs} +7 -10
  74. package/dist/{field-Cr2DPUG9.mjs → field-CcN4oZy6.mjs} +16 -1
  75. package/dist/{field-BXaUzJvx.mjs → field-CeP-41qf.mjs} +5 -5
  76. package/dist/{field-BPsNa-TO.mjs → field-fDtIrY6D.mjs} +1 -1
  77. package/dist/{fields-LFMSMV5Z.mjs → fields-B3tJI4X2.mjs} +7 -7
  78. package/dist/{get-DCf0O3GJ.mjs → get-3ymehUjQ.mjs} +6 -6
  79. package/dist/{get-Du11BNRd.mjs → get-B9fPTBEQ.mjs} +5 -8
  80. package/dist/{get-B6lWlGeD.mjs → get-BFh5ctuV.mjs} +6 -6
  81. package/dist/{get-XcSH5Zyz.mjs → get-BMZ3UoJz.mjs} +6 -6
  82. package/dist/{get-DvCgLmPW.mjs → get-Be9oShms.mjs} +4 -4
  83. package/dist/{get-BempHTsm.mjs → get-BkTiIo_7.mjs} +4 -4
  84. package/dist/{get-M3zgKoZr.mjs → get-C-E-I10i.mjs} +6 -6
  85. package/dist/{get-DiRtfImy.mjs → get-CIlXE4zy.mjs} +6 -6
  86. package/dist/{get-7-OiP8ma.mjs → get-Cqfb4zZM.mjs} +4 -4
  87. package/dist/{get-DhxE02Ia.mjs → get-Cxvi9pSj.mjs} +6 -6
  88. package/dist/{get-DAsSPKxF.mjs → get-D2Bt3r3M.mjs} +4 -4
  89. package/dist/{get-DCHhq5Qv.mjs → get-DJDV3NMU.mjs} +5 -5
  90. package/dist/{get-BvI5QqjY.mjs → get-D_f0INnl.mjs} +6 -6
  91. package/dist/{get-CapP9GiI.mjs → get-Diozf-D0.mjs} +6 -6
  92. package/dist/{get-BM7MA5-7.mjs → get-Dl9WoeCd.mjs} +4 -4
  93. package/dist/{get-Bjvu5GM7.mjs → get-DlPhNHPX.mjs} +6 -6
  94. package/dist/{get-Cjx_5Zm-.mjs → get-DnVGJfW42.mjs} +6 -6
  95. package/dist/get-Dx4k6_Qt.mjs +93 -0
  96. package/dist/{get-DlQHyv4D.mjs → get-lRUl1Dnb.mjs} +4 -4
  97. package/dist/{get-C2DWxXYb.mjs → get-pGqPQ0Of.mjs} +6 -6
  98. package/dist/{get-run-UJmyRo7H.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-DmhFpgJe.mjs → has-remote-changes-BS6jOb2-.mjs} +5 -8
  104. package/dist/{import-BRC0TzWQ.mjs → import-Cur2I6Yc.mjs} +7 -10
  105. package/dist/{input-DH9i67x_.mjs → input-DEvkIjGr.mjs} +1 -1
  106. package/dist/{is-dirty-CT9e5vSd.mjs → is-dirty-7Jo0tglq.mjs} +3 -6
  107. package/dist/{items-BSAEWZlw.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-Zxh_MRVL.mjs → library-CpDosMc5.mjs} +5 -5
  111. package/dist/{library-DfYAT2Ep.mjs → library-PGCfm0UA.mjs} +1 -1
  112. package/dist/{list-DDFk1IFP.mjs → list--Frwwg4i.mjs} +7 -7
  113. package/dist/{list-C3IRtLP6.mjs → list-40V_8T3H.mjs} +4 -4
  114. package/dist/{list-DGLK2lso.mjs → list-BAO7rPNU.mjs} +4 -4
  115. package/dist/{list-QFieRzSf.mjs → list-BAaBsdMk.mjs} +6 -6
  116. package/dist/{list-08dyODsP.mjs → list-BCD9lkxc.mjs} +4 -4
  117. package/dist/{list-CAalCea_.mjs → list-BuZaFlV-.mjs} +4 -4
  118. package/dist/{list-BOUmEn2X.mjs → list-C7kqJAc8.mjs} +4 -4
  119. package/dist/{list-D6qH2PUE.mjs → list-CBGsfTib.mjs} +7 -7
  120. package/dist/{list-DCA0T8bS.mjs → list-CFJyXUsF.mjs} +14 -13
  121. package/dist/{list-De0ebgzc.mjs → list-CQJoLqy0.mjs} +7 -7
  122. package/dist/{list-Dqyd2TZI.mjs → list-CVs3TyU7.mjs} +6 -6
  123. package/dist/{list-Drm6l_tt.mjs → list-CX2668xz.mjs} +6 -6
  124. package/dist/{list-DCBLu0KG.mjs → list-CcyZu5Jp.mjs} +6 -6
  125. package/dist/{list-D9RmPIEJ.mjs → list-DPvJihmj.mjs} +7 -7
  126. package/dist/{list-CleMHJBY.mjs → list-D_Kv8Ezq.mjs} +7 -7
  127. package/dist/{list-BZbC260R.mjs → list-DuZlYCTl.mjs} +5 -5
  128. package/dist/{list-BxCk3QTy.mjs → list-_6JwpPXA.mjs} +6 -6
  129. package/dist/{list-DYlphSxV.mjs → list-bCtszwHJ.mjs} +4 -4
  130. package/dist/list-rojRNBu5.mjs +60 -0
  131. package/dist/{login-DDHEyjWz.mjs → login-BCxYB6ii.mjs} +15 -12
  132. package/dist/{logout-BbB0vvQN.mjs → logout-BVEYg9pV.mjs} +3 -4
  133. package/dist/{measure-CGuwA0KX.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-CI6-CkB7.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-CdZ0-1TM.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-Df2itv7t.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-xUBySB1T.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-BkZvffIM.mjs → query-B8MCziCM.mjs} +9 -10
  148. package/dist/{query-CmkC8sfu.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-DFfmuTwD.mjs → remove-collection-CNWmp8C-.mjs} +6 -9
  151. package/dist/{render-CI93iP0I.mjs → render-MoT089RO.mjs} +13 -2
  152. package/dist/{replace-DjoDBCLa.mjs → replace-DOmUXCyk.mjs} +5 -5
  153. package/dist/{rescan-values-Ca2Wa0A2.mjs → rescan-values-DpU_Ex0F.mjs} +6 -6
  154. package/dist/{run-B_-pMw67.mjs → run-B8Vys-6V.mjs} +5 -5
  155. package/dist/{run-BCYATTjE.mjs → run-CCPUWI0V.mjs} +6 -6
  156. package/dist/{run-CP-chc5O.mjs → run-cyUFpMX3.mjs} +26 -14
  157. package/dist/{runs-B0ypYKmn.mjs → runs-92XSK8ij.mjs} +7 -7
  158. package/dist/{runtime-CJUDVwBu.mjs → runtime-DzVkvFHY.mjs} +946 -246
  159. package/dist/{schema-tables-Nl83e2Zm.mjs → schema-tables-lMGk2fyi.mjs} +7 -7
  160. package/dist/{schemas-Cp29qgn0.mjs → schemas-C83Q8dYY.mjs} +5 -5
  161. package/dist/{search-DFBwUc6d.mjs → search-BAXg-EJw.mjs} +2 -1
  162. package/dist/{search-BbktlnDC.mjs → search-D6qBaNsw.mjs} +6 -6
  163. package/dist/{segment-BHBoMpL9.mjs → segment-BFJd2-ck.mjs} +6 -6
  164. package/dist/{selectors-e_0QdkaG.mjs → selectors-Dcp25rNo.mjs} +3 -3
  165. package/dist/{send-DEGpBT_7.mjs → send-Be-_KmWr.mjs} +4 -4
  166. package/dist/{set-C3tLEVuY.mjs → set-Bg_4elCb.mjs} +5 -5
  167. package/dist/{set-active-CqvLJysE.mjs → set-active-CtQiMzt7.mjs} +5 -5
  168. package/dist/{setting-Dwi-Wifx.mjs → setting-BNEblMco.mjs} +4 -4
  169. package/dist/{setup-CcSVPnEI.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-Cxi3fKMZ.mjs → skills-CGYk6b2r.mjs} +3 -3
  174. package/dist/snippet-vMnFtNwi.mjs +19 -0
  175. package/dist/{stash-CVhkyRIT.mjs → stash-C9SZwusp.mjs} +7 -11
  176. package/dist/{status-B7tYgPVV.mjs → status-D0n7AuQU.mjs} +12 -11
  177. package/dist/{status-C9uhZuip.mjs → status-Dj04FCCv.mjs} +11 -9
  178. package/dist/{subscription-Cj9jyFEB.mjs → subscription-B5Iax7Ci.mjs} +6 -6
  179. package/dist/{subscriptions-B5oVkkZk.mjs → subscriptions-DwvHRO1v.mjs} +7 -7
  180. package/dist/{summary-PVERfPr2.mjs → summary-DaA6Twxk.mjs} +6 -6
  181. package/dist/{sync-schema-CtG6r6Pr.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-6IHwQyr6.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-ox_Bw9F4.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-La1wmOTP.mjs → transform-tag-CbgjSy76.mjs} +5 -5
  195. package/dist/{transform-test-w5hDTx_D.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-DIgACzP-.mjs → transforms-Bhtk_Gil.mjs} +7 -7
  199. package/dist/{tree-CQ0FXBnn.mjs → tree-DLorrdEm.mjs} +4 -5
  200. package/dist/{unpublish-Binr4uOG.mjs → unpublish-DOQhmLAx.mjs} +4 -7
  201. package/dist/{update-lpLLpKhX.mjs → update-BF4DWRT5.mjs} +6 -6
  202. package/dist/{update-BKvSfdXu.mjs → update-BeU02D8b.mjs} +6 -6
  203. package/dist/{update-B4lIwY0G.mjs → update-Bpb2V8Gm.mjs} +9 -9
  204. package/dist/{update-BZS5m-vx.mjs → update-CHNSRFKO.mjs} +7 -7
  205. package/dist/{update-DH9CL61y.mjs → update-CSqPKfTk.mjs} +8 -8
  206. package/dist/{update-mOqedkLk.mjs → update-CTCcgeaY.mjs} +7 -7
  207. package/dist/{update-BiG9eLNH.mjs → update-Ch43eYU-.mjs} +5 -5
  208. package/dist/{update-CIuoW1M9.mjs → update-D2dis8s_.mjs} +8 -8
  209. package/dist/{update-CWIhy9Ax.mjs → update-DEULsCgK.mjs} +6 -6
  210. package/dist/{update-Db3j44fi.mjs → update-DTZ07XFM.mjs} +5 -5
  211. package/dist/{update-BbOX6axn.mjs → update-DWhC3xYc.mjs} +5 -5
  212. package/dist/{update-Cb68f4dx.mjs → update-DeA4gyTG.mjs} +5 -5
  213. package/dist/{update-la0K6wAf.mjs → update-Dq-KEeyS.mjs} +7 -7
  214. package/dist/{update-dashcard-DbZ8NlLZ.mjs → update-dashcard-CfDqxOlj.mjs} +7 -7
  215. package/dist/{update-gGZjfZN3.mjs → update-ezD5XTpy.mjs} +7 -7
  216. package/dist/{update-B5NYEIHU.mjs → update-mmeImeUo.mjs} +7 -7
  217. package/dist/{update-TDaf7Xbt.mjs → update-xjuN7bdu.mjs} +7 -7
  218. package/dist/{upgrade-BCWXgRmG.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-DUViVk1x.mjs → upload-DzFBdNxM.mjs} +4 -7
  222. package/dist/{uuid-D3CGL8wF.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-8XUr04w3.mjs → values-Dk2CAR4T.mjs} +6 -6
  226. package/dist/{verify-deF_hThH.mjs → verify-8TnYrSNm.mjs} +3 -18
  227. package/dist/{wait-Ct0weHol.mjs → wait-Oz6xFpyA.mjs} +7 -10
  228. package/dist/{wait-flags-Cb-bI0RD.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 +19 -4
  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 +17 -3
  243. package/skill-data/transform-test-plan/SKILL.md +1 -0
  244. package/skill-data/visualization/SKILL.md +11 -3
  245. package/skill-data/visualization/references/settings.md +6 -4
  246. package/skills/metabase-cli/SKILL.md +1 -1
  247. package/dist/card-zluRR7xD.mjs +0 -24
  248. package/dist/client-C9HBWl6A.mjs +0 -2282
  249. package/dist/collection-CrIkQWUK.mjs +0 -20
  250. package/dist/document-B1w9aIq7.mjs +0 -19
  251. package/dist/get-BUiHdwdU.mjs +0 -80
  252. package/dist/git-sync-DM5Nuv3a.mjs +0 -28
  253. package/dist/library-ClLgrAXy.mjs +0 -19
  254. package/dist/list-kIMBSzS-.mjs +0 -98
  255. package/dist/network-error-D6CiOEBw.mjs +0 -431
  256. package/dist/predicates-Bkm2IoeX.mjs +0 -170
  257. package/dist/skills-DTCrMcix.mjs +0 -216
  258. package/dist/snippet-hrEAI5Yf.mjs +0 -19
  259. package/dist/timeline-BwQIj-le.mjs +0 -21
  260. package/dist/transform-IPKGUzzd.mjs +0 -28
  261. package/dist/transform-job-COwH1ww7.mjs +0 -22
  262. package/dist/transform-test-C4VRGmGm.mjs +0 -149
  263. package/dist/transform-test-DGYx6MCT.mjs +0 -16
  264. package/dist/upload-BVBs2F69.mjs +0 -13
@@ -1,9 +1,6 @@
1
- import { d as ValidationError, f as errorMessage, i as ConfigError, l as TimeoutError, o as MetabaseError, p as isFileNotFoundError } from "./predicates-Bkm2IoeX.mjs";
2
- import { B as normalizeFlag, D as consumeLegacyEnvWarnings, E as ENV_URL, O as readEnv, S as ENV_DISABLE_KEYRING, T as ENV_SKIP_PREFLIGHT, V as toAliasArray, a as reportError, b as warn, i as mergeCapabilities, j as version, k as setMetabaseAugment, n as BASELINE_CAPABILITIES, r as checkCapabilities, t as interruptSignal, x as ENV_API_KEY, z as flagConsumesValue } from "./cli.mjs";
3
- import { _ as parseJsonResult, a as isRetryableStatus, c as normalizeUrl, f as isOAuthExpired, m as JSON_CONTENT_TYPE, o as assertEndpointOrigin, p as oauthCredentialFromTokens, r as HttpError, t as buildNetworkError } from "./network-error-D6CiOEBw.mjs";
1
+ import { D as ENV_API_KEY, E as warn, F as ProfileRefreshedError, I as setMetabaseAugment, J as normalizeFlag, M as ENV_URL, N as consumeLegacyEnvWarnings, O as ENV_DISABLE_KEYRING, P as readEnv, Q as ConfigError, R as version, Y as toAliasArray, Z as ChainedRequestError, a as Features, at as ValidationError, b as isPlainObject, c as ruleGap, ct as KNOWN_RANGE, et as MetabaseError, i as FEATURE_RULES, j as ENV_SKIP_PREFLIGHT, l as reportError, n as methodRequirements, nt as ResponseShapeError, o as evaluateFeatures, ot as errorMessage, q as flagConsumesValue, r as FEATURE_NAMES, rt as TimeoutError, st as isFileNotFoundError, t as interruptSignal, tt as NetworkError } from "./cli.mjs";
4
2
  import { defineCommand } from "citty";
5
3
  import { z } from "zod";
6
- import { parse } from "semver";
7
4
  import { Entry } from "@napi-rs/keyring";
8
5
  import { promises } from "node:fs";
9
6
  import { dirname, join } from "node:path";
@@ -23,6 +20,21 @@ function parseOptionalInteger(value, options) {
23
20
  }
24
21
  //#endregion
25
22
  //#region ../client/src/version/preflight-error.ts
23
+ const RequirementReason = z.enum(["version-too-old", "missing-token-feature"]);
24
+ const RequirementFailure = z.object({
25
+ reason: RequirementReason,
26
+ detail: z.string(),
27
+ feature: z.enum(FEATURE_NAMES),
28
+ since: z.number().int(),
29
+ tokenFeature: z.string().nullable(),
30
+ serverVersion: z.string().nullable()
31
+ });
32
+ function versionTooOldMessage(since, serverVersion) {
33
+ return `This operation requires Metabase v${since}+ (${serverVersion === null ? "this server's version is unknown" : `this server is ${serverVersion}`}). Upgrade Metabase to use it.`;
34
+ }
35
+ function missingTokenFeatureMessage(tokenFeature) {
36
+ return `This operation requires the '${tokenFeature}' premium feature (not enabled on this server).`;
37
+ }
26
38
  var CapabilityError = class extends MetabaseError {
27
39
  category = "capability";
28
40
  isRetryable = false;
@@ -52,18 +64,842 @@ const ParsedVersion = z.object({
52
64
  major: z.number().int().nonnegative(),
53
65
  patch: z.number().int().nonnegative()
54
66
  });
55
- const DEV_BUILD_SUFFIX = "-SNAPSHOT";
67
+ const Edition = z.enum(["oss", "ee"]);
68
+ const TAG = /^v?([01])\.(\d+)\.(\d+)(?:\.\d+)?(?:-([0-9A-Za-z.-]+))?$/;
69
+ const OSS_EDITION_NUMBER = "0";
70
+ const DEV_BUILD_SUFFIX = "SNAPSHOT";
71
+ function tagParts(tag) {
72
+ const match = TAG.exec(tag);
73
+ if (match === null) return null;
74
+ const [, editionNumber, major, patch, prerelease] = match;
75
+ if (editionNumber === void 0 || major === void 0 || patch === void 0) return null;
76
+ return {
77
+ edition: editionNumber === OSS_EDITION_NUMBER ? "oss" : "ee",
78
+ major: Number(major),
79
+ patch: Number(patch),
80
+ prerelease: prerelease ?? null
81
+ };
82
+ }
56
83
  function tryParseTag(tag) {
57
- if (tag.endsWith(DEV_BUILD_SUFFIX)) return null;
58
- const parsed = parse(tag);
59
- if (parsed === null || parsed.major !== 0 && parsed.major !== 1) return null;
84
+ const parts = tagParts(tag);
85
+ if (parts === null || parts.prerelease === DEV_BUILD_SUFFIX) return null;
60
86
  return {
61
87
  tag,
62
- major: parsed.minor,
63
- patch: parsed.patch
88
+ major: parts.major,
89
+ patch: parts.patch
90
+ };
91
+ }
92
+ function editionFromTag(tag) {
93
+ const parts = tagParts(tag);
94
+ return parts === null ? null : parts.edition;
95
+ }
96
+ //#endregion
97
+ //#region ../client/src/version/probe.ts
98
+ const PROBE_PATH = "/api/session/properties";
99
+ const PROBE_TIMEOUT_MS = 1e4;
100
+ async function probeServer(client, opts = {}) {
101
+ const properties = await client.requestParsed(SessionProperties, PROBE_PATH, {
102
+ timeoutMs: PROBE_TIMEOUT_MS,
103
+ retries: opts.retries ?? 0
104
+ });
105
+ const { tag } = properties.version;
106
+ return {
107
+ version: tryParseTag(tag),
108
+ edition: editionFromTag(tag),
109
+ date: properties.version.date ?? null,
110
+ hash: properties.version.hash ?? null,
111
+ tokenFeatures: properties["token-features"] ?? null
112
+ };
113
+ }
114
+ //#endregion
115
+ //#region ../client/src/version/profile.ts
116
+ const Skew = z.enum([
117
+ "supported",
118
+ "older-than-known",
119
+ "newer-than-known",
120
+ "unknown"
121
+ ]);
122
+ z.object({
123
+ version: ParsedVersion.nullable(),
124
+ buildDate: z.string().nullable(),
125
+ hash: z.string().nullable(),
126
+ edition: Edition,
127
+ tokenFeatures: TokenFeatures.nullable(),
128
+ features: Features,
129
+ skew: Skew
130
+ });
131
+ function createServerProfile(info) {
132
+ const placement = place(info.version);
133
+ return {
134
+ version: info.version,
135
+ buildDate: info.date,
136
+ hash: info.hash,
137
+ edition: detectEdition(info),
138
+ tokenFeatures: info.tokenFeatures,
139
+ features: evaluateFeatures(placement.effectiveMajor, info.tokenFeatures),
140
+ skew: placement.skew
141
+ };
142
+ }
143
+ function featureGap(profile, feature) {
144
+ const placement = place(profile.version);
145
+ return ruleGap(FEATURE_RULES[feature], placement.effectiveMajor, profile.tokenFeatures);
146
+ }
147
+ function place(version) {
148
+ if (version === null) return {
149
+ effectiveMajor: KNOWN_RANGE.max + 1,
150
+ skew: "unknown"
151
+ };
152
+ if (version.major > KNOWN_RANGE.max) return {
153
+ effectiveMajor: KNOWN_RANGE.max + 1,
154
+ skew: "newer-than-known"
155
+ };
156
+ if (version.major < KNOWN_RANGE.min) return {
157
+ effectiveMajor: version.major,
158
+ skew: "older-than-known"
159
+ };
160
+ return {
161
+ effectiveMajor: version.major,
162
+ skew: "supported"
163
+ };
164
+ }
165
+ function detectEdition(info) {
166
+ if (info.edition !== null) return info.edition;
167
+ return grantsAnyFeature(info.tokenFeatures) ? "ee" : "oss";
168
+ }
169
+ function grantsAnyFeature(tokenFeatures) {
170
+ return tokenFeatures !== null && Object.values(tokenFeatures).some((enabled) => enabled);
171
+ }
172
+ //#endregion
173
+ //#region ../client/src/version/requirement-check.ts
174
+ /** The first of `features` the profile lacks, or `null` when it has every one. */
175
+ function checkFeatures(features, profile) {
176
+ for (const feature of features) {
177
+ const gap = featureGap(profile, feature);
178
+ if (gap !== null) return describeGap(gap, feature, profile);
179
+ }
180
+ return null;
181
+ }
182
+ function describeGap(gap, feature, profile) {
183
+ const rule = FEATURE_RULES[feature];
184
+ const serverVersion = profile.version === null ? null : profile.version.tag;
185
+ const tokenFeature = rule.tokenFeature ?? null;
186
+ if (gap.kind === "token") return {
187
+ reason: "missing-token-feature",
188
+ detail: missingTokenFeatureMessage(gap.tokenFeature),
189
+ feature,
190
+ since: rule.since,
191
+ tokenFeature,
192
+ serverVersion
193
+ };
194
+ return {
195
+ reason: "version-too-old",
196
+ detail: versionTooOldMessage(rule.since, serverVersion),
197
+ feature,
198
+ since: rule.since,
199
+ tokenFeature,
200
+ serverVersion
201
+ };
202
+ }
203
+ //#endregion
204
+ //#region src/core/auth/server-summary.ts
205
+ const KnownRange = z.object({
206
+ min: z.number().int(),
207
+ max: z.number().int()
208
+ });
209
+ const ServerSummary = z.object({
210
+ version: ParsedVersion.nullable(),
211
+ edition: Edition.nullable(),
212
+ skew: Skew.nullable(),
213
+ knownRange: KnownRange,
214
+ tokenFeatures: TokenFeatures.nullable(),
215
+ features: Features.nullable()
216
+ });
217
+ function summarizeServer(info) {
218
+ if (info === null) return {
219
+ version: null,
220
+ edition: null,
221
+ skew: null,
222
+ knownRange: KNOWN_RANGE,
223
+ tokenFeatures: null,
224
+ features: null
225
+ };
226
+ const profile = createServerProfile(info);
227
+ return {
228
+ version: profile.version,
229
+ edition: profile.edition,
230
+ skew: profile.skew,
231
+ knownRange: KNOWN_RANGE,
232
+ tokenFeatures: profile.tokenFeatures,
233
+ features: profile.features
234
+ };
235
+ }
236
+ const UNPARSEABLE_VERSION_LABEL = "an unparseable version";
237
+ function versionLabel(version) {
238
+ return version === null ? UNPARSEABLE_VERSION_LABEL : version.tag;
239
+ }
240
+ function skewNotice(profile) {
241
+ const { min, max } = KNOWN_RANGE;
242
+ switch (profile.skew) {
243
+ case "supported": return null;
244
+ case "older-than-known": return `Metabase ${versionLabel(profile.version)} is older than this CLI supports (v${min}+); commands needing a newer feature are refused by name. Upgrade Metabase to v${min} or later.`;
245
+ case "newer-than-known": return `Metabase ${versionLabel(profile.version)} is newer than this CLI supports (up to v${max}); commands run as if it were a head build past v${max}. Run \`mb upgrade\` for a newer CLI.`;
246
+ case "unknown": return `Could not parse the Metabase version; assuming a head build past v${max}.`;
247
+ }
248
+ }
249
+ const PROFILE_REFRESHED_REMEDY = "the profile was refreshed — retry the command.";
250
+ function serverChangeNote(cached, fresh) {
251
+ const before = versionLabel(cached.version);
252
+ const after = versionLabel(fresh.version);
253
+ if (before !== after) return `The server's version changed since the last probe (was ${before}, now ${after}); ${PROFILE_REFRESHED_REMEDY}`;
254
+ if (!sameTokenFeatures(cached.tokenFeatures, fresh.tokenFeatures)) return `The server's premium features changed since the last probe; ${PROFILE_REFRESHED_REMEDY}`;
255
+ return null;
256
+ }
257
+ function sameTokenFeatures(a, b) {
258
+ const grantedA = grantedFeatures(a);
259
+ const grantedB = grantedFeatures(b);
260
+ return grantedA.length === grantedB.length && grantedA.every((key, i) => key === grantedB[i]);
261
+ }
262
+ function grantedFeatures(features) {
263
+ if (features === null) return [];
264
+ return Object.keys(features).filter((key) => features[key] === true).toSorted();
265
+ }
266
+ //#endregion
267
+ //#region ../client/src/url.ts
268
+ function normalizeUrl(input) {
269
+ const trimmed = input.trim().replace(/\/+$/, "");
270
+ if (!/^https?:\/\//i.test(trimmed)) throw new ConfigError("URL must start with http:// or https://");
271
+ return trimmed;
272
+ }
273
+ function displayUrl(input) {
274
+ const parsed = new URL(input);
275
+ const path = parsed.pathname.replace(/\/+$/, "");
276
+ return `${parsed.origin}${path}`;
277
+ }
278
+ const LOOPBACK_HOSTS = /* @__PURE__ */ new Set([
279
+ "localhost",
280
+ "127.0.0.1",
281
+ "::1",
282
+ "[::1]"
283
+ ]);
284
+ function isLoopbackHost(hostname) {
285
+ return LOOPBACK_HOSTS.has(hostname.toLowerCase());
286
+ }
287
+ function assertEndpointOrigin(endpoint, baseUrl, label) {
288
+ let parsed;
289
+ try {
290
+ parsed = new URL(endpoint);
291
+ } catch {
292
+ throw new ConfigError(`OAuth ${label} is not a valid URL: ${endpoint}`);
293
+ }
294
+ const base = new URL(baseUrl);
295
+ if (parsed.protocol !== "https:" && !isLoopbackHost(parsed.hostname)) throw new ConfigError(`OAuth ${label} must use https: ${endpoint}`);
296
+ if (parsed.origin !== base.origin) throw new ConfigError(`OAuth ${label} origin (${parsed.origin}) does not match the Metabase URL (${base.origin})`);
297
+ }
298
+ //#endregion
299
+ //#region ../client/src/auth/credential.ts
300
+ const API_KEY_HEADER = "x-api-key";
301
+ const AUTHORIZATION_HEADER = "authorization";
302
+ const BEARER_PREFIX = "Bearer ";
303
+ const EXPIRY_SKEW_MS = 6e4;
304
+ function credentialAuthHeader(credential) {
305
+ if (credential.kind === "apiKey") return {
306
+ name: API_KEY_HEADER,
307
+ value: credential.apiKey
308
+ };
309
+ return {
310
+ name: AUTHORIZATION_HEADER,
311
+ value: BEARER_PREFIX + credential.accessToken
312
+ };
313
+ }
314
+ const MAX_HEADER_CODE_UNIT = 255;
315
+ function headerBearingSecret(credential) {
316
+ if (credential.kind === "apiKey") return {
317
+ field: "apiKey",
318
+ value: credential.apiKey
319
+ };
320
+ return {
321
+ field: "accessToken",
322
+ value: credential.accessToken
323
+ };
324
+ }
325
+ function assertCredentialHeaderSafe(credential) {
326
+ const { field, value } = headerBearingSecret(credential);
327
+ for (let index = 0; index < value.length; index += 1) {
328
+ const codeUnit = value.charCodeAt(index);
329
+ if (codeUnit > MAX_HEADER_CODE_UNIT) {
330
+ const codePoint = codeUnit.toString(16).toUpperCase().padStart(4, "0");
331
+ throw new ConfigError(`Credential field "${field}" has a character at index ${index} (U+${codePoint}) that cannot be sent in an HTTP header. Header values are limited to Latin-1; a smart quote, ellipsis, or dash substituted during copy-paste is the usual cause.`);
332
+ }
333
+ }
334
+ }
335
+ function credentialSecrets(credential) {
336
+ if (credential.kind === "apiKey") return [credential.apiKey];
337
+ return [credential.accessToken, credential.refreshToken];
338
+ }
339
+ function isOAuthExpired(credential, nowMs) {
340
+ const expiryMs = Date.parse(credential.expiresAt);
341
+ if (Number.isNaN(expiryMs)) return true;
342
+ return expiryMs - EXPIRY_SKEW_MS <= nowMs;
343
+ }
344
+ function expiresAtFromNow(expiresInSeconds, nowMs) {
345
+ return new Date(nowMs + expiresInSeconds * 1e3).toISOString();
346
+ }
347
+ function oauthCredentialFromTokens(tokens, refreshToken, clientId, nowMs) {
348
+ return {
349
+ kind: "oauth",
350
+ accessToken: tokens.access_token,
351
+ refreshToken,
352
+ expiresAt: expiresAtFromNow(tokens.expires_in ?? 3600, nowMs),
353
+ clientId
354
+ };
355
+ }
356
+ //#endregion
357
+ //#region ../client/src/json.ts
358
+ const JSON_CONTENT_TYPE = "application/json";
359
+ function parseJson(input, schema, opts = {}) {
360
+ const result = parseJsonResult(input, schema, opts);
361
+ if (!result.ok) throw result.error;
362
+ return result.value;
363
+ }
364
+ function parseJsonResult(input, schema, opts = {}) {
365
+ const sourcePrefix = opts.source === void 0 ? "" : `${opts.source}: `;
366
+ let raw;
367
+ try {
368
+ raw = JSON.parse(input);
369
+ } catch (error) {
370
+ return {
371
+ ok: false,
372
+ error: new ConfigError(`${sourcePrefix}invalid JSON: ${errorMessage(error)}`)
373
+ };
374
+ }
375
+ const parsed = schema.safeParse(raw);
376
+ if (!parsed.success) return {
377
+ ok: false,
378
+ error: new ValidationError(`${sourcePrefix}value did not match expected schema`, {
379
+ source: opts.source ?? "<input>",
380
+ zodIssues: parsed.error.issues
381
+ })
382
+ };
383
+ return {
384
+ ok: true,
385
+ value: parsed.data
386
+ };
387
+ }
388
+ function parseJsonOrPlain(text, contentType, schema, opts = {}) {
389
+ if (!isJsonContentType(contentType)) return parseJson(JSON.stringify(text), schema, opts);
390
+ const attempt = parseJsonResult(text, schema, opts);
391
+ if (attempt.ok) return attempt.value;
392
+ if (attempt.error instanceof ValidationError) throw attempt.error;
393
+ return parseJson(JSON.stringify(text), schema, opts);
394
+ }
395
+ function isJsonContentType(contentType) {
396
+ return contentType !== null && contentType.includes("application/json");
397
+ }
398
+ //#endregion
399
+ //#region ../client/src/http/sanitize.ts
400
+ const SECRET_HEADER_NAMES = /* @__PURE__ */ new Set([
401
+ "authorization",
402
+ "x-api-key",
403
+ "x-metabase-session",
404
+ "cookie",
405
+ "set-cookie",
406
+ "proxy-authorization"
407
+ ]);
408
+ const REDACTED = "[REDACTED]";
409
+ function redactHeaders(headers) {
410
+ const result = {};
411
+ const entries = headers instanceof Headers ? headers.entries() : Object.entries(headers);
412
+ for (const [key, value] of entries) result[key] = SECRET_HEADER_NAMES.has(key.toLowerCase()) ? REDACTED : value;
413
+ return result;
414
+ }
415
+ function redactBody(body, ctx) {
416
+ let result = body;
417
+ for (const secret of ctx.knownSecrets) {
418
+ if (secret.length === 0) continue;
419
+ result = result.replaceAll(secret, REDACTED);
420
+ }
421
+ return result;
422
+ }
423
+ //#endregion
424
+ //#region ../client/src/http/errors.ts
425
+ const NOT_FOUND_STATUS = 404;
426
+ const TEXT_CONTENT_TYPE = "text/plain";
427
+ const ROUTE_MISSING_LITERAL = "API endpoint does not exist.";
428
+ const RESOURCE_MISSING_LITERAL = "Not found.";
429
+ const STATUS_CLASSIFICATIONS = {
430
+ 401: { retryable: false },
431
+ 403: { retryable: false },
432
+ 404: { retryable: false },
433
+ 408: {
434
+ retryable: true,
435
+ message: "Metabase timed out responding."
436
+ },
437
+ 425: { retryable: true },
438
+ 429: {
439
+ retryable: true,
440
+ message: "Metabase rate-limited the request."
441
+ },
442
+ 500: { retryable: true },
443
+ 502: { retryable: true },
444
+ 503: { retryable: true },
445
+ 504: {
446
+ retryable: true,
447
+ message: "Metabase timed out responding."
448
+ }
449
+ };
450
+ const ErrorEnvelope = z.object({
451
+ message: z.string().optional(),
452
+ error: z.string().optional(),
453
+ "error-message": z.string().optional(),
454
+ via: z.array(z.object({ message: z.string().optional() }).loose()).optional(),
455
+ "specific-errors": z.unknown().optional(),
456
+ errors: z.unknown().optional(),
457
+ "error-code": z.string().optional()
458
+ }).loose();
459
+ const FieldErrorNodeSchema = z.lazy(() => z.union([
460
+ z.string(),
461
+ z.array(z.string()),
462
+ z.record(z.string(), FieldErrorNodeSchema)
463
+ ]));
464
+ const FieldErrorTree = z.record(z.string(), FieldErrorNodeSchema);
465
+ const FIELD_MESSAGE_SEPARATOR = "; ";
466
+ const MAX_EXTRACTED_MESSAGE_LEN = 500;
467
+ const ELLIPSIS = "…";
468
+ var HttpError = class extends MetabaseError {
469
+ category = "http";
470
+ status;
471
+ kind;
472
+ developerDetail;
473
+ constructor(input) {
474
+ const sanitizedBody = sanitizeBody(input.rawBody, input.redactionContext);
475
+ const redactedHeaders = redactHeaders(input.responseHeaders);
476
+ const kind = classifyKind(input.status, sanitizedBody, redactedHeaders);
477
+ super(input.overrideUserMessage ?? buildUserMessage(kind, input, sanitizedBody, redactedHeaders));
478
+ const fields = extractEnvelopeViews(sanitizedBody);
479
+ this.name = "HttpError";
480
+ this.status = input.status;
481
+ this.kind = kind;
482
+ this.developerDetail = {
483
+ status: input.status,
484
+ statusText: input.statusText,
485
+ method: input.method,
486
+ url: input.url,
487
+ responseHeaders: redactedHeaders,
488
+ body: sanitizedBody,
489
+ fieldErrors: fields.fieldErrors,
490
+ specificFieldErrors: fields.specificFieldErrors,
491
+ errorCode: fields.errorCode
492
+ };
493
+ }
494
+ get isRetryable() {
495
+ return isRetryableStatus(this.status);
496
+ }
497
+ get fieldErrors() {
498
+ return this.developerDetail.fieldErrors;
499
+ }
500
+ get specificFieldErrors() {
501
+ return this.developerDetail.specificFieldErrors;
502
+ }
503
+ get errorCode() {
504
+ return this.developerDetail.errorCode;
505
+ }
506
+ };
507
+ function chainRequestFailure(cause, message) {
508
+ if (cause instanceof HttpError) return new HttpError({
509
+ status: cause.status,
510
+ statusText: cause.developerDetail.statusText,
511
+ method: cause.developerDetail.method,
512
+ url: cause.developerDetail.url,
513
+ responseHeaders: cause.developerDetail.responseHeaders,
514
+ rawBody: cause.developerDetail.body,
515
+ overrideUserMessage: message
516
+ });
517
+ return new ChainedRequestError(message, cause);
518
+ }
519
+ function isRetryableStatus(status) {
520
+ return STATUS_CLASSIFICATIONS[status]?.retryable === true;
521
+ }
522
+ function sanitizeBody(rawBody, ctx) {
523
+ if (rawBody === null) return null;
524
+ if (ctx === void 0) return rawBody;
525
+ return redactBody(rawBody, ctx);
526
+ }
527
+ function classifyKind(status, sanitizedBody, redactedHeaders) {
528
+ if (status === 401 || status === 403) return "auth";
529
+ if (status === NOT_FOUND_STATUS) return isRouteMissingResponse(sanitizedBody, redactedHeaders) ? "route-missing" : "resource-missing";
530
+ if (status === 429) return "rate-limit";
531
+ if (status >= 500 && status < 600) return "server-error";
532
+ return "generic";
533
+ }
534
+ function isRouteMissingResponse(sanitizedBody, redactedHeaders) {
535
+ if (sanitizedBody?.includes(ROUTE_MISSING_LITERAL)) return true;
536
+ if (sanitizedBody?.includes(RESOURCE_MISSING_LITERAL)) return false;
537
+ if (redactedHeaders["content-type"]?.includes("application/json")) return false;
538
+ if (sanitizedBody === null || sanitizedBody.trim() === "") return true;
539
+ return parseEnvelope(sanitizedBody) === null;
540
+ }
541
+ function buildUserMessage(kind, input, sanitizedBody, redactedHeaders) {
542
+ if (kind === "route-missing") return buildRouteMissingMessage(input);
543
+ if (kind === "resource-missing") return `Not found: ${input.method} ${pathFromUrl(input.url)}.`;
544
+ const fromBody = parseEnvelopeMessage(sanitizedBody);
545
+ if (fromBody !== null) return fromBody;
546
+ if (kind === "auth") return `Invalid or unauthorized API key (host: ${hostFromUrl(input.url)}).`;
547
+ const fromText = plainTextMessage(sanitizedBody, redactedHeaders);
548
+ if (fromText !== null) return fromText;
549
+ return defaultMessageForStatus(input.status);
550
+ }
551
+ function plainTextMessage(sanitizedBody, redactedHeaders) {
552
+ if (sanitizedBody === null || !redactedHeaders["content-type"]?.includes(TEXT_CONTENT_TYPE)) return null;
553
+ const trimmed = sanitizedBody.trim();
554
+ return trimmed === "" ? null : capLength(trimmed);
555
+ }
556
+ function buildRouteMissingMessage(input) {
557
+ const path = pathFromUrl(input.url);
558
+ if (!input.serverTag) return `This endpoint is not available on the connected Metabase: ${input.method} ${path}.`;
559
+ return `This endpoint is not available on Metabase ${input.serverTag}: ${input.method} ${path}. It may require a newer Metabase major version.`;
560
+ }
561
+ function pathFromUrl(url) {
562
+ const parsed = new URL(url);
563
+ return parsed.pathname + parsed.search;
564
+ }
565
+ function hostFromUrl(url) {
566
+ return new URL(url).host;
567
+ }
568
+ function parseEnvelope(sanitizedBody) {
569
+ if (!sanitizedBody) return null;
570
+ const result = parseJsonResult(sanitizedBody, ErrorEnvelope);
571
+ return result.ok ? result.value : null;
572
+ }
573
+ const NO_ENVELOPE_VIEWS = {
574
+ fieldErrors: null,
575
+ specificFieldErrors: null,
576
+ errorCode: null
577
+ };
578
+ function extractEnvelopeViews(sanitizedBody) {
579
+ const envelope = parseEnvelope(sanitizedBody);
580
+ if (envelope === null) return NO_ENVELOPE_VIEWS;
581
+ return {
582
+ fieldErrors: parseFieldErrors(envelope.errors),
583
+ specificFieldErrors: parseFieldErrors(envelope["specific-errors"]),
584
+ errorCode: envelope["error-code"] ?? null
585
+ };
586
+ }
587
+ function parseFieldErrors(value) {
588
+ const parsed = FieldErrorTree.safeParse(value);
589
+ if (!parsed.success) return null;
590
+ const entries = collectLeafEntries(parsed.data, []);
591
+ if (entries.length === 0) return null;
592
+ return Object.fromEntries(entries.map((entry) => [entry.path, entry.message]));
593
+ }
594
+ function parseEnvelopeMessage(sanitizedBody) {
595
+ const envelope = parseEnvelope(sanitizedBody);
596
+ if (envelope === null) return null;
597
+ const topLevel = envelope.message ?? envelope.error ?? envelope["error-message"];
598
+ if (topLevel) return capLength(topLevel);
599
+ const viaMessage = envelope.via?.find((entry) => entry.message)?.message;
600
+ if (viaMessage) return capLength(viaMessage);
601
+ const specific = formatErrorTree(envelope["specific-errors"]);
602
+ if (specific) return capLength(specific);
603
+ const generic = formatErrorTree(envelope.errors);
604
+ if (generic) return capLength(generic);
605
+ return null;
606
+ }
607
+ function formatErrorTree(value) {
608
+ const entries = collectLeafEntries(value, []);
609
+ if (entries.length === 0) return null;
610
+ return entries.map(formatLeafEntry).join(FIELD_MESSAGE_SEPARATOR);
611
+ }
612
+ function formatLeafEntry(entry) {
613
+ return entry.path === "" ? entry.message : `${entry.path}: ${entry.message}`;
614
+ }
615
+ function collectLeafEntries(value, path) {
616
+ if (typeof value === "string") {
617
+ const trimmed = value.trim();
618
+ return trimmed === "" ? [] : [{
619
+ path: path.join("."),
620
+ message: trimmed
621
+ }];
622
+ }
623
+ if (Array.isArray(value)) {
624
+ const messages = value.filter((entry) => typeof entry === "string" && entry.trim() !== "");
625
+ if (messages.length === 0) return [];
626
+ return [{
627
+ path: path.join("."),
628
+ message: messages.join(FIELD_MESSAGE_SEPARATOR)
629
+ }];
630
+ }
631
+ if (isPlainObject(value)) return Object.entries(value).flatMap(([key, child]) => collectLeafEntries(child, [...path, key]));
632
+ return [];
633
+ }
634
+ function capLength(message) {
635
+ if (message.length <= MAX_EXTRACTED_MESSAGE_LEN) return message;
636
+ return message.slice(0, MAX_EXTRACTED_MESSAGE_LEN - 1) + ELLIPSIS;
637
+ }
638
+ function defaultMessageForStatus(status) {
639
+ return STATUS_CLASSIFICATIONS[status]?.message ?? `Metabase returned ${status}.`;
640
+ }
641
+ //#endregion
642
+ //#region ../client/src/http/network-error.ts
643
+ const NETWORK_HINTS = {
644
+ ECONNREFUSED: (t) => `Connection refused by ${t.host} — is Metabase running and is the port correct?`,
645
+ ENOTFOUND: (t) => `Host not found: ${t.hostname} — check the URL.`,
646
+ EAI_AGAIN: (t) => `Could not resolve ${t.hostname} — check your network connection and the URL.`,
647
+ ECONNRESET: (t) => `Connection to ${t.host} was reset — the server may have closed it, or http/https may be mismatched.`,
648
+ UND_ERR_SOCKET: (t) => `Connection to ${t.host} was closed by the other side — a pooled connection or a proxy may have dropped it.`,
649
+ EPIPE: (t) => `Connection to ${t.host} closed while the request was still being written — the server or a proxy dropped it.`,
650
+ ETIMEDOUT: (t) => `Connection to ${t.host} timed out — check the host, port, and your network.`
651
+ };
652
+ const CONNECTION_CLOSED_CODES = /* @__PURE__ */ new Set([
653
+ "ECONNRESET",
654
+ "UND_ERR_SOCKET",
655
+ "EPIPE"
656
+ ]);
657
+ const TLS_ERROR_CODES = /* @__PURE__ */ new Set([
658
+ "EPROTO",
659
+ "DEPTH_ZERO_SELF_SIGNED_CERT",
660
+ "SELF_SIGNED_CERT_IN_CHAIN",
661
+ "UNABLE_TO_VERIFY_LEAF_SIGNATURE",
662
+ "CERT_HAS_EXPIRED",
663
+ "ERR_TLS_CERT_ALTNAME_INVALID"
664
+ ]);
665
+ function buildNetworkError(error, method, url) {
666
+ const fallback = errorMessage(error);
667
+ const code = failureCode(error);
668
+ return new NetworkError(networkMessage(code, networkTarget(url), fallback), {
669
+ method,
670
+ url,
671
+ cause: code ?? fallback
672
+ });
673
+ }
674
+ function isConnectionClosed(error) {
675
+ const code = failureCode(error);
676
+ return code !== null && CONNECTION_CLOSED_CODES.has(code);
677
+ }
678
+ function networkMessage(code, target, fallback) {
679
+ if (code === null) return `Could not reach Metabase: ${fallback}`;
680
+ if (TLS_ERROR_CODES.has(code)) return `Could not reach Metabase: TLS error contacting ${target.host} (${code}) — the certificate could not be verified, or https:// was used against a plain-HTTP server. For a certificate the OS does not trust either, set NODE_EXTRA_CA_CERTS to its CA bundle.`;
681
+ const hint = NETWORK_HINTS[code];
682
+ if (hint === void 0) return `Could not reach Metabase: ${fallback} (${code})`;
683
+ return `Could not reach Metabase: ${hint(target)}`;
684
+ }
685
+ function failureCode(error) {
686
+ const own = errorCode(error);
687
+ if (own !== null) return own;
688
+ return errorCode(error instanceof Error ? error.cause : void 0);
689
+ }
690
+ function errorCode(value) {
691
+ if (value instanceof Error && "code" in value && typeof value.code === "string") return value.code;
692
+ return null;
693
+ }
694
+ function networkTarget(url) {
695
+ const parsed = new URL(url);
696
+ return {
697
+ host: parsed.host,
698
+ hostname: parsed.hostname
64
699
  };
65
700
  }
66
701
  //#endregion
702
+ //#region ../client/src/http/oauth.ts
703
+ const DISCOVERY_PATH = "/.well-known/oauth-authorization-server";
704
+ const FORM_CONTENT_TYPE = "application/x-www-form-urlencoded";
705
+ const OAUTH_TIMEOUT_MS = 3e4;
706
+ async function oauthFetch(request) {
707
+ const timeoutSignal = AbortSignal.timeout(OAUTH_TIMEOUT_MS);
708
+ try {
709
+ return await fetch(request.url, {
710
+ method: request.method,
711
+ headers: {
712
+ ...request.headers,
713
+ "user-agent": request.userAgent
714
+ },
715
+ ...request.body !== void 0 ? { body: request.body } : {},
716
+ signal: timeoutSignal
717
+ });
718
+ } catch (error) {
719
+ if (timeoutSignal.aborted) throw new TimeoutError(`OAuth request timed out after ${OAUTH_TIMEOUT_MS}ms`, {
720
+ kind: "http",
721
+ method: request.method,
722
+ url: request.url,
723
+ timeoutMs: OAUTH_TIMEOUT_MS
724
+ });
725
+ throw buildNetworkError(error, request.method, request.url);
726
+ }
727
+ }
728
+ const OAUTH_SCOPE = "mb:full";
729
+ const OAuthServerMetadata = z.object({
730
+ issuer: z.string(),
731
+ authorization_endpoint: z.string(),
732
+ token_endpoint: z.string(),
733
+ registration_endpoint: z.string().optional(),
734
+ revocation_endpoint: z.string().optional(),
735
+ scopes_supported: z.array(z.string()).optional()
736
+ }).loose();
737
+ const RegisteredClient = z.object({ client_id: z.string() }).loose();
738
+ const OAuthTokens = z.object({
739
+ access_token: z.string(),
740
+ token_type: z.string(),
741
+ expires_in: z.number().int().optional(),
742
+ refresh_token: z.string().optional()
743
+ }).loose();
744
+ const OAuthErrorBody = z.object({
745
+ error: z.string(),
746
+ error_description: z.string().optional()
747
+ }).loose();
748
+ async function readJson(response, schema, source) {
749
+ let raw;
750
+ try {
751
+ raw = await response.json();
752
+ } catch (error) {
753
+ throw new ConfigError(`${source}: invalid JSON response (${errorMessage(error)})`);
754
+ }
755
+ const parsed = schema.safeParse(raw);
756
+ if (!parsed.success) throw new ConfigError(`${source}: unexpected response shape`);
757
+ return parsed.data;
758
+ }
759
+ async function failure(response, source, method, url) {
760
+ const rawBody = await response.text().catch(() => "");
761
+ if (isRetryableStatus(response.status)) return new HttpError({
762
+ status: response.status,
763
+ statusText: response.statusText,
764
+ method,
765
+ url,
766
+ responseHeaders: response.headers,
767
+ rawBody
768
+ });
769
+ const parsed = parseJsonResult(rawBody, OAuthErrorBody);
770
+ if (parsed.ok) {
771
+ const detail = parsed.value.error_description ?? parsed.value.error;
772
+ return new ConfigError(`${source} failed (${response.status}): ${detail}`);
773
+ }
774
+ return new ConfigError(`${source} failed (${response.status})`);
775
+ }
776
+ async function postForm(url, userAgent, params, schema, source) {
777
+ const response = await oauthFetch({
778
+ url,
779
+ method: "POST",
780
+ userAgent,
781
+ headers: {
782
+ "content-type": FORM_CONTENT_TYPE,
783
+ accept: JSON_CONTENT_TYPE
784
+ },
785
+ body: new URLSearchParams(params)
786
+ });
787
+ if (!response.ok) throw await failure(response, source, "POST", url);
788
+ return readJson(response, schema, source);
789
+ }
790
+ const OAUTH_UNSUPPORTED_MESSAGE = "this Metabase does not support OAuth login (requires Metabase v63 or newer)";
791
+ async function tryDiscoverMetadata(baseUrl, userAgent) {
792
+ const response = await oauthFetch({
793
+ url: `${baseUrl}${DISCOVERY_PATH}`,
794
+ method: "GET",
795
+ userAgent,
796
+ headers: { accept: JSON_CONTENT_TYPE }
797
+ });
798
+ const contentType = response.headers.get("content-type") ?? "";
799
+ if (!response.ok || !contentType.includes("json")) {
800
+ await response.body?.cancel().catch(() => void 0);
801
+ return null;
802
+ }
803
+ const metadata = await readJson(response, OAuthServerMetadata, "OAuth discovery");
804
+ const scopes = metadata.scopes_supported;
805
+ if (scopes !== void 0 && !scopes.includes("mb:full")) return null;
806
+ assertEndpointOrigin(metadata.issuer, baseUrl, "issuer");
807
+ assertEndpointOrigin(metadata.authorization_endpoint, baseUrl, "authorization endpoint");
808
+ assertEndpointOrigin(metadata.token_endpoint, baseUrl, "token endpoint");
809
+ if (metadata.registration_endpoint !== void 0) assertEndpointOrigin(metadata.registration_endpoint, baseUrl, "registration endpoint");
810
+ if (metadata.revocation_endpoint !== void 0) assertEndpointOrigin(metadata.revocation_endpoint, baseUrl, "revocation endpoint");
811
+ return metadata;
812
+ }
813
+ async function discoverMetadata(baseUrl, userAgent) {
814
+ const metadata = await tryDiscoverMetadata(baseUrl, userAgent);
815
+ if (metadata === null) throw new ConfigError(OAUTH_UNSUPPORTED_MESSAGE);
816
+ return metadata;
817
+ }
818
+ async function registerClient(input) {
819
+ const response = await oauthFetch({
820
+ url: input.registrationEndpoint,
821
+ method: "POST",
822
+ userAgent: input.userAgent,
823
+ headers: {
824
+ "content-type": JSON_CONTENT_TYPE,
825
+ accept: JSON_CONTENT_TYPE
826
+ },
827
+ body: JSON.stringify({
828
+ application_type: "native",
829
+ client_name: input.clientName,
830
+ redirect_uris: [input.redirectUri],
831
+ grant_types: ["authorization_code", "refresh_token"],
832
+ response_types: ["code"],
833
+ token_endpoint_auth_method: "none",
834
+ scope: OAUTH_SCOPE
835
+ })
836
+ });
837
+ if (!response.ok) throw await failure(response, "OAuth client registration", "POST", input.registrationEndpoint);
838
+ return readJson(response, RegisteredClient, "OAuth client registration");
839
+ }
840
+ function exchangeCode(input) {
841
+ return postForm(input.tokenEndpoint, input.userAgent, {
842
+ grant_type: "authorization_code",
843
+ code: input.code,
844
+ redirect_uri: input.redirectUri,
845
+ client_id: input.clientId,
846
+ code_verifier: input.codeVerifier
847
+ }, OAuthTokens, "OAuth token exchange");
848
+ }
849
+ function refreshTokens(input) {
850
+ return postForm(input.tokenEndpoint, input.userAgent, {
851
+ grant_type: "refresh_token",
852
+ refresh_token: input.refreshToken,
853
+ client_id: input.clientId
854
+ }, OAuthTokens, "OAuth token refresh");
855
+ }
856
+ async function revokeToken(input) {
857
+ const response = await oauthFetch({
858
+ url: input.revocationEndpoint,
859
+ method: "POST",
860
+ userAgent: input.userAgent,
861
+ headers: { "content-type": FORM_CONTENT_TYPE },
862
+ body: new URLSearchParams({
863
+ token: input.token,
864
+ client_id: input.clientId
865
+ })
866
+ });
867
+ if (!response.ok) throw await failure(response, "OAuth token revocation", "POST", input.revocationEndpoint);
868
+ await response.body?.cancel().catch(() => void 0);
869
+ }
870
+ //#endregion
871
+ //#region ../client/src/auth/oauth-session.ts
872
+ async function refreshOAuthCredential(baseUrl, credential, nowMs, userAgent) {
873
+ const tokens = await refreshTokens({
874
+ tokenEndpoint: (await discoverMetadata(baseUrl, userAgent)).token_endpoint,
875
+ refreshToken: credential.refreshToken,
876
+ clientId: credential.clientId,
877
+ userAgent
878
+ });
879
+ return oauthCredentialFromTokens(tokens, tokens.refresh_token ?? credential.refreshToken, credential.clientId, nowMs);
880
+ }
881
+ async function revokeOAuthCredential(baseUrl, credential, userAgent) {
882
+ const revocationEndpoint = (await discoverMetadata(baseUrl, userAgent)).revocation_endpoint;
883
+ if (revocationEndpoint === void 0) return false;
884
+ await revokeToken({
885
+ revocationEndpoint,
886
+ token: credential.refreshToken,
887
+ clientId: credential.clientId,
888
+ userAgent
889
+ });
890
+ await revokeToken({
891
+ revocationEndpoint,
892
+ token: credential.accessToken,
893
+ clientId: credential.clientId,
894
+ userAgent
895
+ });
896
+ return true;
897
+ }
898
+ //#endregion
899
+ //#region src/core/user-agent.ts
900
+ const USER_AGENT = `metabase-cli/${version}`;
901
+ const OAUTH_CLIENT_NAME = "Metabase CLI";
902
+ //#endregion
67
903
  //#region src/core/paths.ts
68
904
  const APP_DIR_NAME = "metabase-cli";
69
905
  function configDir() {
@@ -80,6 +916,9 @@ const ProbedUser = z.object({
80
916
  const ProfileLastProbe = z.object({
81
917
  at: z.iso.datetime(),
82
918
  version: ParsedVersion.nullable(),
919
+ edition: Edition.nullable().default(null),
920
+ date: z.string().nullable().default(null),
921
+ hash: z.string().nullable().default(null),
83
922
  tokenFeatures: TokenFeatures.nullable(),
84
923
  user: ProbedUser
85
924
  });
@@ -374,6 +1213,9 @@ async function writeProbeResult(name, input) {
374
1213
  const probe = ProfileLastProbe.parse({
375
1214
  at: (/* @__PURE__ */ new Date()).toISOString(),
376
1215
  version: input.server.version,
1216
+ edition: input.server.edition,
1217
+ date: input.server.date,
1218
+ hash: input.server.hash,
377
1219
  tokenFeatures: input.server.tokenFeatures,
378
1220
  user: input.user
379
1221
  });
@@ -425,207 +1267,6 @@ async function clearProfile(name = DEFAULT_PROFILE) {
425
1267
  return true;
426
1268
  }
427
1269
  //#endregion
428
- //#region ../client/src/http/oauth.ts
429
- const DISCOVERY_PATH = "/.well-known/oauth-authorization-server";
430
- const FORM_CONTENT_TYPE = "application/x-www-form-urlencoded";
431
- const OAUTH_TIMEOUT_MS = 3e4;
432
- async function oauthFetch(request) {
433
- const timeoutSignal = AbortSignal.timeout(OAUTH_TIMEOUT_MS);
434
- try {
435
- return await fetch(request.url, {
436
- method: request.method,
437
- headers: {
438
- ...request.headers,
439
- "user-agent": request.userAgent
440
- },
441
- ...request.body !== void 0 ? { body: request.body } : {},
442
- signal: timeoutSignal
443
- });
444
- } catch (error) {
445
- if (timeoutSignal.aborted) throw new TimeoutError(`OAuth request timed out after ${OAUTH_TIMEOUT_MS}ms`, {
446
- kind: "http",
447
- method: request.method,
448
- url: request.url,
449
- timeoutMs: OAUTH_TIMEOUT_MS
450
- });
451
- throw buildNetworkError(error, request.method, request.url);
452
- }
453
- }
454
- const OAUTH_SCOPE = "mb:full";
455
- const OAuthServerMetadata = z.object({
456
- issuer: z.string(),
457
- authorization_endpoint: z.string(),
458
- token_endpoint: z.string(),
459
- registration_endpoint: z.string().optional(),
460
- revocation_endpoint: z.string().optional(),
461
- scopes_supported: z.array(z.string()).optional()
462
- }).loose();
463
- const RegisteredClient = z.object({ client_id: z.string() }).loose();
464
- const OAuthTokens = z.object({
465
- access_token: z.string(),
466
- token_type: z.string(),
467
- expires_in: z.number().int().optional(),
468
- refresh_token: z.string().optional()
469
- }).loose();
470
- const OAuthErrorBody = z.object({
471
- error: z.string(),
472
- error_description: z.string().optional()
473
- }).loose();
474
- async function readJson(response, schema, source) {
475
- let raw;
476
- try {
477
- raw = await response.json();
478
- } catch (error) {
479
- throw new ConfigError(`${source}: invalid JSON response (${errorMessage(error)})`);
480
- }
481
- const parsed = schema.safeParse(raw);
482
- if (!parsed.success) throw new ConfigError(`${source}: unexpected response shape`);
483
- return parsed.data;
484
- }
485
- async function failure(response, source, method, url) {
486
- const rawBody = await response.text().catch(() => "");
487
- if (isRetryableStatus(response.status)) return new HttpError({
488
- status: response.status,
489
- statusText: response.statusText,
490
- method,
491
- url,
492
- responseHeaders: response.headers,
493
- rawBody
494
- });
495
- const parsed = parseJsonResult(rawBody, OAuthErrorBody);
496
- if (parsed.ok) {
497
- const detail = parsed.value.error_description ?? parsed.value.error;
498
- return new ConfigError(`${source} failed (${response.status}): ${detail}`);
499
- }
500
- return new ConfigError(`${source} failed (${response.status})`);
501
- }
502
- async function postForm(url, userAgent, params, schema, source) {
503
- const response = await oauthFetch({
504
- url,
505
- method: "POST",
506
- userAgent,
507
- headers: {
508
- "content-type": FORM_CONTENT_TYPE,
509
- accept: JSON_CONTENT_TYPE
510
- },
511
- body: new URLSearchParams(params)
512
- });
513
- if (!response.ok) throw await failure(response, source, "POST", url);
514
- return readJson(response, schema, source);
515
- }
516
- const OAUTH_UNSUPPORTED_MESSAGE = "this Metabase does not support OAuth login (requires Metabase v63 or newer)";
517
- async function tryDiscoverMetadata(baseUrl, userAgent) {
518
- const response = await oauthFetch({
519
- url: `${baseUrl}${DISCOVERY_PATH}`,
520
- method: "GET",
521
- userAgent,
522
- headers: { accept: JSON_CONTENT_TYPE }
523
- });
524
- const contentType = response.headers.get("content-type") ?? "";
525
- if (!response.ok || !contentType.includes("json")) {
526
- await response.body?.cancel().catch(() => void 0);
527
- return null;
528
- }
529
- const metadata = await readJson(response, OAuthServerMetadata, "OAuth discovery");
530
- const scopes = metadata.scopes_supported;
531
- if (scopes !== void 0 && !scopes.includes("mb:full")) return null;
532
- assertEndpointOrigin(metadata.issuer, baseUrl, "issuer");
533
- assertEndpointOrigin(metadata.authorization_endpoint, baseUrl, "authorization endpoint");
534
- assertEndpointOrigin(metadata.token_endpoint, baseUrl, "token endpoint");
535
- if (metadata.registration_endpoint !== void 0) assertEndpointOrigin(metadata.registration_endpoint, baseUrl, "registration endpoint");
536
- if (metadata.revocation_endpoint !== void 0) assertEndpointOrigin(metadata.revocation_endpoint, baseUrl, "revocation endpoint");
537
- return metadata;
538
- }
539
- async function discoverMetadata(baseUrl, userAgent) {
540
- const metadata = await tryDiscoverMetadata(baseUrl, userAgent);
541
- if (metadata === null) throw new ConfigError(OAUTH_UNSUPPORTED_MESSAGE);
542
- return metadata;
543
- }
544
- async function registerClient(input) {
545
- const response = await oauthFetch({
546
- url: input.registrationEndpoint,
547
- method: "POST",
548
- userAgent: input.userAgent,
549
- headers: {
550
- "content-type": JSON_CONTENT_TYPE,
551
- accept: JSON_CONTENT_TYPE
552
- },
553
- body: JSON.stringify({
554
- application_type: "native",
555
- client_name: input.clientName,
556
- redirect_uris: [input.redirectUri],
557
- grant_types: ["authorization_code", "refresh_token"],
558
- response_types: ["code"],
559
- token_endpoint_auth_method: "none",
560
- scope: OAUTH_SCOPE
561
- })
562
- });
563
- if (!response.ok) throw await failure(response, "OAuth client registration", "POST", input.registrationEndpoint);
564
- return readJson(response, RegisteredClient, "OAuth client registration");
565
- }
566
- function exchangeCode(input) {
567
- return postForm(input.tokenEndpoint, input.userAgent, {
568
- grant_type: "authorization_code",
569
- code: input.code,
570
- redirect_uri: input.redirectUri,
571
- client_id: input.clientId,
572
- code_verifier: input.codeVerifier
573
- }, OAuthTokens, "OAuth token exchange");
574
- }
575
- function refreshTokens(input) {
576
- return postForm(input.tokenEndpoint, input.userAgent, {
577
- grant_type: "refresh_token",
578
- refresh_token: input.refreshToken,
579
- client_id: input.clientId
580
- }, OAuthTokens, "OAuth token refresh");
581
- }
582
- async function revokeToken(input) {
583
- const response = await oauthFetch({
584
- url: input.revocationEndpoint,
585
- method: "POST",
586
- userAgent: input.userAgent,
587
- headers: { "content-type": FORM_CONTENT_TYPE },
588
- body: new URLSearchParams({
589
- token: input.token,
590
- client_id: input.clientId
591
- })
592
- });
593
- if (!response.ok) throw await failure(response, "OAuth token revocation", "POST", input.revocationEndpoint);
594
- await response.body?.cancel().catch(() => void 0);
595
- }
596
- //#endregion
597
- //#region ../client/src/auth/oauth-session.ts
598
- async function refreshOAuthCredential(baseUrl, credential, nowMs, userAgent) {
599
- const tokens = await refreshTokens({
600
- tokenEndpoint: (await discoverMetadata(baseUrl, userAgent)).token_endpoint,
601
- refreshToken: credential.refreshToken,
602
- clientId: credential.clientId,
603
- userAgent
604
- });
605
- return oauthCredentialFromTokens(tokens, tokens.refresh_token ?? credential.refreshToken, credential.clientId, nowMs);
606
- }
607
- async function revokeOAuthCredential(baseUrl, credential, userAgent) {
608
- const revocationEndpoint = (await discoverMetadata(baseUrl, userAgent)).revocation_endpoint;
609
- if (revocationEndpoint === void 0) return false;
610
- await revokeToken({
611
- revocationEndpoint,
612
- token: credential.refreshToken,
613
- clientId: credential.clientId,
614
- userAgent
615
- });
616
- await revokeToken({
617
- revocationEndpoint,
618
- token: credential.accessToken,
619
- clientId: credential.clientId,
620
- userAgent
621
- });
622
- return true;
623
- }
624
- //#endregion
625
- //#region src/core/user-agent.ts
626
- const USER_AGENT = `metabase-cli/${version}`;
627
- const OAUTH_CLIENT_NAME = "Metabase CLI";
628
- //#endregion
629
1270
  //#region src/core/config.ts
630
1271
  function isPreflightSkipped() {
631
1272
  return readEnv(ENV_SKIP_PREFLIGHT) === "1";
@@ -741,6 +1382,34 @@ function resolveCredential(flagKey, envKey, stored) {
741
1382
  return null;
742
1383
  }
743
1384
  //#endregion
1385
+ //#region src/core/auth/cached-server.ts
1386
+ async function lookupCachedProbe(profileName, url) {
1387
+ const record = await readProfileRecord(profileName);
1388
+ if (record === null) return { kind: "no-profile" };
1389
+ if (record.lastProbe === null) return { kind: "never-probed" };
1390
+ if (url !== null && normalizeUrl(record.url) !== url) return {
1391
+ kind: "other-url",
1392
+ url
1393
+ };
1394
+ return {
1395
+ kind: "found",
1396
+ probe: record.lastProbe
1397
+ };
1398
+ }
1399
+ async function readCachedProbe(profileName, url) {
1400
+ const hit = await lookupCachedProbe(profileName, url);
1401
+ return hit.kind === "found" ? hit.probe : null;
1402
+ }
1403
+ async function readCachedServerProfile(profileName) {
1404
+ const envUrl = readEnvCredentials().url;
1405
+ const hit = await lookupCachedProbe(profileName, envUrl === null ? null : normalizeUrl(envUrl));
1406
+ if (hit.kind !== "found") return hit;
1407
+ return {
1408
+ kind: "found",
1409
+ profile: createServerProfile(hit.probe)
1410
+ };
1411
+ }
1412
+ //#endregion
744
1413
  //#region src/output/format.ts
745
1414
  function resolveFormat({ json, format, isTty }) {
746
1415
  const explicit = format !== void 0 && format !== "auto" ? format : null;
@@ -875,7 +1544,7 @@ function flagCandidates(token) {
875
1544
  //#endregion
876
1545
  //#region src/commands/runtime.ts
877
1546
  function defineMetabaseCommand(def) {
878
- const required = def.capabilities === null ? null : mergeCapabilities(def.capabilities);
1547
+ const requirements = def.requires === null ? null : deriveRequirements(def.requires);
879
1548
  const cmd = defineCommand({
880
1549
  meta: def.meta,
881
1550
  args: def.args,
@@ -888,35 +1557,44 @@ function defineMetabaseCommand(def) {
888
1557
  assertKnownFlags(rawArgs, def.args);
889
1558
  let cachedConfig = null;
890
1559
  let cachedClient = null;
891
- let cachedServerInfo = null;
892
1560
  const getResolvedConfig = async () => {
893
1561
  if (cachedConfig === null) cachedConfig = await resolveConfig(buildConfigFlags(ctx));
894
1562
  return cachedConfig;
895
1563
  };
896
- const getServerInfo = () => {
897
- if (cachedServerInfo === null) cachedServerInfo = loadServerInfo(getResolvedConfig);
898
- return cachedServerInfo;
899
- };
1564
+ const preflightSkipped = ctx.skipPreflight || isPreflightSkipped();
1565
+ let cachedServer = null;
1566
+ const noticeSkew = createSkewNotifier();
900
1567
  const rawGetClient = async () => {
901
1568
  if (cachedClient === null) {
902
1569
  const resolved = await getResolvedConfig();
903
- const { createClient } = await import("./client-C9HBWl6A.mjs").then((n) => n.t);
1570
+ const probe = await readCachedProbe(resolved.profile, resolved.url);
1571
+ const server = probe === null ? null : createServerProfile(probe);
1572
+ const { createClient } = await import("./client-yPhazV6T.mjs").then((n) => n.t);
904
1573
  cachedClient = createClient({
905
1574
  url: resolved.url,
906
1575
  credential: resolved.credential
907
1576
  }, {
908
1577
  userAgent: USER_AGENT,
909
- getServerTag: async () => (await getServerInfo())?.version?.tag ?? null,
1578
+ ...server !== null && { server },
910
1579
  refreshCredential: createCredentialRefresher(resolved.profile),
911
- signal: interruptSignal
1580
+ signal: interruptSignal,
1581
+ enforceRequirements: !preflightSkipped
912
1582
  });
1583
+ if (probe !== null && server !== null) {
1584
+ cachedServer = {
1585
+ client: cachedClient,
1586
+ profileName: resolved.profile,
1587
+ probe
1588
+ };
1589
+ noticeSkew(server);
1590
+ }
913
1591
  }
914
1592
  return cachedClient;
915
1593
  };
916
- const enforcePreflight = createPreflightEnforcer(required, getServerInfo, ctx.skipPreflight);
1594
+ const enforcePreflight = createPreflightEnforcer(requirements === null ? null : requirements.features, preflightSkipped, noticeSkew);
917
1595
  const getClient = async () => {
918
1596
  const client = await rawGetClient();
919
- await enforcePreflight();
1597
+ await enforcePreflight(client);
920
1598
  return client;
921
1599
  };
922
1600
  try {
@@ -924,9 +1602,10 @@ function defineMetabaseCommand(def) {
924
1602
  args,
925
1603
  ctx,
926
1604
  getClient,
927
- getResolvedConfig,
928
- getServerInfo
1605
+ getResolvedConfig
929
1606
  });
1607
+ } catch (error) {
1608
+ throw await refreshProfileOnStaleError(error, cachedServer);
930
1609
  } finally {
931
1610
  emitPendingWarnings();
932
1611
  }
@@ -941,10 +1620,16 @@ function defineMetabaseCommand(def) {
941
1620
  skills: def.skills ?? [],
942
1621
  inputSchema: def.inputSchema ?? null,
943
1622
  outputSchema: def.outputSchema ?? null,
944
- capabilities: required
1623
+ requires: requirements
945
1624
  });
946
1625
  return cmd;
947
1626
  }
1627
+ function deriveRequirements(methods) {
1628
+ return {
1629
+ methods,
1630
+ features: [...new Set(methods.flatMap((key) => methodRequirements(key)))]
1631
+ };
1632
+ }
948
1633
  function emitPendingWarnings() {
949
1634
  for (const message of consumeLegacyEnvWarnings()) warn(message);
950
1635
  const legacy = consumeLegacyStorageWarning();
@@ -952,34 +1637,49 @@ function emitPendingWarnings() {
952
1637
  const downgrade = consumeKeyringDowngradeWarning();
953
1638
  if (downgrade !== null) warn(downgrade);
954
1639
  }
955
- async function loadServerInfo(getResolvedConfig) {
956
- const record = await readProfileRecord((await getResolvedConfig()).profile);
957
- if (record === null || record.lastProbe === null) return null;
958
- return {
959
- version: record.lastProbe.version,
960
- tokenFeatures: record.lastProbe.tokenFeatures
1640
+ function createSkewNotifier() {
1641
+ let noticed = false;
1642
+ return (profile) => {
1643
+ if (noticed) return;
1644
+ noticed = true;
1645
+ const notice = skewNotice(profile);
1646
+ if (notice !== null) warn(notice);
961
1647
  };
962
1648
  }
963
1649
  const NO_OP_ENFORCER = async () => {};
964
- const NO_PROBE_DATA_WARNING = "Could not detect Metabase server version. Proceeding without preflight check; failures may produce confusing errors. Run `mb auth list` (or `mb auth login`) to populate the version cache.";
965
- function createPreflightEnforcer(required, getServerInfo, skip) {
966
- if (required === null || skip || isPreflightSkipped() || isBaseline(required)) return NO_OP_ENFORCER;
1650
+ function createPreflightEnforcer(features, skip, noticeSkew) {
1651
+ if (features === null || skip || features.length === 0) return NO_OP_ENFORCER;
967
1652
  let done = false;
968
- return async () => {
1653
+ return async (client) => {
969
1654
  if (done) return;
970
1655
  done = true;
971
- const info = await getServerInfo();
972
- if (info === null) {
973
- warn(NO_PROBE_DATA_WARNING);
974
- return;
975
- }
976
- const failure = checkCapabilities(info, required);
977
- if (failure === null || failure.reason === "unknown-version") return;
978
- throw new CapabilityError(failure);
1656
+ const profile = await client.server();
1657
+ noticeSkew(profile);
1658
+ const failure = checkFeatures(features, profile);
1659
+ if (failure !== null) throw new CapabilityError(failure);
979
1660
  };
980
1661
  }
981
- function isBaseline(caps) {
982
- return caps.minVersion === BASELINE_CAPABILITIES.minVersion && caps.tokenFeature === void 0;
1662
+ async function refreshProfileOnStaleError(error, cached) {
1663
+ if (cached === null) return error;
1664
+ if (!(error instanceof ResponseShapeError) && !(error instanceof CapabilityError)) return error;
1665
+ const note = await refreshChangedProbe(cached);
1666
+ return note === null ? error : new ProfileRefreshedError(error, note);
1667
+ }
1668
+ async function refreshChangedProbe(cached) {
1669
+ let fresh;
1670
+ try {
1671
+ fresh = await probeServer(cached.client);
1672
+ } catch (error) {
1673
+ if (error instanceof MetabaseError) return null;
1674
+ throw error;
1675
+ }
1676
+ const note = serverChangeNote(cached.probe, fresh);
1677
+ if (note === null) return null;
1678
+ await writeProbeResult(cached.profileName, {
1679
+ user: cached.probe.user,
1680
+ server: fresh
1681
+ });
1682
+ return note;
983
1683
  }
984
1684
  function pickCommonArgs(args) {
985
1685
  const out = {};
@@ -1004,4 +1704,4 @@ function buildConfigFlags(ctx) {
1004
1704
  return flags;
1005
1705
  }
1006
1706
  //#endregion
1007
- export { ProbedUser as A, readProfileCredential as C, writeProbeFailure as D, writeOAuthProfile as E, tryParseTag as F, SessionProperties as I, TokenFeatures as L, ProfileLastFailure as M, profileAuthMethod as N, writeProbeResult as O, ParsedVersion as P, parseInteger as R, listProfileRecords as S, resolveRecordCredential as T, DEFAULT_PROFILE as _, createCredentialRefresher as a, consumeKeyringDowngradeWarning as b, resolveProfileName as c, revokeOAuthCredential as d, OAUTH_SCOPE as f, tryDiscoverMetadata as g, registerClient as h, parseEnumCsv as i, ProfileAuthMethod as j, writeProfile as k, OAUTH_CLIENT_NAME as l, exchangeCode as m, parseCsv as n, explicitProfileName as o, discoverMetadata as p, parseEnum as r, readEnvCredentials as s, defineMetabaseCommand as t, USER_AGENT as u, clearProfile as v, readProfileRecord as w, keyringFallbackWarning as x, consumeKeychainResidualWarning as y, parseOptionalInteger as z };
1707
+ export { createServerProfile as $, OAUTH_SCOPE as A, JSON_CONTENT_TYPE as B, ProbedUser as C, OAUTH_CLIENT_NAME as D, profileAuthMethod as E, buildNetworkError as F, credentialSecrets as G, parseJsonOrPlain as H, isConnectionClosed as I, normalizeUrl as J, oauthCredentialFromTokens as K, HttpError as L, exchangeCode as M, registerClient as N, USER_AGENT as O, tryDiscoverMetadata as P, Skew as Q, chainRequestFailure as R, writeProfile as S, ProfileLastFailure as T, assertCredentialHeaderSafe as U, parseJson as V, credentialAuthHeader as W, summarizeServer as X, ServerSummary as Y, checkFeatures as Z, readProfileRecord as _, readCachedServerProfile as a, writeProbeFailure as b, readEnvCredentials as c, clearProfile as d, probeServer as et, consumeKeychainResidualWarning as f, readProfileCredential as g, listProfileRecords as h, parseEnumCsv as i, parseOptionalInteger as it, discoverMetadata as j, revokeOAuthCredential as k, resolveProfileName as l, keyringFallbackWarning as m, parseCsv as n, RequirementFailure as nt, createCredentialRefresher as o, consumeKeyringDowngradeWarning as p, displayUrl as q, parseEnum as r, parseInteger as rt, explicitProfileName as s, defineMetabaseCommand as t, CapabilityError as tt, DEFAULT_PROFILE as u, resolveRecordCredential as v, ProfileAuthMethod as w, writeProbeResult as x, writeOAuthProfile as y, isRetryableStatus as z };