@metabase/cli 0.3.1-alpha.support-worktrees.b634907 → 0.3.1-alpha.versioning.9ac5f50

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (268) hide show
  1. package/dist/{add-collection-CxzzDG4z.mjs → add-collection-Dmd-uNeU.mjs} +6 -10
  2. package/dist/{alert-CQ7Az16h.mjs → alert-D1u2MVZj.mjs} +7 -7
  3. package/dist/{alerts-DmwyyBfW.mjs → alerts-DcBjcfEE.mjs} +7 -8
  4. package/dist/{append-B0avMkvW.mjs → append-B9Htvmab.mjs} +5 -6
  5. package/dist/{archive-CMTHh4-w.mjs → archive-B660RguB.mjs} +4 -5
  6. package/dist/{archive-THcEfy9B.mjs → archive-BNivAYGr.mjs} +5 -6
  7. package/dist/{archive-DCyeRNfV.mjs → archive-BUoYMkxO.mjs} +4 -5
  8. package/dist/{archive-BZEu6UfT.mjs → archive-BVmFGFwG.mjs} +6 -7
  9. package/dist/archive-Bf014rFm.mjs +32 -0
  10. package/dist/{archive-DFofUIEC.mjs → archive-BmsZFOZY.mjs} +4 -5
  11. package/dist/archive-CNif6BKy.mjs +32 -0
  12. package/dist/{archive-BPSNe0Ul.mjs → archive-CgmidYZV.mjs} +4 -5
  13. package/dist/{archive-Cvrkz8F8.mjs → archive-CvU2z5192.mjs} +5 -6
  14. package/dist/{archive-BQ50OZ7y.mjs → archive-DhDQIKR_.mjs} +4 -5
  15. package/dist/{archive-BVblae-p.mjs → archive-bPdDITuY.mjs} +4 -5
  16. package/dist/{auth-BEEkuu4J.mjs → auth-CefYEPP5.mjs} +5 -5
  17. package/dist/{body-DxRSAMNC.mjs → body-C7m9q4cm.mjs} +3 -3
  18. package/dist/{branches-CmWc8NyL.mjs → branches-pz04OjF2.mjs} +4 -8
  19. package/dist/{cancel-DrQqmxvn.mjs → cancel-CNLnv19e.mjs} +4 -5
  20. package/dist/cancel-task-DbnxSh7U.mjs +25 -0
  21. package/dist/card-BRarvKYX.mjs +24 -0
  22. package/dist/{card-CrBGUkGQ.mjs → card-DZxRmver.mjs} +0 -1
  23. package/dist/{card-BEeafd4Y.mjs → card-zyUkr2nS.mjs} +1 -1
  24. package/dist/{cards-M_6X8wCI.mjs → cards-DtYlVoGP.mjs} +5 -6
  25. package/dist/cli.mjs +566 -170
  26. package/dist/{client-DYD8WZYy.mjs → client-Bv7Iwdvh.mjs} +285 -269
  27. package/dist/collection-CKeO8X7U.mjs +20 -0
  28. package/dist/{collection-CJHqsFKP.mjs → collection-DALwHnbz.mjs} +1 -1
  29. package/dist/{collection-BxE7OzcQ.mjs → collection-WFdBeyqa.mjs} +4 -7
  30. package/dist/{collection-namespace-CEoQ7G08.mjs → collection-namespace-CvT0TIZA.mjs} +2 -2
  31. package/dist/{content-translation-C8MlXPOF.mjs → content-translation-D7POzJJ6.mjs} +3 -3
  32. package/dist/{create-CoubLR5o.mjs → create-BEE8uvz2.mjs} +9 -6
  33. package/dist/{create-D0anrINz.mjs → create-Bh2j733n.mjs} +11 -16
  34. package/dist/{create-BupBEwR2.mjs → create-Bwg-5p08.mjs} +8 -13
  35. package/dist/{create-ByuJ6T4k.mjs → create-CGPle4nE.mjs} +7 -8
  36. package/dist/{create-hTc131aX.mjs → create-CGgPnb7L.mjs} +4 -5
  37. package/dist/{create-CY-SzM66.mjs → create-CLgalJUe.mjs} +12 -17
  38. package/dist/{create-C2XFfbjx.mjs → create-CN24yp_W.mjs} +6 -7
  39. package/dist/{create-BLWwN0uw.mjs → create-CuYGZ4gu2.mjs} +5 -6
  40. package/dist/{create-CJ7Am4Gc.mjs → create-DGHILnnk.mjs} +5 -6
  41. package/dist/{create-z-oMrlfT.mjs → create-DYd_o9BD.mjs} +5 -9
  42. package/dist/{create-BqpkCjx4.mjs → create-DhDREiiy.mjs} +4 -5
  43. package/dist/{create-myI6doga.mjs → create-Di4YvIbK.mjs} +5 -6
  44. package/dist/{create-ldrghMd1.mjs → create-DnqnjGGf.mjs} +4 -5
  45. package/dist/{create-C7iooS6W.mjs → create-Ds-DnSBe.mjs} +9 -15
  46. package/dist/{create-BA_tTDEk.mjs → create-JOXq0ULN.mjs} +5 -6
  47. package/dist/create-branch-DWcxC30N.mjs +31 -0
  48. package/dist/{csv-DBNzJiWK.mjs → csv-CUQvcCEk.mjs} +5 -6
  49. package/dist/{current-task-YzemU0Ic.mjs → current-task-D6P0eL21.mjs} +8 -16
  50. package/dist/{dashboard-B1mpfCq_.mjs → dashboard-BudI952R.mjs} +10 -10
  51. package/dist/{db-1tLH3nYI.mjs → db-C7UTd-6P.mjs} +7 -7
  52. package/dist/{delete-CD_-B4Kq.mjs → delete-DSxqbcFE.mjs} +5 -6
  53. package/dist/{delete-QNgBV6eS.mjs → delete-DbZZKcYj.mjs} +6 -11
  54. package/dist/{delete-DjAUp9mk.mjs → delete-Ds-zGh9C.mjs} +5 -6
  55. package/dist/{delete-eAUB7p-f.mjs → delete-Ud6iliGM.mjs} +6 -11
  56. package/dist/{delete-CpKH5ia4.mjs → delete-_IHffP-A.mjs} +5 -6
  57. package/dist/{delete-runtime-b2_ZMSjj.mjs → delete-runtime-BjHL1ryM.mjs} +1 -2
  58. package/dist/{delete-table-DamlxnSO.mjs → delete-table-DtXH6IN5.mjs} +6 -11
  59. package/dist/dependencies-CR1dlq-A.mjs +36 -0
  60. package/dist/dirty-CYxnOnh0.mjs +28 -0
  61. package/dist/document-BoILnE_1.mjs +19 -0
  62. package/dist/{download-C4v7u-AV.mjs → download-DPpmmYQe.mjs} +3 -7
  63. package/dist/{eid-CP35PdEF.mjs → eid-D-BbtWjt.mjs} +4 -6
  64. package/dist/{events-DmbzKIh_.mjs → events-CJEnn8WE.mjs} +5 -6
  65. package/dist/{export-i8D6laBG.mjs → export-BOgyuIOQ.mjs} +13 -29
  66. package/dist/{field-BKn9bt7I.mjs → field-CzHBOPER.mjs} +5 -5
  67. package/dist/{fields-8_p81BqN.mjs → fields-Bwgkrvus.mjs} +5 -6
  68. package/dist/get-B89DUSvw.mjs +31 -0
  69. package/dist/get-BL90QC64.mjs +36 -0
  70. package/dist/get-BLJSCw53.mjs +31 -0
  71. package/dist/{get-BBOfshz1.mjs → get-BOLwso0V.mjs} +6 -7
  72. package/dist/{get-BvW21ujw.mjs → get-BaPadzdM.mjs} +4 -5
  73. package/dist/{get-vvs0qzzM.mjs → get-BfVCLBqc.mjs} +4 -5
  74. package/dist/{get-B0g6VMBC.mjs → get-C1ZdOvMm.mjs} +4 -5
  75. package/dist/{get-N4dOaTsp.mjs → get-CLu4yzMp2.mjs} +5 -6
  76. package/dist/get-COwdtskS.mjs +27 -0
  77. package/dist/{get-CPTbySa7.mjs → get-CWfIiXwL.mjs} +4 -5
  78. package/dist/get-CqQ-pf0q.mjs +89 -0
  79. package/dist/{get-DnCE7K0y.mjs → get-CvIgxPXV.mjs} +5 -6
  80. package/dist/{get-vrccOMBk.mjs → get-D4OTJblo.mjs} +4 -5
  81. package/dist/{get-BbHPFNqr.mjs → get-D8lHwu4-.mjs} +4 -5
  82. package/dist/{get-CWf46UFu.mjs → get-DVi3a2nm.mjs} +6 -7
  83. package/dist/{get-DFkbi5L3.mjs → get-DgnYF7LR.mjs} +4 -5
  84. package/dist/{get-BHGgXqUq.mjs → get-DsKmZfM2.mjs} +4 -5
  85. package/dist/{get-CAzSP-7o.mjs → get-DyyPiiaB.mjs} +4 -5
  86. package/dist/{get-Bds6Izxk.mjs → get-Eqq13YY-.mjs} +4 -5
  87. package/dist/{get-run-4Ng8_awa.mjs → get-run-Iya0Yw9s.mjs} +6 -7
  88. package/dist/{git-sync-DLzJrdMi.mjs → git-sync-BDnxPrqU.mjs} +3 -22
  89. package/dist/git-sync-CdN0Maun.mjs +28 -0
  90. package/dist/{git-sync-LQIVMNxO.mjs → git-sync-DxD_ng48.mjs} +2 -31
  91. package/dist/{group-YN6jj2AN.mjs → group-CmVCLBDz.mjs} +3 -3
  92. package/dist/{has-remote-changes-BXPGI9xG.mjs → has-remote-changes-DfJUMP8F.mjs} +7 -18
  93. package/dist/{import-BoxOkA-G.mjs → import-FEAx-Y5A.mjs} +12 -32
  94. package/dist/{input-DH9i67x_.mjs → input-DFZ_qGW_.mjs} +1 -1
  95. package/dist/is-dirty-BsYjBSXG.mjs +32 -0
  96. package/dist/{items-Cv6iAzrI.mjs → items-D4rstE12.mjs} +10 -18
  97. package/dist/{key-BEhqIzIQ.mjs → key-BmWundO3.mjs} +1 -1
  98. package/dist/{library-fhVn1KDC.mjs → library-CmctxHjv.mjs} +1 -1
  99. package/dist/library-DXB8sm4r.mjs +81 -0
  100. package/dist/{library-CRaOhJnj.mjs → library-uzyHWBap.mjs} +5 -5
  101. package/dist/{list-DOaWCx8S.mjs → list-1DkkU82x.mjs} +17 -25
  102. package/dist/{list-BLJkJp5a.mjs → list-B7tqNV8B.mjs} +4 -5
  103. package/dist/{list-WSJLnunb.mjs → list-BRpPbvyS.mjs} +4 -5
  104. package/dist/{list-BBp9XjYs.mjs → list-BXL8HFr_.mjs} +4 -5
  105. package/dist/{list-L2U1l6R4.mjs → list-Bjj0z5BS.mjs} +6 -7
  106. package/dist/{list-DhrapAcy.mjs → list-BmMi_wPD.mjs} +5 -6
  107. package/dist/list-CC1M_n6Z.mjs +28 -0
  108. package/dist/list-CQy0z7f9.mjs +28 -0
  109. package/dist/{list-BwkfWtP2.mjs → list-D_zvX0ms.mjs} +4 -5
  110. package/dist/{list--2T-GUEF.mjs → list-DeNGm9G4.mjs} +5 -6
  111. package/dist/list-Dgm6TkqR.mjs +38 -0
  112. package/dist/list-DoTiQc3D.mjs +36 -0
  113. package/dist/{list-C8J3n8B8.mjs → list-DrS3ePsv.mjs} +4 -5
  114. package/dist/list-bN0RC14-.mjs +59 -0
  115. package/dist/{list-oAAgU5uE.mjs → list-ndIl9XqV.mjs} +11 -18
  116. package/dist/{list-tutXEQRW.mjs → list-sQcA4g05.mjs} +5 -6
  117. package/dist/{list-9uvk9dIA.mjs → list-squb_ioH.mjs} +4 -5
  118. package/dist/{list-DOZNpX4b.mjs → list-xMfCeuZc.mjs} +5 -6
  119. package/dist/{login-DqWRF3Og.mjs → login-D_1-zE4A.mjs} +15 -13
  120. package/dist/{logout-ChCz1bkf.mjs → logout-DPi2q1Wu.mjs} +3 -5
  121. package/dist/{measure-C5dIdFj1.mjs → measure-CdA8Nl3Z.mjs} +6 -6
  122. package/dist/{notification-DVrLkjFT.mjs → notification-Fcq1fIPw.mjs} +1 -1
  123. package/dist/{parameter-values-Dy4cBs5y.mjs → parameter-values-C6dj6I4g.mjs} +4 -6
  124. package/dist/{parse-enum-D0Jfm_Bz.mjs → parse-enum-B1t8S194.mjs} +1 -1
  125. package/dist/{parse-id-DDCn3VXx.mjs → parse-id-DR8aUSdL.mjs} +1 -1
  126. package/dist/{parse-ref-Wv21Roup.mjs → parse-ref-BJ_Q0tNW.mjs} +3 -7
  127. package/dist/{path-IYhuzjQV.mjs → path-B96DI8u2.mjs} +5 -6
  128. package/dist/{poll-75SvT7Zv.mjs → poll-By46YQ5J.mjs} +2 -2
  129. package/dist/{preflight-HLUVr2Yf.mjs → preflight-Bl1oitm8.mjs} +3 -4
  130. package/dist/{process-DBOOrmET.mjs → process-CcQM4qPv.mjs} +1 -1
  131. package/dist/{publish-CMkCSt8i.mjs → publish-BKJYvxif.mjs} +9 -10
  132. package/dist/{pulse-a-83M4DV.mjs → pulse-DhG6I9mI.mjs} +1 -1
  133. package/dist/{query-tWQAV9pb.mjs → query-BKSM-pbi.mjs} +9 -11
  134. package/dist/{query-Bka77J62.mjs → query-qBHjZQc_.mjs} +7 -10
  135. package/dist/{query-result-E4Q-Gra6.mjs → query-result-DBDwk8TS.mjs} +1 -1
  136. package/dist/{remove-collection-BV9wRQZD.mjs → remove-collection-BWFW7Rn6.mjs} +6 -10
  137. package/dist/{render-DHjCcUXn.mjs → render-DmykmrFB.mjs} +11 -8
  138. package/dist/{replace-mt47dlRV.mjs → replace-BmAqD3zY.mjs} +5 -6
  139. package/dist/{rescan-values-6cRjcpTs.mjs → rescan-values-BrCLrihF.mjs} +4 -5
  140. package/dist/{run-DI_pDxji.mjs → run-CtbzjDKY.mjs} +6 -7
  141. package/dist/{run-BmGmC-GQ.mjs → run-q5Y44Fxj.mjs} +26 -15
  142. package/dist/{runs-9Fu0mug5.mjs → runs-JFlbezkQ.mjs} +7 -8
  143. package/dist/{runtime-CNAZ_FuR.mjs → runtime-BQiGgbgZ.mjs} +851 -361
  144. package/dist/{schema-tables-CLG0mtQb.mjs → schema-tables-Bzx2ShyE.mjs} +5 -6
  145. package/dist/{schemas-Cm5NWy59.mjs → schemas-ww5mU2AS.mjs} +5 -6
  146. package/dist/{search-CljYyf2F.mjs → search-J4RwCof-.mjs} +9 -15
  147. package/dist/{segment-IRzlQggt.mjs → segment-XXTjU0eG.mjs} +6 -6
  148. package/dist/{selectors-D4iOP5uB.mjs → selectors-BAAZMi43.mjs} +3 -3
  149. package/dist/{send-D7DBnQbu.mjs → send-BmpDlw9O.mjs} +4 -5
  150. package/dist/{set-DKN8fuC6.mjs → set-DUWrSza9.mjs} +5 -6
  151. package/dist/{set-active-CkE0Eiqh.mjs → set-active-BiUlbNI5.mjs} +5 -6
  152. package/dist/{setting-CN4l8N-b.mjs → setting-B1KBQN3M.mjs} +4 -4
  153. package/dist/{setup-BpTptmdO.mjs → setup-CVaNVwOd.mjs} +4 -5
  154. package/dist/{signal-CMd0EFUa.mjs → signal-GhGmuHfx.mjs} +11 -2
  155. package/dist/{list-CtZAu4im.mjs → skill-list-DTnDhnL5.mjs} +17 -47
  156. package/dist/{skills-BSAiLI3Z.mjs → skills-BWrAlj9l.mjs} +3 -3
  157. package/dist/{skills-hVKSOCUf.mjs → skills-DkDsSH5F.mjs} +102 -14
  158. package/dist/snippet-CG75L2DS.mjs +19 -0
  159. package/dist/{snippet-BxgvQ09J.mjs → snippet-CyKAgIZl.mjs} +2 -5
  160. package/dist/{snippet-DecHB4Dn.mjs → snippet-oJLaYW9V.mjs} +1 -1
  161. package/dist/{stash-DJs6A6BA.mjs → stash-DMm8YF8V.mjs} +7 -12
  162. package/dist/{status-N_2EaWb7.mjs → status-BzEQjQ_t.mjs} +15 -23
  163. package/dist/{status-DtwBDRtc.mjs → status-ClWsQD6v.mjs} +22 -48
  164. package/dist/{subscription-BnGDp1oy.mjs → subscription-CdFn2hre.mjs} +6 -6
  165. package/dist/{subscriptions-BfFwV__x.mjs → subscriptions-DBda1pE5.mjs} +7 -8
  166. package/dist/{summary-CHiq-4mz.mjs → summary-B4GPiuqD.mjs} +4 -5
  167. package/dist/{sync-schema-DhnM-rpm.mjs → sync-schema-DsIM5g2U.mjs} +5 -6
  168. package/dist/{sync-task-G1K47Nvn.mjs → sync-task-BACcrs0i.mjs} +1 -1
  169. package/dist/{table-BQaiCSNS.mjs → table-D4Alrrwh.mjs} +5 -5
  170. package/dist/timeline-DmM0BuX8.mjs +21 -0
  171. package/dist/{timeline-event-B7H1y8s8.mjs → timeline-event-DWIh3Tdt.mjs} +6 -6
  172. package/dist/transform-BcV_XlSX.mjs +28 -0
  173. package/dist/{transform-CiDOJGBW.mjs → transform-Bk0D0nIs.mjs} +2 -2
  174. package/dist/{transform-BvOEn41C.mjs → transform-DpuG-ON3.mjs} +25 -7
  175. package/dist/{transform-job-50GZHhKH.mjs → transform-job-AaMZRxAq.mjs} +1 -1
  176. package/dist/{transform-job-DRrK28IH.mjs → transform-job-CCguL6LP.mjs} +41 -4
  177. package/dist/transform-job-CjtwBGoM.mjs +22 -0
  178. package/dist/{transform-tag-jBVd6wXd.mjs → transform-tag-CcElGp3C.mjs} +4 -9
  179. package/dist/{transform-tag-Dip51YBa.mjs → transform-tag-DJ3_bksm.mjs} +5 -5
  180. package/dist/{transform-tag-DiXWRCQG.mjs → transform-tag-Dmb4u3-Q.mjs} +1 -1
  181. package/dist/{transforms-C-jYgS6z.mjs → transforms-Dg2MfB2a.mjs} +7 -8
  182. package/dist/tree-BQL0f7YX.mjs +26 -0
  183. package/dist/{unpublish-BokbnLng.mjs → unpublish-DfSvb_Rs.mjs} +4 -8
  184. package/dist/{update-D9OTkZhw.mjs → update-B-hRR8gW.mjs} +5 -6
  185. package/dist/{update-CpLEEbiJ.mjs → update-BCgAyfj_.mjs} +8 -9
  186. package/dist/{update-BCGE5UYC.mjs → update-Bhmli02m.mjs} +6 -7
  187. package/dist/{update-rkbpH0lF.mjs → update-BxIyFtrX.mjs} +5 -6
  188. package/dist/{update-AZSXMJqu.mjs → update-CDo0Orvu.mjs} +9 -15
  189. package/dist/{update-B9DcRSBQ.mjs → update-CKoBDTL7.mjs} +13 -19
  190. package/dist/{update-CfQoYVTc.mjs → update-CiYxcf8M.mjs} +7 -8
  191. package/dist/{update-e7lyQPxq.mjs → update-Cr5zHb0D.mjs} +9 -15
  192. package/dist/{update-CPEU8ZEu.mjs → update-CtDHMxW8.mjs} +6 -7
  193. package/dist/{update-BBQInyiJ.mjs → update-D1QdfpKR.mjs} +6 -7
  194. package/dist/{update-C4PbAYgW.mjs → update-D4qdTlLF.mjs} +5 -6
  195. package/dist/{update-BRXKLeJH.mjs → update-DBGaJDsj.mjs} +5 -6
  196. package/dist/{update-BErxnZrj.mjs → update-Izqip6jY.mjs} +6 -7
  197. package/dist/{update-Bc8s1TL1.mjs → update-NZhIjTCf.mjs} +5 -6
  198. package/dist/{update-dashcard-St-dGcE3.mjs → update-dashcard-D5b971AO.mjs} +5 -6
  199. package/dist/{update-CKL2FtoX.mjs → update-sYLQIUgh.mjs} +6 -7
  200. package/dist/{upgrade-CUoRHfVg.mjs → upgrade-CD1xtsIv.mjs} +6 -9
  201. package/dist/{upload-CD555ui1.mjs → upload-BUd3MG90.mjs} +2 -2
  202. package/dist/upload-DzGTlldn.mjs +13 -0
  203. package/dist/{upload-BPd1Uzxc.mjs → upload-akKFxpVA.mjs} +4 -8
  204. package/dist/{uuid-CFN8LIkP.mjs → uuid-oVdJ62eA.mjs} +3 -5
  205. package/dist/{validate-BWchyW0V.mjs → validate-CWd6l6KZ.mjs} +1 -1
  206. package/dist/{validate-query-Chc43ezW.mjs → validate-query-Boi8-cAP.mjs} +2 -3
  207. package/dist/{values-BL_U-Zdw.mjs → values-DLwZl-P8.mjs} +4 -5
  208. package/dist/{verify-DnBaRmkI.mjs → verify-CH9Tw8yv.mjs} +3 -18
  209. package/dist/{wait-flags-DzytMEG8.mjs → wait-flags-DiQ_kRjZ.mjs} +3 -3
  210. package/dist/{wait-mPoOZxrw.mjs → wait-rfTdQWdi.mjs} +9 -17
  211. package/dist/{window-DSb1tqSe.mjs → window-BkvrP0gB.mjs} +1 -1
  212. package/package.json +1 -1
  213. package/skill-data/core/SKILL.md +24 -16
  214. package/skill-data/data-workflow/references/building-clean-tables.md +6 -2
  215. package/skill-data/data-workflow/references/reusable-definitions.md +11 -3
  216. package/skill-data/document/SKILL.md +4 -1
  217. package/skill-data/git-sync/SKILL.md +6 -91
  218. package/skill-data/mbql/SKILL.md +1 -1
  219. package/skill-data/mbql/references/operators.md +20 -15
  220. package/skill-data/metadata/SKILL.md +1 -1
  221. package/skill-data/metadata/references/semantic-types.md +7 -1
  222. package/skill-data/native-sql/references/template-tags.md +6 -2
  223. package/skill-data/notification/SKILL.md +7 -1
  224. package/skill-data/transform/SKILL.md +13 -11
  225. package/skill-data/visualization/SKILL.md +11 -3
  226. package/skill-data/visualization/references/settings.md +6 -4
  227. package/skills/metabase-cli/SKILL.md +1 -1
  228. package/dist/archive-CqOKKrb2.mjs +0 -38
  229. package/dist/archive-DCjdICg7.mjs +0 -38
  230. package/dist/branch-BSeGrtP7.mjs +0 -28
  231. package/dist/cancel-task-BMQXtjW5.mjs +0 -34
  232. package/dist/card-RlzLDB2z.mjs +0 -24
  233. package/dist/collection-Bhe20ckt.mjs +0 -20
  234. package/dist/create-DwrhcI8r2.mjs +0 -144
  235. package/dist/create-branch-B3BMpF1g.mjs +0 -49
  236. package/dist/delete-D_OgiI4v.mjs +0 -86
  237. package/dist/dependencies-DEx0BsZ3.mjs +0 -41
  238. package/dist/dirty-dC1-Ud0G.mjs +0 -40
  239. package/dist/document-DOJbBWLF.mjs +0 -19
  240. package/dist/export-preflight-B5MvYhm3.mjs +0 -67
  241. package/dist/get-CNEQK0-9.mjs +0 -81
  242. package/dist/get-Cfagmy1i.mjs +0 -42
  243. package/dist/get-DvLuY5Xu.mjs +0 -38
  244. package/dist/get-DwdMvWXU.mjs +0 -44
  245. package/dist/get-jV8G90Zy.mjs +0 -42
  246. package/dist/get-mGEv-kag.mjs +0 -33
  247. package/dist/git-sync-DjoaNmRM.mjs +0 -29
  248. package/dist/is-dirty-Cwxq4_gd.mjs +0 -44
  249. package/dist/library-Cfw6eF35.mjs +0 -19
  250. package/dist/list-5Iojbr_p.mjs +0 -37
  251. package/dist/list-BD4onDqO.mjs +0 -37
  252. package/dist/list-C2yL7-CH.mjs +0 -45
  253. package/dist/list-CbbKip6U.mjs +0 -32
  254. package/dist/list-Dg2XeDON.mjs +0 -47
  255. package/dist/network-error-D6CiOEBw.mjs +0 -431
  256. package/dist/pin-BuZ_kg-u.mjs +0 -62
  257. package/dist/predicates-Bkm2IoeX.mjs +0 -170
  258. package/dist/scope-DsGuWG5w.mjs +0 -11
  259. package/dist/snippet-LlHz3FdJ.mjs +0 -19
  260. package/dist/timeline-C2VW0Ph6.mjs +0 -21
  261. package/dist/transform-DAf0Y02t.mjs +0 -28
  262. package/dist/transform-job-ntiT5Rrh.mjs +0 -22
  263. package/dist/tree-DtyJhD54.mjs +0 -36
  264. package/dist/unpin-DxbXmLtW.mjs +0 -45
  265. package/dist/upload-Dc3QLhZw.mjs +0 -13
  266. package/dist/worktree-ChdDlG3Q.mjs +0 -25
  267. package/dist/worktree-DC0kTxxQ.mjs +0 -20
  268. package/dist/worktree-xAro1xAB.mjs +0 -24
@@ -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 { A as ENV_SKIP_PREFLIGHT, D as ENV_DISABLE_KEYRING, E as ENV_API_KEY, F as setMetabaseAugment, J as toAliasArray, K as flagConsumesValue, L as version, M as ENV_WORKTREE, N as consumeLegacyEnvWarnings, P as readEnv, T as warn, c as checkCapabilities, i as mainOnlyRefusal, j as ENV_URL, l as mergeCapabilities, n as interruptSignal, o as resolveScopeSource, q as normalizeFlag, r as formatWorktreeRef, s as BASELINE_CAPABILITIES, t as readVerbChain, u as reportError } 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 { $ as ValidationError, A as setMetabaseAugment, C as ENV_DISABLE_KEYRING, D as ENV_URL, E as ENV_SKIP_PREFLIGHT, G as ChainedRequestError, H as normalizeFlag, J as MetabaseError, K as ConfigError, M as version, O as consumeLegacyEnvWarnings, S as ENV_API_KEY, U as toAliasArray, V as flagConsumesValue, X as ResponseShapeError, Y as NetworkError, Z as TimeoutError, at as featureGap, ct as editionFromTag, dt as FEATURE_RULES, et as errorMessage, ft as Features, h as isPlainObject, ht as TokenFeatures, i as reportError, it as createServerProfile, k as readEnv, lt as tryParseTag, mt as SessionProperties, n as methodRequirements, nt as KNOWN_RANGE, ot as Edition, r as summarizeCapabilities, rt as Skew, st as ParsedVersion, t as interruptSignal, tt as isFileNotFoundError, ut as FEATURE_NAMES, x as warn } 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;
@@ -34,36 +46,750 @@ var CapabilityError = class extends MetabaseError {
34
46
  }
35
47
  };
36
48
  //#endregion
37
- //#region ../client/src/domain/session-properties.ts
38
- const ServerVersion = z.object({
39
- tag: z.string(),
40
- date: z.string().optional(),
41
- hash: z.string().optional()
42
- }).loose();
43
- const TokenFeatures = z.record(z.string(), z.boolean());
44
- const SessionProperties = z.object({
45
- version: ServerVersion,
46
- "token-features": TokenFeatures.optional()
47
- }).loose();
49
+ //#region ../client/src/version/probe.ts
50
+ const PROBE_PATH = "/api/session/properties";
51
+ const PROBE_TIMEOUT_MS = 1e4;
52
+ async function probeServer(client, opts = {}) {
53
+ const properties = await client.requestParsed(SessionProperties, PROBE_PATH, {
54
+ timeoutMs: PROBE_TIMEOUT_MS,
55
+ retries: opts.retries ?? 0
56
+ });
57
+ const { tag } = properties.version;
58
+ return {
59
+ version: tryParseTag(tag),
60
+ edition: editionFromTag(tag),
61
+ date: properties.version.date ?? null,
62
+ hash: properties.version.hash ?? null,
63
+ tokenFeatures: properties["token-features"] ?? null
64
+ };
65
+ }
48
66
  //#endregion
49
- //#region ../client/src/version/tag.ts
50
- const ParsedVersion = z.object({
51
- tag: z.string(),
52
- major: z.number().int().nonnegative(),
53
- patch: z.number().int().nonnegative()
67
+ //#region ../client/src/version/requirement-check.ts
68
+ /** The first feature a method needs that the profile lacks, or `null` when it may proceed. */
69
+ function checkRequirements(key, profile) {
70
+ return checkFeatures(methodRequirements(key), profile);
71
+ }
72
+ /** The first of `features` the profile lacks, or `null` when it has every one. */
73
+ function checkFeatures(features, profile) {
74
+ for (const feature of features) {
75
+ const gap = featureGap(profile, feature);
76
+ if (gap !== null) return describeGap(gap, feature, profile);
77
+ }
78
+ return null;
79
+ }
80
+ function describeGap(gap, feature, profile) {
81
+ const rule = FEATURE_RULES[feature];
82
+ const serverVersion = profile.version === null ? null : profile.version.tag;
83
+ const tokenFeature = rule.tokenFeature ?? null;
84
+ if (gap.kind === "token") return {
85
+ reason: "missing-token-feature",
86
+ detail: missingTokenFeatureMessage(gap.tokenFeature),
87
+ feature,
88
+ since: rule.since,
89
+ tokenFeature,
90
+ serverVersion
91
+ };
92
+ return {
93
+ reason: "version-too-old",
94
+ detail: versionTooOldMessage(rule.since, serverVersion),
95
+ feature,
96
+ since: rule.since,
97
+ tokenFeature,
98
+ serverVersion
99
+ };
100
+ }
101
+ //#endregion
102
+ //#region src/core/auth/server-summary.ts
103
+ const KnownRange = z.object({
104
+ min: z.number().int(),
105
+ max: z.number().int()
106
+ });
107
+ const ServerSummary = z.object({
108
+ version: ParsedVersion.nullable(),
109
+ edition: Edition.nullable(),
110
+ skew: Skew.nullable(),
111
+ knownRange: KnownRange,
112
+ tokenFeatures: TokenFeatures.nullable(),
113
+ features: Features.nullable()
54
114
  });
55
- const DEV_BUILD_SUFFIX = "-SNAPSHOT";
56
- 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;
115
+ function summarizeServer(info) {
116
+ if (info === null) return {
117
+ version: null,
118
+ edition: null,
119
+ skew: null,
120
+ knownRange: KNOWN_RANGE,
121
+ tokenFeatures: null,
122
+ features: null
123
+ };
124
+ const profile = createServerProfile(info);
125
+ return {
126
+ version: profile.version,
127
+ edition: profile.edition,
128
+ skew: profile.skew,
129
+ knownRange: KNOWN_RANGE,
130
+ tokenFeatures: profile.tokenFeatures,
131
+ features: profile.features
132
+ };
133
+ }
134
+ const UNPARSEABLE_VERSION_LABEL = "an unparseable version";
135
+ function versionLabel(version) {
136
+ return version === null ? UNPARSEABLE_VERSION_LABEL : version.tag;
137
+ }
138
+ function skewNotice(profile) {
139
+ const max = KNOWN_RANGE.max;
140
+ switch (profile.skew) {
141
+ case "supported": return null;
142
+ 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.`;
143
+ case "unknown": return `Could not parse the Metabase version; assuming a head build past v${max}.`;
144
+ }
145
+ }
146
+ const PROFILE_REFRESHED_REMEDY = "the profile was refreshed — retry the command.";
147
+ function serverChangeNote(cached, fresh) {
148
+ const before = versionLabel(cached.version);
149
+ const after = versionLabel(fresh.version);
150
+ if (before !== after) return `The server's version changed since the last probe (was ${before}, now ${after}); ${PROFILE_REFRESHED_REMEDY}`;
151
+ if (!sameTokenFeatures(cached.tokenFeatures, fresh.tokenFeatures)) return `The server's premium features changed since the last probe; ${PROFILE_REFRESHED_REMEDY}`;
152
+ return null;
153
+ }
154
+ function sameTokenFeatures(a, b) {
155
+ const grantedA = grantedFeatures(a);
156
+ const grantedB = grantedFeatures(b);
157
+ return grantedA.length === grantedB.length && grantedA.every((key, i) => key === grantedB[i]);
158
+ }
159
+ function grantedFeatures(features) {
160
+ if (features === null) return [];
161
+ return Object.keys(features).filter((key) => features[key] === true).toSorted();
162
+ }
163
+ //#endregion
164
+ //#region ../client/src/url.ts
165
+ function normalizeUrl(input) {
166
+ const trimmed = input.trim().replace(/\/+$/, "");
167
+ if (!/^https?:\/\//i.test(trimmed)) throw new ConfigError("URL must start with http:// or https://");
168
+ return trimmed;
169
+ }
170
+ function displayUrl(input) {
171
+ const parsed = new URL(input);
172
+ const path = parsed.pathname.replace(/\/+$/, "");
173
+ return `${parsed.origin}${path}`;
174
+ }
175
+ const LOOPBACK_HOSTS = /* @__PURE__ */ new Set([
176
+ "localhost",
177
+ "127.0.0.1",
178
+ "::1",
179
+ "[::1]"
180
+ ]);
181
+ function isLoopbackHost(hostname) {
182
+ return LOOPBACK_HOSTS.has(hostname.toLowerCase());
183
+ }
184
+ function assertEndpointOrigin(endpoint, baseUrl, label) {
185
+ let parsed;
186
+ try {
187
+ parsed = new URL(endpoint);
188
+ } catch {
189
+ throw new ConfigError(`OAuth ${label} is not a valid URL: ${endpoint}`);
190
+ }
191
+ const base = new URL(baseUrl);
192
+ if (parsed.protocol !== "https:" && !isLoopbackHost(parsed.hostname)) throw new ConfigError(`OAuth ${label} must use https: ${endpoint}`);
193
+ if (parsed.origin !== base.origin) throw new ConfigError(`OAuth ${label} origin (${parsed.origin}) does not match the Metabase URL (${base.origin})`);
194
+ }
195
+ //#endregion
196
+ //#region ../client/src/auth/credential.ts
197
+ const API_KEY_HEADER = "x-api-key";
198
+ const AUTHORIZATION_HEADER = "authorization";
199
+ const BEARER_PREFIX = "Bearer ";
200
+ const EXPIRY_SKEW_MS = 6e4;
201
+ function credentialAuthHeader(credential) {
202
+ if (credential.kind === "apiKey") return {
203
+ name: API_KEY_HEADER,
204
+ value: credential.apiKey
205
+ };
206
+ return {
207
+ name: AUTHORIZATION_HEADER,
208
+ value: BEARER_PREFIX + credential.accessToken
209
+ };
210
+ }
211
+ const MAX_HEADER_CODE_UNIT = 255;
212
+ function headerBearingSecret(credential) {
213
+ if (credential.kind === "apiKey") return {
214
+ field: "apiKey",
215
+ value: credential.apiKey
216
+ };
217
+ return {
218
+ field: "accessToken",
219
+ value: credential.accessToken
220
+ };
221
+ }
222
+ function assertCredentialHeaderSafe(credential) {
223
+ const { field, value } = headerBearingSecret(credential);
224
+ for (let index = 0; index < value.length; index += 1) {
225
+ const codeUnit = value.charCodeAt(index);
226
+ if (codeUnit > MAX_HEADER_CODE_UNIT) {
227
+ const codePoint = codeUnit.toString(16).toUpperCase().padStart(4, "0");
228
+ 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.`);
229
+ }
230
+ }
231
+ }
232
+ function credentialSecrets(credential) {
233
+ if (credential.kind === "apiKey") return [credential.apiKey];
234
+ return [credential.accessToken, credential.refreshToken];
235
+ }
236
+ function isOAuthExpired(credential, nowMs) {
237
+ const expiryMs = Date.parse(credential.expiresAt);
238
+ if (Number.isNaN(expiryMs)) return true;
239
+ return expiryMs - EXPIRY_SKEW_MS <= nowMs;
240
+ }
241
+ function expiresAtFromNow(expiresInSeconds, nowMs) {
242
+ return new Date(nowMs + expiresInSeconds * 1e3).toISOString();
243
+ }
244
+ function oauthCredentialFromTokens(tokens, refreshToken, clientId, nowMs) {
245
+ return {
246
+ kind: "oauth",
247
+ accessToken: tokens.access_token,
248
+ refreshToken,
249
+ expiresAt: expiresAtFromNow(tokens.expires_in ?? 3600, nowMs),
250
+ clientId
251
+ };
252
+ }
253
+ //#endregion
254
+ //#region ../client/src/json.ts
255
+ const JSON_CONTENT_TYPE = "application/json";
256
+ function parseJson(input, schema, opts = {}) {
257
+ const result = parseJsonResult(input, schema, opts);
258
+ if (!result.ok) throw result.error;
259
+ return result.value;
260
+ }
261
+ function parseJsonResult(input, schema, opts = {}) {
262
+ const sourcePrefix = opts.source === void 0 ? "" : `${opts.source}: `;
263
+ let raw;
264
+ try {
265
+ raw = JSON.parse(input);
266
+ } catch (error) {
267
+ return {
268
+ ok: false,
269
+ error: new ConfigError(`${sourcePrefix}invalid JSON: ${errorMessage(error)}`)
270
+ };
271
+ }
272
+ const parsed = schema.safeParse(raw);
273
+ if (!parsed.success) return {
274
+ ok: false,
275
+ error: new ValidationError(`${sourcePrefix}value did not match expected schema`, {
276
+ source: opts.source ?? "<input>",
277
+ zodIssues: parsed.error.issues
278
+ })
279
+ };
280
+ return {
281
+ ok: true,
282
+ value: parsed.data
283
+ };
284
+ }
285
+ function parseJsonOrPlain(text, contentType, schema, opts = {}) {
286
+ if (!isJsonContentType(contentType)) return parseJson(JSON.stringify(text), schema, opts);
287
+ const attempt = parseJsonResult(text, schema, opts);
288
+ if (attempt.ok) return attempt.value;
289
+ if (attempt.error instanceof ValidationError) throw attempt.error;
290
+ return parseJson(JSON.stringify(text), schema, opts);
291
+ }
292
+ function isJsonContentType(contentType) {
293
+ return contentType !== null && contentType.includes("application/json");
294
+ }
295
+ //#endregion
296
+ //#region ../client/src/http/sanitize.ts
297
+ const SECRET_HEADER_NAMES = /* @__PURE__ */ new Set([
298
+ "authorization",
299
+ "x-api-key",
300
+ "x-metabase-session",
301
+ "cookie",
302
+ "set-cookie",
303
+ "proxy-authorization"
304
+ ]);
305
+ const REDACTED = "[REDACTED]";
306
+ function redactHeaders(headers) {
307
+ const result = {};
308
+ const entries = headers instanceof Headers ? headers.entries() : Object.entries(headers);
309
+ for (const [key, value] of entries) result[key] = SECRET_HEADER_NAMES.has(key.toLowerCase()) ? REDACTED : value;
310
+ return result;
311
+ }
312
+ function redactBody(body, ctx) {
313
+ let result = body;
314
+ for (const secret of ctx.knownSecrets) {
315
+ if (secret.length === 0) continue;
316
+ result = result.replaceAll(secret, REDACTED);
317
+ }
318
+ return result;
319
+ }
320
+ //#endregion
321
+ //#region ../client/src/http/errors.ts
322
+ const NOT_FOUND_STATUS = 404;
323
+ const TEXT_CONTENT_TYPE = "text/plain";
324
+ const ROUTE_MISSING_LITERAL = "API endpoint does not exist.";
325
+ const RESOURCE_MISSING_LITERAL = "Not found.";
326
+ const STATUS_CLASSIFICATIONS = {
327
+ 401: { retryable: false },
328
+ 403: { retryable: false },
329
+ 404: { retryable: false },
330
+ 408: {
331
+ retryable: true,
332
+ message: "Metabase timed out responding."
333
+ },
334
+ 425: { retryable: true },
335
+ 429: {
336
+ retryable: true,
337
+ message: "Metabase rate-limited the request."
338
+ },
339
+ 500: { retryable: true },
340
+ 502: { retryable: true },
341
+ 503: { retryable: true },
342
+ 504: {
343
+ retryable: true,
344
+ message: "Metabase timed out responding."
345
+ }
346
+ };
347
+ const ErrorEnvelope = z.object({
348
+ message: z.string().optional(),
349
+ error: z.string().optional(),
350
+ "error-message": z.string().optional(),
351
+ via: z.array(z.object({ message: z.string().optional() }).loose()).optional(),
352
+ "specific-errors": z.unknown().optional(),
353
+ errors: z.unknown().optional()
354
+ }).loose();
355
+ const FieldErrorNodeSchema = z.lazy(() => z.union([
356
+ z.string(),
357
+ z.array(z.string()),
358
+ z.record(z.string(), FieldErrorNodeSchema)
359
+ ]));
360
+ const FieldErrorTree = z.record(z.string(), FieldErrorNodeSchema);
361
+ const FIELD_MESSAGE_SEPARATOR = "; ";
362
+ const MAX_EXTRACTED_MESSAGE_LEN = 500;
363
+ const ELLIPSIS = "…";
364
+ var HttpError = class extends MetabaseError {
365
+ category = "http";
366
+ status;
367
+ kind;
368
+ developerDetail;
369
+ constructor(input) {
370
+ const sanitizedBody = sanitizeBody(input.rawBody, input.redactionContext);
371
+ const redactedHeaders = redactHeaders(input.responseHeaders);
372
+ const kind = classifyKind(input.status, sanitizedBody, redactedHeaders);
373
+ super(input.overrideUserMessage ?? buildUserMessage(kind, input, sanitizedBody, redactedHeaders));
374
+ const fields = extractFieldErrors(sanitizedBody);
375
+ this.name = "HttpError";
376
+ this.status = input.status;
377
+ this.kind = kind;
378
+ this.developerDetail = {
379
+ status: input.status,
380
+ statusText: input.statusText,
381
+ method: input.method,
382
+ url: input.url,
383
+ responseHeaders: redactedHeaders,
384
+ body: sanitizedBody,
385
+ fieldErrors: fields.fieldErrors,
386
+ specificFieldErrors: fields.specificFieldErrors
387
+ };
388
+ }
389
+ get isRetryable() {
390
+ return isRetryableStatus(this.status);
391
+ }
392
+ get fieldErrors() {
393
+ return this.developerDetail.fieldErrors;
394
+ }
395
+ get specificFieldErrors() {
396
+ return this.developerDetail.specificFieldErrors;
397
+ }
398
+ };
399
+ function chainRequestFailure(cause, message) {
400
+ if (cause instanceof HttpError) return new HttpError({
401
+ status: cause.status,
402
+ statusText: cause.developerDetail.statusText,
403
+ method: cause.developerDetail.method,
404
+ url: cause.developerDetail.url,
405
+ responseHeaders: cause.developerDetail.responseHeaders,
406
+ rawBody: cause.developerDetail.body,
407
+ overrideUserMessage: message
408
+ });
409
+ return new ChainedRequestError(message, cause);
410
+ }
411
+ function isRetryableStatus(status) {
412
+ return STATUS_CLASSIFICATIONS[status]?.retryable === true;
413
+ }
414
+ function sanitizeBody(rawBody, ctx) {
415
+ if (rawBody === null) return null;
416
+ if (ctx === void 0) return rawBody;
417
+ return redactBody(rawBody, ctx);
418
+ }
419
+ function classifyKind(status, sanitizedBody, redactedHeaders) {
420
+ if (status === 401 || status === 403) return "auth";
421
+ if (status === NOT_FOUND_STATUS) return isRouteMissingResponse(sanitizedBody, redactedHeaders) ? "route-missing" : "resource-missing";
422
+ if (status === 429) return "rate-limit";
423
+ if (status >= 500 && status < 600) return "server-error";
424
+ return "generic";
425
+ }
426
+ function isRouteMissingResponse(sanitizedBody, redactedHeaders) {
427
+ if (sanitizedBody?.includes(ROUTE_MISSING_LITERAL)) return true;
428
+ if (sanitizedBody?.includes(RESOURCE_MISSING_LITERAL)) return false;
429
+ if (redactedHeaders["content-type"]?.includes("application/json")) return false;
430
+ if (sanitizedBody === null || sanitizedBody.trim() === "") return true;
431
+ return parseEnvelope(sanitizedBody) === null;
432
+ }
433
+ function buildUserMessage(kind, input, sanitizedBody, redactedHeaders) {
434
+ if (kind === "route-missing") return buildRouteMissingMessage(input);
435
+ if (kind === "resource-missing") return `Not found: ${input.method} ${pathFromUrl(input.url)}.`;
436
+ const fromBody = parseEnvelopeMessage(sanitizedBody);
437
+ if (fromBody !== null) return fromBody;
438
+ if (kind === "auth") return `Invalid or unauthorized API key (host: ${hostFromUrl(input.url)}).`;
439
+ const fromText = plainTextMessage(sanitizedBody, redactedHeaders);
440
+ if (fromText !== null) return fromText;
441
+ return defaultMessageForStatus(input.status);
442
+ }
443
+ function plainTextMessage(sanitizedBody, redactedHeaders) {
444
+ if (sanitizedBody === null || !redactedHeaders["content-type"]?.includes(TEXT_CONTENT_TYPE)) return null;
445
+ const trimmed = sanitizedBody.trim();
446
+ return trimmed === "" ? null : capLength(trimmed);
447
+ }
448
+ function buildRouteMissingMessage(input) {
449
+ const path = pathFromUrl(input.url);
450
+ if (!input.serverTag) return `This endpoint is not available on the connected Metabase: ${input.method} ${path}.`;
451
+ return `This endpoint is not available on Metabase ${input.serverTag}: ${input.method} ${path}. It may require a newer Metabase major version.`;
452
+ }
453
+ function pathFromUrl(url) {
454
+ const parsed = new URL(url);
455
+ return parsed.pathname + parsed.search;
456
+ }
457
+ function hostFromUrl(url) {
458
+ return new URL(url).host;
459
+ }
460
+ function parseEnvelope(sanitizedBody) {
461
+ if (!sanitizedBody) return null;
462
+ const result = parseJsonResult(sanitizedBody, ErrorEnvelope);
463
+ return result.ok ? result.value : null;
464
+ }
465
+ const NO_FIELD_ERRORS = {
466
+ fieldErrors: null,
467
+ specificFieldErrors: null
468
+ };
469
+ function extractFieldErrors(sanitizedBody) {
470
+ const envelope = parseEnvelope(sanitizedBody);
471
+ if (envelope === null) return NO_FIELD_ERRORS;
472
+ return {
473
+ fieldErrors: parseFieldErrors(envelope.errors),
474
+ specificFieldErrors: parseFieldErrors(envelope["specific-errors"])
475
+ };
476
+ }
477
+ function parseFieldErrors(value) {
478
+ const parsed = FieldErrorTree.safeParse(value);
479
+ if (!parsed.success) return null;
480
+ const entries = collectLeafEntries(parsed.data, []);
481
+ if (entries.length === 0) return null;
482
+ return Object.fromEntries(entries.map((entry) => [entry.path, entry.message]));
483
+ }
484
+ function parseEnvelopeMessage(sanitizedBody) {
485
+ const envelope = parseEnvelope(sanitizedBody);
486
+ if (envelope === null) return null;
487
+ const topLevel = envelope.message ?? envelope.error ?? envelope["error-message"];
488
+ if (topLevel) return capLength(topLevel);
489
+ const viaMessage = envelope.via?.find((entry) => entry.message)?.message;
490
+ if (viaMessage) return capLength(viaMessage);
491
+ const specific = formatErrorTree(envelope["specific-errors"]);
492
+ if (specific) return capLength(specific);
493
+ const generic = formatErrorTree(envelope.errors);
494
+ if (generic) return capLength(generic);
495
+ return null;
496
+ }
497
+ function formatErrorTree(value) {
498
+ const entries = collectLeafEntries(value, []);
499
+ if (entries.length === 0) return null;
500
+ return entries.map(formatLeafEntry).join(FIELD_MESSAGE_SEPARATOR);
501
+ }
502
+ function formatLeafEntry(entry) {
503
+ return entry.path === "" ? entry.message : `${entry.path}: ${entry.message}`;
504
+ }
505
+ function collectLeafEntries(value, path) {
506
+ if (typeof value === "string") {
507
+ const trimmed = value.trim();
508
+ return trimmed === "" ? [] : [{
509
+ path: path.join("."),
510
+ message: trimmed
511
+ }];
512
+ }
513
+ if (Array.isArray(value)) {
514
+ const messages = value.filter((entry) => typeof entry === "string" && entry.trim() !== "");
515
+ if (messages.length === 0) return [];
516
+ return [{
517
+ path: path.join("."),
518
+ message: messages.join(FIELD_MESSAGE_SEPARATOR)
519
+ }];
520
+ }
521
+ if (isPlainObject(value)) return Object.entries(value).flatMap(([key, child]) => collectLeafEntries(child, [...path, key]));
522
+ return [];
523
+ }
524
+ function capLength(message) {
525
+ if (message.length <= MAX_EXTRACTED_MESSAGE_LEN) return message;
526
+ return message.slice(0, MAX_EXTRACTED_MESSAGE_LEN - 1) + ELLIPSIS;
527
+ }
528
+ function defaultMessageForStatus(status) {
529
+ return STATUS_CLASSIFICATIONS[status]?.message ?? `Metabase returned ${status}.`;
530
+ }
531
+ //#endregion
532
+ //#region ../client/src/http/network-error.ts
533
+ const NETWORK_HINTS = {
534
+ ECONNREFUSED: (t) => `Connection refused by ${t.host} — is Metabase running and is the port correct?`,
535
+ ENOTFOUND: (t) => `Host not found: ${t.hostname} — check the URL.`,
536
+ EAI_AGAIN: (t) => `Could not resolve ${t.hostname} — check your network connection and the URL.`,
537
+ ECONNRESET: (t) => `Connection to ${t.host} was reset — the server may have closed it, or http/https may be mismatched.`,
538
+ UND_ERR_SOCKET: (t) => `Connection to ${t.host} was closed by the other side — a pooled connection or a proxy may have dropped it.`,
539
+ EPIPE: (t) => `Connection to ${t.host} closed while the request was still being written — the server or a proxy dropped it.`,
540
+ ETIMEDOUT: (t) => `Connection to ${t.host} timed out — check the host, port, and your network.`
541
+ };
542
+ const CONNECTION_CLOSED_CODES = /* @__PURE__ */ new Set([
543
+ "ECONNRESET",
544
+ "UND_ERR_SOCKET",
545
+ "EPIPE"
546
+ ]);
547
+ const TLS_ERROR_CODES = /* @__PURE__ */ new Set([
548
+ "EPROTO",
549
+ "DEPTH_ZERO_SELF_SIGNED_CERT",
550
+ "SELF_SIGNED_CERT_IN_CHAIN",
551
+ "UNABLE_TO_VERIFY_LEAF_SIGNATURE",
552
+ "CERT_HAS_EXPIRED",
553
+ "ERR_TLS_CERT_ALTNAME_INVALID"
554
+ ]);
555
+ function buildNetworkError(error, method, url) {
556
+ const fallback = errorMessage(error);
557
+ const code = failureCode(error);
558
+ return new NetworkError(networkMessage(code, networkTarget(url), fallback), {
559
+ method,
560
+ url,
561
+ cause: code ?? fallback
562
+ });
563
+ }
564
+ function isConnectionClosed(error) {
565
+ const code = failureCode(error);
566
+ return code !== null && CONNECTION_CLOSED_CODES.has(code);
567
+ }
568
+ function networkMessage(code, target, fallback) {
569
+ if (code === null) return `Could not reach Metabase: ${fallback}`;
570
+ 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.`;
571
+ const hint = NETWORK_HINTS[code];
572
+ if (hint === void 0) return `Could not reach Metabase: ${fallback} (${code})`;
573
+ return `Could not reach Metabase: ${hint(target)}`;
574
+ }
575
+ function failureCode(error) {
576
+ const own = errorCode(error);
577
+ if (own !== null) return own;
578
+ return errorCode(error instanceof Error ? error.cause : void 0);
579
+ }
580
+ function errorCode(value) {
581
+ if (value instanceof Error && "code" in value && typeof value.code === "string") return value.code;
582
+ return null;
583
+ }
584
+ function networkTarget(url) {
585
+ const parsed = new URL(url);
60
586
  return {
61
- tag,
62
- major: parsed.minor,
63
- patch: parsed.patch
587
+ host: parsed.host,
588
+ hostname: parsed.hostname
64
589
  };
65
590
  }
66
591
  //#endregion
592
+ //#region ../client/src/http/oauth.ts
593
+ const DISCOVERY_PATH = "/.well-known/oauth-authorization-server";
594
+ const FORM_CONTENT_TYPE = "application/x-www-form-urlencoded";
595
+ const OAUTH_TIMEOUT_MS = 3e4;
596
+ async function oauthFetch(request) {
597
+ const timeoutSignal = AbortSignal.timeout(OAUTH_TIMEOUT_MS);
598
+ try {
599
+ return await fetch(request.url, {
600
+ method: request.method,
601
+ headers: {
602
+ ...request.headers,
603
+ "user-agent": request.userAgent
604
+ },
605
+ ...request.body !== void 0 ? { body: request.body } : {},
606
+ signal: timeoutSignal
607
+ });
608
+ } catch (error) {
609
+ if (timeoutSignal.aborted) throw new TimeoutError(`OAuth request timed out after ${OAUTH_TIMEOUT_MS}ms`, {
610
+ kind: "http",
611
+ method: request.method,
612
+ url: request.url,
613
+ timeoutMs: OAUTH_TIMEOUT_MS
614
+ });
615
+ throw buildNetworkError(error, request.method, request.url);
616
+ }
617
+ }
618
+ const OAUTH_SCOPE = "mb:full";
619
+ const OAuthServerMetadata = z.object({
620
+ issuer: z.string(),
621
+ authorization_endpoint: z.string(),
622
+ token_endpoint: z.string(),
623
+ registration_endpoint: z.string().optional(),
624
+ revocation_endpoint: z.string().optional(),
625
+ scopes_supported: z.array(z.string()).optional()
626
+ }).loose();
627
+ const RegisteredClient = z.object({ client_id: z.string() }).loose();
628
+ const OAuthTokens = z.object({
629
+ access_token: z.string(),
630
+ token_type: z.string(),
631
+ expires_in: z.number().int().optional(),
632
+ refresh_token: z.string().optional()
633
+ }).loose();
634
+ const OAuthErrorBody = z.object({
635
+ error: z.string(),
636
+ error_description: z.string().optional()
637
+ }).loose();
638
+ async function readJson(response, schema, source) {
639
+ let raw;
640
+ try {
641
+ raw = await response.json();
642
+ } catch (error) {
643
+ throw new ConfigError(`${source}: invalid JSON response (${errorMessage(error)})`);
644
+ }
645
+ const parsed = schema.safeParse(raw);
646
+ if (!parsed.success) throw new ConfigError(`${source}: unexpected response shape`);
647
+ return parsed.data;
648
+ }
649
+ async function failure(response, source, method, url) {
650
+ const rawBody = await response.text().catch(() => "");
651
+ if (isRetryableStatus(response.status)) return new HttpError({
652
+ status: response.status,
653
+ statusText: response.statusText,
654
+ method,
655
+ url,
656
+ responseHeaders: response.headers,
657
+ rawBody
658
+ });
659
+ const parsed = parseJsonResult(rawBody, OAuthErrorBody);
660
+ if (parsed.ok) {
661
+ const detail = parsed.value.error_description ?? parsed.value.error;
662
+ return new ConfigError(`${source} failed (${response.status}): ${detail}`);
663
+ }
664
+ return new ConfigError(`${source} failed (${response.status})`);
665
+ }
666
+ async function postForm(url, userAgent, params, schema, source) {
667
+ const response = await oauthFetch({
668
+ url,
669
+ method: "POST",
670
+ userAgent,
671
+ headers: {
672
+ "content-type": FORM_CONTENT_TYPE,
673
+ accept: JSON_CONTENT_TYPE
674
+ },
675
+ body: new URLSearchParams(params)
676
+ });
677
+ if (!response.ok) throw await failure(response, source, "POST", url);
678
+ return readJson(response, schema, source);
679
+ }
680
+ const OAUTH_UNSUPPORTED_MESSAGE = "this Metabase does not support OAuth login (requires Metabase v63 or newer)";
681
+ async function tryDiscoverMetadata(baseUrl, userAgent) {
682
+ const response = await oauthFetch({
683
+ url: `${baseUrl}${DISCOVERY_PATH}`,
684
+ method: "GET",
685
+ userAgent,
686
+ headers: { accept: JSON_CONTENT_TYPE }
687
+ });
688
+ const contentType = response.headers.get("content-type") ?? "";
689
+ if (!response.ok || !contentType.includes("json")) {
690
+ await response.body?.cancel().catch(() => void 0);
691
+ return null;
692
+ }
693
+ const metadata = await readJson(response, OAuthServerMetadata, "OAuth discovery");
694
+ const scopes = metadata.scopes_supported;
695
+ if (scopes !== void 0 && !scopes.includes("mb:full")) return null;
696
+ assertEndpointOrigin(metadata.issuer, baseUrl, "issuer");
697
+ assertEndpointOrigin(metadata.authorization_endpoint, baseUrl, "authorization endpoint");
698
+ assertEndpointOrigin(metadata.token_endpoint, baseUrl, "token endpoint");
699
+ if (metadata.registration_endpoint !== void 0) assertEndpointOrigin(metadata.registration_endpoint, baseUrl, "registration endpoint");
700
+ if (metadata.revocation_endpoint !== void 0) assertEndpointOrigin(metadata.revocation_endpoint, baseUrl, "revocation endpoint");
701
+ return metadata;
702
+ }
703
+ async function discoverMetadata(baseUrl, userAgent) {
704
+ const metadata = await tryDiscoverMetadata(baseUrl, userAgent);
705
+ if (metadata === null) throw new ConfigError(OAUTH_UNSUPPORTED_MESSAGE);
706
+ return metadata;
707
+ }
708
+ async function registerClient(input) {
709
+ const response = await oauthFetch({
710
+ url: input.registrationEndpoint,
711
+ method: "POST",
712
+ userAgent: input.userAgent,
713
+ headers: {
714
+ "content-type": JSON_CONTENT_TYPE,
715
+ accept: JSON_CONTENT_TYPE
716
+ },
717
+ body: JSON.stringify({
718
+ application_type: "native",
719
+ client_name: input.clientName,
720
+ redirect_uris: [input.redirectUri],
721
+ grant_types: ["authorization_code", "refresh_token"],
722
+ response_types: ["code"],
723
+ token_endpoint_auth_method: "none",
724
+ scope: OAUTH_SCOPE
725
+ })
726
+ });
727
+ if (!response.ok) throw await failure(response, "OAuth client registration", "POST", input.registrationEndpoint);
728
+ return readJson(response, RegisteredClient, "OAuth client registration");
729
+ }
730
+ function exchangeCode(input) {
731
+ return postForm(input.tokenEndpoint, input.userAgent, {
732
+ grant_type: "authorization_code",
733
+ code: input.code,
734
+ redirect_uri: input.redirectUri,
735
+ client_id: input.clientId,
736
+ code_verifier: input.codeVerifier
737
+ }, OAuthTokens, "OAuth token exchange");
738
+ }
739
+ function refreshTokens(input) {
740
+ return postForm(input.tokenEndpoint, input.userAgent, {
741
+ grant_type: "refresh_token",
742
+ refresh_token: input.refreshToken,
743
+ client_id: input.clientId
744
+ }, OAuthTokens, "OAuth token refresh");
745
+ }
746
+ async function revokeToken(input) {
747
+ const response = await oauthFetch({
748
+ url: input.revocationEndpoint,
749
+ method: "POST",
750
+ userAgent: input.userAgent,
751
+ headers: { "content-type": FORM_CONTENT_TYPE },
752
+ body: new URLSearchParams({
753
+ token: input.token,
754
+ client_id: input.clientId
755
+ })
756
+ });
757
+ if (!response.ok) throw await failure(response, "OAuth token revocation", "POST", input.revocationEndpoint);
758
+ await response.body?.cancel().catch(() => void 0);
759
+ }
760
+ //#endregion
761
+ //#region ../client/src/auth/oauth-session.ts
762
+ async function refreshOAuthCredential(baseUrl, credential, nowMs, userAgent) {
763
+ const tokens = await refreshTokens({
764
+ tokenEndpoint: (await discoverMetadata(baseUrl, userAgent)).token_endpoint,
765
+ refreshToken: credential.refreshToken,
766
+ clientId: credential.clientId,
767
+ userAgent
768
+ });
769
+ return oauthCredentialFromTokens(tokens, tokens.refresh_token ?? credential.refreshToken, credential.clientId, nowMs);
770
+ }
771
+ async function revokeOAuthCredential(baseUrl, credential, userAgent) {
772
+ const revocationEndpoint = (await discoverMetadata(baseUrl, userAgent)).revocation_endpoint;
773
+ if (revocationEndpoint === void 0) return false;
774
+ await revokeToken({
775
+ revocationEndpoint,
776
+ token: credential.refreshToken,
777
+ clientId: credential.clientId,
778
+ userAgent
779
+ });
780
+ await revokeToken({
781
+ revocationEndpoint,
782
+ token: credential.accessToken,
783
+ clientId: credential.clientId,
784
+ userAgent
785
+ });
786
+ return true;
787
+ }
788
+ //#endregion
789
+ //#region src/core/user-agent.ts
790
+ const USER_AGENT = `metabase-cli/${version}`;
791
+ const OAUTH_CLIENT_NAME = "Metabase CLI";
792
+ //#endregion
67
793
  //#region src/core/paths.ts
68
794
  const APP_DIR_NAME = "metabase-cli";
69
795
  function configDir() {
@@ -80,6 +806,9 @@ const ProbedUser = z.object({
80
806
  const ProfileLastProbe = z.object({
81
807
  at: z.iso.datetime(),
82
808
  version: ParsedVersion.nullable(),
809
+ edition: Edition.nullable().default(null),
810
+ date: z.string().nullable().default(null),
811
+ hash: z.string().nullable().default(null),
83
812
  tokenFeatures: TokenFeatures.nullable(),
84
813
  user: ProbedUser
85
814
  });
@@ -100,18 +829,13 @@ const ProfileOAuth = z.object({
100
829
  clientId: z.string()
101
830
  }).loose();
102
831
  const ProfileAuthMethod = z.enum(["oauth", "apiKey"]);
103
- const ProfilePin = z.object({
104
- id: z.number().int().positive(),
105
- branch: z.string()
106
- });
107
832
  const ProfileRecord = z.object({
108
833
  name: z.string(),
109
834
  url: z.string(),
110
835
  apiKey: z.string().nullable(),
111
836
  oauth: ProfileOAuth.nullable().default(null),
112
837
  lastProbe: ProfileLastProbe.nullable(),
113
- lastFailure: ProfileLastFailure.nullable(),
114
- worktree: ProfilePin.nullable().default(null)
838
+ lastFailure: ProfileLastFailure.nullable()
115
839
  }).loose();
116
840
  const ProfilesFile = z.object({ profiles: z.array(ProfileRecord) }).loose();
117
841
  function profileAuthMethod(record) {
@@ -331,8 +1055,7 @@ async function writeProfile(profile, name = DEFAULT_PROFILE) {
331
1055
  apiKey: inlineApiKey,
332
1056
  oauth: null,
333
1057
  lastProbe: null,
334
- lastFailure: null,
335
- worktree: null
1058
+ lastFailure: null
336
1059
  } : {
337
1060
  ...existing,
338
1061
  url: profile.url,
@@ -363,8 +1086,7 @@ async function writeOAuthProfile(url, credential, name = DEFAULT_PROFILE) {
363
1086
  apiKey: null,
364
1087
  oauth,
365
1088
  lastProbe: null,
366
- lastFailure: null,
367
- worktree: null
1089
+ lastFailure: null
368
1090
  } : {
369
1091
  ...existing,
370
1092
  url,
@@ -381,6 +1103,9 @@ async function writeProbeResult(name, input) {
381
1103
  const probe = ProfileLastProbe.parse({
382
1104
  at: (/* @__PURE__ */ new Date()).toISOString(),
383
1105
  version: input.server.version,
1106
+ edition: input.server.edition,
1107
+ date: input.server.date,
1108
+ hash: input.server.hash,
384
1109
  tokenFeatures: input.server.tokenFeatures,
385
1110
  user: input.user
386
1111
  });
@@ -415,18 +1140,6 @@ async function writeProbeFailure(name, input) {
415
1140
  });
416
1141
  return failure;
417
1142
  }
418
- async function writeProfileWorktree(name, pin) {
419
- const file = await readProfilesFile();
420
- if (findRecord(file, name) === null) throw new ConfigError(`no such profile "${name}"; run \`mb auth login --profile ${name}\` first`);
421
- const profiles = file.profiles.map((entry) => entry.name === name ? {
422
- ...entry,
423
- worktree: pin
424
- } : entry);
425
- await writeProfilesFile({
426
- ...file,
427
- profiles
428
- });
429
- }
430
1143
  async function clearProfile(name = DEFAULT_PROFILE) {
431
1144
  const file = await readProfilesFile();
432
1145
  const existing = findRecord(file, name);
@@ -444,207 +1157,6 @@ async function clearProfile(name = DEFAULT_PROFILE) {
444
1157
  return true;
445
1158
  }
446
1159
  //#endregion
447
- //#region ../client/src/http/oauth.ts
448
- const DISCOVERY_PATH = "/.well-known/oauth-authorization-server";
449
- const FORM_CONTENT_TYPE = "application/x-www-form-urlencoded";
450
- const OAUTH_TIMEOUT_MS = 3e4;
451
- async function oauthFetch(request) {
452
- const timeoutSignal = AbortSignal.timeout(OAUTH_TIMEOUT_MS);
453
- try {
454
- return await fetch(request.url, {
455
- method: request.method,
456
- headers: {
457
- ...request.headers,
458
- "user-agent": request.userAgent
459
- },
460
- ...request.body !== void 0 ? { body: request.body } : {},
461
- signal: timeoutSignal
462
- });
463
- } catch (error) {
464
- if (timeoutSignal.aborted) throw new TimeoutError(`OAuth request timed out after ${OAUTH_TIMEOUT_MS}ms`, {
465
- kind: "http",
466
- method: request.method,
467
- url: request.url,
468
- timeoutMs: OAUTH_TIMEOUT_MS
469
- });
470
- throw buildNetworkError(error, request.method, request.url);
471
- }
472
- }
473
- const OAUTH_SCOPE = "mb:full";
474
- const OAuthServerMetadata = z.object({
475
- issuer: z.string(),
476
- authorization_endpoint: z.string(),
477
- token_endpoint: z.string(),
478
- registration_endpoint: z.string().optional(),
479
- revocation_endpoint: z.string().optional(),
480
- scopes_supported: z.array(z.string()).optional()
481
- }).loose();
482
- const RegisteredClient = z.object({ client_id: z.string() }).loose();
483
- const OAuthTokens = z.object({
484
- access_token: z.string(),
485
- token_type: z.string(),
486
- expires_in: z.number().int().optional(),
487
- refresh_token: z.string().optional()
488
- }).loose();
489
- const OAuthErrorBody = z.object({
490
- error: z.string(),
491
- error_description: z.string().optional()
492
- }).loose();
493
- async function readJson(response, schema, source) {
494
- let raw;
495
- try {
496
- raw = await response.json();
497
- } catch (error) {
498
- throw new ConfigError(`${source}: invalid JSON response (${errorMessage(error)})`);
499
- }
500
- const parsed = schema.safeParse(raw);
501
- if (!parsed.success) throw new ConfigError(`${source}: unexpected response shape`);
502
- return parsed.data;
503
- }
504
- async function failure(response, source, method, url) {
505
- const rawBody = await response.text().catch(() => "");
506
- if (isRetryableStatus(response.status)) return new HttpError({
507
- status: response.status,
508
- statusText: response.statusText,
509
- method,
510
- url,
511
- responseHeaders: response.headers,
512
- rawBody
513
- });
514
- const parsed = parseJsonResult(rawBody, OAuthErrorBody);
515
- if (parsed.ok) {
516
- const detail = parsed.value.error_description ?? parsed.value.error;
517
- return new ConfigError(`${source} failed (${response.status}): ${detail}`);
518
- }
519
- return new ConfigError(`${source} failed (${response.status})`);
520
- }
521
- async function postForm(url, userAgent, params, schema, source) {
522
- const response = await oauthFetch({
523
- url,
524
- method: "POST",
525
- userAgent,
526
- headers: {
527
- "content-type": FORM_CONTENT_TYPE,
528
- accept: JSON_CONTENT_TYPE
529
- },
530
- body: new URLSearchParams(params)
531
- });
532
- if (!response.ok) throw await failure(response, source, "POST", url);
533
- return readJson(response, schema, source);
534
- }
535
- const OAUTH_UNSUPPORTED_MESSAGE = "this Metabase does not support OAuth login (requires Metabase v63 or newer)";
536
- async function tryDiscoverMetadata(baseUrl, userAgent) {
537
- const response = await oauthFetch({
538
- url: `${baseUrl}${DISCOVERY_PATH}`,
539
- method: "GET",
540
- userAgent,
541
- headers: { accept: JSON_CONTENT_TYPE }
542
- });
543
- const contentType = response.headers.get("content-type") ?? "";
544
- if (!response.ok || !contentType.includes("json")) {
545
- await response.body?.cancel().catch(() => void 0);
546
- return null;
547
- }
548
- const metadata = await readJson(response, OAuthServerMetadata, "OAuth discovery");
549
- const scopes = metadata.scopes_supported;
550
- if (scopes !== void 0 && !scopes.includes("mb:full")) return null;
551
- assertEndpointOrigin(metadata.issuer, baseUrl, "issuer");
552
- assertEndpointOrigin(metadata.authorization_endpoint, baseUrl, "authorization endpoint");
553
- assertEndpointOrigin(metadata.token_endpoint, baseUrl, "token endpoint");
554
- if (metadata.registration_endpoint !== void 0) assertEndpointOrigin(metadata.registration_endpoint, baseUrl, "registration endpoint");
555
- if (metadata.revocation_endpoint !== void 0) assertEndpointOrigin(metadata.revocation_endpoint, baseUrl, "revocation endpoint");
556
- return metadata;
557
- }
558
- async function discoverMetadata(baseUrl, userAgent) {
559
- const metadata = await tryDiscoverMetadata(baseUrl, userAgent);
560
- if (metadata === null) throw new ConfigError(OAUTH_UNSUPPORTED_MESSAGE);
561
- return metadata;
562
- }
563
- async function registerClient(input) {
564
- const response = await oauthFetch({
565
- url: input.registrationEndpoint,
566
- method: "POST",
567
- userAgent: input.userAgent,
568
- headers: {
569
- "content-type": JSON_CONTENT_TYPE,
570
- accept: JSON_CONTENT_TYPE
571
- },
572
- body: JSON.stringify({
573
- application_type: "native",
574
- client_name: input.clientName,
575
- redirect_uris: [input.redirectUri],
576
- grant_types: ["authorization_code", "refresh_token"],
577
- response_types: ["code"],
578
- token_endpoint_auth_method: "none",
579
- scope: OAUTH_SCOPE
580
- })
581
- });
582
- if (!response.ok) throw await failure(response, "OAuth client registration", "POST", input.registrationEndpoint);
583
- return readJson(response, RegisteredClient, "OAuth client registration");
584
- }
585
- function exchangeCode(input) {
586
- return postForm(input.tokenEndpoint, input.userAgent, {
587
- grant_type: "authorization_code",
588
- code: input.code,
589
- redirect_uri: input.redirectUri,
590
- client_id: input.clientId,
591
- code_verifier: input.codeVerifier
592
- }, OAuthTokens, "OAuth token exchange");
593
- }
594
- function refreshTokens(input) {
595
- return postForm(input.tokenEndpoint, input.userAgent, {
596
- grant_type: "refresh_token",
597
- refresh_token: input.refreshToken,
598
- client_id: input.clientId
599
- }, OAuthTokens, "OAuth token refresh");
600
- }
601
- async function revokeToken(input) {
602
- const response = await oauthFetch({
603
- url: input.revocationEndpoint,
604
- method: "POST",
605
- userAgent: input.userAgent,
606
- headers: { "content-type": FORM_CONTENT_TYPE },
607
- body: new URLSearchParams({
608
- token: input.token,
609
- client_id: input.clientId
610
- })
611
- });
612
- if (!response.ok) throw await failure(response, "OAuth token revocation", "POST", input.revocationEndpoint);
613
- await response.body?.cancel().catch(() => void 0);
614
- }
615
- //#endregion
616
- //#region ../client/src/auth/oauth-session.ts
617
- async function refreshOAuthCredential(baseUrl, credential, nowMs, userAgent) {
618
- const tokens = await refreshTokens({
619
- tokenEndpoint: (await discoverMetadata(baseUrl, userAgent)).token_endpoint,
620
- refreshToken: credential.refreshToken,
621
- clientId: credential.clientId,
622
- userAgent
623
- });
624
- return oauthCredentialFromTokens(tokens, tokens.refresh_token ?? credential.refreshToken, credential.clientId, nowMs);
625
- }
626
- async function revokeOAuthCredential(baseUrl, credential, userAgent) {
627
- const revocationEndpoint = (await discoverMetadata(baseUrl, userAgent)).revocation_endpoint;
628
- if (revocationEndpoint === void 0) return false;
629
- await revokeToken({
630
- revocationEndpoint,
631
- token: credential.refreshToken,
632
- clientId: credential.clientId,
633
- userAgent
634
- });
635
- await revokeToken({
636
- revocationEndpoint,
637
- token: credential.accessToken,
638
- clientId: credential.clientId,
639
- userAgent
640
- });
641
- return true;
642
- }
643
- //#endregion
644
- //#region src/core/user-agent.ts
645
- const USER_AGENT = `metabase-cli/${version}`;
646
- const OAUTH_CLIENT_NAME = "Metabase CLI";
647
- //#endregion
648
1160
  //#region src/core/config.ts
649
1161
  function isPreflightSkipped() {
650
1162
  return readEnv(ENV_SKIP_PREFLIGHT) === "1";
@@ -760,6 +1272,19 @@ function resolveCredential(flagKey, envKey, stored) {
760
1272
  return null;
761
1273
  }
762
1274
  //#endregion
1275
+ //#region src/core/auth/cached-server.ts
1276
+ async function readCachedProbe(profileName, url) {
1277
+ const record = await readProfileRecord(profileName);
1278
+ if (record === null || record.lastProbe === null) return null;
1279
+ if (url !== null && normalizeUrl(record.url) !== url) return null;
1280
+ return record.lastProbe;
1281
+ }
1282
+ async function readCachedServerProfile(profileName) {
1283
+ const envUrl = readEnvCredentials().url;
1284
+ const probe = await readCachedProbe(profileName, envUrl === null ? null : normalizeUrl(envUrl));
1285
+ return probe === null ? null : createServerProfile(probe);
1286
+ }
1287
+ //#endregion
763
1288
  //#region src/output/format.ts
764
1289
  function resolveFormat({ json, format, isTty }) {
765
1290
  const explicit = format !== void 0 && format !== "auto" ? format : null;
@@ -819,7 +1344,6 @@ function resolveCommonFlags(args, options = {}) {
819
1344
  url: args.url,
820
1345
  apiKey: args.apiKey,
821
1346
  profile: args.profile,
822
- worktree: args.worktree,
823
1347
  skipPreflight: args.skipPreflight === true
824
1348
  };
825
1349
  }
@@ -893,45 +1417,9 @@ function flagCandidates(token) {
893
1417
  return candidates;
894
1418
  }
895
1419
  //#endregion
896
- //#region src/commands/worktree-scope.ts
897
- const WORKTREE_REF_LABEL = "worktree ref";
898
- const WORKTREE_SCOPE_DETAIL = "Pass --worktree <id|branch> (or set MB_WORKTREE, or pin the profile with `mb worktree pin`) to operate inside a git-sync worktree.";
899
- async function findWorktree(ref, mb) {
900
- if (ref.kind === "id") return mb.gitSync.getWorktree(ref.id);
901
- const { data } = await mb.gitSync.worktrees();
902
- const match = data.find((worktree) => worktree.branch === ref.branch);
903
- if (match === void 0) throw new ConfigError(`worktree ${formatWorktreeRef(ref)} not found; run \`mb worktree list\``);
904
- return match;
905
- }
906
- async function resolveWorktreeScope(source, mb) {
907
- if (source.scope !== null) return source.scope;
908
- const worktree = await findWorktree(source.ref, mb);
909
- return {
910
- id: worktree.id,
911
- branch: worktree.branch
912
- };
913
- }
914
- function scopeQuery(scope) {
915
- return { "worktree-id": scope === null ? void 0 : scope.id };
916
- }
917
- function assertInWorktree(kind, id, worktreeId, scope) {
918
- if (scope === null || worktreeId === scope.id) return;
919
- throw new ConfigError(`${kind} ${id} is not in worktree ${scope.id} (${scope.branch}); refusing to touch main-app content`);
920
- }
921
- function scopeBody(body, scope) {
922
- if (scope === null) return body;
923
- const stated = body.worktree_id;
924
- if (stated !== void 0 && stated !== null && stated !== scope.id) throw new ConfigError(`body names worktree_id ${stated}, but the active scope is worktree ${scope.id} (${scope.branch})`);
925
- return {
926
- ...body,
927
- worktree_id: scope.id
928
- };
929
- }
930
- //#endregion
931
1420
  //#region src/commands/runtime.ts
932
- const UNNAMED_COMMAND = "this command";
933
1421
  function defineMetabaseCommand(def) {
934
- const required = def.capabilities === null ? null : mergeCapabilities(def.capabilities);
1422
+ const requirements = def.requires === null ? null : deriveRequirements(def.requires);
935
1423
  const cmd = defineCommand({
936
1424
  meta: def.meta,
937
1425
  args: def.args,
@@ -944,62 +1432,55 @@ function defineMetabaseCommand(def) {
944
1432
  assertKnownFlags(rawArgs, def.args);
945
1433
  let cachedConfig = null;
946
1434
  let cachedClient = null;
947
- let cachedServerInfo = null;
948
1435
  const getResolvedConfig = async () => {
949
1436
  if (cachedConfig === null) cachedConfig = await resolveConfig(buildConfigFlags(ctx));
950
1437
  return cachedConfig;
951
1438
  };
952
- const getServerInfo = () => {
953
- if (cachedServerInfo === null) cachedServerInfo = loadServerInfo(getResolvedConfig);
954
- return cachedServerInfo;
955
- };
1439
+ const preflightSkipped = ctx.skipPreflight || isPreflightSkipped();
1440
+ let cachedServer = null;
1441
+ const noticeSkew = createSkewNotifier();
956
1442
  const rawGetClient = async () => {
957
1443
  if (cachedClient === null) {
958
1444
  const resolved = await getResolvedConfig();
959
- const { createClient } = await import("./client-DYD8WZYy.mjs").then((n) => n.t);
1445
+ const probe = await readCachedProbe(resolved.profile, resolved.url);
1446
+ const server = probe === null ? null : createServerProfile(probe);
1447
+ const { createClient } = await import("./client-Bv7Iwdvh.mjs").then((n) => n.t);
960
1448
  cachedClient = createClient({
961
1449
  url: resolved.url,
962
1450
  credential: resolved.credential
963
1451
  }, {
964
1452
  userAgent: USER_AGENT,
965
- getServerTag: async () => (await getServerInfo())?.version?.tag ?? null,
1453
+ ...server !== null && { server },
966
1454
  refreshCredential: createCredentialRefresher(resolved.profile),
967
- signal: interruptSignal
1455
+ signal: interruptSignal,
1456
+ enforceRequirements: !preflightSkipped
968
1457
  });
1458
+ if (probe !== null && server !== null) {
1459
+ cachedServer = {
1460
+ client: cachedClient,
1461
+ profileName: resolved.profile,
1462
+ probe
1463
+ };
1464
+ noticeSkew(server);
1465
+ }
969
1466
  }
970
1467
  return cachedClient;
971
1468
  };
972
- const enforcePreflight = createPreflightEnforcer(required, getServerInfo, ctx.skipPreflight);
973
- let cachedScopeSource = null;
974
- const getScopeSource = () => {
975
- if (cachedScopeSource === null) cachedScopeSource = loadScopeSource(ctx, getResolvedConfig);
976
- return cachedScopeSource;
977
- };
978
- const enforceWorktreePolicy = async () => {
979
- const source = await getScopeSource();
980
- if (source === null || def.worktree !== "main-only") return;
981
- throw new ConfigError(mainOnlyRefusal(commandName(def.meta), source));
982
- };
1469
+ const enforcePreflight = createPreflightEnforcer(requirements === null ? null : requirements.features, preflightSkipped, noticeSkew);
983
1470
  const getClient = async () => {
984
1471
  const client = await rawGetClient();
985
- await enforceWorktreePolicy();
986
- await enforcePreflight();
1472
+ await enforcePreflight(client);
987
1473
  return client;
988
1474
  };
989
- let cachedScope = null;
990
- const getWorktree = () => {
991
- if (cachedScope === null) cachedScope = loadWorktreeScope(getScopeSource, getClient);
992
- return cachedScope;
993
- };
994
1475
  try {
995
1476
  await def.run({
996
1477
  args,
997
1478
  ctx,
998
1479
  getClient,
999
- getResolvedConfig,
1000
- getServerInfo,
1001
- getWorktree
1480
+ getResolvedConfig
1002
1481
  });
1482
+ } catch (error) {
1483
+ throw await refreshProfileOnStaleError(error, cachedServer);
1003
1484
  } finally {
1004
1485
  emitPendingWarnings();
1005
1486
  }
@@ -1014,30 +1495,16 @@ function defineMetabaseCommand(def) {
1014
1495
  skills: def.skills ?? [],
1015
1496
  inputSchema: def.inputSchema ?? null,
1016
1497
  outputSchema: def.outputSchema ?? null,
1017
- capabilities: required,
1018
- worktree: def.worktree
1498
+ requires: requirements,
1499
+ capabilities: requirements === null ? null : summarizeCapabilities(requirements.features)
1019
1500
  });
1020
1501
  return cmd;
1021
1502
  }
1022
- function commandName(meta) {
1023
- const chain = readVerbChain();
1024
- if (chain !== null) return chain;
1025
- return typeof meta.name === "string" && meta.name !== "" ? meta.name : UNNAMED_COMMAND;
1026
- }
1027
- async function loadScopeSource(ctx, getResolvedConfig) {
1028
- const resolved = await getResolvedConfig();
1029
- const record = await readProfileRecord(resolved.profile);
1030
- return resolveScopeSource({
1031
- profile: resolved.profile,
1032
- flag: ctx.worktree,
1033
- env: readEnv(ENV_WORKTREE),
1034
- pin: record?.worktree ?? null
1035
- });
1036
- }
1037
- async function loadWorktreeScope(getScopeSource, getClient) {
1038
- const source = await getScopeSource();
1039
- if (source === null) return null;
1040
- return resolveWorktreeScope(source, await getClient());
1503
+ function deriveRequirements(methods) {
1504
+ return {
1505
+ methods,
1506
+ features: [...new Set(methods.flatMap((key) => methodRequirements(key)))]
1507
+ };
1041
1508
  }
1042
1509
  function emitPendingWarnings() {
1043
1510
  for (const message of consumeLegacyEnvWarnings()) warn(message);
@@ -1046,34 +1513,58 @@ function emitPendingWarnings() {
1046
1513
  const downgrade = consumeKeyringDowngradeWarning();
1047
1514
  if (downgrade !== null) warn(downgrade);
1048
1515
  }
1049
- async function loadServerInfo(getResolvedConfig) {
1050
- const record = await readProfileRecord((await getResolvedConfig()).profile);
1051
- if (record === null || record.lastProbe === null) return null;
1052
- return {
1053
- version: record.lastProbe.version,
1054
- tokenFeatures: record.lastProbe.tokenFeatures
1516
+ function createSkewNotifier() {
1517
+ let noticed = false;
1518
+ return (profile) => {
1519
+ if (noticed) return;
1520
+ noticed = true;
1521
+ const notice = skewNotice(profile);
1522
+ if (notice !== null) warn(notice);
1055
1523
  };
1056
1524
  }
1057
1525
  const NO_OP_ENFORCER = async () => {};
1058
- 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.";
1059
- function createPreflightEnforcer(required, getServerInfo, skip) {
1060
- if (required === null || skip || isPreflightSkipped() || isBaseline(required)) return NO_OP_ENFORCER;
1526
+ function createPreflightEnforcer(features, skip, noticeSkew) {
1527
+ if (features === null || skip || features.length === 0) return NO_OP_ENFORCER;
1061
1528
  let done = false;
1062
- return async () => {
1529
+ return async (client) => {
1063
1530
  if (done) return;
1064
1531
  done = true;
1065
- const info = await getServerInfo();
1066
- if (info === null) {
1067
- warn(NO_PROBE_DATA_WARNING);
1068
- return;
1069
- }
1070
- const failure = checkCapabilities(info, required);
1071
- if (failure === null || failure.reason === "unknown-version") return;
1072
- throw new CapabilityError(failure);
1532
+ const profile = await client.server();
1533
+ noticeSkew(profile);
1534
+ const failure = checkFeatures(features, profile);
1535
+ if (failure !== null) throw new CapabilityError(failure);
1073
1536
  };
1074
1537
  }
1075
- function isBaseline(caps) {
1076
- return caps.minVersion === BASELINE_CAPABILITIES.minVersion && caps.tokenFeature === void 0;
1538
+ async function refreshProfileOnStaleError(error, cached) {
1539
+ if (cached === null) return error;
1540
+ if (error instanceof ResponseShapeError) {
1541
+ const note = await refreshChangedProbe(cached);
1542
+ return note === null ? error : new ResponseShapeError(`${error.message}\n${note}`, error.developerDetail);
1543
+ }
1544
+ if (error instanceof CapabilityError) {
1545
+ const note = await refreshChangedProbe(cached);
1546
+ return note === null ? error : new CapabilityError({
1547
+ ...error.developerDetail,
1548
+ detail: `${error.message}\n${note}`
1549
+ });
1550
+ }
1551
+ return error;
1552
+ }
1553
+ async function refreshChangedProbe(cached) {
1554
+ let fresh;
1555
+ try {
1556
+ fresh = await probeServer(cached.client);
1557
+ } catch (error) {
1558
+ if (error instanceof MetabaseError) return null;
1559
+ throw error;
1560
+ }
1561
+ const note = serverChangeNote(cached.probe, fresh);
1562
+ if (note === null) return null;
1563
+ await writeProbeResult(cached.profileName, {
1564
+ user: cached.probe.user,
1565
+ server: fresh
1566
+ });
1567
+ return note;
1077
1568
  }
1078
1569
  function pickCommonArgs(args) {
1079
1570
  const out = {};
@@ -1085,7 +1576,6 @@ function pickCommonArgs(args) {
1085
1576
  if (typeof args["limit"] === "string") out.limit = args["limit"];
1086
1577
  if (typeof args["offset"] === "string") out.offset = args["offset"];
1087
1578
  if (typeof args["profile"] === "string") out.profile = args["profile"];
1088
- if (typeof args["worktree"] === "string") out.worktree = args["worktree"];
1089
1579
  if (typeof args["url"] === "string") out.url = args["url"];
1090
1580
  if (typeof args["apiKey"] === "string") out.apiKey = args["apiKey"];
1091
1581
  if (typeof args["skipPreflight"] === "boolean") out.skipPreflight = args["skipPreflight"];
@@ -1099,4 +1589,4 @@ function buildConfigFlags(ctx) {
1099
1589
  return flags;
1100
1590
  }
1101
1591
  //#endregion
1102
- export { readProfileRecord as A, ProfilePin as B, DEFAULT_PROFILE as C, keyringFallbackWarning as D, consumeKeyringDowngradeWarning as E, writeProfile as F, TokenFeatures as G, ParsedVersion as H, writeProfileWorktree as I, parseInteger as K, ProbedUser as L, writeOAuthProfile as M, writeProbeFailure as N, listProfileRecords as O, writeProbeResult as P, ProfileAuthMethod as R, tryDiscoverMetadata as S, consumeKeychainResidualWarning as T, tryParseTag as U, profileAuthMethod as V, SessionProperties as W, revokeOAuthCredential as _, findWorktree as a, exchangeCode as b, parseCsv as c, createCredentialRefresher as d, explicitProfileName as f, USER_AGENT as g, OAUTH_CLIENT_NAME as h, assertInWorktree as i, resolveRecordCredential as j, readProfileCredential as k, parseEnum as l, resolveProfileName as m, WORKTREE_REF_LABEL as n, scopeBody as o, readEnvCredentials as p, parseOptionalInteger as q, WORKTREE_SCOPE_DETAIL as r, scopeQuery as s, defineMetabaseCommand as t, parseEnumCsv as u, OAUTH_SCOPE as v, clearProfile as w, registerClient as x, discoverMetadata as y, ProfileLastFailure as z };
1592
+ export { probeServer 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, checkRequirements 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, CapabilityError as et, consumeKeychainResidualWarning as f, readProfileCredential as g, listProfileRecords as h, parseEnumCsv as i, discoverMetadata as j, revokeOAuthCredential as k, resolveProfileName as l, keyringFallbackWarning as m, parseCsv as n, parseInteger as nt, createCredentialRefresher as o, consumeKeyringDowngradeWarning as p, displayUrl as q, parseEnum as r, parseOptionalInteger as rt, explicitProfileName as s, defineMetabaseCommand as t, RequirementFailure as tt, DEFAULT_PROFILE as u, resolveRecordCredential as v, ProfileAuthMethod as w, writeProbeResult as x, writeOAuthProfile as y, isRetryableStatus as z };