@metabase/cli 0.3.0 → 0.3.1-alpha.fix-transform-test-ee-path.a3ca6dd
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.
- package/dist/{add-collection-B3Ty8SzB.mjs → add-collection-BEg-1pt8.mjs} +6 -9
- package/dist/{alert-DT-ee7yf.mjs → alert-CBwtJ3lE.mjs} +7 -7
- package/dist/{alerts-Bf2RH_p_.mjs → alerts-Bn9ZhFYK.mjs} +7 -7
- package/dist/{append-DFzQRPMd.mjs → append-F7kfyk0p.mjs} +6 -5
- package/dist/{archive-ByvA49Kz.mjs → archive-2VqBgcyE.mjs} +5 -5
- package/dist/{archive-4tmm946K.mjs → archive-3_KVbxIk.mjs} +4 -4
- package/dist/{archive-Cd29QC0c.mjs → archive-7tZyaUWv.mjs} +4 -4
- package/dist/{archive-Dr9Xnx_Z.mjs → archive-Bonv-Hcf.mjs} +6 -6
- package/dist/{archive-C7w49Grr.mjs → archive-BzEvapLz.mjs} +6 -6
- package/dist/{archive-CwAdlv63.mjs → archive-CAwDiQWt2.mjs} +6 -6
- package/dist/{archive-lQqs13Uz.mjs → archive-CE-RKcle.mjs} +6 -6
- package/dist/{archive-B6eXiyER.mjs → archive-Da3-hnRM.mjs} +4 -4
- package/dist/{archive-gid9Y09v.mjs → archive-IBHOtOMk.mjs} +4 -4
- package/dist/{archive-BxNPHxOY.mjs → archive-TBo05bZZ.mjs} +6 -6
- package/dist/{archive-ChORH5JH.mjs → archive-k79AXZhh.mjs} +4 -4
- package/dist/{auth-Dltxua89.mjs → auth-CLZuUSzL.mjs} +5 -5
- package/dist/{body-Cur4NJt9.mjs → body-Q8iNnt-X.mjs} +3 -3
- package/dist/{branches-DchlyU0i.mjs → branches-CjMIMKse.mjs} +4 -7
- package/dist/{cancel-BMQa5R1Z.mjs → cancel-H4vYr5Jv.mjs} +4 -4
- package/dist/{cancel-task-C5CU1pxU.mjs → cancel-task-p09LCbgs.mjs} +5 -8
- package/dist/{card-zyUkr2nS.mjs → card-CEkp1mcI.mjs} +1 -1
- package/dist/card-DlVb10D3.mjs +24 -0
- package/dist/{card-DZxRmver.mjs → card-voh1k4hl.mjs} +14 -11
- package/dist/{cards-SccWvRQD.mjs → cards-DDG6RObF.mjs} +7 -7
- package/dist/cli.mjs +567 -68
- package/dist/client-toDDqakD.mjs +4093 -0
- package/dist/{collection-CfulNRBG.mjs → collection-BxdPxD38.mjs} +1 -1
- package/dist/{collection-CGoVLvcD.mjs → collection-DYM0p3Xl.mjs} +1 -1
- package/dist/{collection-namespace-GwydWBF3.mjs → collection-namespace-DDI9-HgU.mjs} +2 -2
- package/dist/collection-p_sficxo.mjs +20 -0
- package/dist/content-translation-BrHOrmj9.mjs +5 -0
- package/dist/content-translation-DcTEH_d7.mjs +12 -0
- package/dist/{create-CAWytBE5.mjs → create-BLxdMJgQ.mjs} +5 -5
- package/dist/{create-BNQ_DytP.mjs → create-BPN1cX7b.mjs} +4 -4
- package/dist/{create-CHQx7jq4.mjs → create-BjCpsMQM.mjs} +5 -5
- package/dist/{create-CD008jdE.mjs → create-BovrhBQn.mjs} +12 -8
- package/dist/{create-DV-Ln5Mo.mjs → create-CVCPD-1F.mjs} +4 -4
- package/dist/{create-DJmXXQoq.mjs → create-CVPGOx7u2.mjs} +8 -8
- package/dist/{create-Beh-2uoN.mjs → create-Chs5c8vx.mjs} +6 -6
- package/dist/{create-BOLwWt8Q.mjs → create-D04fl6ec.mjs} +5 -5
- package/dist/{create-C79vErX0.mjs → create-D5mN20oE.mjs} +7 -7
- package/dist/{create-DF4QtgDL.mjs → create-D88Im3X22.mjs} +6 -6
- package/dist/{create-tQbnuz-I.mjs → create-DQfOV9Sm.mjs} +6 -6
- package/dist/{create-CCh_LyW9.mjs → create-DWU4j22P.mjs} +4 -4
- package/dist/create-DjP2yUyn.mjs +34 -0
- package/dist/{create-CAQV2g6V.mjs → create-Dk6Zm3ZH.mjs} +7 -7
- package/dist/{create-zeveFdnd.mjs → create-DkmeJGMy.mjs} +5 -8
- package/dist/{create-i14Wv3Tj.mjs → create-TQr3briq.mjs} +4 -4
- package/dist/{create-branch-CYo6jZth.mjs → create-branch-Bs6BlkgQ.mjs} +5 -9
- package/dist/{csv-B2Jgb1GM.mjs → csv-BsN6FmY-.mjs} +6 -5
- package/dist/{current-task-MpBFGttd.mjs → current-task-cCmLLVcv.mjs} +5 -8
- package/dist/{dashboard-BHJBoaG7.mjs → dashboard-CpIEKEgu.mjs} +10 -10
- package/dist/{dashboard-BCpSq_G-.mjs → dashboard-D0hwTC-f.mjs} +12 -2
- package/dist/{dashboard-CsIFFpzK.mjs → dashboard-DgK81azj.mjs} +1 -1
- package/dist/{database-B19qlLKZ.mjs → database-C3E9PZSx.mjs} +1 -1
- package/dist/{database-C8G6ZKG0.mjs → database-JtHTqSpq.mjs} +1 -1
- package/dist/{db-DsfojyeH.mjs → db-BbvcmfWM.mjs} +7 -7
- package/dist/{delete-B8e01xAG.mjs → delete-C4_rcfNu.mjs} +5 -5
- package/dist/delete-CLdDYdYG.mjs +44 -0
- package/dist/{delete-DFmX7jTp.mjs → delete-D13SLwhr.mjs} +5 -5
- package/dist/{delete-Ob06PPie.mjs → delete-D3-jMLu5.mjs} +5 -5
- package/dist/{delete-BApOjQvl.mjs → delete-DLirF5iq.mjs} +5 -5
- package/dist/{delete-Ck0q4Dzp.mjs → delete-JBjvxdIU.mjs} +5 -5
- package/dist/{delete-runtime-D74s6vhu.mjs → delete-runtime-BKEzJn22.mjs} +1 -2
- package/dist/{delete-table-DuyhGrvA.mjs → delete-table-Gwk7JL5c.mjs} +5 -5
- package/dist/{dependencies-Bj3QrGIm.mjs → dependencies-B7vl9Ovb.mjs} +7 -7
- package/dist/{dirty-DNYoM6Bp.mjs → dirty-CIZeASXG.mjs} +6 -9
- package/dist/{document-Cd2mmqCp.mjs → document-BHpLJbKU.mjs} +5 -0
- package/dist/{document-D6OybtP2.mjs → document-CA0Q6lqu.mjs} +1 -1
- package/dist/document-ceJW4VuL.mjs +19 -0
- package/dist/download-B-krJch0.mjs +25 -0
- package/dist/{eid-WTZmDdsr.mjs → eid-C0D92gZW.mjs} +4 -5
- package/dist/{events-Bn7jh5lP.mjs → events-CuLeaey6.mjs} +5 -5
- package/dist/{export-BjfoZRDJ.mjs → export-DeuLpt3x.mjs} +7 -10
- package/dist/{field-Zau6Hc6X.mjs → field-B8Hndt4p.mjs} +5 -5
- package/dist/{field-Cr2DPUG9.mjs → field-CcN4oZy6.mjs} +16 -1
- package/dist/{field-BPsNa-TO.mjs → field-fDtIrY6D.mjs} +1 -1
- package/dist/{fields-CBBa-Prp.mjs → fields-CAchmFh4.mjs} +7 -7
- package/dist/{get-CDJFVvhj.mjs → get-BH3Tgfgf.mjs} +4 -4
- package/dist/{get-CDMGbgrh.mjs → get-BJOxfbDP.mjs} +4 -4
- package/dist/{get-B_xdF1kq.mjs → get-BOjTqIMx.mjs} +6 -6
- package/dist/{get-D_h-G9bn.mjs → get-C1BPEbyl.mjs} +6 -6
- package/dist/{get-Dmj9Ygz1.mjs → get-C8dcHjd6.mjs} +6 -6
- package/dist/{get-DkWO0EI0.mjs → get-CArTALOt.mjs} +6 -6
- package/dist/get-CMCAgpxn.mjs +93 -0
- package/dist/{get-CnbUCzDM.mjs → get-CjDHpz6A.mjs} +4 -4
- package/dist/{get-ByBOq30r.mjs → get-ClNkea9I.mjs} +6 -6
- package/dist/{get-DRvsATp-.mjs → get-CvAMxfPD.mjs} +6 -6
- package/dist/{get-B7sMgsFs.mjs → get-D8qaSSEH.mjs} +4 -4
- package/dist/{get-00lyLv6R.mjs → get-DCvnNk3f.mjs} +6 -6
- package/dist/{get-DY03Azx9.mjs → get-DEwfm3Yl.mjs} +5 -8
- package/dist/{get-C2-Q3iQ5.mjs → get-DXWrGwWH.mjs} +4 -4
- package/dist/get-DbXTkB4u.mjs +32 -0
- package/dist/{get-DYO1kywc.mjs → get-DvF9oooq.mjs} +5 -5
- package/dist/{get-DdsoHaKH.mjs → get-d055CJ1T.mjs} +4 -4
- package/dist/{get-Bz99dAxK.mjs → get-kBTeBtLe.mjs} +6 -6
- package/dist/{get-DmpB6J9g.mjs → get-ohue3YrV2.mjs} +6 -6
- package/dist/{get-run-Cnux9ln0.mjs → get-run-X6zhp0dW.mjs} +6 -6
- package/dist/{get-Dn9ZiSZr.mjs → get-wIZrb7oN.mjs} +6 -6
- package/dist/git-sync-BkTmSgdD.mjs +28 -0
- package/dist/{git-sync-BDnxPrqU.mjs → git-sync-BwBRmEhE.mjs} +18 -1
- package/dist/{git-sync-DxD_ng48.mjs → git-sync-TjX1r_wF.mjs} +1 -1
- package/dist/{group-DBM87IgC.mjs → group-YQQ5GIcP.mjs} +2 -2
- package/dist/{has-remote-changes-C684Redh.mjs → has-remote-changes-zCtdEGs-.mjs} +5 -8
- package/dist/{import-Rmmttboo.mjs → import-DkAy_Xi8.mjs} +7 -10
- package/dist/{input-DH9i67x_.mjs → input-DEvkIjGr.mjs} +1 -1
- package/dist/{is-dirty-DYeJYhBz.mjs → is-dirty-Dfk2Xf-W.mjs} +3 -6
- package/dist/{items-CQlPXBXE.mjs → items-CiSBrc9d.mjs} +7 -7
- package/dist/{key-BEhqIzIQ.mjs → key-PYetuQ13.mjs} +1 -1
- package/dist/library-BPIzb3K_.mjs +81 -0
- package/dist/{library-Bsm5KsFF.mjs → library-FBj2Je-M.mjs} +5 -5
- package/dist/{library-DfYAT2Ep.mjs → library-PGCfm0UA.mjs} +1 -1
- package/dist/list-9CJczyF5.mjs +60 -0
- package/dist/{list-DE9FM957.mjs → list-B6tDzQsv.mjs} +4 -4
- package/dist/{list-BtkWNtvY.mjs → list-BDJkJc8s.mjs} +7 -7
- package/dist/{list-BzVTHOoH.mjs → list-Br0g0oDR.mjs} +6 -6
- package/dist/{list-CNUiF8Z7.mjs → list-C9-2J0Nu.mjs} +6 -6
- package/dist/{list-B4hJuMhA.mjs → list-CGjdrAhT.mjs} +7 -7
- package/dist/{list-BtmsNOEn.mjs → list-CHOJQ1uR.mjs} +4 -4
- package/dist/{list-CKK-s3Ty.mjs → list-CK4S_aDK.mjs} +4 -4
- package/dist/{list-C5Zs8nrb.mjs → list-CYONHM9n.mjs} +6 -6
- package/dist/{list-CQwOgIlj.mjs → list-CrwbvMEG.mjs} +6 -6
- package/dist/{list-BOET6zhP.mjs → list-D6WZmnG_.mjs} +4 -4
- package/dist/{list-DMKDsBRd.mjs → list-DD_tjCmP.mjs} +7 -7
- package/dist/{list-DF2rvoO1.mjs → list-Dqv3nOEe.mjs} +14 -13
- package/dist/{list-CQDprvW0.mjs → list-Hjsg2N8L.mjs} +7 -7
- package/dist/{list-CMpoc2TN.mjs → list-M4Twal0d.mjs} +5 -5
- package/dist/{list-BpFp9Wre.mjs → list-UbzhJFFn.mjs} +4 -4
- package/dist/list-W5y4079U.mjs +35 -0
- package/dist/{list-BP3MPq-M.mjs → list-f5HIVoLN.mjs} +4 -4
- package/dist/{list-B8nAGwP4.mjs → list-uCAP4vmQ.mjs} +6 -6
- package/dist/{login-CGHeSjlP.mjs → login-CIzUMkf3.mjs} +15 -12
- package/dist/{logout-DAxOlbv4.mjs → logout-CRm_AaoF.mjs} +3 -4
- package/dist/{measure-BsYv0p26.mjs → measure-DPXeIN18.mjs} +6 -6
- package/dist/{notification-Fcq1fIPw.mjs → notification-DVrLkjFT.mjs} +1 -1
- package/dist/{parameter-DUKR8NXo.mjs → parameter-Celg0wZa.mjs} +1 -1
- package/dist/{parameter-values-CJTdqd8c.mjs → parameter-values-rOHoy3k0.mjs} +5 -6
- package/dist/{parse-enum-D0Jfm_Bz.mjs → parse-enum-Dc0dMZ3P.mjs} +1 -1
- package/dist/{parse-id-C_jmKFaa.mjs → parse-id-CYZAIB58.mjs} +1 -1
- package/dist/{parse-ref-ibKVB0J4.mjs → parse-ref-DTDld_LJ.mjs} +1 -1
- package/dist/{path-B5gHvrYL.mjs → path-D9_unWc1.mjs} +5 -5
- package/dist/{poll-75SvT7Zv.mjs → poll-CZeXepUQ.mjs} +2 -2
- package/dist/{preflight-YpPQo-sa.mjs → preflight-BIxRV-bm.mjs} +3 -4
- package/dist/{process-DBOOrmET.mjs → process-CTrfxxaC.mjs} +1 -1
- package/dist/{publish-DijrxaCW.mjs → publish-N509vd0U.mjs} +9 -9
- package/dist/{pulse-BmsDenXm.mjs → pulse-Dz0ocv0l.mjs} +1 -1
- package/dist/{pulse-DhG6I9mI.mjs → pulse-x0gFxWfG.mjs} +2 -2
- package/dist/{query-Dc__-KJH.mjs → query-JvMjF22L.mjs} +9 -10
- package/dist/{query-result-DBDwk8TS.mjs → query-result-E4Q-Gra6.mjs} +1 -1
- package/dist/{query-BbqECzmF.mjs → query-yh5Wkfmc.mjs} +11 -18
- package/dist/{remove-collection-BOnxYvhj.mjs → remove-collection-B0E0dlZt.mjs} +6 -9
- package/dist/{render-CI93iP0I.mjs → render-Tlz6OCMU.mjs} +13 -2
- package/dist/{replace-Cq4CxVa-.mjs → replace-BwbYo6-2.mjs} +6 -5
- package/dist/{rescan-values-Dr_j416g.mjs → rescan-values-BiMPb5Z5.mjs} +6 -6
- package/dist/{run-DdGJ544X.mjs → run-B9aA1aNI.mjs} +26 -14
- package/dist/run-D37ntUQo.mjs +50 -0
- package/dist/{run-C3DkS6NP.mjs → run-Dbh3nvzF.mjs} +6 -6
- package/dist/{runs-CUNWiidL.mjs → runs-BuUzKR-x.mjs} +7 -7
- package/dist/{runtime-DiKyBxOw.mjs → runtime-CwhhhwcB.mjs} +946 -246
- package/dist/{schema-tables-CV386fnC.mjs → schema-tables-9PvvygPu.mjs} +7 -7
- package/dist/{schemas-DM-UqZBQ.mjs → schemas-DqkQI39t.mjs} +5 -5
- package/dist/{search-DFBwUc6d.mjs → search-BAXg-EJw.mjs} +2 -1
- package/dist/{search-DmGScXs8.mjs → search-BjAwR-oP.mjs} +6 -6
- package/dist/{segment-BzUGM2Fr.mjs → segment-1nBcugv8.mjs} +6 -6
- package/dist/{selectors-DGDn0Hto.mjs → selectors-DFNdyhPn.mjs} +3 -3
- package/dist/{send-CVxxEpDB.mjs → send-D4tYN3aN.mjs} +4 -4
- package/dist/{set-DFolTjbd.mjs → set-D_Mh2eVO.mjs} +5 -5
- package/dist/{set-active-BD8L1lPX.mjs → set-active-jY5VZsO8.mjs} +5 -5
- package/dist/{setting-DyhaeICs.mjs → setting-9ULb5wjN.mjs} +4 -4
- package/dist/{setup-BbDQN8fe.mjs → setup-DMaIuuCV.mjs} +4 -4
- package/dist/{signal-CMd0EFUa.mjs → signal-k7cm5N6h.mjs} +11 -2
- package/dist/skill-list-Bucy7UE2.mjs +76 -0
- package/dist/{skills--vK6J-e4.mjs → skills-Dyfqgobg.mjs} +3 -3
- package/dist/skills-PjjRtYqi.mjs +351 -0
- package/dist/snippet-DNoTIGAs.mjs +19 -0
- package/dist/{stash-D0S4JmAz.mjs → stash-C6BEM6_u.mjs} +7 -11
- package/dist/{status-BhswxJL1.mjs → status-DiP093Vm.mjs} +11 -9
- package/dist/{status-hL1am-HV.mjs → status-wAg5ajzM.mjs} +12 -11
- package/dist/stream-McixcoUl.mjs +7 -0
- package/dist/{subscription-_d5fB45F.mjs → subscription-CEeI0pSr.mjs} +6 -6
- package/dist/{subscriptions-s4TF6Ax3.mjs → subscriptions-B9cMNuIS.mjs} +7 -7
- package/dist/{summary-CsPvcUwW.mjs → summary-D0NP2NoT.mjs} +6 -6
- package/dist/{sync-schema-DaZ_MV-u.mjs → sync-schema-BgJ6KEqa.mjs} +7 -7
- package/dist/{sync-task-BACcrs0i.mjs → sync-task-BXeWuARG.mjs} +1 -1
- package/dist/{table-DYoC1kPn.mjs → table-9bTG6zSa.mjs} +5 -5
- package/dist/{table-CsIJNPFf.mjs → table-C6h4tIRw.mjs} +1 -1
- package/dist/{table-CeeTJgQb.mjs → table-DfuY0N8e.mjs} +51 -4
- package/dist/timeline-Ck53UgDh.mjs +21 -0
- package/dist/{timeline-event-CNQdCTDg.mjs → timeline-event-POmQ2TD2.mjs} +6 -6
- package/dist/transform-BC39AgQF.mjs +28 -0
- package/dist/{transform-DoTyyXAu.mjs → transform-CtqB1WYo.mjs} +2 -2
- package/dist/{transform-D3QX0jxA.mjs → transform-DiW7bREn.mjs} +68 -5
- package/dist/{transform-job-50GZHhKH.mjs → transform-job-AaMZRxAq.mjs} +1 -1
- package/dist/{transform-job-DRrK28IH.mjs → transform-job-CCguL6LP.mjs} +41 -4
- package/dist/transform-job-D-zUFmZU.mjs +22 -0
- package/dist/{transform-tag-_tgwlsdB.mjs → transform-tag-CP7FRU5G.mjs} +5 -5
- package/dist/transform-test-BjjCQ2xm.mjs +169 -0
- package/dist/transform-test-CKNQS_kC.mjs +16 -0
- package/dist/transform-test-gzDcbypy.mjs +25 -0
- package/dist/{transforms-oU4zizbO.mjs → transforms-DDSNP4eL.mjs} +7 -7
- package/dist/{tree-CH-f3bjP.mjs → tree-CAnMS2dm.mjs} +4 -5
- package/dist/{unpublish-BUl9RU5C.mjs → unpublish-DF1XQMWJ.mjs} +4 -7
- package/dist/{update-BZPllQoR.mjs → update-BS1yiwOO.mjs} +5 -5
- package/dist/{update-CO4m4wH3.mjs → update-Bb89y-0M.mjs} +8 -8
- package/dist/{update-C4YJQFDS.mjs → update-BbiVvdm1.mjs} +7 -7
- package/dist/{update-BCS5FxKr.mjs → update-BcdLQu7-.mjs} +9 -9
- package/dist/{update-cYkvbqK8.mjs → update-BjcWwrPc.mjs} +5 -5
- package/dist/{update-tX9mKBN_.mjs → update-BoJJ6Gel.mjs} +9 -9
- package/dist/{update-CHNSUHK4.mjs → update-C09GGTjN.mjs} +5 -5
- package/dist/{update-BzMDeZiU.mjs → update-C33R41eM.mjs} +7 -7
- package/dist/{update-CmDTljK-.mjs → update-C6KQZMDF.mjs} +7 -7
- package/dist/{update-bD_Jh5-s.mjs → update-CFqdElFO.mjs} +6 -6
- package/dist/{update-CVPAwJaH.mjs → update-CHsXoUJQ.mjs} +6 -6
- package/dist/update-CaJO1rWk.mjs +41 -0
- package/dist/{update-CvOO8TED.mjs → update-CmXGZPCR.mjs} +7 -7
- package/dist/{update-D-NE60AV.mjs → update-DFJSD3_l.mjs} +7 -7
- package/dist/{update-Nfi44RrE.mjs → update-DOeBAoul.mjs} +6 -6
- package/dist/{update-BiFDBcEH.mjs → update-DiowA7ud.mjs} +5 -5
- package/dist/{update-dashcard-C3TuYO_k.mjs → update-dashcard-DSL6Bogg.mjs} +7 -7
- package/dist/{upgrade-DXMV4AyP.mjs → upgrade-CBxr91bH.mjs} +6 -8
- package/dist/upload-C3z5ZaXA.mjs +24 -0
- package/dist/upload-CSHcnonI.mjs +13 -0
- package/dist/upload-DTyF-p8X.mjs +39 -0
- package/dist/upload-Do2PBSeH.mjs +23 -0
- package/dist/{uuid-BJkDWj9p.mjs → uuid-CwEbjDp8.mjs} +3 -4
- package/dist/{validate-BWchyW0V.mjs → validate-EAB-1EkK.mjs} +1 -1
- package/dist/{validate-query-DaGYSmpQ.mjs → validate-query-CQG86147.mjs} +2 -3
- package/dist/{values-Dxf1JEoA.mjs → values-69IZEVXu.mjs} +6 -6
- package/dist/{verify-K96rItG5.mjs → verify-Dg5YBI0l.mjs} +3 -18
- package/dist/{wait-DoMDH226.mjs → wait-DVXEJXd3.mjs} +7 -10
- package/dist/{wait-flags-DWEF9tX4.mjs → wait-flags-CkRgnfww.mjs} +2 -2
- package/dist/{window-BkvrP0gB.mjs → window-DSb1tqSe.mjs} +1 -1
- package/package.json +1 -1
- package/skill-data/core/SKILL.md +31 -14
- package/skill-data/dashboard/SKILL.md +2 -2
- package/skill-data/data-workflow/references/building-clean-tables.md +6 -2
- package/skill-data/data-workflow/references/reusable-definitions.md +11 -3
- package/skill-data/document/SKILL.md +4 -1
- package/skill-data/git-sync/SKILL.md +5 -0
- package/skill-data/mbql/SKILL.md +1 -1
- package/skill-data/mbql/references/operators.md +20 -15
- package/skill-data/metadata/SKILL.md +1 -1
- package/skill-data/metadata/references/semantic-types.md +7 -1
- package/skill-data/native-sql/references/template-tags.md +6 -2
- package/skill-data/notification/SKILL.md +7 -1
- package/skill-data/transform/SKILL.md +75 -3
- package/skill-data/transform-test-plan/SKILL.md +171 -0
- package/skill-data/transform-test-plan/references/checklist.md +81 -0
- package/skill-data/transform-test-plan/references/checks.md +259 -0
- package/skill-data/visualization/SKILL.md +11 -3
- package/skill-data/visualization/references/settings.md +6 -4
- package/skills/metabase-cli/SKILL.md +1 -1
- package/dist/card-CHI2bmds.mjs +0 -24
- package/dist/client-BqhzKdLM.mjs +0 -2194
- package/dist/collection-CY0AB99E.mjs +0 -20
- package/dist/document-BbskZPTT.mjs +0 -19
- package/dist/get-CvI--9S_.mjs +0 -80
- package/dist/git-sync-MQQYRYLg.mjs +0 -28
- package/dist/library-ClLgrAXy.mjs +0 -19
- package/dist/list-UhpKG6_m.mjs +0 -98
- package/dist/network-error-CEb9ymDW.mjs +0 -423
- package/dist/predicates-Bkm2IoeX.mjs +0 -170
- package/dist/skills-DTCrMcix.mjs +0 -216
- package/dist/snippet-DRwKb2x7.mjs +0 -19
- package/dist/timeline-xlDbEKWg.mjs +0 -21
- package/dist/transform-Bs0EWijQ.mjs +0 -28
- package/dist/transform-job-BcLChRup.mjs +0 -22
- package/dist/upload-CH632qW6.mjs +0 -46
- package/dist/upload-Dey_8rLf.mjs +0 -13
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import { t as defineCommandGroup } from "./group-DBM87IgC.mjs";
|
|
2
|
-
//#region src/commands/collection/index.ts
|
|
3
|
-
var collection_default = defineCommandGroup({
|
|
4
|
-
name: "collection",
|
|
5
|
-
description: "Manage Metabase collections",
|
|
6
|
-
skills: [{
|
|
7
|
-
skill: "core",
|
|
8
|
-
purpose: "collection ref forms and the transforms namespace"
|
|
9
|
-
}],
|
|
10
|
-
subCommands: {
|
|
11
|
-
list: () => import("./list-DMKDsBRd.mjs").then((mod) => mod.default),
|
|
12
|
-
get: () => import("./get-DkWO0EI0.mjs").then((mod) => mod.default),
|
|
13
|
-
items: () => import("./items-CQlPXBXE.mjs").then((mod) => mod.default),
|
|
14
|
-
tree: () => import("./tree-CH-f3bjP.mjs").then((mod) => mod.default),
|
|
15
|
-
create: () => import("./create-CAQV2g6V.mjs").then((mod) => mod.default),
|
|
16
|
-
archive: () => import("./archive-BxNPHxOY.mjs").then((mod) => mod.default)
|
|
17
|
-
}
|
|
18
|
-
});
|
|
19
|
-
//#endregion
|
|
20
|
-
export { collection_default as default };
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import { t as defineCommandGroup } from "./group-DBM87IgC.mjs";
|
|
2
|
-
//#region src/commands/document/index.ts
|
|
3
|
-
var document_default = defineCommandGroup({
|
|
4
|
-
name: "document",
|
|
5
|
-
description: "Manage Metabase documents",
|
|
6
|
-
skills: [{
|
|
7
|
-
skill: "document",
|
|
8
|
-
purpose: "author the ProseMirror document body"
|
|
9
|
-
}],
|
|
10
|
-
subCommands: {
|
|
11
|
-
list: () => import("./list-CNUiF8Z7.mjs").then((mod) => mod.default),
|
|
12
|
-
get: () => import("./get-D_h-G9bn.mjs").then((mod) => mod.default),
|
|
13
|
-
create: () => import("./create-tQbnuz-I.mjs").then((mod) => mod.default),
|
|
14
|
-
update: () => import("./update-D-NE60AV.mjs").then((mod) => mod.default),
|
|
15
|
-
archive: () => import("./archive-lQqs13Uz.mjs").then((mod) => mod.default)
|
|
16
|
-
}
|
|
17
|
-
});
|
|
18
|
-
//#endregion
|
|
19
|
-
export { document_default as default };
|
package/dist/get-CvI--9S_.mjs
DELETED
|
@@ -1,80 +0,0 @@
|
|
|
1
|
-
import { i as ConfigError } from "./predicates-Bkm2IoeX.mjs";
|
|
2
|
-
import { F as outputFlags, N as listFlags, R as listEnvelopeSchema, s as renderList, u as writeText } from "./cli.mjs";
|
|
3
|
-
import { n as parseCsv, t as defineMetabaseCommand } from "./runtime-DiKyBxOw.mjs";
|
|
4
|
-
import { n as windowList } from "./window-BkvrP0gB.mjs";
|
|
5
|
-
import { a as readSkillContent, i as loadVisibleSkills, o as selectSkillsByNames, r as loadAllSkills, t as SkillContent } from "./skills-DTCrMcix.mjs";
|
|
6
|
-
//#region src/commands/skills/get.ts
|
|
7
|
-
const SkillGetEnvelope = listEnvelopeSchema(SkillContent);
|
|
8
|
-
const SKILL_OVERSIZE_HINT = "a skill body is indivisible — pass --max-bytes 0 to print it whole, or `mb skills path <name>` to read it from disk";
|
|
9
|
-
const skillContentView = {
|
|
10
|
-
compactPick: SkillContent,
|
|
11
|
-
tableColumns: [{
|
|
12
|
-
key: "name",
|
|
13
|
-
label: "Name"
|
|
14
|
-
}, {
|
|
15
|
-
key: "description",
|
|
16
|
-
label: "Description"
|
|
17
|
-
}]
|
|
18
|
-
};
|
|
19
|
-
var get_default = defineMetabaseCommand({
|
|
20
|
-
meta: {
|
|
21
|
-
name: "get",
|
|
22
|
-
description: "Print one or more skills' SKILL.md content. Pass comma-separated names, or --all for every non-hidden skill. --full includes references and templates."
|
|
23
|
-
},
|
|
24
|
-
capabilities: null,
|
|
25
|
-
args: {
|
|
26
|
-
...outputFlags,
|
|
27
|
-
...listFlags,
|
|
28
|
-
names: {
|
|
29
|
-
type: "positional",
|
|
30
|
-
description: "Skill name (or comma-separated list). Omit when using --all.",
|
|
31
|
-
required: false
|
|
32
|
-
},
|
|
33
|
-
all: {
|
|
34
|
-
type: "boolean",
|
|
35
|
-
description: "Fetch every non-hidden skill"
|
|
36
|
-
}
|
|
37
|
-
},
|
|
38
|
-
outputSchema: SkillGetEnvelope,
|
|
39
|
-
examples: [
|
|
40
|
-
"mb skills get core",
|
|
41
|
-
"mb skills get core --full",
|
|
42
|
-
"mb skills get git-sync,transform --json",
|
|
43
|
-
"mb skills get --all --json"
|
|
44
|
-
],
|
|
45
|
-
run({ args, ctx }) {
|
|
46
|
-
const envelope = windowList(pickSkills({
|
|
47
|
-
names: args.names,
|
|
48
|
-
all: args.all === true
|
|
49
|
-
}).map((info) => readSkillContent(info, { includeExtras: ctx.full })), ctx.range);
|
|
50
|
-
if (ctx.format === "json") {
|
|
51
|
-
renderList(envelope, skillContentView, {
|
|
52
|
-
...ctx,
|
|
53
|
-
oversizeHint: SKILL_OVERSIZE_HINT
|
|
54
|
-
});
|
|
55
|
-
return;
|
|
56
|
-
}
|
|
57
|
-
writeText(renderText(envelope.data, ctx.full));
|
|
58
|
-
}
|
|
59
|
-
});
|
|
60
|
-
function pickSkills({ names, all }) {
|
|
61
|
-
if (all && names !== void 0) throw new ConfigError("--all conflicts with a positional skill name");
|
|
62
|
-
if (all) return loadVisibleSkills();
|
|
63
|
-
if (names === void 0) throw new ConfigError("provide a skill name (comma-separated for multiple) or --all");
|
|
64
|
-
return selectSkillsByNames(loadAllSkills(), parseCsv(names));
|
|
65
|
-
}
|
|
66
|
-
function renderText(payloads, includeExtras) {
|
|
67
|
-
return payloads.map((payload) => renderTextSection(payload, includeExtras)).join("\n\n");
|
|
68
|
-
}
|
|
69
|
-
function renderTextSection(payload, includeExtras) {
|
|
70
|
-
const parts = [payload.body.trimEnd()];
|
|
71
|
-
if (!includeExtras) return parts.join("\n\n");
|
|
72
|
-
for (const ref of payload.references) parts.push(extraFileHeader(payload.name, ref.path), ref.content.trimEnd());
|
|
73
|
-
for (const tpl of payload.templates) parts.push(extraFileHeader(payload.name, tpl.path), tpl.content.trimEnd());
|
|
74
|
-
return parts.join("\n\n");
|
|
75
|
-
}
|
|
76
|
-
function extraFileHeader(skillName, relPath) {
|
|
77
|
-
return `=== ${skillName}/${relPath} ===`;
|
|
78
|
-
}
|
|
79
|
-
//#endregion
|
|
80
|
-
export { get_default as default };
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
import { t as defineCommandGroup } from "./group-DBM87IgC.mjs";
|
|
2
|
-
//#region src/commands/git-sync/index.ts
|
|
3
|
-
var git_sync_default = defineCommandGroup({
|
|
4
|
-
name: "git-sync",
|
|
5
|
-
description: "Sync Metabase content with a git remote",
|
|
6
|
-
skills: [{
|
|
7
|
-
skill: "git-sync",
|
|
8
|
-
purpose: "import/export round-trip and dirty checks"
|
|
9
|
-
}],
|
|
10
|
-
subCommands: {
|
|
11
|
-
status: () => import("./status-BhswxJL1.mjs").then((mod) => mod.default),
|
|
12
|
-
"is-dirty": () => import("./is-dirty-DYeJYhBz.mjs").then((mod) => mod.default),
|
|
13
|
-
"has-remote-changes": () => import("./has-remote-changes-C684Redh.mjs").then((mod) => mod.default),
|
|
14
|
-
dirty: () => import("./dirty-DNYoM6Bp.mjs").then((mod) => mod.default),
|
|
15
|
-
"current-task": () => import("./current-task-MpBFGttd.mjs").then((mod) => mod.default),
|
|
16
|
-
"cancel-task": () => import("./cancel-task-C5CU1pxU.mjs").then((mod) => mod.default),
|
|
17
|
-
wait: () => import("./wait-DoMDH226.mjs").then((mod) => mod.default),
|
|
18
|
-
import: () => import("./import-Rmmttboo.mjs").then((mod) => mod.default),
|
|
19
|
-
export: () => import("./export-BjfoZRDJ.mjs").then((mod) => mod.default),
|
|
20
|
-
stash: () => import("./stash-D0S4JmAz.mjs").then((mod) => mod.default),
|
|
21
|
-
branches: () => import("./branches-DchlyU0i.mjs").then((mod) => mod.default),
|
|
22
|
-
"create-branch": () => import("./create-branch-CYo6jZth.mjs").then((mod) => mod.default),
|
|
23
|
-
"add-collection": () => import("./add-collection-B3Ty8SzB.mjs").then((mod) => mod.default),
|
|
24
|
-
"remove-collection": () => import("./remove-collection-BOnxYvhj.mjs").then((mod) => mod.default)
|
|
25
|
-
}
|
|
26
|
-
});
|
|
27
|
-
//#endregion
|
|
28
|
-
export { git_sync_default as default };
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import { r as Collection } from "./collection-CfulNRBG.mjs";
|
|
2
|
-
import { z } from "zod";
|
|
3
|
-
//#region ../client/src/domain/library.ts
|
|
4
|
-
const LibraryChild = Collection.pick({
|
|
5
|
-
id: true,
|
|
6
|
-
name: true,
|
|
7
|
-
type: true,
|
|
8
|
-
description: true,
|
|
9
|
-
is_remote_synced: true
|
|
10
|
-
}).strip();
|
|
11
|
-
const Library = Collection.extend({ effective_children: z.array(LibraryChild) }).loose();
|
|
12
|
-
const LibraryCompact = Library.pick({
|
|
13
|
-
id: true,
|
|
14
|
-
name: true,
|
|
15
|
-
type: true,
|
|
16
|
-
effective_children: true
|
|
17
|
-
}).strip();
|
|
18
|
-
//#endregion
|
|
19
|
-
export { LibraryCompact as n, Library as t };
|
package/dist/list-UhpKG6_m.mjs
DELETED
|
@@ -1,98 +0,0 @@
|
|
|
1
|
-
import { F as outputFlags, N as listFlags, R as listEnvelopeSchema, b as warn, s as renderList, y as listTruncationNotice } from "./cli.mjs";
|
|
2
|
-
import { t as defineMetabaseCommand } from "./runtime-DiKyBxOw.mjs";
|
|
3
|
-
import { n as windowList } from "./window-BkvrP0gB.mjs";
|
|
4
|
-
import { i as loadVisibleSkills } from "./skills-DTCrMcix.mjs";
|
|
5
|
-
import { z } from "zod";
|
|
6
|
-
//#region src/output/skill-list.ts
|
|
7
|
-
const DEFAULT_TERMINAL_WIDTH = 80;
|
|
8
|
-
const MIN_WRAP_WIDTH = 24;
|
|
9
|
-
const DESCRIPTION_INDENT = " ";
|
|
10
|
-
function renderSkillList(rows, maxBytes) {
|
|
11
|
-
if (rows.length === 0) {
|
|
12
|
-
process.stdout.write("(no results)\n");
|
|
13
|
-
return;
|
|
14
|
-
}
|
|
15
|
-
const width = wrapWidth();
|
|
16
|
-
const blocks = rows.map((row) => renderSkillBlock(row, width));
|
|
17
|
-
const fullText = blocks.join("");
|
|
18
|
-
const fullBytes = Buffer.byteLength(fullText, "utf8");
|
|
19
|
-
if (maxBytes <= 0 || fullBytes <= maxBytes) {
|
|
20
|
-
process.stdout.write(fullText);
|
|
21
|
-
return;
|
|
22
|
-
}
|
|
23
|
-
let used = 0;
|
|
24
|
-
let kept = "";
|
|
25
|
-
for (const block of blocks) {
|
|
26
|
-
const next = used + Buffer.byteLength(block, "utf8");
|
|
27
|
-
if (next > maxBytes) break;
|
|
28
|
-
used = next;
|
|
29
|
-
kept += block;
|
|
30
|
-
}
|
|
31
|
-
process.stdout.write(kept);
|
|
32
|
-
warn(listTruncationNotice(fullBytes));
|
|
33
|
-
}
|
|
34
|
-
function renderSkillBlock(row, width) {
|
|
35
|
-
const body = wrapText(row.description, width - 2).map((line) => DESCRIPTION_INDENT + line).join("\n");
|
|
36
|
-
return body === "" ? `${row.name}\n\n` : `${row.name}\n${body}\n\n`;
|
|
37
|
-
}
|
|
38
|
-
function wrapText(text, width) {
|
|
39
|
-
const limit = Math.max(width, MIN_WRAP_WIDTH);
|
|
40
|
-
const words = text.split(/\s+/).filter((word) => word.length > 0);
|
|
41
|
-
const lines = [];
|
|
42
|
-
let current = "";
|
|
43
|
-
for (const word of words) if (current === "") current = word;
|
|
44
|
-
else if (current.length + 1 + word.length <= limit) current += ` ${word}`;
|
|
45
|
-
else {
|
|
46
|
-
lines.push(current);
|
|
47
|
-
current = word;
|
|
48
|
-
}
|
|
49
|
-
if (current !== "") lines.push(current);
|
|
50
|
-
return lines;
|
|
51
|
-
}
|
|
52
|
-
function wrapWidth() {
|
|
53
|
-
const columns = process.stdout.columns;
|
|
54
|
-
return typeof columns === "number" && columns > 0 ? columns : DEFAULT_TERMINAL_WIDTH;
|
|
55
|
-
}
|
|
56
|
-
//#endregion
|
|
57
|
-
//#region src/commands/skills/list.ts
|
|
58
|
-
const SkillSummary = z.object({
|
|
59
|
-
name: z.string(),
|
|
60
|
-
description: z.string()
|
|
61
|
-
});
|
|
62
|
-
const SkillListEnvelope = listEnvelopeSchema(SkillSummary);
|
|
63
|
-
const skillSummaryView = {
|
|
64
|
-
compactPick: SkillSummary,
|
|
65
|
-
tableColumns: [{
|
|
66
|
-
key: "name",
|
|
67
|
-
label: "Name"
|
|
68
|
-
}, {
|
|
69
|
-
key: "description",
|
|
70
|
-
label: "Description"
|
|
71
|
-
}]
|
|
72
|
-
};
|
|
73
|
-
var list_default = defineMetabaseCommand({
|
|
74
|
-
meta: {
|
|
75
|
-
name: "list",
|
|
76
|
-
description: "List CLI-bundled skills — always consult the matching skill before acting on a task; they are the source of truth for every workflow."
|
|
77
|
-
},
|
|
78
|
-
capabilities: null,
|
|
79
|
-
args: {
|
|
80
|
-
...outputFlags,
|
|
81
|
-
...listFlags
|
|
82
|
-
},
|
|
83
|
-
outputSchema: SkillListEnvelope,
|
|
84
|
-
examples: ["mb skills list", "mb skills list --json"],
|
|
85
|
-
run({ ctx }) {
|
|
86
|
-
const envelope = windowList(loadVisibleSkills().map((s) => ({
|
|
87
|
-
name: s.name,
|
|
88
|
-
description: s.description
|
|
89
|
-
})), ctx.range);
|
|
90
|
-
if (ctx.format === "json" || ctx.fields !== void 0 || ctx.full) {
|
|
91
|
-
renderList(envelope, skillSummaryView, ctx);
|
|
92
|
-
return;
|
|
93
|
-
}
|
|
94
|
-
renderSkillList(envelope.data, ctx.maxBytes);
|
|
95
|
-
}
|
|
96
|
-
});
|
|
97
|
-
//#endregion
|
|
98
|
-
export { list_default as default };
|
|
@@ -1,423 +0,0 @@
|
|
|
1
|
-
import { d as ValidationError, f as errorMessage, i as ConfigError, o as MetabaseError, r as ChainedRequestError, s as NetworkError, t as isPlainObject } from "./predicates-Bkm2IoeX.mjs";
|
|
2
|
-
import { z } from "zod";
|
|
3
|
-
//#region ../client/src/json.ts
|
|
4
|
-
const JSON_CONTENT_TYPE = "application/json";
|
|
5
|
-
function parseJson(input, schema, opts = {}) {
|
|
6
|
-
const result = parseJsonResult(input, schema, opts);
|
|
7
|
-
if (!result.ok) throw result.error;
|
|
8
|
-
return result.value;
|
|
9
|
-
}
|
|
10
|
-
function parseJsonResult(input, schema, opts = {}) {
|
|
11
|
-
const sourcePrefix = opts.source === void 0 ? "" : `${opts.source}: `;
|
|
12
|
-
let raw;
|
|
13
|
-
try {
|
|
14
|
-
raw = JSON.parse(input);
|
|
15
|
-
} catch (error) {
|
|
16
|
-
return {
|
|
17
|
-
ok: false,
|
|
18
|
-
error: new ConfigError(`${sourcePrefix}invalid JSON: ${errorMessage(error)}`)
|
|
19
|
-
};
|
|
20
|
-
}
|
|
21
|
-
const parsed = schema.safeParse(raw);
|
|
22
|
-
if (!parsed.success) return {
|
|
23
|
-
ok: false,
|
|
24
|
-
error: new ValidationError(`${sourcePrefix}value did not match expected schema`, {
|
|
25
|
-
source: opts.source ?? "<input>",
|
|
26
|
-
zodIssues: parsed.error.issues
|
|
27
|
-
})
|
|
28
|
-
};
|
|
29
|
-
return {
|
|
30
|
-
ok: true,
|
|
31
|
-
value: parsed.data
|
|
32
|
-
};
|
|
33
|
-
}
|
|
34
|
-
function parseJsonOrPlain(text, contentType, schema, opts = {}) {
|
|
35
|
-
if (!isJsonContentType(contentType)) return parseJson(JSON.stringify(text), schema, opts);
|
|
36
|
-
const attempt = parseJsonResult(text, schema, opts);
|
|
37
|
-
if (attempt.ok) return attempt.value;
|
|
38
|
-
if (attempt.error instanceof ValidationError) throw attempt.error;
|
|
39
|
-
return parseJson(JSON.stringify(text), schema, opts);
|
|
40
|
-
}
|
|
41
|
-
function isJsonContentType(contentType) {
|
|
42
|
-
return contentType !== null && contentType.includes("application/json");
|
|
43
|
-
}
|
|
44
|
-
//#endregion
|
|
45
|
-
//#region ../client/src/auth/credential.ts
|
|
46
|
-
const API_KEY_HEADER = "x-api-key";
|
|
47
|
-
const AUTHORIZATION_HEADER = "authorization";
|
|
48
|
-
const BEARER_PREFIX = "Bearer ";
|
|
49
|
-
const EXPIRY_SKEW_MS = 6e4;
|
|
50
|
-
function credentialAuthHeader(credential) {
|
|
51
|
-
if (credential.kind === "apiKey") return {
|
|
52
|
-
name: API_KEY_HEADER,
|
|
53
|
-
value: credential.apiKey
|
|
54
|
-
};
|
|
55
|
-
return {
|
|
56
|
-
name: AUTHORIZATION_HEADER,
|
|
57
|
-
value: BEARER_PREFIX + credential.accessToken
|
|
58
|
-
};
|
|
59
|
-
}
|
|
60
|
-
const MAX_HEADER_CODE_UNIT = 255;
|
|
61
|
-
function headerBearingSecret(credential) {
|
|
62
|
-
if (credential.kind === "apiKey") return {
|
|
63
|
-
field: "apiKey",
|
|
64
|
-
value: credential.apiKey
|
|
65
|
-
};
|
|
66
|
-
return {
|
|
67
|
-
field: "accessToken",
|
|
68
|
-
value: credential.accessToken
|
|
69
|
-
};
|
|
70
|
-
}
|
|
71
|
-
function assertCredentialHeaderSafe(credential) {
|
|
72
|
-
const { field, value } = headerBearingSecret(credential);
|
|
73
|
-
for (let index = 0; index < value.length; index += 1) {
|
|
74
|
-
const codeUnit = value.charCodeAt(index);
|
|
75
|
-
if (codeUnit > MAX_HEADER_CODE_UNIT) {
|
|
76
|
-
const codePoint = codeUnit.toString(16).toUpperCase().padStart(4, "0");
|
|
77
|
-
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.`);
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
function credentialSecrets(credential) {
|
|
82
|
-
if (credential.kind === "apiKey") return [credential.apiKey];
|
|
83
|
-
return [credential.accessToken, credential.refreshToken];
|
|
84
|
-
}
|
|
85
|
-
function isOAuthExpired(credential, nowMs) {
|
|
86
|
-
const expiryMs = Date.parse(credential.expiresAt);
|
|
87
|
-
if (Number.isNaN(expiryMs)) return true;
|
|
88
|
-
return expiryMs - EXPIRY_SKEW_MS <= nowMs;
|
|
89
|
-
}
|
|
90
|
-
function expiresAtFromNow(expiresInSeconds, nowMs) {
|
|
91
|
-
return new Date(nowMs + expiresInSeconds * 1e3).toISOString();
|
|
92
|
-
}
|
|
93
|
-
function oauthCredentialFromTokens(tokens, refreshToken, clientId, nowMs) {
|
|
94
|
-
return {
|
|
95
|
-
kind: "oauth",
|
|
96
|
-
accessToken: tokens.access_token,
|
|
97
|
-
refreshToken,
|
|
98
|
-
expiresAt: expiresAtFromNow(tokens.expires_in ?? 3600, nowMs),
|
|
99
|
-
clientId
|
|
100
|
-
};
|
|
101
|
-
}
|
|
102
|
-
//#endregion
|
|
103
|
-
//#region ../client/src/url.ts
|
|
104
|
-
function normalizeUrl(input) {
|
|
105
|
-
const trimmed = input.trim().replace(/\/+$/, "");
|
|
106
|
-
if (!/^https?:\/\//i.test(trimmed)) throw new ConfigError("URL must start with http:// or https://");
|
|
107
|
-
return trimmed;
|
|
108
|
-
}
|
|
109
|
-
function displayUrl(input) {
|
|
110
|
-
const parsed = new URL(input);
|
|
111
|
-
const path = parsed.pathname.replace(/\/+$/, "");
|
|
112
|
-
return `${parsed.origin}${path}`;
|
|
113
|
-
}
|
|
114
|
-
const LOOPBACK_HOSTS = /* @__PURE__ */ new Set([
|
|
115
|
-
"localhost",
|
|
116
|
-
"127.0.0.1",
|
|
117
|
-
"::1",
|
|
118
|
-
"[::1]"
|
|
119
|
-
]);
|
|
120
|
-
function isLoopbackHost(hostname) {
|
|
121
|
-
return LOOPBACK_HOSTS.has(hostname.toLowerCase());
|
|
122
|
-
}
|
|
123
|
-
function assertEndpointOrigin(endpoint, baseUrl, label) {
|
|
124
|
-
let parsed;
|
|
125
|
-
try {
|
|
126
|
-
parsed = new URL(endpoint);
|
|
127
|
-
} catch {
|
|
128
|
-
throw new ConfigError(`OAuth ${label} is not a valid URL: ${endpoint}`);
|
|
129
|
-
}
|
|
130
|
-
const base = new URL(baseUrl);
|
|
131
|
-
if (parsed.protocol !== "https:" && !isLoopbackHost(parsed.hostname)) throw new ConfigError(`OAuth ${label} must use https: ${endpoint}`);
|
|
132
|
-
if (parsed.origin !== base.origin) throw new ConfigError(`OAuth ${label} origin (${parsed.origin}) does not match the Metabase URL (${base.origin})`);
|
|
133
|
-
}
|
|
134
|
-
//#endregion
|
|
135
|
-
//#region ../client/src/http/sanitize.ts
|
|
136
|
-
const SECRET_HEADER_NAMES = /* @__PURE__ */ new Set([
|
|
137
|
-
"authorization",
|
|
138
|
-
"x-api-key",
|
|
139
|
-
"x-metabase-session",
|
|
140
|
-
"cookie",
|
|
141
|
-
"set-cookie",
|
|
142
|
-
"proxy-authorization"
|
|
143
|
-
]);
|
|
144
|
-
const REDACTED = "[REDACTED]";
|
|
145
|
-
function redactHeaders(headers) {
|
|
146
|
-
const result = {};
|
|
147
|
-
const entries = headers instanceof Headers ? headers.entries() : Object.entries(headers);
|
|
148
|
-
for (const [key, value] of entries) result[key] = SECRET_HEADER_NAMES.has(key.toLowerCase()) ? REDACTED : value;
|
|
149
|
-
return result;
|
|
150
|
-
}
|
|
151
|
-
function redactBody(body, ctx) {
|
|
152
|
-
let result = body;
|
|
153
|
-
for (const secret of ctx.knownSecrets) {
|
|
154
|
-
if (secret.length === 0) continue;
|
|
155
|
-
result = result.replaceAll(secret, REDACTED);
|
|
156
|
-
}
|
|
157
|
-
return result;
|
|
158
|
-
}
|
|
159
|
-
//#endregion
|
|
160
|
-
//#region ../client/src/http/errors.ts
|
|
161
|
-
const NOT_FOUND_STATUS = 404;
|
|
162
|
-
const ROUTE_MISSING_LITERAL = "API endpoint does not exist.";
|
|
163
|
-
const RESOURCE_MISSING_LITERAL = "Not found.";
|
|
164
|
-
const STATUS_CLASSIFICATIONS = {
|
|
165
|
-
401: { retryable: false },
|
|
166
|
-
403: { retryable: false },
|
|
167
|
-
404: { retryable: false },
|
|
168
|
-
408: {
|
|
169
|
-
retryable: true,
|
|
170
|
-
message: "Metabase timed out responding."
|
|
171
|
-
},
|
|
172
|
-
425: { retryable: true },
|
|
173
|
-
429: {
|
|
174
|
-
retryable: true,
|
|
175
|
-
message: "Metabase rate-limited the request."
|
|
176
|
-
},
|
|
177
|
-
500: { retryable: true },
|
|
178
|
-
502: { retryable: true },
|
|
179
|
-
503: { retryable: true },
|
|
180
|
-
504: {
|
|
181
|
-
retryable: true,
|
|
182
|
-
message: "Metabase timed out responding."
|
|
183
|
-
}
|
|
184
|
-
};
|
|
185
|
-
const ErrorEnvelope = z.object({
|
|
186
|
-
message: z.string().optional(),
|
|
187
|
-
error: z.string().optional(),
|
|
188
|
-
"error-message": z.string().optional(),
|
|
189
|
-
via: z.array(z.object({ message: z.string().optional() }).loose()).optional(),
|
|
190
|
-
"specific-errors": z.unknown().optional(),
|
|
191
|
-
errors: z.unknown().optional()
|
|
192
|
-
}).loose();
|
|
193
|
-
const FieldErrorNodeSchema = z.lazy(() => z.union([
|
|
194
|
-
z.string(),
|
|
195
|
-
z.array(z.string()),
|
|
196
|
-
z.record(z.string(), FieldErrorNodeSchema)
|
|
197
|
-
]));
|
|
198
|
-
const FieldErrorTree = z.record(z.string(), FieldErrorNodeSchema);
|
|
199
|
-
const FIELD_MESSAGE_SEPARATOR = "; ";
|
|
200
|
-
const MAX_EXTRACTED_MESSAGE_LEN = 500;
|
|
201
|
-
const ELLIPSIS = "…";
|
|
202
|
-
var HttpError = class extends MetabaseError {
|
|
203
|
-
category = "http";
|
|
204
|
-
status;
|
|
205
|
-
kind;
|
|
206
|
-
developerDetail;
|
|
207
|
-
constructor(input) {
|
|
208
|
-
const sanitizedBody = sanitizeBody(input.rawBody, input.redactionContext);
|
|
209
|
-
const redactedHeaders = redactHeaders(input.responseHeaders);
|
|
210
|
-
const kind = classifyKind(input.status, sanitizedBody, redactedHeaders);
|
|
211
|
-
super(input.overrideUserMessage ?? buildUserMessage(kind, input, sanitizedBody));
|
|
212
|
-
const fields = extractFieldErrors(sanitizedBody);
|
|
213
|
-
this.name = "HttpError";
|
|
214
|
-
this.status = input.status;
|
|
215
|
-
this.kind = kind;
|
|
216
|
-
this.developerDetail = {
|
|
217
|
-
status: input.status,
|
|
218
|
-
statusText: input.statusText,
|
|
219
|
-
method: input.method,
|
|
220
|
-
url: input.url,
|
|
221
|
-
responseHeaders: redactedHeaders,
|
|
222
|
-
body: sanitizedBody,
|
|
223
|
-
fieldErrors: fields.fieldErrors,
|
|
224
|
-
specificFieldErrors: fields.specificFieldErrors
|
|
225
|
-
};
|
|
226
|
-
}
|
|
227
|
-
get isRetryable() {
|
|
228
|
-
return isRetryableStatus(this.status);
|
|
229
|
-
}
|
|
230
|
-
get fieldErrors() {
|
|
231
|
-
return this.developerDetail.fieldErrors;
|
|
232
|
-
}
|
|
233
|
-
get specificFieldErrors() {
|
|
234
|
-
return this.developerDetail.specificFieldErrors;
|
|
235
|
-
}
|
|
236
|
-
};
|
|
237
|
-
function chainRequestFailure(cause, message) {
|
|
238
|
-
if (cause instanceof HttpError) return new HttpError({
|
|
239
|
-
status: cause.status,
|
|
240
|
-
statusText: cause.developerDetail.statusText,
|
|
241
|
-
method: cause.developerDetail.method,
|
|
242
|
-
url: cause.developerDetail.url,
|
|
243
|
-
responseHeaders: cause.developerDetail.responseHeaders,
|
|
244
|
-
rawBody: cause.developerDetail.body,
|
|
245
|
-
overrideUserMessage: message
|
|
246
|
-
});
|
|
247
|
-
return new ChainedRequestError(message, cause);
|
|
248
|
-
}
|
|
249
|
-
function isRetryableStatus(status) {
|
|
250
|
-
return STATUS_CLASSIFICATIONS[status]?.retryable === true;
|
|
251
|
-
}
|
|
252
|
-
function sanitizeBody(rawBody, ctx) {
|
|
253
|
-
if (rawBody === null) return null;
|
|
254
|
-
if (ctx === void 0) return rawBody;
|
|
255
|
-
return redactBody(rawBody, ctx);
|
|
256
|
-
}
|
|
257
|
-
function classifyKind(status, sanitizedBody, redactedHeaders) {
|
|
258
|
-
if (status === 401 || status === 403) return "auth";
|
|
259
|
-
if (status === NOT_FOUND_STATUS) return isRouteMissingResponse(sanitizedBody, redactedHeaders) ? "route-missing" : "resource-missing";
|
|
260
|
-
if (status === 429) return "rate-limit";
|
|
261
|
-
if (status >= 500 && status < 600) return "server-error";
|
|
262
|
-
return "generic";
|
|
263
|
-
}
|
|
264
|
-
function isRouteMissingResponse(sanitizedBody, redactedHeaders) {
|
|
265
|
-
if (sanitizedBody?.includes(ROUTE_MISSING_LITERAL)) return true;
|
|
266
|
-
if (sanitizedBody?.includes(RESOURCE_MISSING_LITERAL)) return false;
|
|
267
|
-
if (redactedHeaders["content-type"]?.includes("application/json")) return false;
|
|
268
|
-
if (sanitizedBody === null || sanitizedBody.trim() === "") return true;
|
|
269
|
-
return parseEnvelope(sanitizedBody) === null;
|
|
270
|
-
}
|
|
271
|
-
function buildUserMessage(kind, input, sanitizedBody) {
|
|
272
|
-
if (kind === "route-missing") return buildRouteMissingMessage(input);
|
|
273
|
-
if (kind === "resource-missing") return `Not found: ${input.method} ${pathFromUrl(input.url)}.`;
|
|
274
|
-
const fromBody = parseEnvelopeMessage(sanitizedBody);
|
|
275
|
-
if (fromBody !== null) return fromBody;
|
|
276
|
-
if (kind === "auth") return `Invalid or unauthorized API key (host: ${hostFromUrl(input.url)}).`;
|
|
277
|
-
return defaultMessageForStatus(input.status);
|
|
278
|
-
}
|
|
279
|
-
function buildRouteMissingMessage(input) {
|
|
280
|
-
const path = pathFromUrl(input.url);
|
|
281
|
-
if (!input.serverTag) return `This endpoint is not available on the connected Metabase: ${input.method} ${path}.`;
|
|
282
|
-
return `This endpoint is not available on Metabase ${input.serverTag}: ${input.method} ${path}. It may require a newer Metabase major version.`;
|
|
283
|
-
}
|
|
284
|
-
function pathFromUrl(url) {
|
|
285
|
-
const parsed = new URL(url);
|
|
286
|
-
return parsed.pathname + parsed.search;
|
|
287
|
-
}
|
|
288
|
-
function hostFromUrl(url) {
|
|
289
|
-
return new URL(url).host;
|
|
290
|
-
}
|
|
291
|
-
function parseEnvelope(sanitizedBody) {
|
|
292
|
-
if (!sanitizedBody) return null;
|
|
293
|
-
const result = parseJsonResult(sanitizedBody, ErrorEnvelope);
|
|
294
|
-
return result.ok ? result.value : null;
|
|
295
|
-
}
|
|
296
|
-
const NO_FIELD_ERRORS = {
|
|
297
|
-
fieldErrors: null,
|
|
298
|
-
specificFieldErrors: null
|
|
299
|
-
};
|
|
300
|
-
function extractFieldErrors(sanitizedBody) {
|
|
301
|
-
const envelope = parseEnvelope(sanitizedBody);
|
|
302
|
-
if (envelope === null) return NO_FIELD_ERRORS;
|
|
303
|
-
return {
|
|
304
|
-
fieldErrors: parseFieldErrors(envelope.errors),
|
|
305
|
-
specificFieldErrors: parseFieldErrors(envelope["specific-errors"])
|
|
306
|
-
};
|
|
307
|
-
}
|
|
308
|
-
function parseFieldErrors(value) {
|
|
309
|
-
const parsed = FieldErrorTree.safeParse(value);
|
|
310
|
-
if (!parsed.success) return null;
|
|
311
|
-
const entries = collectLeafEntries(parsed.data, []);
|
|
312
|
-
if (entries.length === 0) return null;
|
|
313
|
-
return Object.fromEntries(entries.map((entry) => [entry.path, entry.message]));
|
|
314
|
-
}
|
|
315
|
-
function parseEnvelopeMessage(sanitizedBody) {
|
|
316
|
-
const envelope = parseEnvelope(sanitizedBody);
|
|
317
|
-
if (envelope === null) return null;
|
|
318
|
-
const topLevel = envelope.message ?? envelope.error ?? envelope["error-message"];
|
|
319
|
-
if (topLevel) return capLength(topLevel);
|
|
320
|
-
const viaMessage = envelope.via?.find((entry) => entry.message)?.message;
|
|
321
|
-
if (viaMessage) return capLength(viaMessage);
|
|
322
|
-
const specific = formatErrorTree(envelope["specific-errors"]);
|
|
323
|
-
if (specific) return capLength(specific);
|
|
324
|
-
const generic = formatErrorTree(envelope.errors);
|
|
325
|
-
if (generic) return capLength(generic);
|
|
326
|
-
return null;
|
|
327
|
-
}
|
|
328
|
-
function formatErrorTree(value) {
|
|
329
|
-
const entries = collectLeafEntries(value, []);
|
|
330
|
-
if (entries.length === 0) return null;
|
|
331
|
-
return entries.map(formatLeafEntry).join(FIELD_MESSAGE_SEPARATOR);
|
|
332
|
-
}
|
|
333
|
-
function formatLeafEntry(entry) {
|
|
334
|
-
return entry.path === "" ? entry.message : `${entry.path}: ${entry.message}`;
|
|
335
|
-
}
|
|
336
|
-
function collectLeafEntries(value, path) {
|
|
337
|
-
if (typeof value === "string") {
|
|
338
|
-
const trimmed = value.trim();
|
|
339
|
-
return trimmed === "" ? [] : [{
|
|
340
|
-
path: path.join("."),
|
|
341
|
-
message: trimmed
|
|
342
|
-
}];
|
|
343
|
-
}
|
|
344
|
-
if (Array.isArray(value)) {
|
|
345
|
-
const messages = value.filter((entry) => typeof entry === "string" && entry.trim() !== "");
|
|
346
|
-
if (messages.length === 0) return [];
|
|
347
|
-
return [{
|
|
348
|
-
path: path.join("."),
|
|
349
|
-
message: messages.join(FIELD_MESSAGE_SEPARATOR)
|
|
350
|
-
}];
|
|
351
|
-
}
|
|
352
|
-
if (isPlainObject(value)) return Object.entries(value).flatMap(([key, child]) => collectLeafEntries(child, [...path, key]));
|
|
353
|
-
return [];
|
|
354
|
-
}
|
|
355
|
-
function capLength(message) {
|
|
356
|
-
if (message.length <= MAX_EXTRACTED_MESSAGE_LEN) return message;
|
|
357
|
-
return message.slice(0, MAX_EXTRACTED_MESSAGE_LEN - 1) + ELLIPSIS;
|
|
358
|
-
}
|
|
359
|
-
function defaultMessageForStatus(status) {
|
|
360
|
-
return STATUS_CLASSIFICATIONS[status]?.message ?? `Metabase returned ${status}.`;
|
|
361
|
-
}
|
|
362
|
-
//#endregion
|
|
363
|
-
//#region ../client/src/http/network-error.ts
|
|
364
|
-
const NETWORK_HINTS = {
|
|
365
|
-
ECONNREFUSED: (t) => `Connection refused by ${t.host} — is Metabase running and is the port correct?`,
|
|
366
|
-
ENOTFOUND: (t) => `Host not found: ${t.hostname} — check the URL.`,
|
|
367
|
-
EAI_AGAIN: (t) => `Could not resolve ${t.hostname} — check your network connection and the URL.`,
|
|
368
|
-
ECONNRESET: (t) => `Connection to ${t.host} was reset — the server may have closed it, or http/https may be mismatched.`,
|
|
369
|
-
UND_ERR_SOCKET: (t) => `Connection to ${t.host} was closed by the other side — a pooled connection or a proxy may have dropped it.`,
|
|
370
|
-
EPIPE: (t) => `Connection to ${t.host} closed while the request was still being written — the server or a proxy dropped it.`,
|
|
371
|
-
ETIMEDOUT: (t) => `Connection to ${t.host} timed out — check the host, port, and your network.`
|
|
372
|
-
};
|
|
373
|
-
const CONNECTION_CLOSED_CODES = /* @__PURE__ */ new Set([
|
|
374
|
-
"ECONNRESET",
|
|
375
|
-
"UND_ERR_SOCKET",
|
|
376
|
-
"EPIPE"
|
|
377
|
-
]);
|
|
378
|
-
const TLS_ERROR_CODES = /* @__PURE__ */ new Set([
|
|
379
|
-
"EPROTO",
|
|
380
|
-
"DEPTH_ZERO_SELF_SIGNED_CERT",
|
|
381
|
-
"SELF_SIGNED_CERT_IN_CHAIN",
|
|
382
|
-
"UNABLE_TO_VERIFY_LEAF_SIGNATURE",
|
|
383
|
-
"CERT_HAS_EXPIRED",
|
|
384
|
-
"ERR_TLS_CERT_ALTNAME_INVALID"
|
|
385
|
-
]);
|
|
386
|
-
function buildNetworkError(error, method, url) {
|
|
387
|
-
const fallback = errorMessage(error);
|
|
388
|
-
const code = failureCode(error);
|
|
389
|
-
return new NetworkError(networkMessage(code, networkTarget(url), fallback), {
|
|
390
|
-
method,
|
|
391
|
-
url,
|
|
392
|
-
cause: code ?? fallback
|
|
393
|
-
});
|
|
394
|
-
}
|
|
395
|
-
function isConnectionClosed(error) {
|
|
396
|
-
const code = failureCode(error);
|
|
397
|
-
return code !== null && CONNECTION_CLOSED_CODES.has(code);
|
|
398
|
-
}
|
|
399
|
-
function networkMessage(code, target, fallback) {
|
|
400
|
-
if (code === null) return `Could not reach Metabase: ${fallback}`;
|
|
401
|
-
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.`;
|
|
402
|
-
const hint = NETWORK_HINTS[code];
|
|
403
|
-
if (hint === void 0) return `Could not reach Metabase: ${fallback} (${code})`;
|
|
404
|
-
return `Could not reach Metabase: ${hint(target)}`;
|
|
405
|
-
}
|
|
406
|
-
function failureCode(error) {
|
|
407
|
-
const own = errorCode(error);
|
|
408
|
-
if (own !== null) return own;
|
|
409
|
-
return errorCode(error instanceof Error ? error.cause : void 0);
|
|
410
|
-
}
|
|
411
|
-
function errorCode(value) {
|
|
412
|
-
if (value instanceof Error && "code" in value && typeof value.code === "string") return value.code;
|
|
413
|
-
return null;
|
|
414
|
-
}
|
|
415
|
-
function networkTarget(url) {
|
|
416
|
-
const parsed = new URL(url);
|
|
417
|
-
return {
|
|
418
|
-
host: parsed.host,
|
|
419
|
-
hostname: parsed.hostname
|
|
420
|
-
};
|
|
421
|
-
}
|
|
422
|
-
//#endregion
|
|
423
|
-
export { parseJsonResult as _, isRetryableStatus as a, normalizeUrl as c, credentialSecrets as d, isOAuthExpired as f, parseJsonOrPlain as g, parseJson as h, chainRequestFailure as i, assertCredentialHeaderSafe as l, JSON_CONTENT_TYPE as m, isConnectionClosed as n, assertEndpointOrigin as o, oauthCredentialFromTokens as p, HttpError as r, displayUrl as s, buildNetworkError as t, credentialAuthHeader as u };
|