@metabase/cli 0.1.12 → 0.1.14

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 (191) hide show
  1. package/README.md +109 -22
  2. package/dist/add-collection-Cdhj6DJb.mjs +10 -0
  3. package/dist/{add-collection-DEME4IOy.mjs → add-collection-Cubho2HN.mjs} +5 -5
  4. package/dist/{archive-CMeTr8jv.mjs → archive-BBboJ-z3.mjs} +6 -6
  5. package/dist/{archive-DUlrUlok.mjs → archive-BrzOTxSA.mjs} +6 -6
  6. package/dist/{archive-BNioNJtG.mjs → archive-C8G0KIPI.mjs} +7 -7
  7. package/dist/{archive-BtDvBsr8.mjs → archive-D6eMYNI5.mjs} +6 -6
  8. package/dist/{archive-BFk-oupo.mjs → archive-DCIwtfv0.mjs} +6 -6
  9. package/dist/{archive-MTTQv3wR.mjs → archive-DTN6Anme.mjs} +7 -7
  10. package/dist/{archive-Dc-FwNZm.mjs → archive-F2g-bAXf.mjs} +7 -7
  11. package/dist/auth-D4cXDeiH.mjs +19 -0
  12. package/dist/{body-89w3r7In.mjs → body-CXpIB6hY.mjs} +3 -3
  13. package/dist/{branches-DuVKH8Ye.mjs → branches-r9SVJIV5.mjs} +6 -6
  14. package/dist/{cancel-BEMQKVuR.mjs → cancel-BbLZsVYQ.mjs} +5 -5
  15. package/dist/{cancel-task-D2mSPFXO.mjs → cancel-task-CojB-8XX.mjs} +6 -6
  16. package/dist/{capabilities-7L9GVMd_.mjs → capabilities-BX1rnVuH.mjs} +2 -14
  17. package/dist/card-BMN-mcxn.mjs +20 -0
  18. package/dist/{card-DnIeMmUn.mjs → card-wCPcuKSi.mjs} +1 -1
  19. package/dist/{cards-L9jksUMD.mjs → cards-e9Wgnbnq.mjs} +6 -6
  20. package/dist/cli.mjs +26 -25
  21. package/dist/collection-DZnA3zXr.mjs +20 -0
  22. package/dist/{collection-namespace-w26SavJH.mjs → collection-namespace-DmKMqLr0.mjs} +2 -2
  23. package/dist/{command-augment-BH9qgQ5u.mjs → command-augment-CAur0XOQ.mjs} +13 -2
  24. package/dist/{create-Cxg_h8Kf.mjs → create-Bbe2EM9f.mjs} +10 -10
  25. package/dist/{create-8hMjPz7j.mjs → create-Bu9edPBn.mjs} +8 -8
  26. package/dist/create-Bz4hf7W0.mjs +44 -0
  27. package/dist/{create-Bu9Jayck.mjs → create-BzKW27Hh.mjs} +12 -12
  28. package/dist/{create-Dew3rKsR.mjs → create-C4G_z8qO.mjs} +8 -8
  29. package/dist/{create-DoeqRVmx.mjs → create-C5-JhEUc.mjs} +11 -11
  30. package/dist/{create-zEq4ZJAT.mjs → create-Cq-ay6cJ.mjs} +8 -8
  31. package/dist/{create-D6QqOX6u.mjs → create-DFMpgUvH.mjs} +9 -9
  32. package/dist/{create-C3b3MoIN.mjs → create-UzeYyGq6.mjs} +10 -10
  33. package/dist/{create-branch-C5P2y8U5.mjs → create-branch--GJ_RxIN.mjs} +6 -6
  34. package/dist/{create-DCYc032c.mjs → create-onFRzFwS.mjs} +11 -11
  35. package/dist/{current-task-uD4QO5bM.mjs → current-task-C0mMBzdB.mjs} +6 -6
  36. package/dist/dashboard-PB_c3Irl.mjs +21 -0
  37. package/dist/{database-Dsv4QBs0.mjs → database-BmsxuRmO.mjs} +1 -1
  38. package/dist/db-q0lYg3k8.mjs +22 -0
  39. package/dist/{delete-DGaNAFdQ.mjs → delete-CGw1hwGZ.mjs} +7 -7
  40. package/dist/{delete-Bftif2R3.mjs → delete-CxTPHzom.mjs} +7 -7
  41. package/dist/delete-Dbzs51x3.mjs +50 -0
  42. package/dist/{delete-runtime-CjFc69tS.mjs → delete-runtime-BhZAAvjc.mjs} +3 -3
  43. package/dist/{delete-table-C0qxP6FE.mjs → delete-table-B6obSpLU.mjs} +7 -7
  44. package/dist/dependencies-DfkbJqzQ.mjs +40 -0
  45. package/dist/{dirty-CZZLpWt1.mjs → dirty-BqL_DE6p.mjs} +6 -6
  46. package/dist/document-4TwzGwl3.mjs +19 -0
  47. package/dist/{eid-C8xTmR8e.mjs → eid-C31VGHAM.mjs} +7 -7
  48. package/dist/{error-BGH4gxGN.mjs → error-BOi_ux9O.mjs} +40 -5
  49. package/dist/{export-DWdjnBKo.mjs → export--_0e40xU.mjs} +8 -8
  50. package/dist/field-Bi_O_Sdg.mjs +18 -0
  51. package/dist/{fields-Cq08PQec.mjs → fields-BRiL6KEF.mjs} +7 -7
  52. package/dist/{get-Bbij6RjC.mjs → get--bNbxDkk.mjs} +6 -6
  53. package/dist/{get-DHPN1716.mjs → get-B-phl324.mjs} +7 -7
  54. package/dist/{get-DtKv-gl3.mjs → get-B2-RLrYJ.mjs} +6 -6
  55. package/dist/{get-ug26gcOI.mjs → get-B_TdMKu-.mjs} +8 -8
  56. package/dist/{get-f5ENeUNw.mjs → get-C-o2-vnf.mjs} +6 -6
  57. package/dist/{get-BaKKF50e.mjs → get-C6njgZmF.mjs} +6 -6
  58. package/dist/{get-B_BJ10pV.mjs → get-CCyfx_AY.mjs} +6 -6
  59. package/dist/{get-Cr8oz_jr.mjs → get-CcGU3YaY.mjs} +6 -6
  60. package/dist/{get-8nAjRL2H.mjs → get-Cs7a7s2Z.mjs} +7 -7
  61. package/dist/{get-B2vGW7Aw.mjs → get-DGZw_U0s.mjs} +6 -6
  62. package/dist/{get-DzLAmSKd.mjs → get-DMeF2FLQ.mjs} +5 -5
  63. package/dist/{get-7IhxPyE_.mjs → get-DQOvqH9P.mjs} +6 -6
  64. package/dist/{get-Bcr_5fAb.mjs → get-LJam7ZQ-.mjs} +6 -6
  65. package/dist/{get-Rqz7UHv1.mjs → get-ev4Zw3Gj.mjs} +6 -6
  66. package/dist/{get-run-DhbHXaZE.mjs → get-run-Cp7ATZPQ.mjs} +6 -6
  67. package/dist/git-sync-BOZdFF09.mjs +28 -0
  68. package/dist/{has-remote-changes-CTLh3WjZ.mjs → has-remote-changes-Bw_Xp9Ii.mjs} +6 -6
  69. package/dist/{import-XakIQfRp.mjs → import-BmoC0ECq.mjs} +8 -8
  70. package/dist/{input-BZwm4yby.mjs → input-BXWgdKiS.mjs} +1 -1
  71. package/dist/is-dirty-B6usK-aU.mjs +9 -0
  72. package/dist/{is-dirty-DkOOyjsZ.mjs → is-dirty-BDmXm34E.mjs} +4 -4
  73. package/dist/{items-DC985V8K.mjs → items-BI-O48Sc.mjs} +8 -8
  74. package/dist/{key-y4TtxKwU.mjs → key-C8q5oIr5.mjs} +1 -1
  75. package/dist/{list-DfPwBQrZ.mjs → list-B7g2c9K7.mjs} +5 -5
  76. package/dist/{list-CEbMS6g3.mjs → list-BE3wVc-a.mjs} +5 -5
  77. package/dist/{list-CtAFlkLe.mjs → list-BcSjOiK1.mjs} +5 -5
  78. package/dist/{list-CIEI8XK_.mjs → list-BkEFHJe8.mjs} +5 -5
  79. package/dist/{list-STlBcPs8.mjs → list-CNeaMSjy.mjs} +5 -5
  80. package/dist/{list-BtNboYpZ.mjs → list-CRUjh592.mjs} +25 -18
  81. package/dist/{list-PYNFVJGM.mjs → list-CTfCgMTk.mjs} +7 -7
  82. package/dist/{list-OGkVAG6b.mjs → list-Cju3N2kB.mjs} +6 -6
  83. package/dist/{list-Df4MhR2A.mjs → list-Cqvt6gpK.mjs} +7 -7
  84. package/dist/{list-CyIgwqFB.mjs → list-Cz_2UyGV.mjs} +6 -6
  85. package/dist/{list-B83-hnq5.mjs → list-DIFjjwBV.mjs} +5 -5
  86. package/dist/list-DM-Oa-oB.mjs +32 -0
  87. package/dist/{list-Cnb9mQdd.mjs → list-DhWVjE6U.mjs} +7 -7
  88. package/dist/{list-xfmTxHNu.mjs → list-JCMQ06wX.mjs} +5 -5
  89. package/dist/{list-gy64AAWO.mjs → list-RC1HQ2dg.mjs} +5 -5
  90. package/dist/login-BF6LkxPI.mjs +453 -0
  91. package/dist/{logout-BUgUTFol.mjs → logout-Cg8Z_XD_.mjs} +15 -6
  92. package/dist/{manifest-BPHqF5LY.mjs → manifest-DYeLri80.mjs} +2 -2
  93. package/dist/measure-BRzkMY5y.mjs +19 -0
  94. package/dist/{metadata-B1EmV1l5.mjs → metadata-B15u_YYT.mjs} +7 -7
  95. package/dist/{metadata-Dwkcsa1c.mjs → metadata-CmvvOpKI.mjs} +8 -8
  96. package/dist/{parse-enum-Dr7ACrTR.mjs → parse-enum-BatHQ-Gs.mjs} +1 -1
  97. package/dist/{parse-id-sKNP6yu5.mjs → parse-id-DMs04KM3.mjs} +1 -1
  98. package/dist/{parse-ref-BiETXmvm.mjs → parse-ref-CZr1bYIl.mjs} +1 -1
  99. package/dist/{path-BZJR7YLR.mjs → path-YsfpMb_h.mjs} +5 -5
  100. package/dist/{poll-Cyw-dQi4.mjs → poll-13tgWrN_.mjs} +2 -2
  101. package/dist/{poll-task-BG0oVnfZ.mjs → poll-task-BuAHsDEK.mjs} +2 -2
  102. package/dist/{preflight-BjR63JnX.mjs → preflight-wCSgVqbX.mjs} +4 -4
  103. package/dist/process-DsGf7Mg5.mjs +73 -0
  104. package/dist/{prompt-u4WhE4T5.mjs → prompt-Bc_bHSD0.mjs} +13 -3
  105. package/dist/{query-Dk55Wp2p.mjs → query-DnYdI0fl.mjs} +12 -12
  106. package/dist/{query-result-B4kTRid7.mjs → query-result-L5_NrwQR.mjs} +1 -1
  107. package/dist/{query-C2xqnz24.mjs → query-x6g6unDt.mjs} +8 -8
  108. package/dist/{remove-collection-DbVNWGyb.mjs → remove-collection-CLTqx7ys.mjs} +8 -8
  109. package/dist/{render-BQHJhSP1.mjs → render-CkuFkWlQ.mjs} +6 -1
  110. package/dist/{rescan-values-CuLQ9UHP.mjs → rescan-values-C7b78yA2.mjs} +8 -8
  111. package/dist/{run-PDN33QjN.mjs → run-CsYI4Sqv.mjs} +8 -8
  112. package/dist/run-DR5O1_EU.mjs +59 -0
  113. package/dist/{runs-B9T-7lei.mjs → runs-DWbtqOyw.mjs} +7 -7
  114. package/dist/{runtime-DgHh4T6t.mjs → runtime-7JTC-usO.mjs} +591 -123
  115. package/dist/{schema-tables-DjmNwrlT.mjs → schema-tables-Cte09dhE.mjs} +7 -7
  116. package/dist/{schemas-CWL8gv1C.mjs → schemas-DAmSPGiC.mjs} +5 -5
  117. package/dist/{search-D7JzmvfR.mjs → search-Di-SFcZm.mjs} +5 -5
  118. package/dist/segment-DiHHHk2a.mjs +19 -0
  119. package/dist/{set-C0dCLnUA.mjs → set-C1rIETEg.mjs} +8 -8
  120. package/dist/set-active-CJ1VaxEC.mjs +56 -0
  121. package/dist/{setting-Licy7ZSs.mjs → setting-6WqN3L3F.mjs} +3 -3
  122. package/dist/{setup-BL4fqxoU.mjs → setup-DbXhTopr.mjs} +7 -7
  123. package/dist/{skills-CY_FmaPo.mjs → skills-CJ8g8fhQ.mjs} +1 -1
  124. package/dist/{skills-Cn8FMCxG.mjs → skills-CfWrH-1L.mjs} +3 -3
  125. package/dist/snippet-B-anQo6y.mjs +19 -0
  126. package/dist/{stash-SGod4B8-.mjs → stash-BCNSzoYQ.mjs} +8 -8
  127. package/dist/{status-CvUuZVvC.mjs → status-BocNdqNq.mjs} +14 -6
  128. package/dist/{status-BCb5iCsQ.mjs → status-CG3Lbl5_.mjs} +7 -7
  129. package/dist/{summary-qaTPTLWs.mjs → summary-TApK2JbW.mjs} +6 -6
  130. package/dist/{sync-schema-CjjAYTbO.mjs → sync-schema-COA-OlO3.mjs} +10 -10
  131. package/dist/table-Bnj8IBKx.mjs +19 -0
  132. package/dist/{table-CkWja2UH.mjs → table-qDD2kApF.mjs} +1 -1
  133. package/dist/transform-QCDItglq.mjs +25 -0
  134. package/dist/transform-job-Dawm4Lag.mjs +22 -0
  135. package/dist/transform-tag-BLAbrywB.mjs +36 -0
  136. package/dist/transform-tag-CN-bTSne.mjs +18 -0
  137. package/dist/transforms-Bo4u0YqS.mjs +40 -0
  138. package/dist/{tree-C0MFcweC.mjs → tree-CGh-ZG4n.mjs} +5 -5
  139. package/dist/{update-BqsGGrzx.mjs → update-Bob7lvnr.mjs} +13 -13
  140. package/dist/{update-BUoWwmQV.mjs → update-Br_cd74H.mjs} +9 -9
  141. package/dist/{update-vk_M0eOR.mjs → update-BuJjTYAx.mjs} +11 -11
  142. package/dist/{update-CJASCsG4.mjs → update-CCIkTuxz.mjs} +9 -9
  143. package/dist/{update-Dty6LvU2.mjs → update-Co4WLVkK.mjs} +12 -12
  144. package/dist/update-DCvTlxUK.mjs +51 -0
  145. package/dist/{update-qoP7hZTg.mjs → update-DLQygCXg.mjs} +10 -10
  146. package/dist/{update-BTzsE8GU.mjs → update-DtUhmJar.mjs} +9 -9
  147. package/dist/{update-DCR0wFNl.mjs → update-ETzjZl17.mjs} +11 -11
  148. package/dist/{update-BImaz9vj.mjs → update-ZPsCSWR6.mjs} +12 -12
  149. package/dist/{update-dashcard-BkJaVVvf.mjs → update-dashcard-Du-h_8oY.mjs} +9 -9
  150. package/dist/{update-CHUUY-IB.mjs → update-ysNL-mE-.mjs} +9 -9
  151. package/dist/{upgrade-TdaiAYbH.mjs → upgrade-CavKMkQ4.mjs} +6 -34
  152. package/dist/{uuid-BeUz8VpP.mjs → uuid-BL33x41p.mjs} +4 -4
  153. package/dist/{validate-B62TRDGV.mjs → validate-VawhJ5Sc.mjs} +2 -2
  154. package/dist/{validate-query-BpiN1CFu.mjs → validate-query-CSV-TTnd.mjs} +3 -3
  155. package/dist/{values-DR-3HcK6.mjs → values-DVu97Fcd.mjs} +6 -6
  156. package/dist/{verify-D2uBlvmt.mjs → verify-BLUei79N.mjs} +5 -5
  157. package/dist/{wait-FAnqO-LT.mjs → wait-C0P8Qt37.mjs} +7 -7
  158. package/dist/{wait-flags-B5BI_xob.mjs → wait-flags-Z_JC7x4L.mjs} +2 -2
  159. package/package.json +1 -1
  160. package/skill-data/core/SKILL.md +1 -1
  161. package/skill-data/transform/SKILL.md +17 -3
  162. package/dist/add-collection-BPtBMh8Y.mjs +0 -10
  163. package/dist/auth-CjFnuPe9.mjs +0 -19
  164. package/dist/card-DoDpwR4t.mjs +0 -20
  165. package/dist/collection-CF-1RIPY.mjs +0 -20
  166. package/dist/dashboard-C5zTX345.mjs +0 -21
  167. package/dist/db-4y5Z1CQw.mjs +0 -22
  168. package/dist/document-97l9Non_.mjs +0 -19
  169. package/dist/field-BwUTrelF.mjs +0 -18
  170. package/dist/git-sync-JIMEYW-E.mjs +0 -28
  171. package/dist/is-dirty-4gf8ujws.mjs +0 -9
  172. package/dist/login-C0VFlX8y.mjs +0 -180
  173. package/dist/measure-BmcmxRQ3.mjs +0 -19
  174. package/dist/segment-DrZNuxsM.mjs +0 -19
  175. package/dist/snippet-C5_4nPGj.mjs +0 -19
  176. package/dist/table-DK1B8Hzq.mjs +0 -19
  177. package/dist/transform-Dh5746zH.mjs +0 -24
  178. package/dist/transform-job-D0nRGPYN.mjs +0 -19
  179. /package/dist/{body-flags-D78h_-Ua.mjs → body-flags-D7q87Btw.mjs} +0 -0
  180. /package/dist/{collection-BPTlcFw5.mjs → collection-Deiziuu2.mjs} +0 -0
  181. /package/dist/{dashboard-FY5UzJ_Z.mjs → dashboard-B4bn3z6t.mjs} +0 -0
  182. /package/dist/{document-CcfiiV3b.mjs → document-qfwR0r63.mjs} +0 -0
  183. /package/dist/{field-MGxpNQUH.mjs → field-E0IBy4Uw.mjs} +0 -0
  184. /package/dist/{measure-COGAoZpo.mjs → measure-JJAdFoqK.mjs} +0 -0
  185. /package/dist/{paginate-Dfm9eO9A.mjs → paginate-BexjkjbY.mjs} +0 -0
  186. /package/dist/{revision-message-flag-Bo-Kvv6F.mjs → revision-message-flag-C7zBeWEt.mjs} +0 -0
  187. /package/dist/{segment-d-708KKO.mjs → segment-B9SEv9V_.mjs} +0 -0
  188. /package/dist/{setting-CSJvi1-6.mjs → setting-i0pugNHl.mjs} +0 -0
  189. /package/dist/{snippet-BZvo05ua.mjs → snippet-NNzqlksR.mjs} +0 -0
  190. /package/dist/{transform-job-n8W6tLqF.mjs → transform-job-B9pXBOwr.mjs} +0 -0
  191. /package/dist/{transform--dviwMA1.mjs → transform-qczxOAzn.mjs} +0 -0
@@ -0,0 +1,453 @@
1
+ import { ConfigError, errorMessage, warn } from "./command-augment-CAur0XOQ.mjs";
2
+ import { connectionFlags, outputFlags, profileFlag } from "./error-BOi_ux9O.mjs";
3
+ import { DEFAULT_PROFILE, OAUTH_SCOPE, ParsedVersionSchema, ProbedUser, consumeKeychainResidualWarning, consumeKeyringDowngradeWarning, defineMetabaseCommand, discoverMetadata, exchangeCode, explicitProfileName, keyringFallbackWarning, normalizeUrl, oauthCredentialFromTokens, readEnvCredentials, registerClient, revokeOAuthCredential, tryDiscoverMetadata, writeOAuthProfile, writeProbeFailure, writeProbeResult, writeProfile } from "./runtime-7JTC-usO.mjs";
4
+ import { verifyAndProbe } from "./verify-BLUei79N.mjs";
5
+ import { renderSummary } from "./capabilities-BX1rnVuH.mjs";
6
+ import { EMPTY_CELL, renderUserName, renderUserRole, renderVersionTag } from "./render-CkuFkWlQ.mjs";
7
+ import { promptPassword, promptSelect, promptText } from "./prompt-Bc_bHSD0.mjs";
8
+ import { openBrowser } from "./process-DsGf7Mg5.mjs";
9
+ import { readInput } from "./input-BXWgdKiS.mjs";
10
+ import { z } from "zod";
11
+ import { createServer } from "node:http";
12
+ import { createHash, randomBytes } from "node:crypto";
13
+
14
+ //#region src/core/auth/callback-server.ts
15
+ const LOOPBACK_HOST = "127.0.0.1";
16
+ const CALLBACK_PATH = "/callback";
17
+ const DEFAULT_TIMEOUT_MS = 3e5;
18
+ function parseCallbackQuery(rawUrl) {
19
+ const queryStart = rawUrl.indexOf("?");
20
+ const params = new URLSearchParams(queryStart === -1 ? "" : rawUrl.slice(queryStart + 1));
21
+ return {
22
+ code: params.get("code"),
23
+ state: params.get("state"),
24
+ error: params.get("error"),
25
+ errorDescription: params.get("error_description")
26
+ };
27
+ }
28
+ function isCallbackPath(rawUrl) {
29
+ const queryStart = rawUrl.indexOf("?");
30
+ const path = queryStart === -1 ? rawUrl : rawUrl.slice(0, queryStart);
31
+ return path === CALLBACK_PATH;
32
+ }
33
+ function escapeHtml(value) {
34
+ return value.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#39;");
35
+ }
36
+ function htmlPage(title, message) {
37
+ return "<!DOCTYPE html><html><head><meta charset=\"utf-8\"><title>" + escapeHtml(title) + "</title></head><body style=\"font-family:system-ui;text-align:center;padding-top:4rem;color:#4c5773\"><h1>" + escapeHtml(title) + "</h1><p>" + escapeHtml(message) + "</p><p>You can close this tab and return to your terminal.</p></body></html>";
38
+ }
39
+ function respond(res, status, title, message) {
40
+ res.writeHead(status, {
41
+ "content-type": "text/html; charset=utf-8",
42
+ connection: "close"
43
+ });
44
+ res.end(htmlPage(title, message));
45
+ }
46
+ function serverPort(server) {
47
+ const address = server.address();
48
+ if (address === null || typeof address === "string") throw new ConfigError("could not determine loopback callback port");
49
+ const info = address;
50
+ return info.port;
51
+ }
52
+ function startCallbackServer(expectedState, timeoutMs = DEFAULT_TIMEOUT_MS) {
53
+ return new Promise((resolveServer, rejectServer) => {
54
+ let settle = null;
55
+ let fail = null;
56
+ let outcome = null;
57
+ const server = createServer((req, res) => {
58
+ const rawUrl = req.url ?? "";
59
+ if (!isCallbackPath(rawUrl)) {
60
+ respond(res, 404, "Not found", "Unexpected request.");
61
+ return;
62
+ }
63
+ const query = parseCallbackQuery(rawUrl);
64
+ if (query.state !== expectedState) {
65
+ respond(res, 400, "Login failed", "Invalid or missing state.");
66
+ return;
67
+ }
68
+ if (query.error !== null) {
69
+ const detail = query.errorDescription ?? query.error;
70
+ respond(res, 400, "Login failed", detail);
71
+ deliver(new ConfigError(`authorization denied: ${detail}`));
72
+ return;
73
+ }
74
+ if (query.code === null) {
75
+ respond(res, 400, "Login failed", "Missing authorization code.");
76
+ deliver(new ConfigError("authorization callback missing code"));
77
+ return;
78
+ }
79
+ respond(res, 200, "Login complete", "Metabase CLI is now authorized.");
80
+ deliver({
81
+ code: query.code,
82
+ state: query.state
83
+ });
84
+ });
85
+ function deliver(result) {
86
+ if (outcome !== null) return;
87
+ outcome = result;
88
+ if (result instanceof Error) fail?.(result);
89
+ else settle?.(result);
90
+ }
91
+ const timer = setTimeout(() => {
92
+ deliver(new ConfigError(`timed out waiting for browser login after ${timeoutMs}ms`));
93
+ }, timeoutMs);
94
+ timer.unref();
95
+ server.on("error", (error) => {
96
+ rejectServer(error);
97
+ deliver(error);
98
+ });
99
+ server.listen(0, LOOPBACK_HOST, () => {
100
+ const port = serverPort(server);
101
+ resolveServer({
102
+ redirectUri: `http://${LOOPBACK_HOST}:${port}${CALLBACK_PATH}`,
103
+ waitForCallback() {
104
+ return new Promise((resolve, reject) => {
105
+ if (outcome !== null) {
106
+ if (outcome instanceof Error) reject(outcome);
107
+ else resolve(outcome);
108
+ return;
109
+ }
110
+ settle = resolve;
111
+ fail = reject;
112
+ });
113
+ },
114
+ close() {
115
+ clearTimeout(timer);
116
+ server.close();
117
+ server.closeAllConnections();
118
+ }
119
+ });
120
+ });
121
+ });
122
+ }
123
+
124
+ //#endregion
125
+ //#region src/core/auth/pkce.ts
126
+ const VERIFIER_BYTES = 32;
127
+ const STATE_BYTES = 16;
128
+ function base64Url(buffer) {
129
+ return buffer.toString("base64url");
130
+ }
131
+ function generatePkce() {
132
+ const verifier = base64Url(randomBytes(VERIFIER_BYTES));
133
+ const challenge = base64Url(createHash("sha256").update(verifier).digest());
134
+ return {
135
+ verifier,
136
+ challenge
137
+ };
138
+ }
139
+ function randomState() {
140
+ return base64Url(randomBytes(STATE_BYTES));
141
+ }
142
+
143
+ //#endregion
144
+ //#region src/core/auth/oauth-login.ts
145
+ const CLIENT_NAME = "Metabase CLI";
146
+ function buildAuthorizeUrl(authorizationEndpoint, params) {
147
+ const separator = authorizationEndpoint.includes("?") ? "&" : "?";
148
+ return `${authorizationEndpoint}${separator}${new URLSearchParams(params).toString()}`;
149
+ }
150
+ async function resolveClientId(registrationEndpoint, redirectUri, provided) {
151
+ if (provided !== void 0) return provided;
152
+ if (registrationEndpoint === void 0) throw new ConfigError("this Metabase has dynamic client registration disabled; pass --client-id with a pre-registered native client");
153
+ const registered = await registerClient({
154
+ registrationEndpoint,
155
+ redirectUri,
156
+ clientName: CLIENT_NAME
157
+ });
158
+ return registered.client_id;
159
+ }
160
+ async function oauthLogin(input, deps) {
161
+ const metadata = input.metadata ?? await discoverMetadata(input.baseUrl);
162
+ const pkce = generatePkce();
163
+ const state = randomState();
164
+ const server = await startCallbackServer(state, input.timeoutMs);
165
+ try {
166
+ const clientId = await resolveClientId(metadata.registration_endpoint, server.redirectUri, input.clientId);
167
+ const authorizeUrl = buildAuthorizeUrl(metadata.authorization_endpoint, {
168
+ response_type: "code",
169
+ client_id: clientId,
170
+ redirect_uri: server.redirectUri,
171
+ code_challenge: pkce.challenge,
172
+ code_challenge_method: "S256",
173
+ state,
174
+ scope: OAUTH_SCOPE
175
+ });
176
+ const opened = await deps.openBrowser(authorizeUrl);
177
+ deps.onAuthorizeUrl(authorizeUrl, opened);
178
+ const callback = await server.waitForCallback();
179
+ const tokens = await exchangeCode({
180
+ tokenEndpoint: metadata.token_endpoint,
181
+ code: callback.code,
182
+ redirectUri: server.redirectUri,
183
+ clientId,
184
+ codeVerifier: pkce.verifier
185
+ });
186
+ if (tokens.refresh_token === void 0) throw new ConfigError("token endpoint did not return a refresh token");
187
+ return oauthCredentialFromTokens(tokens, tokens.refresh_token, clientId, deps.now());
188
+ } finally {
189
+ server.close();
190
+ }
191
+ }
192
+
193
+ //#endregion
194
+ //#region src/commands/auth/login.ts
195
+ const LoginResult = z.object({
196
+ profile: z.string(),
197
+ url: z.string(),
198
+ authenticated: z.boolean(),
199
+ user: ProbedUser.nullable(),
200
+ version: ParsedVersionSchema.nullable()
201
+ });
202
+ const loginView = {
203
+ compactPick: LoginResult,
204
+ tableColumns: [
205
+ {
206
+ key: "profile",
207
+ label: "Profile"
208
+ },
209
+ {
210
+ key: "url",
211
+ label: "Metabase URL"
212
+ },
213
+ {
214
+ key: "authenticated",
215
+ label: "Authenticated",
216
+ format: (value) => value === true ? "credentials verified" : "saved without verification"
217
+ },
218
+ {
219
+ key: "user",
220
+ label: "Logged in as",
221
+ format: (value) => renderUserName(value)
222
+ },
223
+ {
224
+ key: "user",
225
+ label: "Role",
226
+ format: (value) => renderUserRole(value)
227
+ },
228
+ {
229
+ key: "version",
230
+ label: "Version",
231
+ format: (value) => renderVersionTag(value)
232
+ }
233
+ ]
234
+ };
235
+ var login_default = defineMetabaseCommand({
236
+ meta: {
237
+ name: "login",
238
+ description: "Log in to a Metabase instance for a profile"
239
+ },
240
+ details: "Interactive login offers browser OAuth (recommended; Metabase v63+) or an API key — older servers fall back to the API key prompt automatically. Browser login opens Metabase, you sign in (password or SSO) and approve, and the CLI stores a refreshing access token. For CI/non-interactive use, supply an API key via --api-key, piped stdin, or $MB_API_KEY (first non-empty wins); any of these skips the browser flow, even on a TTY. The URL comes from --url or $MB_URL, prompted when stdin is a TTY.",
241
+ capabilities: { minVersion: 58 },
242
+ args: {
243
+ ...outputFlags,
244
+ ...profileFlag,
245
+ ...connectionFlags,
246
+ clientId: {
247
+ type: "string",
248
+ description: "Pre-registered OAuth client id (when dynamic registration is disabled)",
249
+ alias: "client-id"
250
+ },
251
+ "skip-verify": {
252
+ type: "boolean",
253
+ default: false,
254
+ description: "Save without contacting the server"
255
+ }
256
+ },
257
+ outputSchema: LoginResult,
258
+ examples: [
259
+ "mb auth login --url https://metabase.example.com",
260
+ "echo $MB_API_KEY | mb auth login --url https://metabase.example.com",
261
+ "mb auth login --profile staging --url https://staging.example.com"
262
+ ],
263
+ async run({ args, ctx }) {
264
+ const profileName = await resolveLoginProfile(args.profile);
265
+ const env = readEnvCredentials();
266
+ if (args.apiKey) warn("warning: --api-key is visible in shell history and process listings — pipe the key on stdin or set MB_API_KEY instead");
267
+ const url = await resolveUrl(args.url, env.url);
268
+ const apiKey = await nonInteractiveApiKey(args.apiKey, env.apiKey);
269
+ if (apiKey !== null) {
270
+ await completeLogin(profileName, url, {
271
+ kind: "apiKey",
272
+ apiKey
273
+ }, args["skip-verify"], ctx, () => writeProfile({
274
+ url,
275
+ apiKey
276
+ }, profileName));
277
+ return;
278
+ }
279
+ if (!process.stdin.isTTY) throw new ConfigError("interactive login requires a TTY; pass --api-key or set MB_API_KEY for non-interactive login");
280
+ const metadata = await probeOAuthSupport(url);
281
+ const method = await chooseLoginMethod(metadata, args.clientId);
282
+ if (method === "apiKey") {
283
+ const promptedKey = await promptForApiKey();
284
+ await completeLogin(profileName, url, {
285
+ kind: "apiKey",
286
+ apiKey: promptedKey
287
+ }, args["skip-verify"], ctx, () => writeProfile({
288
+ url,
289
+ apiKey: promptedKey
290
+ }, profileName));
291
+ return;
292
+ }
293
+ const credential = await oauthLogin({
294
+ baseUrl: url,
295
+ ...metadata !== null && { metadata },
296
+ ...args.clientId !== void 0 && { clientId: args.clientId }
297
+ }, {
298
+ openBrowser,
299
+ onAuthorizeUrl: announceAuthorizeUrl,
300
+ now: () => Date.now()
301
+ });
302
+ await completeLogin(profileName, url, credential, args["skip-verify"], ctx, () => writeOAuthProfile(url, credential, profileName));
303
+ }
304
+ });
305
+ async function probeOAuthSupport(url) {
306
+ try {
307
+ return await tryDiscoverMetadata(url);
308
+ } catch (error) {
309
+ if (error instanceof ConfigError) throw error;
310
+ throw new ConfigError(`could not reach ${url}: ${errorMessage(error)}`);
311
+ }
312
+ }
313
+ async function chooseLoginMethod(metadata, clientId) {
314
+ if (metadata === null) {
315
+ if (clientId !== void 0) throw new ConfigError("--client-id was given but this Metabase does not support OAuth login (requires Metabase v63 or newer)");
316
+ warn("This Metabase does not support browser login (requires Metabase v63 or newer); using an API key instead.");
317
+ return "apiKey";
318
+ }
319
+ if (clientId !== void 0) return "oauth";
320
+ return promptSelect({
321
+ message: "How do you want to log in?",
322
+ choices: [{
323
+ value: "oauth",
324
+ label: "In your browser (recommended)",
325
+ hint: "sign in to Metabase with password or SSO and approve the CLI"
326
+ }, {
327
+ value: "apiKey",
328
+ label: "With an API key",
329
+ hint: "paste a key from Admin settings → Authentication → API keys"
330
+ }],
331
+ initialValue: "oauth"
332
+ });
333
+ }
334
+ async function promptForApiKey() {
335
+ return promptPassword({
336
+ message: "API key",
337
+ mask: "•",
338
+ validate: (input) => input ? void 0 : "API key is required"
339
+ });
340
+ }
341
+ async function completeLogin(profileName, url, credential, skipVerify, ctx, persist) {
342
+ if (skipVerify) {
343
+ await persistWithWarning(persist);
344
+ renderSummary({
345
+ profile: profileName,
346
+ url,
347
+ authenticated: false,
348
+ user: null,
349
+ version: null
350
+ }, loginView, `Saved credentials for profile "${profileName}" (${url}) without verifying.`, ctx);
351
+ return;
352
+ }
353
+ const result = await verifyAndProbe(url, credential);
354
+ if (!result.ok) {
355
+ await writeProbeFailure(profileName, {
356
+ kind: result.kind,
357
+ reason: result.message
358
+ });
359
+ await revokeUnsavedOAuthCredential(url, credential);
360
+ throw new ConfigError(formatVerifyFailureMessage(profileName, result));
361
+ }
362
+ await persistWithWarning(persist);
363
+ await writeProbeResult(profileName, {
364
+ user: result.user,
365
+ server: result.server
366
+ });
367
+ const who = renderUserName(result.user);
368
+ const role = renderUserRole(result.user);
369
+ const versionTag = renderVersionTag(result.server.version);
370
+ const serverClause = versionTag === EMPTY_CELL ? "" : ` Server ${versionTag}.`;
371
+ renderSummary({
372
+ profile: profileName,
373
+ url,
374
+ authenticated: true,
375
+ user: result.user,
376
+ version: result.server.version
377
+ }, loginView, `Logged in to ${url} as ${who} (${role}). Saved to profile "${profileName}".${serverClause}`, ctx);
378
+ }
379
+ async function revokeUnsavedOAuthCredential(url, credential) {
380
+ if (credential.kind !== "oauth") return;
381
+ try {
382
+ const revoked = await revokeOAuthCredential(url, credential);
383
+ if (!revoked) warn("server does not advertise a revocation endpoint; the unsaved tokens remain valid until they expire");
384
+ } catch (error) {
385
+ warn(`could not revoke the unsaved tokens server-side: ${errorMessage(error)}`);
386
+ }
387
+ }
388
+ async function persistWithWarning(persist) {
389
+ const location = await persist();
390
+ if (location.backend === "file") warn(keyringFallbackWarning(location));
391
+ const residual = consumeKeychainResidualWarning();
392
+ if (residual !== null) warn(residual);
393
+ consumeKeyringDowngradeWarning();
394
+ }
395
+ function announceAuthorizeUrl(url, opened) {
396
+ if (opened) {
397
+ warn(`Opening your browser to finish login. If it didn't open, visit:\n ${url}`);
398
+ return;
399
+ }
400
+ warn(`Open this URL in your browser to finish login:\n ${url}`);
401
+ }
402
+ function formatVerifyFailureMessage(profileName, failure) {
403
+ const which = failure.which === "user" ? "/api/user/current" : "/api/session/properties";
404
+ return `verification failed (${which}): ${failure.message} — credentials were not saved for profile "${profileName}"`;
405
+ }
406
+ async function resolveLoginProfile(flagProfile) {
407
+ const explicit = explicitProfileName(flagProfile);
408
+ if (explicit !== null) return explicit;
409
+ if (!process.stdin.isTTY) return DEFAULT_PROFILE;
410
+ const entered = (await promptText({
411
+ message: "Profile name",
412
+ placeholder: DEFAULT_PROFILE,
413
+ defaultValue: DEFAULT_PROFILE
414
+ })).trim();
415
+ return entered === "" ? DEFAULT_PROFILE : entered;
416
+ }
417
+ async function resolveUrl(flagUrl, envUrl) {
418
+ if (flagUrl) return normalizeUrl(flagUrl);
419
+ if (envUrl) return normalizeUrl(envUrl);
420
+ return promptForUrl();
421
+ }
422
+ async function nonInteractiveApiKey(flagKey, envKey) {
423
+ if (flagKey) return flagKey;
424
+ if (!process.stdin.isTTY) {
425
+ const piped = (await readInput({ required: false })).trim();
426
+ if (piped) return piped;
427
+ }
428
+ if (envKey) {
429
+ if (process.stdin.isTTY) warn("using the API key from $MB_API_KEY; unset it to choose browser login");
430
+ return envKey;
431
+ }
432
+ return null;
433
+ }
434
+ async function promptForUrl() {
435
+ if (!process.stdin.isTTY) throw new ConfigError("--url is required when stdin is not a TTY (cannot prompt interactively)");
436
+ const value = await promptText({
437
+ message: "Metabase URL",
438
+ placeholder: "https://metabase.example.com",
439
+ validate(input) {
440
+ if (!input) return "URL is required";
441
+ try {
442
+ normalizeUrl(input);
443
+ } catch (error) {
444
+ return errorMessage(error);
445
+ }
446
+ return void 0;
447
+ }
448
+ });
449
+ return normalizeUrl(value);
450
+ }
451
+
452
+ //#endregion
453
+ export { login_default as default };
@@ -1,8 +1,8 @@
1
- import "./command-augment-BH9qgQ5u.mjs";
2
- import { outputFlags, profileFlag } from "./error-BGH4gxGN.mjs";
3
- import { clearProfile, defineMetabaseCommand, resolveProfileName } from "./runtime-DgHh4T6t.mjs";
4
- import { renderSummary } from "./capabilities-7L9GVMd_.mjs";
5
- import { promptConfirm } from "./prompt-u4WhE4T5.mjs";
1
+ import { errorMessage, warn } from "./command-augment-CAur0XOQ.mjs";
2
+ import { outputFlags, profileFlag } from "./error-BOi_ux9O.mjs";
3
+ import { clearProfile, consumeKeychainResidualWarning, defineMetabaseCommand, readProfileCredential, resolveProfileName, revokeOAuthCredential } from "./runtime-7JTC-usO.mjs";
4
+ import { renderSummary } from "./capabilities-BX1rnVuH.mjs";
5
+ import { promptConfirm } from "./prompt-Bc_bHSD0.mjs";
6
6
  import { z } from "zod";
7
7
 
8
8
  //#region src/commands/auth/logout.ts
@@ -33,7 +33,7 @@ var logout_default = defineMetabaseCommand({
33
33
  name: "logout",
34
34
  description: "Clear stored credentials for a profile"
35
35
  },
36
- capabilities: null,
36
+ capabilities: { minVersion: 58 },
37
37
  args: {
38
38
  ...outputFlags,
39
39
  ...profileFlag,
@@ -61,7 +61,16 @@ var logout_default = defineMetabaseCommand({
61
61
  return;
62
62
  }
63
63
  }
64
+ const resolved = await readProfileCredential(profileName);
64
65
  const cleared = await clearProfile(profileName);
66
+ const residual = consumeKeychainResidualWarning();
67
+ if (residual !== null) warn(residual);
68
+ if (resolved !== null && resolved.credential.kind === "oauth") try {
69
+ const revoked = await revokeOAuthCredential(resolved.url, resolved.credential);
70
+ if (!revoked) warn("server does not advertise a revocation endpoint; tokens remain valid until they expire");
71
+ } catch (error) {
72
+ warn(`could not revoke tokens server-side: ${errorMessage(error)}`);
73
+ }
65
74
  const message = cleared ? `Cleared stored credentials for profile "${profileName}".` : `No stored credentials for profile "${profileName}".`;
66
75
  renderSummary({
67
76
  profile: profileName,
@@ -1,5 +1,5 @@
1
- import { getMetabaseAugment, resolveCitty, toAliasArray } from "./command-augment-BH9qgQ5u.mjs";
2
- import { Capabilities, writeJson } from "./capabilities-7L9GVMd_.mjs";
1
+ import { getMetabaseAugment, resolveCitty, toAliasArray } from "./command-augment-CAur0XOQ.mjs";
2
+ import { Capabilities, writeJson } from "./capabilities-BX1rnVuH.mjs";
3
3
  import { defineCommand } from "citty";
4
4
  import { z } from "zod";
5
5
 
@@ -0,0 +1,19 @@
1
+ import { defineCommand } from "citty";
2
+
3
+ //#region src/commands/measure/index.ts
4
+ var measure_default = defineCommand({
5
+ meta: {
6
+ name: "measure",
7
+ description: "Manage Metabase measures"
8
+ },
9
+ subCommands: {
10
+ list: () => import("./list-BkEFHJe8.mjs").then((mod) => mod.default),
11
+ get: () => import("./get-B2-RLrYJ.mjs").then((mod) => mod.default),
12
+ create: () => import("./create-Bbe2EM9f.mjs").then((mod) => mod.default),
13
+ update: () => import("./update-BuJjTYAx.mjs").then((mod) => mod.default),
14
+ archive: () => import("./archive-DTN6Anme.mjs").then((mod) => mod.default)
15
+ }
16
+ });
17
+
18
+ //#endregion
19
+ export { measure_default as default };
@@ -1,10 +1,10 @@
1
- import "./command-augment-BH9qgQ5u.mjs";
2
- import { connectionFlags, outputFlags, profileFlag } from "./error-BGH4gxGN.mjs";
3
- import { defineMetabaseCommand } from "./runtime-DgHh4T6t.mjs";
4
- import { renderItem } from "./capabilities-7L9GVMd_.mjs";
5
- import "./field-MGxpNQUH.mjs";
6
- import { parseId } from "./parse-id-sKNP6yu5.mjs";
7
- import { TableQueryMetadata, tableView } from "./table-CkWja2UH.mjs";
1
+ import "./command-augment-CAur0XOQ.mjs";
2
+ import { connectionFlags, outputFlags, profileFlag } from "./error-BOi_ux9O.mjs";
3
+ import { defineMetabaseCommand } from "./runtime-7JTC-usO.mjs";
4
+ import { renderItem } from "./capabilities-BX1rnVuH.mjs";
5
+ import "./field-E0IBy4Uw.mjs";
6
+ import { parseId } from "./parse-id-DMs04KM3.mjs";
7
+ import { TableQueryMetadata, tableView } from "./table-qDD2kApF.mjs";
8
8
 
9
9
  //#region src/commands/table/metadata.ts
10
10
  var metadata_default = defineMetabaseCommand({
@@ -1,11 +1,11 @@
1
- import "./command-augment-BH9qgQ5u.mjs";
2
- import { connectionFlags, outputFlags, profileFlag } from "./error-BGH4gxGN.mjs";
3
- import { defineMetabaseCommand } from "./runtime-DgHh4T6t.mjs";
4
- import { renderItem } from "./capabilities-7L9GVMd_.mjs";
5
- import "./field-MGxpNQUH.mjs";
6
- import { parseId } from "./parse-id-sKNP6yu5.mjs";
7
- import "./table-CkWja2UH.mjs";
8
- import { Database, databaseView } from "./database-Dsv4QBs0.mjs";
1
+ import "./command-augment-CAur0XOQ.mjs";
2
+ import { connectionFlags, outputFlags, profileFlag } from "./error-BOi_ux9O.mjs";
3
+ import { defineMetabaseCommand } from "./runtime-7JTC-usO.mjs";
4
+ import { renderItem } from "./capabilities-BX1rnVuH.mjs";
5
+ import "./field-E0IBy4Uw.mjs";
6
+ import { parseId } from "./parse-id-DMs04KM3.mjs";
7
+ import "./table-qDD2kApF.mjs";
8
+ import { Database, databaseView } from "./database-BmsxuRmO.mjs";
9
9
 
10
10
  //#region src/commands/db/metadata.ts
11
11
  var metadata_default = defineMetabaseCommand({
@@ -1,4 +1,4 @@
1
- import { ConfigError } from "./command-augment-BH9qgQ5u.mjs";
1
+ import { ConfigError } from "./command-augment-CAur0XOQ.mjs";
2
2
 
3
3
  //#region src/commands/parse-enum.ts
4
4
  function parseEnumFlag(value, schema, name) {
@@ -1,4 +1,4 @@
1
- import { parseInteger } from "./runtime-DgHh4T6t.mjs";
1
+ import { parseInteger } from "./runtime-7JTC-usO.mjs";
2
2
 
3
3
  //#region src/commands/parse-id.ts
4
4
  function parseId(value, name = "id") {
@@ -1,4 +1,4 @@
1
- import { ConfigError } from "./command-augment-BH9qgQ5u.mjs";
1
+ import { ConfigError } from "./command-augment-CAur0XOQ.mjs";
2
2
 
3
3
  //#region src/commands/collection/parse-ref.ts
4
4
  const SPECIAL_TOKENS = new Set(["root", "trash"]);
@@ -1,8 +1,8 @@
1
- import "./command-augment-BH9qgQ5u.mjs";
2
- import { listEnvelopeSchema, outputFlags, wrapList } from "./error-BGH4gxGN.mjs";
3
- import { defineMetabaseCommand } from "./runtime-DgHh4T6t.mjs";
4
- import { renderList } from "./capabilities-7L9GVMd_.mjs";
5
- import { findSkillByName, loadAllSkills, loadVisibleSkills } from "./skills-CY_FmaPo.mjs";
1
+ import "./command-augment-CAur0XOQ.mjs";
2
+ import { listEnvelopeSchema, outputFlags, wrapList } from "./error-BOi_ux9O.mjs";
3
+ import { defineMetabaseCommand } from "./runtime-7JTC-usO.mjs";
4
+ import { renderList } from "./capabilities-BX1rnVuH.mjs";
5
+ import { findSkillByName, loadAllSkills, loadVisibleSkills } from "./skills-CJ8g8fhQ.mjs";
6
6
  import { z } from "zod";
7
7
 
8
8
  //#region src/commands/skills/path.ts
@@ -1,5 +1,5 @@
1
- import { TimeoutError } from "./command-augment-BH9qgQ5u.mjs";
2
- import { combineAborts, throwIfAborted } from "./runtime-DgHh4T6t.mjs";
1
+ import { TimeoutError } from "./command-augment-CAur0XOQ.mjs";
2
+ import { combineAborts, throwIfAborted } from "./runtime-7JTC-usO.mjs";
3
3
  import { setTimeout } from "node:timers/promises";
4
4
 
5
5
  //#region src/runtime/poll.ts
@@ -1,5 +1,5 @@
1
- import { parseJsonOrPlain } from "./runtime-DgHh4T6t.mjs";
2
- import { pollUntil } from "./poll-Cyw-dQi4.mjs";
1
+ import { parseJsonOrPlain } from "./runtime-7JTC-usO.mjs";
2
+ import { pollUntil } from "./poll-13tgWrN_.mjs";
3
3
  import { z } from "zod";
4
4
 
5
5
  //#region src/domain/git-sync.ts
@@ -1,7 +1,7 @@
1
- import { ChainedRequestError, ConfigError, MetabaseError } from "./command-augment-BH9qgQ5u.mjs";
2
- import { HttpError } from "./runtime-DgHh4T6t.mjs";
3
- import { writeJson } from "./capabilities-7L9GVMd_.mjs";
4
- import { Card } from "./card-DnIeMmUn.mjs";
1
+ import { ChainedRequestError, ConfigError, MetabaseError } from "./command-augment-CAur0XOQ.mjs";
2
+ import { HttpError } from "./runtime-7JTC-usO.mjs";
3
+ import { writeJson } from "./capabilities-BX1rnVuH.mjs";
4
+ import { Card } from "./card-wCPcuKSi.mjs";
5
5
  import { z } from "zod";
6
6
 
7
7
  //#region src/commands/dashboard/preflight.ts