@metabase/cli 0.3.1 → 0.3.2-alpha.fix-transform-test-ee-path.8ac2a7a
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-CYDUm_XO.mjs → add-collection-B_-eMU_k.mjs} +6 -9
- package/dist/{alert-ClyhtxIz.mjs → alert-Dalin_DD.mjs} +7 -7
- package/dist/{alerts-Dt3D1gcz.mjs → alerts-DpBgrjPI.mjs} +7 -7
- package/dist/{append-Bl_Ensmr.mjs → append-C1JNVALm.mjs} +5 -5
- package/dist/{archive-BOyKhNOz.mjs → archive-52ZHbFDm2.mjs} +6 -6
- package/dist/{archive-DiGxCojL.mjs → archive-B51prFgS.mjs} +4 -4
- package/dist/{archive-CWceyy8x.mjs → archive-BkITQyWW.mjs} +5 -5
- package/dist/{archive-BJZ7Dace.mjs → archive-CISXgZAI.mjs} +6 -6
- package/dist/{archive-D3a3Wgz0.mjs → archive-CdKf_Eqq.mjs} +4 -4
- package/dist/{archive-DVGDg8mP.mjs → archive-CicPYX27.mjs} +6 -6
- package/dist/{archive-CNblz55j.mjs → archive-CwITzj_j.mjs} +6 -6
- package/dist/{archive-DSMqHRr1.mjs → archive-DA3OiLEE.mjs} +4 -4
- package/dist/{archive-nKD3mOB8.mjs → archive-DVHxeDKS.mjs} +6 -6
- package/dist/{archive-BdHXQg4I.mjs → archive-DckxlWBt.mjs} +4 -4
- package/dist/{archive-DDru3vdy.mjs → archive-cAdUa1-2.mjs} +4 -4
- package/dist/{auth-aCksg8q2.mjs → auth-A96JOCQx.mjs} +5 -5
- package/dist/{body-DxRSAMNC.mjs → body-CshgcV6U.mjs} +3 -3
- package/dist/{branches-_0VWR2Zm.mjs → branches-CbcwWYL9.mjs} +4 -7
- package/dist/{cancel-ctpVE8uC.mjs → cancel-DpDcVY7M.mjs} +4 -4
- package/dist/{cancel-task-FtxBka-M.mjs → cancel-task-B4RDvIYb.mjs} +5 -8
- package/dist/{card-zyUkr2nS.mjs → card-CEkp1mcI.mjs} +1 -1
- package/dist/card-CefVYtF7.mjs +24 -0
- package/dist/{card-DZxRmver.mjs → card-voh1k4hl.mjs} +14 -11
- package/dist/{cards-DHOWAvfv.mjs → cards-BC0JX8Yg.mjs} +7 -7
- package/dist/cli.mjs +582 -69
- package/dist/client-ClL6gf7G.mjs +3783 -0
- package/dist/collection-Be5AHVWP.mjs +20 -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-CEoQ7G08.mjs → collection-namespace-Dv0l-V9K.mjs} +2 -2
- package/dist/{content-translation-DNKerjS3.mjs → content-translation-BXIXL4eW.mjs} +3 -3
- package/dist/{create-DmvoibX8.mjs → create--fiwuTWc.mjs} +4 -4
- package/dist/{create-CLG2-bso.mjs → create-B9qXQ_wV.mjs} +6 -6
- package/dist/{create-CEydRMWS.mjs → create-BVNhtAgF.mjs} +7 -7
- package/dist/{create-C9vy4ZG6.mjs → create-BbjSOTN-.mjs} +5 -5
- package/dist/{create-BdPVWYSi.mjs → create-BcsVwXgS2.mjs} +6 -6
- package/dist/{create-CcLchJAN.mjs → create-Bryrkb9g.mjs} +7 -7
- package/dist/{create-7ddYK4TA.mjs → create-CHr8MPPq.mjs} +6 -6
- package/dist/{create-DaYRnK5P.mjs → create-D--Z1S3p2.mjs} +8 -8
- package/dist/{create-F4Lf09xq.mjs → create-DWFJdyIr.mjs} +4 -4
- package/dist/{create-vlrlY-2E.mjs → create-Dhai9zAt.mjs} +4 -4
- package/dist/create-DiJ8bUb-.mjs +34 -0
- package/dist/{create-C78g8Crb.mjs → create-DmN2gFc4.mjs} +5 -5
- package/dist/{create-wJR4CxHA.mjs → create-NCKHHdov.mjs} +5 -8
- package/dist/{create-C3IaXXty.mjs → create-YetX69Re.mjs} +4 -4
- package/dist/{create-e650zxzX.mjs → create-Za1EskpV.mjs} +5 -5
- package/dist/{create-branch-B8C7jl-J.mjs → create-branch-CseVn3lp.mjs} +5 -9
- package/dist/{create-DIVhBIyE.mjs → create-kZIIEN2Y.mjs} +11 -7
- package/dist/{csv-BLPJtlSC.mjs → csv-DNzesu8y.mjs} +5 -5
- package/dist/{current-task-C-ldJbWE.mjs → current-task-DRTKZcP9.mjs} +5 -8
- package/dist/{dashboard-CtO_3EfC.mjs → dashboard-CMw13KXM.mjs} +10 -10
- package/dist/{dashboard-CKUR8ZpQ.mjs → dashboard-D0hwTC-f.mjs} +11 -2
- package/dist/{dashboard-BlbNszi8.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-xXselnBq.mjs → db-BDijt81U.mjs} +7 -7
- package/dist/{delete-BZZHw6pm.mjs → delete--15it-A8.mjs} +5 -5
- package/dist/delete-Bsdwqh7H.mjs +44 -0
- package/dist/{delete-ZJJyqsRh.mjs → delete-BudvZkvK.mjs} +5 -5
- package/dist/{delete-BwSPQy7m.mjs → delete-BxjJ66BS.mjs} +5 -5
- package/dist/{delete-BZwAOQxG.mjs → delete-Dc8E5YwZ.mjs} +5 -5
- package/dist/{delete-runtime-D74s6vhu.mjs → delete-runtime-BKEzJn22.mjs} +1 -2
- package/dist/{delete-table-CJktZE3w.mjs → delete-table-5AQpn8OB.mjs} +5 -5
- package/dist/{delete-D6WxgWRp.mjs → delete-wFsy80db.mjs} +5 -5
- package/dist/{dependencies-BdqIqEIy.mjs → dependencies-C1ogC3BV.mjs} +7 -7
- package/dist/{dirty-BW2As2wS.mjs → dirty-CSLDYO-K.mjs} +6 -9
- package/dist/document-BGzVip5_.mjs +19 -0
- package/dist/{document-Cd2mmqCp.mjs → document-BHpLJbKU.mjs} +5 -0
- package/dist/{document-D6OybtP2.mjs → document-CA0Q6lqu.mjs} +1 -1
- package/dist/{download-mfFJ9oRS.mjs → download-Ddap1OAo.mjs} +3 -6
- package/dist/{eid-DZ-4t2xe.mjs → eid-HnrWhPoe.mjs} +4 -5
- package/dist/{events-D6yFmXP1.mjs → events-CXqetjcS.mjs} +5 -5
- package/dist/{export-DYZjz1WP.mjs → export-IFZdgYZ2.mjs} +7 -10
- package/dist/{field-BJ54wmIX.mjs → field-BJ6HoLRd.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-FUWCgPOa.mjs → fields-DxHxuxwO.mjs} +7 -7
- package/dist/{get-ByZJf9nO.mjs → get-B2pj2q3X.mjs} +5 -5
- package/dist/{get-C_5AbfpO.mjs → get-BF2vdF3W.mjs} +4 -4
- package/dist/{get-DAOSGt5Z.mjs → get-BGLvyOO3.mjs} +6 -6
- package/dist/{get-DMECsioX.mjs → get-BcoJ9Aha.mjs} +4 -4
- package/dist/{get-CsN7NBI0.mjs → get-BiPclcIP.mjs} +4 -4
- package/dist/{get-DCutQeiV.mjs → get-C3cuZNeW.mjs} +4 -4
- package/dist/{get-CQ0-fFWP.mjs → get-CDnmpfHQ.mjs} +5 -8
- package/dist/{get-DRJtsS1_.mjs → get-CE9_4Q7E.mjs} +4 -4
- package/dist/{get-C5q49Dgx.mjs → get-C_tdSMwW2.mjs} +6 -6
- package/dist/{get-CWnriw33.mjs → get-CxUQyhte.mjs} +6 -6
- package/dist/{get-DVyesErX.mjs → get-DW7mCaGe.mjs} +6 -6
- package/dist/{get-DYaQpixt.mjs → get-D_x-ENFe.mjs} +6 -6
- package/dist/{get-Ba2HRdrx.mjs → get-DjlQhgD4.mjs} +6 -6
- package/dist/{get-DhkltKIV.mjs → get-DmKtPNOy.mjs} +4 -4
- package/dist/{get-BWl3vzsf.mjs → get-Dtre5jzh.mjs} +6 -6
- package/dist/get-H6kInHIx.mjs +93 -0
- package/dist/{get-BraVQ1FJ.mjs → get-b0CoPz5B.mjs} +6 -6
- package/dist/{get-LAew34ID.mjs → get-eJilYnHk.mjs} +6 -6
- package/dist/get-i0KInCw9.mjs +32 -0
- package/dist/{get-_ggLr1tY.mjs → get-jofVjU6e.mjs} +6 -6
- package/dist/{get-run-oH4dRCBx.mjs → get-run-BE1HtJDW.mjs} +6 -6
- 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/git-sync-xKC1sqC4.mjs +28 -0
- package/dist/{group-DBM87IgC.mjs → group-YQQ5GIcP.mjs} +2 -2
- package/dist/{has-remote-changes-CnmyIw_7.mjs → has-remote-changes-Cj1KhBOT.mjs} +5 -8
- package/dist/{import-B7Si-bSI.mjs → import-DLb9VN4l.mjs} +7 -10
- package/dist/{input-DH9i67x_.mjs → input-D5tQEfqN.mjs} +1 -1
- package/dist/{is-dirty-BOH_VEA8.mjs → is-dirty-BxtgV2xF.mjs} +3 -6
- package/dist/{items-DouHkWev.mjs → items-DLUYc5-z.mjs} +7 -7
- package/dist/{key-BEhqIzIQ.mjs → key-PYetuQ13.mjs} +1 -1
- package/dist/{library-1J_4Dicw.mjs → library-BNSxXOpc.mjs} +5 -5
- package/dist/library-BPIzb3K_.mjs +81 -0
- package/dist/{library-DfYAT2Ep.mjs → library-PGCfm0UA.mjs} +1 -1
- package/dist/{list-D25ofn4v.mjs → list-B1soS8QW.mjs} +7 -7
- package/dist/{list-Cy0w4Fap.mjs → list-BQnOEB3W.mjs} +4 -4
- package/dist/{list-BeMYIeiI.mjs → list-BUz6KOfw.mjs} +7 -7
- package/dist/{list-C1bAtgO1.mjs → list-BcP1DTJH.mjs} +4 -4
- package/dist/{list-DJK9_BEF.mjs → list-C5mS_ehX.mjs} +14 -13
- package/dist/{list-qs9wAtC3.mjs → list-CBLxhaNZ.mjs} +4 -4
- package/dist/{list-aKUk-a1Y.mjs → list-CERbeLbQ.mjs} +7 -7
- package/dist/{list-B2Ddf4W0.mjs → list-COLpwXW4.mjs} +5 -5
- package/dist/{list-sDpy4nDU.mjs → list-CQbiSx26.mjs} +6 -6
- package/dist/{list-C0zJ2ehz.mjs → list-CX9qZ-bx.mjs} +6 -6
- package/dist/{list-DhViDVx_.mjs → list-CehE6KBV.mjs} +6 -6
- package/dist/list-Cuhf2lKL.mjs +35 -0
- package/dist/{list-D2IYZ6lk.mjs → list-CzRzCbCY.mjs} +6 -6
- package/dist/{list-DWLGpMvr.mjs → list-D-SyhKFw.mjs} +7 -7
- package/dist/{list-DptEWB5Y.mjs → list-Dat8QNcf.mjs} +4 -4
- package/dist/{list-C7UvO3Uw.mjs → list-M8J10Ozk.mjs} +6 -6
- package/dist/{list-BXlTYsYA.mjs → list-Sd7jGZoX.mjs} +4 -4
- package/dist/list-cIMww2Me.mjs +60 -0
- package/dist/{list-BK_6VNm_.mjs → list-jhQSgh6i.mjs} +4 -4
- package/dist/{login-BmyCAfRV.mjs → login-BfLqBfCd.mjs} +18 -15
- package/dist/{logout-DUR32q0V.mjs → logout-BpRXB3Ze.mjs} +3 -4
- package/dist/{measure-DdVp-8jw.mjs → measure-Ds8O5Evr.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-CBR-cBev.mjs → parameter-values-DhrkLXoN.mjs} +5 -6
- package/dist/{parse-enum-D0Jfm_Bz.mjs → parse-enum-Dc0dMZ3P.mjs} +1 -1
- package/dist/{parse-id-B3YwNojT.mjs → parse-id-DtM6q9HU.mjs} +1 -1
- package/dist/{parse-ref-ibKVB0J4.mjs → parse-ref-DTDld_LJ.mjs} +1 -1
- package/dist/{path-D8BQmEhL.mjs → path-_GHFrTLx.mjs} +5 -5
- package/dist/{poll-75SvT7Zv.mjs → poll-KLl4Eq8Y.mjs} +2 -2
- package/dist/{preflight-CoF1Em99.mjs → preflight-BpYtF0IU.mjs} +3 -4
- package/dist/{process-DBOOrmET.mjs → process-CLtOWKBn.mjs} +1 -1
- package/dist/{publish-Cb7XrQ3X.mjs → publish-D-7Zlmuk.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-D35B588l.mjs → query-B1CZztxs.mjs} +10 -12
- package/dist/query-CxESKMve.mjs +114 -0
- package/dist/{query-result-DBDwk8TS.mjs → query-result-E4Q-Gra6.mjs} +1 -1
- package/dist/{remove-collection-DJem6V26.mjs → remove-collection-C4saCFxz.mjs} +6 -9
- package/dist/{render-CI93iP0I.mjs → render-6O_eF-P1.mjs} +13 -2
- package/dist/{replace-CtsWICrD.mjs → replace-BuR4f2Ai.mjs} +5 -5
- package/dist/{rescan-values-CaXUL6z5.mjs → rescan-values-CNOiiWQ5.mjs} +6 -6
- package/dist/{run-CM-Amtbf.mjs → run-DijA_BXt.mjs} +26 -14
- package/dist/run-FmRruANb.mjs +64 -0
- package/dist/{run-BeLm17F4.mjs → run-QEUbWNm7.mjs} +9 -9
- package/dist/{runs-DFG63zgr.mjs → runs-BSlhVeDO.mjs} +7 -7
- package/dist/{runtime-z8rra6-I.mjs → runtime-Dtb93zKy.mjs} +994 -252
- package/dist/{schema-tables-COAHkIcy.mjs → schema-tables-BE3rEb6I.mjs} +7 -7
- package/dist/{schemas-BX5BATiV.mjs → schemas-yDjBiwlH.mjs} +5 -5
- package/dist/{search-DFBwUc6d.mjs → search-BAXg-EJw.mjs} +2 -1
- package/dist/{search-CPvvmhdt.mjs → search-CR_xNArA.mjs} +6 -6
- package/dist/{segment-C62L6BI3.mjs → segment-Cm6zQjJW.mjs} +6 -6
- package/dist/{selectors-P4QnrORk.mjs → selectors-C-vgMcGK.mjs} +3 -3
- package/dist/{send-PZh5IKF8.mjs → send-kC8oerkT.mjs} +4 -4
- package/dist/{set-active-DL4QzWDO.mjs → set-active-lDKhAlij.mjs} +5 -5
- package/dist/{set-DbCtUoFd.mjs → set-tFhPkxrL.mjs} +5 -5
- package/dist/{setting-BlRcZbhC.mjs → setting-DrJXCaFE.mjs} +4 -4
- package/dist/{setup-D_SLaC-3.mjs → setup-BWY9M0iR.mjs} +4 -4
- package/dist/{signal-CMd0EFUa.mjs → signal-Csom0mt5.mjs} +11 -2
- package/dist/skill-list-CCes8pKe.mjs +76 -0
- package/dist/skills-DE9ej5Rg.mjs +351 -0
- package/dist/{skills-D991LB1M.mjs → skills-DPRN2384.mjs} +3 -3
- package/dist/snippet-DWHTSo9c.mjs +19 -0
- package/dist/{stash-DyBxFoP6.mjs → stash-C9oDvQ9P.mjs} +7 -11
- package/dist/{status-DUsiogz5.mjs → status-CkpujA26.mjs} +11 -9
- package/dist/{status-cfDHqK2Q.mjs → status-DSdXmNC3.mjs} +12 -11
- package/dist/{subscription-Bn0AU7GN.mjs → subscription-DKOKoHRG.mjs} +6 -6
- package/dist/{subscriptions-DwqjCVlc.mjs → subscriptions-C5SyJL4B.mjs} +7 -7
- package/dist/{summary-BGwSNzf4.mjs → summary-DTPgXsc0.mjs} +6 -6
- package/dist/{sync-schema-dtkDOAKe.mjs → sync-schema-DKKkNSR7.mjs} +7 -7
- package/dist/{sync-task-BACcrs0i.mjs → sync-task-BtDnTXCP.mjs} +3 -2
- package/dist/{table-CsIJNPFf.mjs → table-C6h4tIRw.mjs} +1 -1
- package/dist/{table-CeeTJgQb.mjs → table-DfuY0N8e.mjs} +51 -4
- package/dist/{table-BJoEAoCU.mjs → table-I8NXSdUC.mjs} +5 -5
- package/dist/timeline-B_ESH-6W.mjs +21 -0
- package/dist/{timeline-event-BsF7YqzZ.mjs → timeline-event-n4Lzet7l.mjs} +6 -6
- package/dist/transform-BNuNiH9d.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-B7yc6dfH.mjs +22 -0
- package/dist/{transform-job-DRrK28IH.mjs → transform-job-CCguL6LP.mjs} +41 -4
- package/dist/{transform-tag-VM9R7Q_M.mjs → transform-tag-D6NXqWaX.mjs} +5 -5
- package/dist/transform-test-BjjCQ2xm.mjs +169 -0
- package/dist/transform-test-C1Oqtfb-.mjs +16 -0
- package/dist/transform-test-gzDcbypy.mjs +25 -0
- package/dist/{transforms-BjACGbBp.mjs → transforms-O4NtXqFz.mjs} +7 -7
- package/dist/transport-CyVo29u7.mjs +313 -0
- package/dist/{tree-BwS6JAmk.mjs → tree-CuyF116R.mjs} +4 -5
- package/dist/{unpublish-DWdPnENY.mjs → unpublish-DvWefKJi.mjs} +4 -7
- package/dist/{update-DkviXwSg.mjs → update-2KIpYgyj.mjs} +7 -7
- package/dist/{update-DKEHY-gt.mjs → update-76nzOc71.mjs} +7 -7
- package/dist/{update-B2CF2DK4.mjs → update-7oKvP1HC.mjs} +6 -6
- package/dist/{update-DTmRHBik.mjs → update-AJ2JmwDl.mjs} +7 -7
- package/dist/{update-BR_vkkd1.mjs → update-BB6Go_RX.mjs} +5 -5
- package/dist/{update-DCjAjihm.mjs → update-Bah7N8QX.mjs} +6 -6
- package/dist/{update-cqR1U6DU.mjs → update-CGJvIS-l.mjs} +5 -5
- package/dist/{update-tLIhVIPp.mjs → update-D7dG7H-z.mjs} +8 -8
- package/dist/{update-C1FBVLfC.mjs → update-DOdcflLH.mjs} +8 -8
- package/dist/{update-DlTaD1x3.mjs → update-DV54H3L5.mjs} +9 -9
- package/dist/{update-C4y3iQsv.mjs → update-DXmZuJho.mjs} +7 -7
- package/dist/{update-3idz42uD.mjs → update-DmgRIp7o.mjs} +7 -7
- package/dist/{update-DsZttiSC.mjs → update-H_fdjugs.mjs} +5 -5
- package/dist/{update-BCT9qpVr.mjs → update-To6A1Ugu.mjs} +5 -5
- package/dist/{update-dashcard-DlE_bb2F.mjs → update-dashcard-DjT5QOkL.mjs} +7 -7
- package/dist/update-l3PyNQKG.mjs +41 -0
- package/dist/{update-BpPaacCF.mjs → update-xEegxIyH.mjs} +6 -6
- package/dist/{upgrade-mNV7XuJG.mjs → upgrade-CuJx9fX4.mjs} +6 -8
- package/dist/upload-2YFFBSln.mjs +13 -0
- package/dist/{upload-CEGVxmYB.mjs → upload-CboARPZm.mjs} +4 -7
- package/dist/{upload-CD555ui1.mjs → upload-DOO94rCQ.mjs} +2 -2
- package/dist/{uuid-C4hqn3kA.mjs → uuid-InwZlrpQ.mjs} +10 -7
- package/dist/{validate-BWchyW0V.mjs → validate-D6-Vg_kn.mjs} +69 -23
- package/dist/{validate-query-DaGYSmpQ.mjs → validate-query-B90KYPQr.mjs} +3 -4
- package/dist/{values-C0O3eNaW.mjs → values-CsZLk1Ls.mjs} +6 -6
- package/dist/{verify-DfTjYF7s.mjs → verify-DrGjZwBM.mjs} +3 -18
- package/dist/{wait-WZmFenN_.mjs → wait-BmzdarP9.mjs} +7 -10
- package/dist/{wait-flags-BbfDSP8R.mjs → wait-flags-CiJGrTCT.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 -15
- package/skill-data/dashboard/SKILL.md +1 -1
- 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 +84 -115
- package/skill-data/mbql/references/operators.md +77 -231
- package/skill-data/metadata/SKILL.md +1 -1
- package/skill-data/metadata/references/semantic-types.md +7 -1
- package/skill-data/native-sql/SKILL.md +8 -9
- package/skill-data/native-sql/references/template-tags.md +27 -27
- package/skill-data/notification/SKILL.md +7 -1
- package/skill-data/transform/SKILL.md +76 -4
- 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 +263 -0
- package/skill-data/visualization/SKILL.md +13 -6
- package/skill-data/visualization/references/settings.md +13 -11
- package/skills/metabase-cli/SKILL.md +1 -1
- package/dist/card-CGCXbdmD.mjs +0 -24
- package/dist/client-mKuHg_sc.mjs +0 -2218
- package/dist/collection-D8Tk8i3a.mjs +0 -20
- package/dist/document-KbcHhzFz.mjs +0 -19
- package/dist/get-BC8J8BXB.mjs +0 -80
- package/dist/git-sync-Dik8nKfw.mjs +0 -28
- package/dist/library-ClLgrAXy.mjs +0 -19
- package/dist/list-CW5PdYCX.mjs +0 -98
- package/dist/network-error-D6CiOEBw.mjs +0 -431
- package/dist/predicates-Bkm2IoeX.mjs +0 -170
- package/dist/query-C256WBYG.mjs +0 -87
- package/dist/skills-DTCrMcix.mjs +0 -216
- package/dist/snippet-DTDO55Cg.mjs +0 -19
- package/dist/timeline-DcXPshcT.mjs +0 -21
- package/dist/transform-Dsf_wHAj.mjs +0 -28
- package/dist/transform-job-B1yLv5l-.mjs +0 -22
- package/dist/upload-DsYCf5kB.mjs +0 -13
package/dist/client-mKuHg_sc.mjs
DELETED
|
@@ -1,2218 +0,0 @@
|
|
|
1
|
-
import { a as InternalError, c as ResponseShapeError, d as ValidationError, f as errorMessage, i as ConfigError, l as TimeoutError, s as NetworkError } from "./predicates-Bkm2IoeX.mjs";
|
|
2
|
-
import { n as Notification, r as NotificationCardPayload, t as CARD_PAYLOAD_TYPE } from "./notification-DaA4bBHW.mjs";
|
|
3
|
-
import { a as isRetryableStatus, c as normalizeUrl, d as credentialSecrets, g as parseJsonOrPlain, h as parseJson, l as assertCredentialHeaderSafe, m as JSON_CONTENT_TYPE, n as isConnectionClosed, r as HttpError, t as buildNetworkError, u as credentialAuthHeader } from "./network-error-D6CiOEBw.mjs";
|
|
4
|
-
import { n as throwIfAborted, t as combineAborts } from "./signal-CMd0EFUa.mjs";
|
|
5
|
-
import { s as FieldValues, t as Field } from "./field-Cr2DPUG9.mjs";
|
|
6
|
-
import { r as ParameterValues } from "./parameter-DUKR8NXo.mjs";
|
|
7
|
-
import { o as CardQueryResult, t as Card } from "./card-DZxRmver.mjs";
|
|
8
|
-
import { f as CollectionTreeNode, o as CollectionItem, r as Collection } from "./collection-CfulNRBG.mjs";
|
|
9
|
-
import { t as ContentTranslationUploadResult } from "./content-translation-BrHOrmj9.mjs";
|
|
10
|
-
import { i as DashboardDetail, s as Dashcard, t as Dashboard } from "./dashboard-CKUR8ZpQ.mjs";
|
|
11
|
-
import { i as TableQueryMetadata, t as Table } from "./table-CeeTJgQb.mjs";
|
|
12
|
-
import { t as Database } from "./database-C8G6ZKG0.mjs";
|
|
13
|
-
import { r as pollUntil } from "./poll-75SvT7Zv.mjs";
|
|
14
|
-
import { t as Document } from "./document-Cd2mmqCp.mjs";
|
|
15
|
-
import { i as EidTranslateResult } from "./eid-translation-zEHtr5Oc.mjs";
|
|
16
|
-
import { f as isSyncTaskTerminal, l as SyncTask, n as SyncDirtyItem, o as SyncRemoteChanges, s as SyncSettingsUpdateResult, t as SyncBranchCreated } from "./git-sync-BDnxPrqU.mjs";
|
|
17
|
-
import { t as Library } from "./library-ClLgrAXy.mjs";
|
|
18
|
-
import { t as Measure } from "./measure-CtfjqJFP.mjs";
|
|
19
|
-
import { t as Pulse } from "./pulse-BmsDenXm.mjs";
|
|
20
|
-
import { r as SearchResult } from "./search-DFBwUc6d.mjs";
|
|
21
|
-
import { t as Segment } from "./segment-OsrbUDzw.mjs";
|
|
22
|
-
import { t as Setting } from "./setting-DTiLCW8g.mjs";
|
|
23
|
-
import { n as SetupResult } from "./setup-CO7QV-ao.mjs";
|
|
24
|
-
import { t as Snippet } from "./snippet-CyKAgIZl.mjs";
|
|
25
|
-
import { i as TimelineEvent, t as Timeline } from "./timeline-CCSU2qOS.mjs";
|
|
26
|
-
import { i as TransformRun, l as isTransformRunFailed, t as Transform, u as isTransformRunTerminal } from "./transform-D3QX0jxA.mjs";
|
|
27
|
-
import { a as TransformJobRunResult, n as TransformJobActiveResult, t as TransformJob } from "./transform-job-DRrK28IH.mjs";
|
|
28
|
-
import { t as TransformTag } from "./transform-tag-CcElGp3C.mjs";
|
|
29
|
-
import { t as UploadResult } from "./upload-DAtxBBms.mjs";
|
|
30
|
-
import { z } from "zod";
|
|
31
|
-
import { setTimeout } from "node:timers/promises";
|
|
32
|
-
//#region \0rolldown/runtime.js
|
|
33
|
-
var __defProp = Object.defineProperty;
|
|
34
|
-
var __exportAll = (all, no_symbols) => {
|
|
35
|
-
let target = {};
|
|
36
|
-
for (var name in all) __defProp(target, name, {
|
|
37
|
-
get: all[name],
|
|
38
|
-
enumerable: true
|
|
39
|
-
});
|
|
40
|
-
if (!no_symbols) __defProp(target, Symbol.toStringTag, { value: "Module" });
|
|
41
|
-
return target;
|
|
42
|
-
};
|
|
43
|
-
//#endregion
|
|
44
|
-
//#region ../client/src/http/response-shape.ts
|
|
45
|
-
const NO_SERVER_TAG = async () => null;
|
|
46
|
-
async function parseJsonResponse(text, schema, context) {
|
|
47
|
-
try {
|
|
48
|
-
return parseJson(text, schema, { source: context.url });
|
|
49
|
-
} catch (error) {
|
|
50
|
-
if (error instanceof ValidationError) throw ResponseShapeError.fromZodIssues({
|
|
51
|
-
kind: "zod",
|
|
52
|
-
method: context.method,
|
|
53
|
-
url: context.url,
|
|
54
|
-
status: context.status,
|
|
55
|
-
zodIssues: error.developerDetail.zodIssues,
|
|
56
|
-
serverTag: await context.getServerTag()
|
|
57
|
-
});
|
|
58
|
-
throw error;
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
//#endregion
|
|
62
|
-
//#region ../client/src/http/retry.ts
|
|
63
|
-
const BASE_DELAY_MS = 250;
|
|
64
|
-
const MAX_DELAY_MS = 8e3;
|
|
65
|
-
const MS_PER_SECOND = 1e3;
|
|
66
|
-
function backoffDelay({ attempt, retryAfterHeader }) {
|
|
67
|
-
const fromHeader = parseRetryAfter(retryAfterHeader);
|
|
68
|
-
if (fromHeader !== null) return fromHeader;
|
|
69
|
-
return Math.min(MAX_DELAY_MS, BASE_DELAY_MS * 2 ** attempt);
|
|
70
|
-
}
|
|
71
|
-
function parseRetryAfter(header) {
|
|
72
|
-
if (!header) return null;
|
|
73
|
-
const numeric = Number(header);
|
|
74
|
-
if (Number.isFinite(numeric) && numeric >= 0) return Math.round(numeric * MS_PER_SECOND);
|
|
75
|
-
const dateMs = Date.parse(header);
|
|
76
|
-
if (Number.isFinite(dateMs)) return Math.max(0, dateMs - Date.now());
|
|
77
|
-
return null;
|
|
78
|
-
}
|
|
79
|
-
function sleep(ms, signal) {
|
|
80
|
-
return setTimeout(ms, void 0, { signal });
|
|
81
|
-
}
|
|
82
|
-
async function runWithRetries(attempt, signal) {
|
|
83
|
-
let attemptIndex = 0;
|
|
84
|
-
while (true) {
|
|
85
|
-
const outcome = await attempt(attemptIndex);
|
|
86
|
-
if (outcome.kind === "success") return outcome.response;
|
|
87
|
-
await sleep(outcome.delayMs, signal);
|
|
88
|
-
attemptIndex += 1;
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
//#endregion
|
|
92
|
-
//#region ../client/src/http/transport.ts
|
|
93
|
-
const UNAUTHORIZED_STATUS = 401;
|
|
94
|
-
const DEFAULT_TIMEOUT_MS = 3e4;
|
|
95
|
-
const OCTET_STREAM_CONTENT_TYPE = "application/octet-stream";
|
|
96
|
-
const TEXT_CONTENT_TYPE_PREFIX = "text/";
|
|
97
|
-
const ERROR_BODY_BYTE_CAP = 64 * 1024;
|
|
98
|
-
const IDEMPOTENT_METHODS = /* @__PURE__ */ new Set([
|
|
99
|
-
"GET",
|
|
100
|
-
"HEAD",
|
|
101
|
-
"OPTIONS"
|
|
102
|
-
]);
|
|
103
|
-
function createTransport(config, options) {
|
|
104
|
-
const baseUrl = normalizeUrl(config.url);
|
|
105
|
-
assertCredentialHeaderSafe(config.credential);
|
|
106
|
-
const fetchImpl = options.fetchImpl ?? globalThis.fetch.bind(globalThis);
|
|
107
|
-
const getServerTag = options.getServerTag ?? NO_SERVER_TAG;
|
|
108
|
-
const refreshCredential = options.refreshCredential;
|
|
109
|
-
let credential = config.credential;
|
|
110
|
-
const knownSecrets = new Set(credentialSecrets(credential));
|
|
111
|
-
const redactionContext = { knownSecrets };
|
|
112
|
-
let refreshInFlight = null;
|
|
113
|
-
function tryRefreshCredential() {
|
|
114
|
-
const refresh = refreshCredential;
|
|
115
|
-
if (credential.kind !== "oauth" || refresh === void 0) return Promise.resolve(false);
|
|
116
|
-
refreshInFlight ??= refreshOnce(refresh).finally(() => {
|
|
117
|
-
refreshInFlight = null;
|
|
118
|
-
});
|
|
119
|
-
return refreshInFlight;
|
|
120
|
-
}
|
|
121
|
-
async function refreshOnce(refresh) {
|
|
122
|
-
const next = await refresh();
|
|
123
|
-
if (next === null) return false;
|
|
124
|
-
credential = next;
|
|
125
|
-
for (const secret of credentialSecrets(next)) knownSecrets.add(secret);
|
|
126
|
-
return true;
|
|
127
|
-
}
|
|
128
|
-
async function attemptOnce(prepared, attempt) {
|
|
129
|
-
const hasRetriesLeft = attempt < prepared.retries;
|
|
130
|
-
const timeoutSignal = AbortSignal.timeout(prepared.timeoutMs);
|
|
131
|
-
const combined = combineAborts(timeoutSignal, prepared.cancelSignal);
|
|
132
|
-
let response;
|
|
133
|
-
try {
|
|
134
|
-
response = await fetchImpl(prepared.url, {
|
|
135
|
-
method: prepared.method,
|
|
136
|
-
headers: prepared.headers,
|
|
137
|
-
body: prepared.body,
|
|
138
|
-
signal: combined
|
|
139
|
-
});
|
|
140
|
-
} catch (error) {
|
|
141
|
-
throwIfAborted(prepared.cancelSignal);
|
|
142
|
-
const isStaleSocketFirstTry = attempt === 0 && isConnectionClosed(error);
|
|
143
|
-
if (prepared.idempotent && (hasRetriesLeft || isStaleSocketFirstTry)) return {
|
|
144
|
-
kind: "retry",
|
|
145
|
-
delayMs: backoffDelay({ attempt })
|
|
146
|
-
};
|
|
147
|
-
if (timeoutSignal.aborted) throw new TimeoutError(`Request timed out after ${prepared.timeoutMs}ms`, {
|
|
148
|
-
kind: "http",
|
|
149
|
-
method: prepared.method,
|
|
150
|
-
url: prepared.url,
|
|
151
|
-
timeoutMs: prepared.timeoutMs
|
|
152
|
-
});
|
|
153
|
-
throw buildNetworkError(error, prepared.method, prepared.url);
|
|
154
|
-
}
|
|
155
|
-
const canRetryStatus = hasRetriesLeft && prepared.idempotent;
|
|
156
|
-
if (!response.ok && isRetryableStatus(response.status) && canRetryStatus) {
|
|
157
|
-
const retryAfter = response.headers.get("Retry-After");
|
|
158
|
-
response.body?.cancel().catch(() => void 0);
|
|
159
|
-
return {
|
|
160
|
-
kind: "retry",
|
|
161
|
-
delayMs: backoffDelay({
|
|
162
|
-
attempt,
|
|
163
|
-
retryAfterHeader: retryAfter
|
|
164
|
-
})
|
|
165
|
-
};
|
|
166
|
-
}
|
|
167
|
-
if (!response.ok) {
|
|
168
|
-
const rawBody = await readBodyForError(response);
|
|
169
|
-
const serverTag = await getServerTag();
|
|
170
|
-
throw new HttpError({
|
|
171
|
-
status: response.status,
|
|
172
|
-
statusText: response.statusText,
|
|
173
|
-
method: prepared.method,
|
|
174
|
-
url: prepared.url,
|
|
175
|
-
responseHeaders: response.headers,
|
|
176
|
-
rawBody,
|
|
177
|
-
serverTag,
|
|
178
|
-
redactionContext
|
|
179
|
-
});
|
|
180
|
-
}
|
|
181
|
-
assertContentType(response, prepared);
|
|
182
|
-
return {
|
|
183
|
-
kind: "success",
|
|
184
|
-
response
|
|
185
|
-
};
|
|
186
|
-
}
|
|
187
|
-
async function executeRaw(prepared) {
|
|
188
|
-
try {
|
|
189
|
-
return await runWithRetries((attempt) => attemptOnce(prepared, attempt), prepared.cancelSignal);
|
|
190
|
-
} catch (error) {
|
|
191
|
-
throwIfAborted(prepared.cancelSignal);
|
|
192
|
-
throw error;
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
async function executeWithAuthRefresh(path, opts) {
|
|
196
|
-
const prepared = prepare(path, opts);
|
|
197
|
-
try {
|
|
198
|
-
return {
|
|
199
|
-
response: await executeRaw(prepared),
|
|
200
|
-
prepared
|
|
201
|
-
};
|
|
202
|
-
} catch (error) {
|
|
203
|
-
if (error instanceof HttpError && error.status === UNAUTHORIZED_STATUS) {
|
|
204
|
-
if (await tryRefreshCredential()) {
|
|
205
|
-
const retried = prepare(path, opts);
|
|
206
|
-
return {
|
|
207
|
-
response: await executeRaw(retried),
|
|
208
|
-
prepared: retried
|
|
209
|
-
};
|
|
210
|
-
}
|
|
211
|
-
}
|
|
212
|
-
throw error;
|
|
213
|
-
}
|
|
214
|
-
}
|
|
215
|
-
function prepare(path, opts = {}) {
|
|
216
|
-
const method = opts.method ?? "GET";
|
|
217
|
-
const expectContentType = opts.expectContentType ?? "json";
|
|
218
|
-
const url = buildUrl(baseUrl, path, opts.query);
|
|
219
|
-
const headers = new Headers();
|
|
220
|
-
const auth = credentialAuthHeader(credential);
|
|
221
|
-
headers.set(auth.name, auth.value);
|
|
222
|
-
headers.set("accept", acceptHeader(expectContentType));
|
|
223
|
-
headers.set("user-agent", options.userAgent);
|
|
224
|
-
let body = null;
|
|
225
|
-
if (opts.body !== void 0 && opts.body !== null) if (typeof opts.body === "string" || opts.body instanceof URLSearchParams) body = opts.body;
|
|
226
|
-
else if (opts.body instanceof FormData || opts.body instanceof ReadableStream) body = opts.body;
|
|
227
|
-
else if (opts.body instanceof Uint8Array) {
|
|
228
|
-
body = opts.body;
|
|
229
|
-
headers.set("content-type", OCTET_STREAM_CONTENT_TYPE);
|
|
230
|
-
} else {
|
|
231
|
-
body = JSON.stringify(opts.body);
|
|
232
|
-
headers.set("content-type", JSON_CONTENT_TYPE);
|
|
233
|
-
}
|
|
234
|
-
return {
|
|
235
|
-
url,
|
|
236
|
-
method,
|
|
237
|
-
headers,
|
|
238
|
-
body,
|
|
239
|
-
expectContentType,
|
|
240
|
-
retries: opts.retries ?? 3,
|
|
241
|
-
idempotent: opts.idempotent ?? IDEMPOTENT_METHODS.has(method),
|
|
242
|
-
timeoutMs: opts.timeoutMs ?? DEFAULT_TIMEOUT_MS,
|
|
243
|
-
cancelSignal: combineAborts(opts.signal, options.signal)
|
|
244
|
-
};
|
|
245
|
-
}
|
|
246
|
-
return {
|
|
247
|
-
async requestRaw(path, opts) {
|
|
248
|
-
return (await executeWithAuthRefresh(path, opts ?? {})).response;
|
|
249
|
-
},
|
|
250
|
-
async requestParsed(schema, path, opts) {
|
|
251
|
-
const { response, prepared } = await executeWithAuthRefresh(path, {
|
|
252
|
-
...opts,
|
|
253
|
-
expectContentType: "json"
|
|
254
|
-
});
|
|
255
|
-
return parseJsonResponse(await response.text(), schema, {
|
|
256
|
-
method: prepared.method,
|
|
257
|
-
url: prepared.url,
|
|
258
|
-
status: response.status,
|
|
259
|
-
getServerTag
|
|
260
|
-
});
|
|
261
|
-
},
|
|
262
|
-
async requestStream(path, opts) {
|
|
263
|
-
const { response, prepared } = await executeWithAuthRefresh(path, {
|
|
264
|
-
...opts,
|
|
265
|
-
expectContentType: opts?.expectContentType ?? "binary"
|
|
266
|
-
});
|
|
267
|
-
if (!response.body) throw new NetworkError("Response had no body to stream", {
|
|
268
|
-
method: prepared.method,
|
|
269
|
-
url: prepared.url,
|
|
270
|
-
cause: "missing body"
|
|
271
|
-
});
|
|
272
|
-
return response.body;
|
|
273
|
-
}
|
|
274
|
-
};
|
|
275
|
-
}
|
|
276
|
-
function buildUrl(baseUrl, path, query) {
|
|
277
|
-
const normalizedPath = path.startsWith("/") ? path : `/${path}`;
|
|
278
|
-
const target = new URL(baseUrl + normalizedPath);
|
|
279
|
-
if (query) for (const [key, value] of Object.entries(query)) {
|
|
280
|
-
if (value === void 0) continue;
|
|
281
|
-
if (Array.isArray(value)) for (const entry of value) target.searchParams.append(key, String(entry));
|
|
282
|
-
else target.searchParams.append(key, String(value));
|
|
283
|
-
}
|
|
284
|
-
return target.toString();
|
|
285
|
-
}
|
|
286
|
-
function acceptHeader(expected) {
|
|
287
|
-
if (expected === "json") return JSON_CONTENT_TYPE;
|
|
288
|
-
if (expected === "text") return "text/*";
|
|
289
|
-
return "*/*";
|
|
290
|
-
}
|
|
291
|
-
function assertContentType(response, prepared) {
|
|
292
|
-
if (prepared.expectContentType === "binary") return;
|
|
293
|
-
const contentType = response.headers.get("content-type");
|
|
294
|
-
if (contentType === null) throwContentTypeMismatch(response, prepared, prepared.expectContentType);
|
|
295
|
-
if (prepared.expectContentType === "json" && !contentType.includes("application/json")) throwContentTypeMismatch(response, prepared, "json");
|
|
296
|
-
if (prepared.expectContentType === "text" && !contentType.startsWith(TEXT_CONTENT_TYPE_PREFIX)) throwContentTypeMismatch(response, prepared, "text");
|
|
297
|
-
}
|
|
298
|
-
function throwContentTypeMismatch(response, prepared, expected) {
|
|
299
|
-
const actual = response.headers.get("content-type") ?? "no content-type";
|
|
300
|
-
throw new HttpError({
|
|
301
|
-
status: response.status,
|
|
302
|
-
statusText: response.statusText,
|
|
303
|
-
method: prepared.method,
|
|
304
|
-
url: prepared.url,
|
|
305
|
-
responseHeaders: response.headers,
|
|
306
|
-
rawBody: null,
|
|
307
|
-
overrideUserMessage: `Expected ${expected} response but got ${actual}`
|
|
308
|
-
});
|
|
309
|
-
}
|
|
310
|
-
async function readBodyForError(response) {
|
|
311
|
-
try {
|
|
312
|
-
return Buffer.from(await response.arrayBuffer()).subarray(0, ERROR_BODY_BYTE_CAP).toString("utf8");
|
|
313
|
-
} catch (error) {
|
|
314
|
-
return `[body read failed: ${errorMessage(error)}]`;
|
|
315
|
-
}
|
|
316
|
-
}
|
|
317
|
-
//#endregion
|
|
318
|
-
//#region ../client/src/resources/card.ts
|
|
319
|
-
const CardApiList = z.array(Card);
|
|
320
|
-
function cardResource(transport) {
|
|
321
|
-
/** List cards. `f` picks a server-side preset; `model_id` scopes the presets that need an id. */
|
|
322
|
-
async function list(params = {}, options = {}) {
|
|
323
|
-
return {
|
|
324
|
-
data: await transport.requestParsed(CardApiList, "/api/card", {
|
|
325
|
-
...options,
|
|
326
|
-
query: {
|
|
327
|
-
f: params.f,
|
|
328
|
-
model_id: params.model_id
|
|
329
|
-
}
|
|
330
|
-
}),
|
|
331
|
-
total: null
|
|
332
|
-
};
|
|
333
|
-
}
|
|
334
|
-
/** Get one card by id. */
|
|
335
|
-
async function get(id, options = {}) {
|
|
336
|
-
return transport.requestParsed(Card, `/api/card/${id}`, { ...options });
|
|
337
|
-
}
|
|
338
|
-
/** Create a card — a question, a model, or a metric — from a full card body. */
|
|
339
|
-
async function create(params, options = {}) {
|
|
340
|
-
return transport.requestParsed(Card, "/api/card", {
|
|
341
|
-
...options,
|
|
342
|
-
method: "POST",
|
|
343
|
-
body: params
|
|
344
|
-
});
|
|
345
|
-
}
|
|
346
|
-
/** Update a card by id, patching only the fields the body carries. */
|
|
347
|
-
async function update(id, params, options = {}) {
|
|
348
|
-
return transport.requestParsed(Card, `/api/card/${id}`, {
|
|
349
|
-
...options,
|
|
350
|
-
method: "PUT",
|
|
351
|
-
body: params
|
|
352
|
-
});
|
|
353
|
-
}
|
|
354
|
-
/** Archive (soft-delete) a card by id. Metabase models this as an update, not its own endpoint. */
|
|
355
|
-
async function archive(id, options = {}) {
|
|
356
|
-
return update(id, { archived: true }, options);
|
|
357
|
-
}
|
|
358
|
-
/** Run a saved card and return the query result envelope. */
|
|
359
|
-
async function query(id, params, options = {}) {
|
|
360
|
-
return transport.requestParsed(CardQueryResult, `/api/card/${id}/query`, {
|
|
361
|
-
...options,
|
|
362
|
-
method: "POST",
|
|
363
|
-
body: { parameters: params.parameters }
|
|
364
|
-
});
|
|
365
|
-
}
|
|
366
|
-
/**
|
|
367
|
-
* Run a saved card and stream its result as a download. Unlike `query`, this endpoint takes a
|
|
368
|
-
* form-encoded body and answers bytes, so a caller consumes the stream rather than a value.
|
|
369
|
-
*/
|
|
370
|
-
async function exportQuery(id, format, params, options = {}) {
|
|
371
|
-
const body = new URLSearchParams({
|
|
372
|
-
parameters: JSON.stringify(params.parameters),
|
|
373
|
-
format_rows: String(params.format_rows),
|
|
374
|
-
pivot_results: String(params.pivot_results)
|
|
375
|
-
});
|
|
376
|
-
return transport.requestStream(`/api/card/${id}/query/${format}`, {
|
|
377
|
-
...options,
|
|
378
|
-
method: "POST",
|
|
379
|
-
body
|
|
380
|
-
});
|
|
381
|
-
}
|
|
382
|
-
return {
|
|
383
|
-
list,
|
|
384
|
-
get,
|
|
385
|
-
create,
|
|
386
|
-
update,
|
|
387
|
-
archive,
|
|
388
|
-
query,
|
|
389
|
-
exportQuery
|
|
390
|
-
};
|
|
391
|
-
}
|
|
392
|
-
async function* paginatePages(client, path, itemSchema, opts = {}) {
|
|
393
|
-
const envelopeSchema = paginatedEnvelopeSchema(itemSchema);
|
|
394
|
-
const pageSize = opts.pageSize ?? 50;
|
|
395
|
-
if (!Number.isInteger(pageSize) || pageSize < 1) throw new InternalError(`pageSize must be an integer of at least 1, got ${pageSize}`);
|
|
396
|
-
const start = opts.offset ?? 0;
|
|
397
|
-
const max = opts.max ?? Number.POSITIVE_INFINITY;
|
|
398
|
-
let taken = 0;
|
|
399
|
-
let previousHead = null;
|
|
400
|
-
while (taken < max) {
|
|
401
|
-
const remaining = max - taken;
|
|
402
|
-
const limit = Math.min(pageSize, remaining);
|
|
403
|
-
const offset = start + taken;
|
|
404
|
-
const envelope = await client.requestParsed(envelopeSchema, path, {
|
|
405
|
-
query: {
|
|
406
|
-
...opts.query,
|
|
407
|
-
limit,
|
|
408
|
-
offset
|
|
409
|
-
},
|
|
410
|
-
...opts.signal !== void 0 && { signal: opts.signal }
|
|
411
|
-
});
|
|
412
|
-
const items = envelope.data.length > remaining ? envelope.data.slice(0, remaining) : envelope.data;
|
|
413
|
-
const total = envelope.total ?? null;
|
|
414
|
-
const head = items.length === 0 ? null : JSON.stringify(items[0]);
|
|
415
|
-
if (head !== null && head === previousHead) throw new ConfigError(`the endpoint returned the same first row at offset ${offset} as at the previous offset; it is ignoring the offset parameter, so paging cannot advance`);
|
|
416
|
-
previousHead = head;
|
|
417
|
-
yield {
|
|
418
|
-
items,
|
|
419
|
-
total
|
|
420
|
-
};
|
|
421
|
-
if (items.length === 0) return;
|
|
422
|
-
const consumed = taken + items.length;
|
|
423
|
-
if (total !== null && start + consumed === total) return;
|
|
424
|
-
taken = consumed;
|
|
425
|
-
}
|
|
426
|
-
}
|
|
427
|
-
function paginatedEnvelopeSchema(itemSchema) {
|
|
428
|
-
return z.object({
|
|
429
|
-
data: z.array(itemSchema),
|
|
430
|
-
total: z.number().int().nonnegative().nullable().optional(),
|
|
431
|
-
limit: z.number().int().nonnegative().optional(),
|
|
432
|
-
offset: z.number().int().nonnegative().optional()
|
|
433
|
-
}).loose();
|
|
434
|
-
}
|
|
435
|
-
//#endregion
|
|
436
|
-
//#region ../client/src/resources/collection.ts
|
|
437
|
-
const CollectionApiList = z.array(Collection);
|
|
438
|
-
const CollectionTreeApiList = z.array(CollectionTreeNode);
|
|
439
|
-
const COLLECTION_LIST_QUERY = {
|
|
440
|
-
all: {},
|
|
441
|
-
archived: { archived: true },
|
|
442
|
-
personal: { "personal-only": true }
|
|
443
|
-
};
|
|
444
|
-
const DEFAULT_LIST_FILTER = "all";
|
|
445
|
-
function refPath(ref) {
|
|
446
|
-
return encodeURIComponent(ref);
|
|
447
|
-
}
|
|
448
|
-
/**
|
|
449
|
-
* List collections including the Library and its children, parsing each through the caller's own
|
|
450
|
-
* projection. `Collection` pins `type`, `namespace` and `authority_level` to closed enums, so a
|
|
451
|
-
* consumer reading a few fields off every collection on the instance narrows here: one collection
|
|
452
|
-
* carrying a server value outside those sets then costs nothing to a caller that never reads the
|
|
453
|
-
* field.
|
|
454
|
-
*/
|
|
455
|
-
async function listCollectionsWithLibrary(transport, schema, options = {}) {
|
|
456
|
-
return transport.requestParsed(z.array(schema), "/api/collection", {
|
|
457
|
-
...options,
|
|
458
|
-
query: { "include-library": true }
|
|
459
|
-
});
|
|
460
|
-
}
|
|
461
|
-
function collectionResource(transport) {
|
|
462
|
-
/** List collections. `filter` picks a server-side preset: everything, archived, or personal. */
|
|
463
|
-
async function list(params = {}, options = {}) {
|
|
464
|
-
return {
|
|
465
|
-
data: await transport.requestParsed(CollectionApiList, "/api/collection", {
|
|
466
|
-
...options,
|
|
467
|
-
query: COLLECTION_LIST_QUERY[params.filter ?? DEFAULT_LIST_FILTER]
|
|
468
|
-
}),
|
|
469
|
-
total: null
|
|
470
|
-
};
|
|
471
|
-
}
|
|
472
|
-
/**
|
|
473
|
-
* List collections including the Library and its children, which the plain listing omits.
|
|
474
|
-
* The Library's own children carry neither `type` nor `is_remote_synced`, so this is where a
|
|
475
|
-
* caller resolves both.
|
|
476
|
-
*/
|
|
477
|
-
async function listWithLibrary(options = {}) {
|
|
478
|
-
return {
|
|
479
|
-
data: await listCollectionsWithLibrary(transport, Collection, options),
|
|
480
|
-
total: null
|
|
481
|
-
};
|
|
482
|
-
}
|
|
483
|
-
/** Get one collection by id, entity id, or the `root`/`trash` alias. */
|
|
484
|
-
async function get(ref, options = {}) {
|
|
485
|
-
return transport.requestParsed(Collection, `/api/collection/${refPath(ref)}`, { ...options });
|
|
486
|
-
}
|
|
487
|
-
/** Create a new collection. */
|
|
488
|
-
async function create(params, options = {}) {
|
|
489
|
-
return transport.requestParsed(Collection, "/api/collection", {
|
|
490
|
-
...options,
|
|
491
|
-
method: "POST",
|
|
492
|
-
body: params
|
|
493
|
-
});
|
|
494
|
-
}
|
|
495
|
-
/** Update a collection, patching only the fields the body carries. */
|
|
496
|
-
async function update(ref, params, options = {}) {
|
|
497
|
-
return transport.requestParsed(Collection, `/api/collection/${refPath(ref)}`, {
|
|
498
|
-
...options,
|
|
499
|
-
method: "PUT",
|
|
500
|
-
body: params
|
|
501
|
-
});
|
|
502
|
-
}
|
|
503
|
-
/** Archive (soft-delete) a collection. Metabase models this as an update, not its own endpoint. */
|
|
504
|
-
async function archive(ref, options = {}) {
|
|
505
|
-
return update(ref, { archived: true }, options);
|
|
506
|
-
}
|
|
507
|
-
/**
|
|
508
|
-
* Walk the items inside a collection one page at a time. This endpoint pages on the server, so
|
|
509
|
-
* the caller consumes pages rather than a single list and decides how far to pull.
|
|
510
|
-
*/
|
|
511
|
-
function itemPages(ref, params = {}, options = {}) {
|
|
512
|
-
return paginatePages(transport, `/api/collection/${refPath(ref)}/items`, CollectionItem, {
|
|
513
|
-
query: {
|
|
514
|
-
models: params.models,
|
|
515
|
-
archived: params.archived,
|
|
516
|
-
pinned_state: params.pinned_state
|
|
517
|
-
},
|
|
518
|
-
...options.offset !== void 0 && { offset: options.offset },
|
|
519
|
-
...options.max !== void 0 && { max: options.max },
|
|
520
|
-
...options.pageSize !== void 0 && { pageSize: options.pageSize },
|
|
521
|
-
...options.signal !== void 0 && { signal: options.signal }
|
|
522
|
-
});
|
|
523
|
-
}
|
|
524
|
-
/** Fetch the collection hierarchy as a forest of nested nodes. */
|
|
525
|
-
async function tree(options = {}) {
|
|
526
|
-
return {
|
|
527
|
-
data: await transport.requestParsed(CollectionTreeApiList, "/api/collection/tree", { ...options }),
|
|
528
|
-
total: null
|
|
529
|
-
};
|
|
530
|
-
}
|
|
531
|
-
return {
|
|
532
|
-
list,
|
|
533
|
-
listWithLibrary,
|
|
534
|
-
get,
|
|
535
|
-
create,
|
|
536
|
-
update,
|
|
537
|
-
archive,
|
|
538
|
-
itemPages,
|
|
539
|
-
tree
|
|
540
|
-
};
|
|
541
|
-
}
|
|
542
|
-
//#endregion
|
|
543
|
-
//#region ../client/src/resources/csv-upload.ts
|
|
544
|
-
const CSV_CONTENT_TYPE = "text/csv";
|
|
545
|
-
function buildCsvFormData(file) {
|
|
546
|
-
const form = new FormData();
|
|
547
|
-
form.append("file", new Blob([file.bytes], { type: CSV_CONTENT_TYPE }), file.filename);
|
|
548
|
-
return form;
|
|
549
|
-
}
|
|
550
|
-
//#endregion
|
|
551
|
-
//#region ../client/src/resources/content-translation.ts
|
|
552
|
-
const CONTENT_TRANSLATION_PATH = "/api/ee/content-translation";
|
|
553
|
-
function contentTranslationResource(transport) {
|
|
554
|
-
/** Download the complete content translation dictionary as CSV. */
|
|
555
|
-
async function download(options = {}) {
|
|
556
|
-
return transport.requestStream(`${CONTENT_TRANSLATION_PATH}/csv`, options);
|
|
557
|
-
}
|
|
558
|
-
/** Replace the complete content translation dictionary with the attached CSV. */
|
|
559
|
-
async function upload(file, options = {}) {
|
|
560
|
-
const form = buildCsvFormData(file);
|
|
561
|
-
return transport.requestParsed(ContentTranslationUploadResult, `${CONTENT_TRANSLATION_PATH}/upload-dictionary`, {
|
|
562
|
-
...options,
|
|
563
|
-
method: "POST",
|
|
564
|
-
body: form
|
|
565
|
-
});
|
|
566
|
-
}
|
|
567
|
-
return {
|
|
568
|
-
download,
|
|
569
|
-
upload
|
|
570
|
-
};
|
|
571
|
-
}
|
|
572
|
-
//#endregion
|
|
573
|
-
//#region ../client/src/resources/dashboard.ts
|
|
574
|
-
const DashboardApiList = z.array(Dashboard);
|
|
575
|
-
const PreflightDashcard = z.looseObject({ card_id: z.number().int().nullable().optional() });
|
|
576
|
-
function dashboardResource(transport) {
|
|
577
|
-
const card = cardResource(transport);
|
|
578
|
-
/** List dashboards. `f` picks a server-side preset. */
|
|
579
|
-
async function list(params = {}, options = {}) {
|
|
580
|
-
return {
|
|
581
|
-
data: await transport.requestParsed(DashboardApiList, "/api/dashboard", {
|
|
582
|
-
...options,
|
|
583
|
-
query: { f: params.f }
|
|
584
|
-
}),
|
|
585
|
-
total: null
|
|
586
|
-
};
|
|
587
|
-
}
|
|
588
|
-
/** Get one dashboard by id, with its dashcards, tabs and parameters. */
|
|
589
|
-
async function get(id, options = {}) {
|
|
590
|
-
return transport.requestParsed(DashboardDetail, `/api/dashboard/${id}`, { ...options });
|
|
591
|
-
}
|
|
592
|
-
/**
|
|
593
|
-
* Create a dashboard. The endpoint accepts no dashcards or tabs — a follow-up `update` is what
|
|
594
|
-
* puts content on a fresh dashboard.
|
|
595
|
-
*/
|
|
596
|
-
async function create(params, options = {}) {
|
|
597
|
-
return transport.requestParsed(Dashboard, "/api/dashboard", {
|
|
598
|
-
...options,
|
|
599
|
-
method: "POST",
|
|
600
|
-
body: params
|
|
601
|
-
});
|
|
602
|
-
}
|
|
603
|
-
/**
|
|
604
|
-
* Update a dashboard by id, patching only the fields the body carries. `dashcards` and `tabs` are
|
|
605
|
-
* full replacements: whatever the body omits is deleted from the dashboard.
|
|
606
|
-
*/
|
|
607
|
-
async function update(id, params, options = {}) {
|
|
608
|
-
return transport.requestParsed(DashboardDetail, `/api/dashboard/${id}`, {
|
|
609
|
-
...options,
|
|
610
|
-
method: "PUT",
|
|
611
|
-
body: params
|
|
612
|
-
});
|
|
613
|
-
}
|
|
614
|
-
/**
|
|
615
|
-
* Archive (soft-delete) a dashboard by id. Metabase models this as an update, not its own
|
|
616
|
-
* endpoint. The answer is read as `Dashboard` rather than the `DashboardDetail` `update` returns:
|
|
617
|
-
* an archive is a state change on the dashboard itself, and its dashcards are not part of it.
|
|
618
|
-
*/
|
|
619
|
-
async function archive(id, options = {}) {
|
|
620
|
-
return transport.requestParsed(Dashboard, `/api/dashboard/${id}`, {
|
|
621
|
-
...options,
|
|
622
|
-
method: "PUT",
|
|
623
|
-
body: { archived: true }
|
|
624
|
-
});
|
|
625
|
-
}
|
|
626
|
-
/**
|
|
627
|
-
* Patch one dashcard on a dashboard. Metabase exposes no dashcard endpoint and its dashboard PUT
|
|
628
|
-
* is a full replace of `dashcards`, so the patch is read-modify-written over the dashboard as it
|
|
629
|
-
* currently stands.
|
|
630
|
-
*/
|
|
631
|
-
async function updateDashcard(dashboardId, dashcardId, params, options = {}) {
|
|
632
|
-
const dashboard = await get(dashboardId, options);
|
|
633
|
-
const target = dashboard.dashcards.find((dashcard) => dashcard.id === dashcardId);
|
|
634
|
-
if (target === void 0) throw new ConfigError(`dashcard ${dashcardId} not found on dashboard ${dashboardId}`);
|
|
635
|
-
const patched = Dashcard.parse({
|
|
636
|
-
...target,
|
|
637
|
-
...params
|
|
638
|
-
});
|
|
639
|
-
const refreshed = (await update(dashboardId, { dashcards: dashboard.dashcards.map((dashcard) => stripEntityId(dashcard.id === dashcardId ? patched : dashcard)) }, options)).dashcards.find((dashcard) => dashcard.id === dashcardId);
|
|
640
|
-
if (refreshed === void 0) throw new Error(`PUT /api/dashboard/${dashboardId}: dashcard ${dashcardId} missing from response`);
|
|
641
|
-
return refreshed;
|
|
642
|
-
}
|
|
643
|
-
/**
|
|
644
|
-
* Check every card a `dashcards` body references before writing it, through `GET /api/card/{id}`
|
|
645
|
-
* once per distinct id. Reports one issue per reference whose card is missing, archived, or
|
|
646
|
-
* unreadable, so an empty result means the body is safe to send; an id the server answers for in
|
|
647
|
-
* any other way propagates as the failure it was.
|
|
648
|
-
*/
|
|
649
|
-
async function checkCardReferences(dashcards, options = {}) {
|
|
650
|
-
const grouped = groupByCardId(collectCardReferences(dashcards));
|
|
651
|
-
return (await Promise.all(Array.from(grouped.entries()).map(async ([cardId, references]) => ({
|
|
652
|
-
references,
|
|
653
|
-
problem: await inspectCard(cardId, options)
|
|
654
|
-
})))).flatMap((check) => {
|
|
655
|
-
const problem = check.problem;
|
|
656
|
-
if (problem === null) return [];
|
|
657
|
-
return check.references.map((reference) => ({
|
|
658
|
-
...reference,
|
|
659
|
-
problem
|
|
660
|
-
}));
|
|
661
|
-
});
|
|
662
|
-
}
|
|
663
|
-
async function inspectCard(cardId, options) {
|
|
664
|
-
try {
|
|
665
|
-
return (await card.get(cardId, options)).archived ? { reason: "archived" } : null;
|
|
666
|
-
} catch (error) {
|
|
667
|
-
if (!(error instanceof HttpError)) throw error;
|
|
668
|
-
if (error.kind === "resource-missing") return { reason: "missing" };
|
|
669
|
-
if (error.kind === "auth") return {
|
|
670
|
-
reason: "unreadable",
|
|
671
|
-
detail: error.userMessage
|
|
672
|
-
};
|
|
673
|
-
throw error;
|
|
674
|
-
}
|
|
675
|
-
}
|
|
676
|
-
/**
|
|
677
|
-
* Fetch the selectable values for a dashboard parameter, through the chain-filter value endpoint.
|
|
678
|
-
*/
|
|
679
|
-
async function parameterValues(dashboardId, parameterId, options = {}) {
|
|
680
|
-
return transport.requestParsed(ParameterValues, `/api/dashboard/${dashboardId}/params/${encodeURIComponent(parameterId)}/values`, { ...options });
|
|
681
|
-
}
|
|
682
|
-
/**
|
|
683
|
-
* Search a dashboard parameter's selectable values: the server returns only values containing the
|
|
684
|
-
* substring, capped at the first 1000 matches.
|
|
685
|
-
*/
|
|
686
|
-
async function searchParameterValues(dashboardId, parameterId, query, options = {}) {
|
|
687
|
-
const parameter = encodeURIComponent(parameterId);
|
|
688
|
-
return transport.requestParsed(ParameterValues, `/api/dashboard/${dashboardId}/params/${parameter}/search/${encodeURIComponent(query)}`, { ...options });
|
|
689
|
-
}
|
|
690
|
-
return {
|
|
691
|
-
list,
|
|
692
|
-
get,
|
|
693
|
-
create,
|
|
694
|
-
update,
|
|
695
|
-
archive,
|
|
696
|
-
updateDashcard,
|
|
697
|
-
checkCardReferences,
|
|
698
|
-
parameterValues,
|
|
699
|
-
searchParameterValues
|
|
700
|
-
};
|
|
701
|
-
}
|
|
702
|
-
function collectCardReferences(dashcards) {
|
|
703
|
-
if (dashcards === void 0 || dashcards === null) return [];
|
|
704
|
-
const references = [];
|
|
705
|
-
dashcards.forEach((dashcard, index) => {
|
|
706
|
-
const parsed = PreflightDashcard.safeParse(dashcard);
|
|
707
|
-
if (!parsed.success) return;
|
|
708
|
-
const cardId = parsed.data.card_id;
|
|
709
|
-
if (typeof cardId === "number" && cardId > 0) references.push({
|
|
710
|
-
cardId,
|
|
711
|
-
path: `/dashcards/${index}/card_id`
|
|
712
|
-
});
|
|
713
|
-
});
|
|
714
|
-
return references;
|
|
715
|
-
}
|
|
716
|
-
function groupByCardId(references) {
|
|
717
|
-
const grouped = /* @__PURE__ */ new Map();
|
|
718
|
-
for (const reference of references) {
|
|
719
|
-
const existing = grouped.get(reference.cardId);
|
|
720
|
-
if (existing === void 0) grouped.set(reference.cardId, [reference]);
|
|
721
|
-
else existing.push(reference);
|
|
722
|
-
}
|
|
723
|
-
return grouped;
|
|
724
|
-
}
|
|
725
|
-
function stripEntityId(dashcard) {
|
|
726
|
-
const { entity_id: _entity_id, id, size_x, size_y, row, col, ...rest } = dashcard;
|
|
727
|
-
return {
|
|
728
|
-
...rest,
|
|
729
|
-
id,
|
|
730
|
-
size_x,
|
|
731
|
-
size_y,
|
|
732
|
-
row,
|
|
733
|
-
col
|
|
734
|
-
};
|
|
735
|
-
}
|
|
736
|
-
//#endregion
|
|
737
|
-
//#region ../client/src/resources/database.ts
|
|
738
|
-
const DatabaseApiList = z.object({
|
|
739
|
-
data: z.array(Database),
|
|
740
|
-
total: z.number().int().nonnegative()
|
|
741
|
-
}).loose();
|
|
742
|
-
const DatabaseTaskAck = z.object({ status: z.literal("ok") });
|
|
743
|
-
const DatabaseApiSchemaList = z.array(z.string());
|
|
744
|
-
const DatabaseApiSchemaTableList = z.array(Table);
|
|
745
|
-
const SYNC_COMPLETE = "complete";
|
|
746
|
-
function databaseResource(transport) {
|
|
747
|
-
/** List databases. `include` hydrates each database's tables; `saved` adds the Saved Questions virtual database. */
|
|
748
|
-
async function list(params = {}, options = {}) {
|
|
749
|
-
const response = await transport.requestParsed(DatabaseApiList, "/api/database", {
|
|
750
|
-
...options,
|
|
751
|
-
query: {
|
|
752
|
-
include: params.include,
|
|
753
|
-
saved: params.saved
|
|
754
|
-
}
|
|
755
|
-
});
|
|
756
|
-
return {
|
|
757
|
-
data: response.data,
|
|
758
|
-
total: response.total
|
|
759
|
-
};
|
|
760
|
-
}
|
|
761
|
-
/** Get one database by id. `include` hydrates its tables, and `tables.fields` their fields too. */
|
|
762
|
-
async function get(id, params = {}, options = {}) {
|
|
763
|
-
return transport.requestParsed(Database, `/api/database/${id}`, {
|
|
764
|
-
...options,
|
|
765
|
-
query: { include: params.include }
|
|
766
|
-
});
|
|
767
|
-
}
|
|
768
|
-
/** List the schema names in a database. */
|
|
769
|
-
async function schemas(id, options = {}) {
|
|
770
|
-
return {
|
|
771
|
-
data: await transport.requestParsed(DatabaseApiSchemaList, `/api/database/${id}/schemas`, { ...options }),
|
|
772
|
-
total: null
|
|
773
|
-
};
|
|
774
|
-
}
|
|
775
|
-
/** List the tables one schema of a database holds. */
|
|
776
|
-
async function schemaTables(id, schema, options = {}) {
|
|
777
|
-
return {
|
|
778
|
-
data: await transport.requestParsed(DatabaseApiSchemaTableList, `/api/database/${id}/schema/${encodeURIComponent(schema)}`, { ...options }),
|
|
779
|
-
total: null
|
|
780
|
-
};
|
|
781
|
-
}
|
|
782
|
-
/**
|
|
783
|
-
* Trigger a manual schema sync for a database. The endpoint queues the sync and returns at once;
|
|
784
|
-
* pass `wait` to poll the database until it reports its initial sync complete.
|
|
785
|
-
*/
|
|
786
|
-
async function syncSchema(id, params = {}, options = {}) {
|
|
787
|
-
const ack = await transport.requestParsed(DatabaseTaskAck, `/api/database/${id}/sync_schema`, {
|
|
788
|
-
...options,
|
|
789
|
-
method: "POST"
|
|
790
|
-
});
|
|
791
|
-
const wait = params.wait;
|
|
792
|
-
if (wait === void 0) return {
|
|
793
|
-
id,
|
|
794
|
-
status: ack.status
|
|
795
|
-
};
|
|
796
|
-
const database = await pollUntil(async (signal) => transport.requestParsed(Database, `/api/database/${id}`, {
|
|
797
|
-
...options,
|
|
798
|
-
signal
|
|
799
|
-
}), (candidate) => candidate.initial_sync_status === SYNC_COMPLETE, wait);
|
|
800
|
-
return {
|
|
801
|
-
id,
|
|
802
|
-
status: ack.status,
|
|
803
|
-
initial_sync_status: database.initial_sync_status ?? null
|
|
804
|
-
};
|
|
805
|
-
}
|
|
806
|
-
/** Trigger a rescan of the cached field values across a database. */
|
|
807
|
-
async function rescanValues(id, options = {}) {
|
|
808
|
-
return {
|
|
809
|
-
id,
|
|
810
|
-
status: (await transport.requestParsed(DatabaseTaskAck, `/api/database/${id}/rescan_values`, {
|
|
811
|
-
...options,
|
|
812
|
-
method: "POST"
|
|
813
|
-
})).status
|
|
814
|
-
};
|
|
815
|
-
}
|
|
816
|
-
return {
|
|
817
|
-
list,
|
|
818
|
-
get,
|
|
819
|
-
schemas,
|
|
820
|
-
schemaTables,
|
|
821
|
-
syncSchema,
|
|
822
|
-
rescanValues
|
|
823
|
-
};
|
|
824
|
-
}
|
|
825
|
-
//#endregion
|
|
826
|
-
//#region ../client/src/resources/dataset.ts
|
|
827
|
-
function datasetResource(transport) {
|
|
828
|
-
/**
|
|
829
|
-
* Run an ad-hoc query and return its result envelope. The body is a whole query — MBQL 5, legacy
|
|
830
|
-
* MBQL, or native — rather than a reference to a saved one, so nothing here is a card.
|
|
831
|
-
*/
|
|
832
|
-
async function query(body, options = {}) {
|
|
833
|
-
return transport.requestParsed(CardQueryResult, "/api/dataset", {
|
|
834
|
-
...options,
|
|
835
|
-
method: "POST",
|
|
836
|
-
body
|
|
837
|
-
});
|
|
838
|
-
}
|
|
839
|
-
return { query };
|
|
840
|
-
}
|
|
841
|
-
//#endregion
|
|
842
|
-
//#region ../client/src/resources/document.ts
|
|
843
|
-
const DocumentApiList = z.object({ items: z.array(Document) }).loose();
|
|
844
|
-
function documentResource(transport) {
|
|
845
|
-
/** Get existing documents. */
|
|
846
|
-
async function list(options = {}) {
|
|
847
|
-
return {
|
|
848
|
-
data: (await transport.requestParsed(DocumentApiList, "/api/document", { ...options })).items,
|
|
849
|
-
total: null
|
|
850
|
-
};
|
|
851
|
-
}
|
|
852
|
-
/** Return an existing document by id. */
|
|
853
|
-
async function get(id, options = {}) {
|
|
854
|
-
return transport.requestParsed(Document, `/api/document/${id}`, { ...options });
|
|
855
|
-
}
|
|
856
|
-
/** Create a new document. */
|
|
857
|
-
async function create(params, options = {}) {
|
|
858
|
-
return transport.requestParsed(Document, "/api/document", {
|
|
859
|
-
...options,
|
|
860
|
-
method: "POST",
|
|
861
|
-
body: params
|
|
862
|
-
});
|
|
863
|
-
}
|
|
864
|
-
/** Update an existing document by id. */
|
|
865
|
-
async function update(id, params, options = {}) {
|
|
866
|
-
return transport.requestParsed(Document, `/api/document/${id}`, {
|
|
867
|
-
...options,
|
|
868
|
-
method: "PUT",
|
|
869
|
-
body: params
|
|
870
|
-
});
|
|
871
|
-
}
|
|
872
|
-
/** Archive (soft-delete) a document by id. Metabase models this as an update, not its own endpoint. */
|
|
873
|
-
async function archive(id, options = {}) {
|
|
874
|
-
return update(id, { archived: true }, options);
|
|
875
|
-
}
|
|
876
|
-
return {
|
|
877
|
-
list,
|
|
878
|
-
get,
|
|
879
|
-
create,
|
|
880
|
-
update,
|
|
881
|
-
archive
|
|
882
|
-
};
|
|
883
|
-
}
|
|
884
|
-
//#endregion
|
|
885
|
-
//#region ../client/src/resources/eid-translation.ts
|
|
886
|
-
function eidTranslationResource(transport) {
|
|
887
|
-
/**
|
|
888
|
-
* Translate entity ids to the numeric ids of the rows they name. The request groups the entity
|
|
889
|
-
* ids by model; the response is keyed by entity id, each entry carrying its model and — when the
|
|
890
|
-
* lookup succeeded — the numeric id.
|
|
891
|
-
*/
|
|
892
|
-
async function translate(params, options = {}) {
|
|
893
|
-
return transport.requestParsed(EidTranslateResult, "/api/eid-translation/translate", {
|
|
894
|
-
...options,
|
|
895
|
-
method: "POST",
|
|
896
|
-
body: params
|
|
897
|
-
});
|
|
898
|
-
}
|
|
899
|
-
return { translate };
|
|
900
|
-
}
|
|
901
|
-
//#endregion
|
|
902
|
-
//#region ../client/src/resources/field.ts
|
|
903
|
-
const FieldApiSummary = z.tuple([z.tuple([z.literal("count"), z.number().int()]), z.tuple([z.literal("distincts"), z.number().int()])]);
|
|
904
|
-
function fieldResource(transport) {
|
|
905
|
-
/** Get one field by id. */
|
|
906
|
-
async function get(id, options = {}) {
|
|
907
|
-
return transport.requestParsed(Field, `/api/field/${id}`, { ...options });
|
|
908
|
-
}
|
|
909
|
-
/** Update a field by id, patching only the fields the body carries. */
|
|
910
|
-
async function update(id, params, options = {}) {
|
|
911
|
-
return transport.requestParsed(Field, `/api/field/${id}`, {
|
|
912
|
-
...options,
|
|
913
|
-
method: "PUT",
|
|
914
|
-
body: params
|
|
915
|
-
});
|
|
916
|
-
}
|
|
917
|
-
/** Get the row count and the distinct-value count for a field. */
|
|
918
|
-
async function summary(id, options = {}) {
|
|
919
|
-
const [[, count], [, distincts]] = await transport.requestParsed(FieldApiSummary, `/api/field/${id}/summary`, { ...options });
|
|
920
|
-
return {
|
|
921
|
-
field_id: id,
|
|
922
|
-
count,
|
|
923
|
-
distincts
|
|
924
|
-
};
|
|
925
|
-
}
|
|
926
|
-
/** Get the cached distinct values Metabase holds for a field. */
|
|
927
|
-
async function values(id, options = {}) {
|
|
928
|
-
return transport.requestParsed(FieldValues, `/api/field/${id}/values`, { ...options });
|
|
929
|
-
}
|
|
930
|
-
return {
|
|
931
|
-
get,
|
|
932
|
-
update,
|
|
933
|
-
summary,
|
|
934
|
-
values
|
|
935
|
-
};
|
|
936
|
-
}
|
|
937
|
-
//#endregion
|
|
938
|
-
//#region ../client/src/resources/optional-parsed.ts
|
|
939
|
-
const NO_CONTENT_STATUS = 204;
|
|
940
|
-
async function fetchOptionalParsed(client, path, schema, options = {}) {
|
|
941
|
-
const response = await client.requestRaw(path, {
|
|
942
|
-
...options,
|
|
943
|
-
method: "GET",
|
|
944
|
-
expectContentType: "binary"
|
|
945
|
-
});
|
|
946
|
-
if (response.status === NO_CONTENT_STATUS) return null;
|
|
947
|
-
return parseJsonOrPlain(await response.text(), response.headers.get("content-type"), schema, { source: response.url });
|
|
948
|
-
}
|
|
949
|
-
//#endregion
|
|
950
|
-
//#region ../client/src/resources/git-sync.ts
|
|
951
|
-
const SyncScopeCollection = Collection.pick({
|
|
952
|
-
id: true,
|
|
953
|
-
name: true,
|
|
954
|
-
is_remote_synced: true
|
|
955
|
-
}).strip();
|
|
956
|
-
const SyncDirtyFlag = z.object({ is_dirty: z.boolean() });
|
|
957
|
-
const SyncDirtyList = z.object({ dirty: z.array(SyncDirtyItem) });
|
|
958
|
-
const SyncBranchList = z.object({ items: z.array(z.string()) });
|
|
959
|
-
const SyncImportStarted = z.object({
|
|
960
|
-
status: z.literal("success"),
|
|
961
|
-
task_id: z.number().int().positive().nullable(),
|
|
962
|
-
message: z.string().nullable().optional()
|
|
963
|
-
});
|
|
964
|
-
const SyncExportStarted = z.object({
|
|
965
|
-
message: z.string(),
|
|
966
|
-
task_id: z.number().int().positive()
|
|
967
|
-
});
|
|
968
|
-
const SyncStashStarted = z.object({
|
|
969
|
-
status: z.literal("success"),
|
|
970
|
-
message: z.string(),
|
|
971
|
-
task_id: z.number().int().positive()
|
|
972
|
-
});
|
|
973
|
-
const RemoteSyncSetting = z.string().nullable();
|
|
974
|
-
const FORBIDDEN_STATUS = 403;
|
|
975
|
-
const UNREGISTERED_STATUS = 404;
|
|
976
|
-
function isRemoteUnreadable(error) {
|
|
977
|
-
if (!(error instanceof HttpError)) return false;
|
|
978
|
-
return error.status === FORBIDDEN_STATUS || error.status === UNREGISTERED_STATUS;
|
|
979
|
-
}
|
|
980
|
-
function gitSyncResource(transport) {
|
|
981
|
-
/** Get the running or most recently finished sync task, or null when the server has none. */
|
|
982
|
-
async function currentTask(options = {}) {
|
|
983
|
-
return fetchOptionalParsed(transport, "/api/ee/remote-sync/current-task", SyncTask, options);
|
|
984
|
-
}
|
|
985
|
-
/** Request cancellation of the running sync task, and answer it in the state that left it. */
|
|
986
|
-
async function cancelTask(options = {}) {
|
|
987
|
-
return transport.requestParsed(SyncTask, "/api/ee/remote-sync/current-task/cancel", {
|
|
988
|
-
...options,
|
|
989
|
-
method: "POST"
|
|
990
|
-
});
|
|
991
|
-
}
|
|
992
|
-
/** Whether Metabase holds content changes the remote has not been told about. */
|
|
993
|
-
async function isDirty(options = {}) {
|
|
994
|
-
return (await transport.requestParsed(SyncDirtyFlag, "/api/ee/remote-sync/is-dirty", { ...options })).is_dirty;
|
|
995
|
-
}
|
|
996
|
-
/** List the objects whose local state differs from the remote. */
|
|
997
|
-
async function dirty(options = {}) {
|
|
998
|
-
return {
|
|
999
|
-
data: (await transport.requestParsed(SyncDirtyList, "/api/ee/remote-sync/dirty", { ...options })).dirty,
|
|
1000
|
-
total: null
|
|
1001
|
-
};
|
|
1002
|
-
}
|
|
1003
|
-
/**
|
|
1004
|
-
* Compare the tracked remote branch against what Metabase last imported. The server caches the
|
|
1005
|
-
* comparison; `force-refresh` re-reads the remote instead.
|
|
1006
|
-
*/
|
|
1007
|
-
async function hasRemoteChanges(params = {}, options = {}) {
|
|
1008
|
-
return transport.requestParsed(SyncRemoteChanges, "/api/ee/remote-sync/has-remote-changes", {
|
|
1009
|
-
...options,
|
|
1010
|
-
query: { "force-refresh": params["force-refresh"] }
|
|
1011
|
-
});
|
|
1012
|
-
}
|
|
1013
|
-
/**
|
|
1014
|
-
* Import content from the remote into Metabase. The endpoint queues a task and returns at once;
|
|
1015
|
-
* pass `wait` to poll that task until it reaches a terminal status. A server already up to date
|
|
1016
|
-
* answers no task id, and there is then nothing to poll.
|
|
1017
|
-
*/
|
|
1018
|
-
async function importFromRemote(params = {}, options = {}) {
|
|
1019
|
-
const started = await transport.requestParsed(SyncImportStarted, "/api/ee/remote-sync/import", {
|
|
1020
|
-
...options,
|
|
1021
|
-
method: "POST",
|
|
1022
|
-
body: {
|
|
1023
|
-
branch: params.branch,
|
|
1024
|
-
force: params.force
|
|
1025
|
-
}
|
|
1026
|
-
});
|
|
1027
|
-
const message = started.message ?? null;
|
|
1028
|
-
if (params.wait === void 0 || started.task_id === null) return {
|
|
1029
|
-
message,
|
|
1030
|
-
task_id: started.task_id
|
|
1031
|
-
};
|
|
1032
|
-
return {
|
|
1033
|
-
message,
|
|
1034
|
-
task_id: started.task_id,
|
|
1035
|
-
final: await settle(params.wait, options)
|
|
1036
|
-
};
|
|
1037
|
-
}
|
|
1038
|
-
/**
|
|
1039
|
-
* Export Metabase's content to the remote. The endpoint queues a task and returns at once; pass
|
|
1040
|
-
* `wait` to poll that task until it reaches a terminal status.
|
|
1041
|
-
*/
|
|
1042
|
-
async function exportToRemote(params = {}, options = {}) {
|
|
1043
|
-
const started = await transport.requestParsed(SyncExportStarted, "/api/ee/remote-sync/export", {
|
|
1044
|
-
...options,
|
|
1045
|
-
method: "POST",
|
|
1046
|
-
body: {
|
|
1047
|
-
branch: params.branch,
|
|
1048
|
-
message: params.message,
|
|
1049
|
-
force: params.force
|
|
1050
|
-
}
|
|
1051
|
-
});
|
|
1052
|
-
if (params.wait === void 0) return {
|
|
1053
|
-
message: started.message,
|
|
1054
|
-
task_id: started.task_id
|
|
1055
|
-
};
|
|
1056
|
-
return {
|
|
1057
|
-
message: started.message,
|
|
1058
|
-
task_id: started.task_id,
|
|
1059
|
-
final: await settle(params.wait, options)
|
|
1060
|
-
};
|
|
1061
|
-
}
|
|
1062
|
-
/**
|
|
1063
|
-
* Export Metabase's current content to a branch the remote does not have yet. The endpoint
|
|
1064
|
-
* queues a task and returns at once; pass `wait` to poll that task to a terminal status.
|
|
1065
|
-
*/
|
|
1066
|
-
async function stash(params, options = {}) {
|
|
1067
|
-
const started = await transport.requestParsed(SyncStashStarted, "/api/ee/remote-sync/stash", {
|
|
1068
|
-
...options,
|
|
1069
|
-
method: "POST",
|
|
1070
|
-
body: {
|
|
1071
|
-
new_branch: params.new_branch,
|
|
1072
|
-
message: params.message
|
|
1073
|
-
}
|
|
1074
|
-
});
|
|
1075
|
-
if (params.wait === void 0) return {
|
|
1076
|
-
status: started.status,
|
|
1077
|
-
message: started.message,
|
|
1078
|
-
task_id: started.task_id
|
|
1079
|
-
};
|
|
1080
|
-
return {
|
|
1081
|
-
status: started.status,
|
|
1082
|
-
message: started.message,
|
|
1083
|
-
task_id: started.task_id,
|
|
1084
|
-
final: await settle(params.wait, options)
|
|
1085
|
-
};
|
|
1086
|
-
}
|
|
1087
|
-
/** List the branches the configured remote carries. */
|
|
1088
|
-
async function branches(options = {}) {
|
|
1089
|
-
return {
|
|
1090
|
-
data: (await transport.requestParsed(SyncBranchList, "/api/ee/remote-sync/branches", { ...options })).items,
|
|
1091
|
-
total: null
|
|
1092
|
-
};
|
|
1093
|
-
}
|
|
1094
|
-
/** Create a branch on the remote and point git-sync at it. */
|
|
1095
|
-
async function createBranch(params, options = {}) {
|
|
1096
|
-
return transport.requestParsed(SyncBranchCreated, "/api/ee/remote-sync/create-branch", {
|
|
1097
|
-
...options,
|
|
1098
|
-
method: "POST",
|
|
1099
|
-
body: { name: params.name }
|
|
1100
|
-
});
|
|
1101
|
-
}
|
|
1102
|
-
/**
|
|
1103
|
-
* Mark one collection as git-synced, or unmark it. The server cascades the flag to descendants
|
|
1104
|
-
* by location prefix, and may queue an export task to carry the change to the remote.
|
|
1105
|
-
*/
|
|
1106
|
-
async function setCollectionSynced(collectionId, synced, options = {}) {
|
|
1107
|
-
return transport.requestParsed(SyncSettingsUpdateResult, "/api/ee/remote-sync/settings", {
|
|
1108
|
-
...options,
|
|
1109
|
-
method: "PUT",
|
|
1110
|
-
body: { collections: { [collectionId]: synced } }
|
|
1111
|
-
});
|
|
1112
|
-
}
|
|
1113
|
-
/** The collections currently in git-sync's scope. */
|
|
1114
|
-
async function syncedCollections(options = {}) {
|
|
1115
|
-
return {
|
|
1116
|
-
data: (await listCollectionsWithLibrary(transport, SyncScopeCollection, options)).filter((entry) => entry.is_remote_synced === true),
|
|
1117
|
-
total: null
|
|
1118
|
-
};
|
|
1119
|
-
}
|
|
1120
|
-
/** The remote's URL, or null when none is configured or the caller may not read it. */
|
|
1121
|
-
async function remoteUrl(options = {}) {
|
|
1122
|
-
try {
|
|
1123
|
-
const url = await fetchOptionalParsed(transport, "/api/setting/remote-sync-url", RemoteSyncSetting, options);
|
|
1124
|
-
return url === "" ? null : url;
|
|
1125
|
-
} catch (error) {
|
|
1126
|
-
if (isRemoteUnreadable(error)) return null;
|
|
1127
|
-
throw error;
|
|
1128
|
-
}
|
|
1129
|
-
}
|
|
1130
|
-
/** The branch git-sync tracks, or null when none is configured or the caller may not read it. */
|
|
1131
|
-
async function branch(options = {}) {
|
|
1132
|
-
return fetchOptionalParsed(transport, "/api/setting/remote-sync-branch", RemoteSyncSetting, options);
|
|
1133
|
-
}
|
|
1134
|
-
/**
|
|
1135
|
-
* Poll the current task until it reaches a terminal status. A server with no task at all
|
|
1136
|
-
* answers null, which is terminal in the same sense: nothing further will happen.
|
|
1137
|
-
*/
|
|
1138
|
-
async function waitForTask(wait, options = {}) {
|
|
1139
|
-
return settle(wait, options);
|
|
1140
|
-
}
|
|
1141
|
-
async function settle(wait, options) {
|
|
1142
|
-
return pollUntil(async (signal) => currentTask({
|
|
1143
|
-
...options,
|
|
1144
|
-
signal
|
|
1145
|
-
}), (task) => task === null || isSyncTaskTerminal(task.status), wait);
|
|
1146
|
-
}
|
|
1147
|
-
return {
|
|
1148
|
-
currentTask,
|
|
1149
|
-
cancelTask,
|
|
1150
|
-
isDirty,
|
|
1151
|
-
dirty,
|
|
1152
|
-
hasRemoteChanges,
|
|
1153
|
-
import: importFromRemote,
|
|
1154
|
-
export: exportToRemote,
|
|
1155
|
-
stash,
|
|
1156
|
-
branches,
|
|
1157
|
-
createBranch,
|
|
1158
|
-
setCollectionSynced,
|
|
1159
|
-
syncedCollections,
|
|
1160
|
-
remoteUrl,
|
|
1161
|
-
branch,
|
|
1162
|
-
waitForTask
|
|
1163
|
-
};
|
|
1164
|
-
}
|
|
1165
|
-
//#endregion
|
|
1166
|
-
//#region ../client/src/resources/library.ts
|
|
1167
|
-
const LIBRARY_ROOT_PATH = "/api/ee/library/";
|
|
1168
|
-
const PUBLISH_TABLES_PATH = "/api/ee/data-studio/table/publish-tables";
|
|
1169
|
-
const UNPUBLISH_TABLES_PATH = "/api/ee/data-studio/table/unpublish-tables";
|
|
1170
|
-
const LIBRARY_DATA_TYPE = "library-data";
|
|
1171
|
-
const AbsentLibrary = z.object({ data: z.null() });
|
|
1172
|
-
const LibraryOrAbsent = z.union([Library, AbsentLibrary]);
|
|
1173
|
-
const PublishTablesResponse = z.object({ target_collection: Collection.nullable() });
|
|
1174
|
-
const LibraryCollectionInfo = Collection.pick({
|
|
1175
|
-
id: true,
|
|
1176
|
-
type: true,
|
|
1177
|
-
is_remote_synced: true
|
|
1178
|
-
}).strip();
|
|
1179
|
-
function libraryResource(transport) {
|
|
1180
|
-
/** Get the Library root and its child collections, or `null` on an instance that has none. */
|
|
1181
|
-
async function get(options = {}) {
|
|
1182
|
-
const result = await transport.requestParsed(LibraryOrAbsent, LIBRARY_ROOT_PATH, { ...options });
|
|
1183
|
-
if (!("effective_children" in result)) return null;
|
|
1184
|
-
const infoById = await libraryCollectionsById(options);
|
|
1185
|
-
const effective_children = result.effective_children.map((child) => {
|
|
1186
|
-
if (typeof child.id !== "number") return child;
|
|
1187
|
-
const info = infoById.get(child.id);
|
|
1188
|
-
if (info === void 0) return child;
|
|
1189
|
-
return {
|
|
1190
|
-
...child,
|
|
1191
|
-
type: info.type ?? child.type,
|
|
1192
|
-
is_remote_synced: info.is_remote_synced ?? child.is_remote_synced
|
|
1193
|
-
};
|
|
1194
|
-
});
|
|
1195
|
-
return {
|
|
1196
|
-
...result,
|
|
1197
|
-
effective_children
|
|
1198
|
-
};
|
|
1199
|
-
}
|
|
1200
|
-
async function libraryCollectionsById(options) {
|
|
1201
|
-
const data = await listCollectionsWithLibrary(transport, LibraryCollectionInfo, options);
|
|
1202
|
-
const byId = /* @__PURE__ */ new Map();
|
|
1203
|
-
for (const collection of data) if (typeof collection.id === "number") byId.set(collection.id, collection);
|
|
1204
|
-
return byId;
|
|
1205
|
-
}
|
|
1206
|
-
/**
|
|
1207
|
-
* Create the Library subtree (its Data and Metrics collections). Metabase takes no body, rejects
|
|
1208
|
-
* a second create with a 400, and answers the bare root collection without its
|
|
1209
|
-
* `effective_children` — so an existing Library short-circuits the call and a fresh one comes
|
|
1210
|
-
* back from a refetch, which together make this idempotent.
|
|
1211
|
-
*/
|
|
1212
|
-
async function create(options = {}) {
|
|
1213
|
-
const existing = await get(options);
|
|
1214
|
-
if (existing !== null) return existing;
|
|
1215
|
-
await transport.requestRaw(LIBRARY_ROOT_PATH, {
|
|
1216
|
-
...options,
|
|
1217
|
-
method: "POST"
|
|
1218
|
-
});
|
|
1219
|
-
const created = await get(options);
|
|
1220
|
-
if (created === null) throw new Error(`Library was not created after POST ${LIBRARY_ROOT_PATH}`);
|
|
1221
|
-
return created;
|
|
1222
|
-
}
|
|
1223
|
-
/** The id of the Library's Data collection, creating the Library first when it does not exist. */
|
|
1224
|
-
async function ensureDataCollectionId(options = {}) {
|
|
1225
|
-
const data = (await create(options)).effective_children.find((child) => child.type === LIBRARY_DATA_TYPE);
|
|
1226
|
-
if (data === void 0) throw new Error("Library has no Data collection to publish into");
|
|
1227
|
-
if (typeof data.id !== "number") throw new Error(`Library Data collection has a non-numeric id ${String(data.id)}`);
|
|
1228
|
-
return data.id;
|
|
1229
|
-
}
|
|
1230
|
-
/**
|
|
1231
|
-
* Publish tables — and every upstream table they depend on — into a collection, so they lead the
|
|
1232
|
-
* data pickers and rank up in search. Answers the collection they landed in.
|
|
1233
|
-
*/
|
|
1234
|
-
async function publishTables(params, options = {}) {
|
|
1235
|
-
return (await transport.requestParsed(PublishTablesResponse, PUBLISH_TABLES_PATH, {
|
|
1236
|
-
...options,
|
|
1237
|
-
method: "POST",
|
|
1238
|
-
body: params
|
|
1239
|
-
})).target_collection;
|
|
1240
|
-
}
|
|
1241
|
-
/**
|
|
1242
|
-
* Clear the Library collection from tables, and recursively from every downstream table that
|
|
1243
|
-
* depends on them. The endpoint answers no JSON body.
|
|
1244
|
-
*/
|
|
1245
|
-
async function unpublishTables(params, options = {}) {
|
|
1246
|
-
await transport.requestRaw(UNPUBLISH_TABLES_PATH, {
|
|
1247
|
-
...options,
|
|
1248
|
-
method: "POST",
|
|
1249
|
-
body: params,
|
|
1250
|
-
expectContentType: "binary"
|
|
1251
|
-
});
|
|
1252
|
-
}
|
|
1253
|
-
return {
|
|
1254
|
-
get,
|
|
1255
|
-
create,
|
|
1256
|
-
ensureDataCollectionId,
|
|
1257
|
-
publishTables,
|
|
1258
|
-
unpublishTables
|
|
1259
|
-
};
|
|
1260
|
-
}
|
|
1261
|
-
//#endregion
|
|
1262
|
-
//#region ../client/src/resources/measure.ts
|
|
1263
|
-
const MeasureApiList = z.array(Measure);
|
|
1264
|
-
function measureResource(transport) {
|
|
1265
|
-
/** List measures. */
|
|
1266
|
-
async function list(options = {}) {
|
|
1267
|
-
return {
|
|
1268
|
-
data: await transport.requestParsed(MeasureApiList, "/api/measure", { ...options }),
|
|
1269
|
-
total: null
|
|
1270
|
-
};
|
|
1271
|
-
}
|
|
1272
|
-
/** Get one measure by id. */
|
|
1273
|
-
async function get(id, options = {}) {
|
|
1274
|
-
return transport.requestParsed(Measure, `/api/measure/${id}`, { ...options });
|
|
1275
|
-
}
|
|
1276
|
-
/** Create a measure — a saved aggregation tied to a table — from a full measure body. */
|
|
1277
|
-
async function create(params, options = {}) {
|
|
1278
|
-
return transport.requestParsed(Measure, "/api/measure", {
|
|
1279
|
-
...options,
|
|
1280
|
-
method: "POST",
|
|
1281
|
-
body: params
|
|
1282
|
-
});
|
|
1283
|
-
}
|
|
1284
|
-
/**
|
|
1285
|
-
* Update a measure by id, patching only the fields the body carries. `revision_message` is
|
|
1286
|
-
* required and lands in the audit log.
|
|
1287
|
-
*/
|
|
1288
|
-
async function update(id, params, options = {}) {
|
|
1289
|
-
return transport.requestParsed(Measure, `/api/measure/${id}`, {
|
|
1290
|
-
...options,
|
|
1291
|
-
method: "PUT",
|
|
1292
|
-
body: params
|
|
1293
|
-
});
|
|
1294
|
-
}
|
|
1295
|
-
/**
|
|
1296
|
-
* Archive (soft-delete) a measure by id. Metabase models this as an update, not its own endpoint,
|
|
1297
|
-
* so it carries the same required `revision_message`.
|
|
1298
|
-
*/
|
|
1299
|
-
async function archive(id, params, options = {}) {
|
|
1300
|
-
return update(id, {
|
|
1301
|
-
archived: true,
|
|
1302
|
-
revision_message: params.revision_message
|
|
1303
|
-
}, options);
|
|
1304
|
-
}
|
|
1305
|
-
return {
|
|
1306
|
-
list,
|
|
1307
|
-
get,
|
|
1308
|
-
create,
|
|
1309
|
-
update,
|
|
1310
|
-
archive
|
|
1311
|
-
};
|
|
1312
|
-
}
|
|
1313
|
-
//#endregion
|
|
1314
|
-
//#region ../client/src/resources/notification.ts
|
|
1315
|
-
const NotificationApiList = z.array(Notification);
|
|
1316
|
-
function assertCardAlert(notification) {
|
|
1317
|
-
if (notification.payload_type !== "notification/card") throw new ConfigError(`notification ${notification.id} is a ${notification.payload_type}, not a question alert — this operation accepts card alerts only`);
|
|
1318
|
-
return notification;
|
|
1319
|
-
}
|
|
1320
|
-
function mergeAlertUpdate(current, patch) {
|
|
1321
|
-
return Notification.parse({
|
|
1322
|
-
...current,
|
|
1323
|
-
...patch,
|
|
1324
|
-
id: current.id,
|
|
1325
|
-
payload: patch.payload === void 0 ? current.payload : mergePayload(current, patch.payload)
|
|
1326
|
-
});
|
|
1327
|
-
}
|
|
1328
|
-
function mergePayload(current, patch) {
|
|
1329
|
-
if (current.payload === null) throw new ConfigError(`alert ${current.id} has lost its card payload — it can be archived, but not patched`);
|
|
1330
|
-
return NotificationCardPayload.parse({
|
|
1331
|
-
...current.payload,
|
|
1332
|
-
...patch
|
|
1333
|
-
});
|
|
1334
|
-
}
|
|
1335
|
-
function notificationResource(transport) {
|
|
1336
|
-
/**
|
|
1337
|
-
* List question alerts, optionally narrowed by the card they watch, their creator, or a
|
|
1338
|
-
* recipient. `/api/notification` also serves Metabase's internal system-event notifications, so
|
|
1339
|
-
* the request pins the card payload type.
|
|
1340
|
-
*/
|
|
1341
|
-
async function list(params = {}, options = {}) {
|
|
1342
|
-
return {
|
|
1343
|
-
data: await transport.requestParsed(NotificationApiList, "/api/notification", {
|
|
1344
|
-
...options,
|
|
1345
|
-
query: {
|
|
1346
|
-
payload_type: CARD_PAYLOAD_TYPE,
|
|
1347
|
-
card_id: params.card_id,
|
|
1348
|
-
creator_id: params.creator_id,
|
|
1349
|
-
recipient_id: params.recipient_id,
|
|
1350
|
-
include_inactive: params.include_inactive
|
|
1351
|
-
}
|
|
1352
|
-
}),
|
|
1353
|
-
total: null
|
|
1354
|
-
};
|
|
1355
|
-
}
|
|
1356
|
-
/** Get one question alert by id, refusing an id that names a system-event notification. */
|
|
1357
|
-
async function get(id, options = {}) {
|
|
1358
|
-
return assertCardAlert(await transport.requestParsed(Notification, `/api/notification/${id}`, { ...options }));
|
|
1359
|
-
}
|
|
1360
|
-
/** Create a question alert — its card payload, schedules and handlers — from a full body. */
|
|
1361
|
-
async function create(params, options = {}) {
|
|
1362
|
-
return transport.requestParsed(Notification, "/api/notification", {
|
|
1363
|
-
...options,
|
|
1364
|
-
method: "POST",
|
|
1365
|
-
body: params
|
|
1366
|
-
});
|
|
1367
|
-
}
|
|
1368
|
-
/** Update a question alert by id, merging the patch over the stored notification. */
|
|
1369
|
-
async function update(id, params, options = {}) {
|
|
1370
|
-
const current = await get(id, options);
|
|
1371
|
-
return transport.requestParsed(Notification, `/api/notification/${id}`, {
|
|
1372
|
-
...options,
|
|
1373
|
-
method: "PUT",
|
|
1374
|
-
body: mergeAlertUpdate(current, params)
|
|
1375
|
-
});
|
|
1376
|
-
}
|
|
1377
|
-
/** Archive a question alert by id, stopping every delivery. Metabase models this as an update. */
|
|
1378
|
-
async function archive(id, options = {}) {
|
|
1379
|
-
return update(id, { active: false }, options);
|
|
1380
|
-
}
|
|
1381
|
-
/**
|
|
1382
|
-
* Send a question alert now, off-schedule, to every handler on it. The server answers with no
|
|
1383
|
-
* body.
|
|
1384
|
-
*/
|
|
1385
|
-
async function send(id, options = {}) {
|
|
1386
|
-
await get(id, options);
|
|
1387
|
-
await transport.requestRaw(`/api/notification/${id}/send`, {
|
|
1388
|
-
...options,
|
|
1389
|
-
method: "POST",
|
|
1390
|
-
expectContentType: "binary"
|
|
1391
|
-
});
|
|
1392
|
-
}
|
|
1393
|
-
return {
|
|
1394
|
-
list,
|
|
1395
|
-
get,
|
|
1396
|
-
create,
|
|
1397
|
-
update,
|
|
1398
|
-
archive,
|
|
1399
|
-
send
|
|
1400
|
-
};
|
|
1401
|
-
}
|
|
1402
|
-
//#endregion
|
|
1403
|
-
//#region ../client/src/resources/pulse.ts
|
|
1404
|
-
const PulseApiList = z.array(Pulse);
|
|
1405
|
-
function mergePulseUpdate(current, patch) {
|
|
1406
|
-
return {
|
|
1407
|
-
...patch,
|
|
1408
|
-
archived: patch.archived ?? current.archived,
|
|
1409
|
-
skip_if_empty: patch.skip_if_empty ?? current.skip_if_empty
|
|
1410
|
-
};
|
|
1411
|
-
}
|
|
1412
|
-
function pulseResource(transport) {
|
|
1413
|
-
/** List dashboard subscriptions, optionally narrowed to one dashboard or to the archived ones. */
|
|
1414
|
-
async function list(params = {}, options = {}) {
|
|
1415
|
-
return {
|
|
1416
|
-
data: await transport.requestParsed(PulseApiList, "/api/pulse", {
|
|
1417
|
-
...options,
|
|
1418
|
-
query: {
|
|
1419
|
-
dashboard_id: params.dashboard_id,
|
|
1420
|
-
archived: params.archived
|
|
1421
|
-
}
|
|
1422
|
-
}),
|
|
1423
|
-
total: null
|
|
1424
|
-
};
|
|
1425
|
-
}
|
|
1426
|
-
/** Get one dashboard subscription by id. */
|
|
1427
|
-
async function get(id, options = {}) {
|
|
1428
|
-
return transport.requestParsed(Pulse, `/api/pulse/${id}`, { ...options });
|
|
1429
|
-
}
|
|
1430
|
-
/** Create a dashboard subscription — its cards and its delivery channels — from a full body. */
|
|
1431
|
-
async function create(params, options = {}) {
|
|
1432
|
-
return transport.requestParsed(Pulse, "/api/pulse", {
|
|
1433
|
-
...options,
|
|
1434
|
-
method: "POST",
|
|
1435
|
-
body: params
|
|
1436
|
-
});
|
|
1437
|
-
}
|
|
1438
|
-
/** Update a dashboard subscription by id, carrying the server-defaulted flags forward. */
|
|
1439
|
-
async function update(id, params, options = {}) {
|
|
1440
|
-
const current = await get(id, options);
|
|
1441
|
-
return transport.requestParsed(Pulse, `/api/pulse/${id}`, {
|
|
1442
|
-
...options,
|
|
1443
|
-
method: "PUT",
|
|
1444
|
-
body: mergePulseUpdate(current, params)
|
|
1445
|
-
});
|
|
1446
|
-
}
|
|
1447
|
-
/**
|
|
1448
|
-
* Archive a dashboard subscription by id, stopping every delivery. Metabase models this as an
|
|
1449
|
-
* update, and disables each of the subscription's channels as a side effect.
|
|
1450
|
-
*/
|
|
1451
|
-
async function archive(id, options = {}) {
|
|
1452
|
-
return update(id, { archived: true }, options);
|
|
1453
|
-
}
|
|
1454
|
-
return {
|
|
1455
|
-
list,
|
|
1456
|
-
get,
|
|
1457
|
-
create,
|
|
1458
|
-
update,
|
|
1459
|
-
archive
|
|
1460
|
-
};
|
|
1461
|
-
}
|
|
1462
|
-
//#endregion
|
|
1463
|
-
//#region ../client/src/resources/search.ts
|
|
1464
|
-
const SearchApiResponse = z.object({
|
|
1465
|
-
data: z.array(SearchResult),
|
|
1466
|
-
total: z.number().int().nonnegative()
|
|
1467
|
-
}).loose();
|
|
1468
|
-
function searchResource(transport) {
|
|
1469
|
-
/**
|
|
1470
|
-
* Search over the instance's content, ranked against `q`. `models` narrows which kinds of entity
|
|
1471
|
-
* may match, `archived` swaps the active set for the archived one, `table_db_id` restricts to
|
|
1472
|
-
* items on one database, `verified` to verified content, and `limit`/`offset` are the window the
|
|
1473
|
-
* server applies before ranking hydration.
|
|
1474
|
-
*/
|
|
1475
|
-
async function query(params = {}, options = {}) {
|
|
1476
|
-
const response = await transport.requestParsed(SearchApiResponse, "/api/search", {
|
|
1477
|
-
...options,
|
|
1478
|
-
query: {
|
|
1479
|
-
q: params.q,
|
|
1480
|
-
models: params.models,
|
|
1481
|
-
archived: params.archived,
|
|
1482
|
-
limit: params.limit,
|
|
1483
|
-
offset: params.offset,
|
|
1484
|
-
table_db_id: params.table_db_id,
|
|
1485
|
-
verified: params.verified
|
|
1486
|
-
}
|
|
1487
|
-
});
|
|
1488
|
-
return {
|
|
1489
|
-
data: response.data,
|
|
1490
|
-
total: response.total
|
|
1491
|
-
};
|
|
1492
|
-
}
|
|
1493
|
-
return { query };
|
|
1494
|
-
}
|
|
1495
|
-
//#endregion
|
|
1496
|
-
//#region ../client/src/resources/segment.ts
|
|
1497
|
-
const SegmentApiList = z.array(Segment);
|
|
1498
|
-
function segmentResource(transport) {
|
|
1499
|
-
/** List every segment the caller can see. */
|
|
1500
|
-
async function list(options = {}) {
|
|
1501
|
-
return {
|
|
1502
|
-
data: await transport.requestParsed(SegmentApiList, "/api/segment", { ...options }),
|
|
1503
|
-
total: null
|
|
1504
|
-
};
|
|
1505
|
-
}
|
|
1506
|
-
/** Get one segment by id. */
|
|
1507
|
-
async function get(id, options = {}) {
|
|
1508
|
-
return transport.requestParsed(Segment, `/api/segment/${id}`, { ...options });
|
|
1509
|
-
}
|
|
1510
|
-
/** Create a segment — a reusable row filter over one table — from a full segment body. */
|
|
1511
|
-
async function create(params, options = {}) {
|
|
1512
|
-
return transport.requestParsed(Segment, "/api/segment", {
|
|
1513
|
-
...options,
|
|
1514
|
-
method: "POST",
|
|
1515
|
-
body: params
|
|
1516
|
-
});
|
|
1517
|
-
}
|
|
1518
|
-
/**
|
|
1519
|
-
* Update a segment by id, patching only the fields the body carries. `revision_message` is
|
|
1520
|
-
* required: Metabase records every segment change in its revision history.
|
|
1521
|
-
*/
|
|
1522
|
-
async function update(id, params, options = {}) {
|
|
1523
|
-
return transport.requestParsed(Segment, `/api/segment/${id}`, {
|
|
1524
|
-
...options,
|
|
1525
|
-
method: "PUT",
|
|
1526
|
-
body: params
|
|
1527
|
-
});
|
|
1528
|
-
}
|
|
1529
|
-
/**
|
|
1530
|
-
* Archive (soft-delete) a segment by id. Metabase models this as an update, so it carries the
|
|
1531
|
-
* same required `revision_message`.
|
|
1532
|
-
*/
|
|
1533
|
-
async function archive(id, params, options = {}) {
|
|
1534
|
-
return update(id, {
|
|
1535
|
-
archived: true,
|
|
1536
|
-
revision_message: params.revision_message
|
|
1537
|
-
}, options);
|
|
1538
|
-
}
|
|
1539
|
-
return {
|
|
1540
|
-
list,
|
|
1541
|
-
get,
|
|
1542
|
-
create,
|
|
1543
|
-
update,
|
|
1544
|
-
archive
|
|
1545
|
-
};
|
|
1546
|
-
}
|
|
1547
|
-
//#endregion
|
|
1548
|
-
//#region ../client/src/resources/setting.ts
|
|
1549
|
-
const SettingApiList = z.array(Setting);
|
|
1550
|
-
const UNKNOWN_SETTING_PREFIX = "Unknown setting:";
|
|
1551
|
-
function rethrowSettingError(error, key) {
|
|
1552
|
-
if (errorMessage(error).startsWith(UNKNOWN_SETTING_PREFIX)) throw new ConfigError(`unknown setting: ${key}`);
|
|
1553
|
-
throw error;
|
|
1554
|
-
}
|
|
1555
|
-
function settingResource(transport) {
|
|
1556
|
-
/** Get all settings and their values, with descriptions and environment-variable names. */
|
|
1557
|
-
async function list(options = {}) {
|
|
1558
|
-
return {
|
|
1559
|
-
data: await transport.requestParsed(SettingApiList, "/api/setting", { ...options }),
|
|
1560
|
-
total: null
|
|
1561
|
-
};
|
|
1562
|
-
}
|
|
1563
|
-
/**
|
|
1564
|
-
* Fetch a single setting's value by key. An unset setting answers 204 rather than 404, which
|
|
1565
|
-
* reaches the caller as `null`; older servers answer the value as bare text rather than JSON.
|
|
1566
|
-
*/
|
|
1567
|
-
async function get(key, options = {}) {
|
|
1568
|
-
return fetchOptionalParsed(transport, `/api/setting/${encodeURIComponent(key)}`, z.unknown(), options).catch((error) => rethrowSettingError(error, key));
|
|
1569
|
-
}
|
|
1570
|
-
/** Set a single setting's value by key. The endpoint answers 204 with no body. */
|
|
1571
|
-
async function set(key, value, options = {}) {
|
|
1572
|
-
await transport.requestRaw(`/api/setting/${encodeURIComponent(key)}`, {
|
|
1573
|
-
...options,
|
|
1574
|
-
method: "PUT",
|
|
1575
|
-
body: { value },
|
|
1576
|
-
expectContentType: "binary"
|
|
1577
|
-
}).catch((error) => rethrowSettingError(error, key));
|
|
1578
|
-
}
|
|
1579
|
-
return {
|
|
1580
|
-
list,
|
|
1581
|
-
get,
|
|
1582
|
-
set
|
|
1583
|
-
};
|
|
1584
|
-
}
|
|
1585
|
-
//#endregion
|
|
1586
|
-
//#region ../client/src/resources/setup.ts
|
|
1587
|
-
function setupResource(transport) {
|
|
1588
|
-
/**
|
|
1589
|
-
* Complete the initial setup wizard on a fresh instance, creating its first admin user and
|
|
1590
|
-
* applying the instance preferences. The setup token is single-use.
|
|
1591
|
-
*/
|
|
1592
|
-
async function create(params, options = {}) {
|
|
1593
|
-
return transport.requestParsed(SetupResult, "/api/setup", {
|
|
1594
|
-
...options,
|
|
1595
|
-
method: "POST",
|
|
1596
|
-
body: params
|
|
1597
|
-
});
|
|
1598
|
-
}
|
|
1599
|
-
return { create };
|
|
1600
|
-
}
|
|
1601
|
-
//#endregion
|
|
1602
|
-
//#region ../client/src/resources/snippet.ts
|
|
1603
|
-
const SnippetApiList = z.array(Snippet);
|
|
1604
|
-
function snippetResource(transport) {
|
|
1605
|
-
/** List native query snippets. `archived` swaps the listing to archived snippets. */
|
|
1606
|
-
async function list(params = {}, options = {}) {
|
|
1607
|
-
return {
|
|
1608
|
-
data: await transport.requestParsed(SnippetApiList, "/api/native-query-snippet", {
|
|
1609
|
-
...options,
|
|
1610
|
-
query: { archived: params.archived }
|
|
1611
|
-
}),
|
|
1612
|
-
total: null
|
|
1613
|
-
};
|
|
1614
|
-
}
|
|
1615
|
-
/** Get one native query snippet by id. */
|
|
1616
|
-
async function get(id, options = {}) {
|
|
1617
|
-
return transport.requestParsed(Snippet, `/api/native-query-snippet/${id}`, { ...options });
|
|
1618
|
-
}
|
|
1619
|
-
/** Create a native query snippet from a name, its SQL fragment, and an optional collection. */
|
|
1620
|
-
async function create(params, options = {}) {
|
|
1621
|
-
return transport.requestParsed(Snippet, "/api/native-query-snippet", {
|
|
1622
|
-
...options,
|
|
1623
|
-
method: "POST",
|
|
1624
|
-
body: params
|
|
1625
|
-
});
|
|
1626
|
-
}
|
|
1627
|
-
/** Update a native query snippet by id, patching only the fields the body carries. */
|
|
1628
|
-
async function update(id, params, options = {}) {
|
|
1629
|
-
return transport.requestParsed(Snippet, `/api/native-query-snippet/${id}`, {
|
|
1630
|
-
...options,
|
|
1631
|
-
method: "PUT",
|
|
1632
|
-
body: params
|
|
1633
|
-
});
|
|
1634
|
-
}
|
|
1635
|
-
/**
|
|
1636
|
-
* Archive (soft-delete) a native query snippet by id. Metabase models this as an update, not its
|
|
1637
|
-
* own endpoint.
|
|
1638
|
-
*/
|
|
1639
|
-
async function archive(id, options = {}) {
|
|
1640
|
-
return update(id, { archived: true }, options);
|
|
1641
|
-
}
|
|
1642
|
-
return {
|
|
1643
|
-
list,
|
|
1644
|
-
get,
|
|
1645
|
-
create,
|
|
1646
|
-
update,
|
|
1647
|
-
archive
|
|
1648
|
-
};
|
|
1649
|
-
}
|
|
1650
|
-
//#endregion
|
|
1651
|
-
//#region ../client/src/resources/table.ts
|
|
1652
|
-
const TableApiList = z.array(Table);
|
|
1653
|
-
const UPLOAD_UPDATE_PATHS = {
|
|
1654
|
-
append: "append-csv",
|
|
1655
|
-
replace: "replace-csv"
|
|
1656
|
-
};
|
|
1657
|
-
function tableResource(transport) {
|
|
1658
|
-
/** List every table the caller can see, across all databases. */
|
|
1659
|
-
async function list(options = {}) {
|
|
1660
|
-
return {
|
|
1661
|
-
data: await transport.requestParsed(TableApiList, "/api/table", { ...options }),
|
|
1662
|
-
total: null
|
|
1663
|
-
};
|
|
1664
|
-
}
|
|
1665
|
-
/** Get one table by id, without its fields. */
|
|
1666
|
-
async function get(id, options = {}) {
|
|
1667
|
-
return transport.requestParsed(Table, `/api/table/${id}`, { ...options });
|
|
1668
|
-
}
|
|
1669
|
-
/** Update a table by id, patching only the fields the body carries. */
|
|
1670
|
-
async function update(id, params, options = {}) {
|
|
1671
|
-
return transport.requestParsed(Table, `/api/table/${id}`, {
|
|
1672
|
-
...options,
|
|
1673
|
-
method: "PUT",
|
|
1674
|
-
body: params
|
|
1675
|
-
});
|
|
1676
|
-
}
|
|
1677
|
-
/** Get a table by id with its fields hydrated — the metadata the query builder runs on. */
|
|
1678
|
-
async function queryMetadata(id, options = {}) {
|
|
1679
|
-
return transport.requestParsed(TableQueryMetadata, `/api/table/${id}/query_metadata`, { ...options });
|
|
1680
|
-
}
|
|
1681
|
-
async function updateFromCsv(id, action, file, options) {
|
|
1682
|
-
await transport.requestRaw(`/api/table/${id}/${UPLOAD_UPDATE_PATHS[action]}`, {
|
|
1683
|
-
...options,
|
|
1684
|
-
method: "POST",
|
|
1685
|
-
body: buildCsvFormData(file),
|
|
1686
|
-
expectContentType: "binary"
|
|
1687
|
-
});
|
|
1688
|
-
return {
|
|
1689
|
-
table_id: id,
|
|
1690
|
-
action
|
|
1691
|
-
};
|
|
1692
|
-
}
|
|
1693
|
-
/**
|
|
1694
|
-
* Inserts the rows of an uploaded CSV file into the table identified by `id`. The table must have
|
|
1695
|
-
* been created by uploading a CSV file.
|
|
1696
|
-
*
|
|
1697
|
-
* The file may be at most 50 MB; larger uploads are rejected with a 413 response.
|
|
1698
|
-
*/
|
|
1699
|
-
async function appendCsv(id, file, options = {}) {
|
|
1700
|
-
return updateFromCsv(id, "append", file, options);
|
|
1701
|
-
}
|
|
1702
|
-
/**
|
|
1703
|
-
* Replaces the contents of the table identified by `id` with the rows of an uploaded CSV file.
|
|
1704
|
-
* The table must have been created by uploading a CSV file.
|
|
1705
|
-
*
|
|
1706
|
-
* The file may be at most 50 MB; larger uploads are rejected with a 413 response.
|
|
1707
|
-
*/
|
|
1708
|
-
async function replaceCsv(id, file, options = {}) {
|
|
1709
|
-
return updateFromCsv(id, "replace", file, options);
|
|
1710
|
-
}
|
|
1711
|
-
return {
|
|
1712
|
-
list,
|
|
1713
|
-
get,
|
|
1714
|
-
update,
|
|
1715
|
-
queryMetadata,
|
|
1716
|
-
appendCsv,
|
|
1717
|
-
replaceCsv
|
|
1718
|
-
};
|
|
1719
|
-
}
|
|
1720
|
-
//#endregion
|
|
1721
|
-
//#region ../client/src/resources/timeline-event.ts
|
|
1722
|
-
function timelineEventResource(transport) {
|
|
1723
|
-
/** Get one timeline event by id. */
|
|
1724
|
-
async function get(id, options = {}) {
|
|
1725
|
-
return transport.requestParsed(TimelineEvent, `/api/timeline-event/${id}`, { ...options });
|
|
1726
|
-
}
|
|
1727
|
-
/** Create a timeline event on an existing timeline. */
|
|
1728
|
-
async function create(params, options = {}) {
|
|
1729
|
-
return transport.requestParsed(TimelineEvent, "/api/timeline-event", {
|
|
1730
|
-
...options,
|
|
1731
|
-
method: "POST",
|
|
1732
|
-
body: params
|
|
1733
|
-
});
|
|
1734
|
-
}
|
|
1735
|
-
/**
|
|
1736
|
-
* Update a timeline event by id, patching only the fields the body carries. `timeline_id` moves
|
|
1737
|
-
* the event to another timeline.
|
|
1738
|
-
*/
|
|
1739
|
-
async function update(id, params, options = {}) {
|
|
1740
|
-
return transport.requestParsed(TimelineEvent, `/api/timeline-event/${id}`, {
|
|
1741
|
-
...options,
|
|
1742
|
-
method: "PUT",
|
|
1743
|
-
body: params
|
|
1744
|
-
});
|
|
1745
|
-
}
|
|
1746
|
-
/**
|
|
1747
|
-
* Archive (soft-delete) a timeline event by id. Metabase models this as an update, not its own
|
|
1748
|
-
* endpoint.
|
|
1749
|
-
*/
|
|
1750
|
-
async function archive(id, options = {}) {
|
|
1751
|
-
return update(id, { archived: true }, options);
|
|
1752
|
-
}
|
|
1753
|
-
/** Permanently delete a timeline event by id. The server answers with no body. */
|
|
1754
|
-
async function remove(id, options = {}) {
|
|
1755
|
-
await transport.requestRaw(`/api/timeline-event/${id}`, {
|
|
1756
|
-
...options,
|
|
1757
|
-
method: "DELETE",
|
|
1758
|
-
expectContentType: "binary"
|
|
1759
|
-
});
|
|
1760
|
-
}
|
|
1761
|
-
return {
|
|
1762
|
-
get,
|
|
1763
|
-
create,
|
|
1764
|
-
update,
|
|
1765
|
-
archive,
|
|
1766
|
-
delete: remove
|
|
1767
|
-
};
|
|
1768
|
-
}
|
|
1769
|
-
//#endregion
|
|
1770
|
-
//#region ../client/src/resources/timeline.ts
|
|
1771
|
-
const TimelineApiList = z.array(Timeline);
|
|
1772
|
-
const TimelineWithEvents = Timeline.required({ events: true });
|
|
1773
|
-
function timelineResource(transport) {
|
|
1774
|
-
/** List timelines. `archived` swaps the active listing for the archived one. */
|
|
1775
|
-
async function list(params = {}, options = {}) {
|
|
1776
|
-
return {
|
|
1777
|
-
data: await transport.requestParsed(TimelineApiList, "/api/timeline", {
|
|
1778
|
-
...options,
|
|
1779
|
-
query: { archived: params.archived }
|
|
1780
|
-
}),
|
|
1781
|
-
total: null
|
|
1782
|
-
};
|
|
1783
|
-
}
|
|
1784
|
-
/** Get one timeline by id, without its events. */
|
|
1785
|
-
async function get(id, options = {}) {
|
|
1786
|
-
return transport.requestParsed(Timeline, `/api/timeline/${id}`, { ...options });
|
|
1787
|
-
}
|
|
1788
|
-
/**
|
|
1789
|
-
* List the events on one timeline. Metabase has no endpoint of its own for these: the same
|
|
1790
|
-
* timeline read hydrates them on request, and `archived` chooses which of them come back.
|
|
1791
|
-
*/
|
|
1792
|
-
async function events(id, params = {}, options = {}) {
|
|
1793
|
-
return {
|
|
1794
|
-
data: (await transport.requestParsed(TimelineWithEvents, `/api/timeline/${id}`, {
|
|
1795
|
-
...options,
|
|
1796
|
-
query: {
|
|
1797
|
-
include: "events",
|
|
1798
|
-
archived: params.archived
|
|
1799
|
-
}
|
|
1800
|
-
})).events,
|
|
1801
|
-
total: null
|
|
1802
|
-
};
|
|
1803
|
-
}
|
|
1804
|
-
/** Create a timeline from a full timeline body. */
|
|
1805
|
-
async function create(params, options = {}) {
|
|
1806
|
-
return transport.requestParsed(Timeline, "/api/timeline", {
|
|
1807
|
-
...options,
|
|
1808
|
-
method: "POST",
|
|
1809
|
-
body: params
|
|
1810
|
-
});
|
|
1811
|
-
}
|
|
1812
|
-
/**
|
|
1813
|
-
* Update a timeline by id, patching only the fields the body carries. Changing `archived`
|
|
1814
|
-
* cascades to every event on the timeline.
|
|
1815
|
-
*/
|
|
1816
|
-
async function update(id, params, options = {}) {
|
|
1817
|
-
return transport.requestParsed(Timeline, `/api/timeline/${id}`, {
|
|
1818
|
-
...options,
|
|
1819
|
-
method: "PUT",
|
|
1820
|
-
body: params
|
|
1821
|
-
});
|
|
1822
|
-
}
|
|
1823
|
-
/**
|
|
1824
|
-
* Archive (soft-delete) a timeline and all its events by id. Metabase models this as an update,
|
|
1825
|
-
* not its own endpoint.
|
|
1826
|
-
*/
|
|
1827
|
-
async function archive(id, options = {}) {
|
|
1828
|
-
return update(id, { archived: true }, options);
|
|
1829
|
-
}
|
|
1830
|
-
/** Permanently delete a timeline and all its events by id. The server answers with no body. */
|
|
1831
|
-
async function remove(id, options = {}) {
|
|
1832
|
-
await transport.requestRaw(`/api/timeline/${id}`, {
|
|
1833
|
-
...options,
|
|
1834
|
-
method: "DELETE",
|
|
1835
|
-
expectContentType: "binary"
|
|
1836
|
-
});
|
|
1837
|
-
}
|
|
1838
|
-
return {
|
|
1839
|
-
list,
|
|
1840
|
-
get,
|
|
1841
|
-
events,
|
|
1842
|
-
create,
|
|
1843
|
-
update,
|
|
1844
|
-
archive,
|
|
1845
|
-
delete: remove
|
|
1846
|
-
};
|
|
1847
|
-
}
|
|
1848
|
-
//#endregion
|
|
1849
|
-
//#region ../client/src/resources/transform-job.ts
|
|
1850
|
-
const TransformJobApiList = z.array(TransformJob);
|
|
1851
|
-
const TransformApiList$1 = z.array(Transform);
|
|
1852
|
-
function transformJobResource(transport) {
|
|
1853
|
-
/** List every transform job the caller can see. */
|
|
1854
|
-
async function list(options = {}) {
|
|
1855
|
-
return {
|
|
1856
|
-
data: await transport.requestParsed(TransformJobApiList, "/api/transform-job", { ...options }),
|
|
1857
|
-
total: null
|
|
1858
|
-
};
|
|
1859
|
-
}
|
|
1860
|
-
/** Get one transform job by id. */
|
|
1861
|
-
async function get(id, options = {}) {
|
|
1862
|
-
return transport.requestParsed(TransformJob, `/api/transform-job/${id}`, { ...options });
|
|
1863
|
-
}
|
|
1864
|
-
/** Create a transform job — a schedule plus the tags it runs — from a full body. */
|
|
1865
|
-
async function create(params, options = {}) {
|
|
1866
|
-
return transport.requestParsed(TransformJob, "/api/transform-job", {
|
|
1867
|
-
...options,
|
|
1868
|
-
method: "POST",
|
|
1869
|
-
body: params
|
|
1870
|
-
});
|
|
1871
|
-
}
|
|
1872
|
-
/** Update a transform job by id, patching only the fields the body carries. */
|
|
1873
|
-
async function update(id, params, options = {}) {
|
|
1874
|
-
return transport.requestParsed(TransformJob, `/api/transform-job/${id}`, {
|
|
1875
|
-
...options,
|
|
1876
|
-
method: "PUT",
|
|
1877
|
-
body: params
|
|
1878
|
-
});
|
|
1879
|
-
}
|
|
1880
|
-
/** Delete a transform job by id, leaving the transforms it ran untouched. */
|
|
1881
|
-
async function remove(id, options = {}) {
|
|
1882
|
-
await transport.requestRaw(`/api/transform-job/${id}`, {
|
|
1883
|
-
...options,
|
|
1884
|
-
method: "DELETE",
|
|
1885
|
-
expectContentType: "binary"
|
|
1886
|
-
});
|
|
1887
|
-
}
|
|
1888
|
-
/**
|
|
1889
|
-
* Start a run of a transform job by id. The job runs every transform carrying one of its tags,
|
|
1890
|
-
* plus those transforms' dependencies; `run_all` re-runs dependencies that are already fresh.
|
|
1891
|
-
*/
|
|
1892
|
-
async function run(id, params = {}, options = {}) {
|
|
1893
|
-
return transport.requestParsed(TransformJobRunResult, `/api/transform-job/${id}/run`, {
|
|
1894
|
-
...options,
|
|
1895
|
-
method: "POST",
|
|
1896
|
-
body: { run_all: params.run_all }
|
|
1897
|
-
});
|
|
1898
|
-
}
|
|
1899
|
-
/** List the transforms a job would execute, resolved from the job's tags. */
|
|
1900
|
-
async function transforms(id, options = {}) {
|
|
1901
|
-
return {
|
|
1902
|
-
data: await transport.requestParsed(TransformApiList$1, `/api/transform-job/${id}/transforms`, { ...options }),
|
|
1903
|
-
total: null
|
|
1904
|
-
};
|
|
1905
|
-
}
|
|
1906
|
-
/**
|
|
1907
|
-
* Flip the active flag on every transform job at once. Inactive jobs do not run on schedule;
|
|
1908
|
-
* manual runs ignore the flag. The path carries no id and is a different endpoint from `update`.
|
|
1909
|
-
*/
|
|
1910
|
-
async function setActive(active, options = {}) {
|
|
1911
|
-
return transport.requestParsed(TransformJobActiveResult, "/api/transform-job/active", {
|
|
1912
|
-
...options,
|
|
1913
|
-
method: "PUT",
|
|
1914
|
-
body: { active }
|
|
1915
|
-
});
|
|
1916
|
-
}
|
|
1917
|
-
return {
|
|
1918
|
-
list,
|
|
1919
|
-
get,
|
|
1920
|
-
create,
|
|
1921
|
-
update,
|
|
1922
|
-
delete: remove,
|
|
1923
|
-
run,
|
|
1924
|
-
transforms,
|
|
1925
|
-
setActive
|
|
1926
|
-
};
|
|
1927
|
-
}
|
|
1928
|
-
//#endregion
|
|
1929
|
-
//#region ../client/src/resources/transform.ts
|
|
1930
|
-
const TransformApiList = z.array(Transform);
|
|
1931
|
-
const TransformRunKickoff = z.object({
|
|
1932
|
-
message: z.string(),
|
|
1933
|
-
run_id: z.number().int().positive().nullable()
|
|
1934
|
-
});
|
|
1935
|
-
function transformResource(transport) {
|
|
1936
|
-
/** List every transform the caller can see. */
|
|
1937
|
-
async function list(options = {}) {
|
|
1938
|
-
return {
|
|
1939
|
-
data: await transport.requestParsed(TransformApiList, "/api/transform", { ...options }),
|
|
1940
|
-
total: null
|
|
1941
|
-
};
|
|
1942
|
-
}
|
|
1943
|
-
/** Get one transform by id. */
|
|
1944
|
-
async function get(id, options = {}) {
|
|
1945
|
-
return transport.requestParsed(Transform, `/api/transform/${id}`, { ...options });
|
|
1946
|
-
}
|
|
1947
|
-
/** Create a transform — a query plus the warehouse table it writes — from a full body. */
|
|
1948
|
-
async function create(params, options = {}) {
|
|
1949
|
-
return transport.requestParsed(Transform, "/api/transform", {
|
|
1950
|
-
...options,
|
|
1951
|
-
method: "POST",
|
|
1952
|
-
body: params
|
|
1953
|
-
});
|
|
1954
|
-
}
|
|
1955
|
-
/** Update a transform by id, patching only the fields the body carries. */
|
|
1956
|
-
async function update(id, params, options = {}) {
|
|
1957
|
-
return transport.requestParsed(Transform, `/api/transform/${id}`, {
|
|
1958
|
-
...options,
|
|
1959
|
-
method: "PUT",
|
|
1960
|
-
body: params
|
|
1961
|
-
});
|
|
1962
|
-
}
|
|
1963
|
-
/** Delete a transform by id, leaving any table it already materialized in place. */
|
|
1964
|
-
async function remove(id, options = {}) {
|
|
1965
|
-
await transport.requestRaw(`/api/transform/${id}`, {
|
|
1966
|
-
...options,
|
|
1967
|
-
method: "DELETE",
|
|
1968
|
-
expectContentType: "binary"
|
|
1969
|
-
});
|
|
1970
|
-
}
|
|
1971
|
-
/** Drop a transform's materialized output table, keeping the transform definition. */
|
|
1972
|
-
async function deleteTable(id, options = {}) {
|
|
1973
|
-
await transport.requestRaw(`/api/transform/${id}/table`, {
|
|
1974
|
-
...options,
|
|
1975
|
-
method: "DELETE",
|
|
1976
|
-
expectContentType: "binary"
|
|
1977
|
-
});
|
|
1978
|
-
}
|
|
1979
|
-
/** List the upstream transforms a transform depends on. */
|
|
1980
|
-
async function dependencies(id, options = {}) {
|
|
1981
|
-
return {
|
|
1982
|
-
data: await transport.requestParsed(TransformApiList, `/api/transform/${id}/dependencies`, { ...options }),
|
|
1983
|
-
total: null
|
|
1984
|
-
};
|
|
1985
|
-
}
|
|
1986
|
-
/** Request cancellation of a transform's current run. */
|
|
1987
|
-
async function cancel(id, options = {}) {
|
|
1988
|
-
await transport.requestRaw(`/api/transform/${id}/cancel`, {
|
|
1989
|
-
...options,
|
|
1990
|
-
method: "POST",
|
|
1991
|
-
expectContentType: "binary"
|
|
1992
|
-
});
|
|
1993
|
-
}
|
|
1994
|
-
/** Get one transform run by run id — not by the id of the transform that produced it. */
|
|
1995
|
-
async function getRun(runId, options = {}) {
|
|
1996
|
-
return transport.requestParsed(TransformRun, `/api/transform/run/${runId}`, { ...options });
|
|
1997
|
-
}
|
|
1998
|
-
/** Walk the run history, newest first, optionally narrowed to a single transform. */
|
|
1999
|
-
function runPages(params = {}, options = {}) {
|
|
2000
|
-
return paginatePages(transport, "/api/transform/run", TransformRun, {
|
|
2001
|
-
query: { "transform-ids": params["transform-ids"] },
|
|
2002
|
-
...options.offset !== void 0 && { offset: options.offset },
|
|
2003
|
-
...options.max !== void 0 && { max: options.max },
|
|
2004
|
-
...options.pageSize !== void 0 && { pageSize: options.pageSize },
|
|
2005
|
-
...options.signal !== void 0 && { signal: options.signal }
|
|
2006
|
-
});
|
|
2007
|
-
}
|
|
2008
|
-
/**
|
|
2009
|
-
* Start a run of a transform by id. The server queues the run and answers at once; `wait` polls
|
|
2010
|
-
* it to a terminal status, and `syncTarget` follows that with the output table's registration.
|
|
2011
|
-
* A server that answers no run id started nothing, and there is then nothing to poll.
|
|
2012
|
-
*/
|
|
2013
|
-
async function run(id, params = {}, options = {}) {
|
|
2014
|
-
const kickoff = await transport.requestParsed(TransformRunKickoff, `/api/transform/${id}/run`, {
|
|
2015
|
-
...options,
|
|
2016
|
-
method: "POST"
|
|
2017
|
-
});
|
|
2018
|
-
const schedule = params.syncTarget === true ? params.wait ?? {} : params.wait;
|
|
2019
|
-
if (schedule === void 0 || kickoff.run_id === null) return {
|
|
2020
|
-
message: kickoff.message,
|
|
2021
|
-
run_id: kickoff.run_id,
|
|
2022
|
-
final: null
|
|
2023
|
-
};
|
|
2024
|
-
const runId = kickoff.run_id;
|
|
2025
|
-
const final = await pollUntil(async (signal) => getRun(runId, {
|
|
2026
|
-
...options,
|
|
2027
|
-
signal
|
|
2028
|
-
}), (candidate) => isTransformRunTerminal(candidate.status), schedule);
|
|
2029
|
-
if (params.syncTarget !== true) return {
|
|
2030
|
-
message: kickoff.message,
|
|
2031
|
-
run_id: runId,
|
|
2032
|
-
final
|
|
2033
|
-
};
|
|
2034
|
-
const targetTableId = isTransformRunFailed(final.status) ? null : await awaitTargetTableId(id, schedule, options);
|
|
2035
|
-
return {
|
|
2036
|
-
message: kickoff.message,
|
|
2037
|
-
run_id: runId,
|
|
2038
|
-
final,
|
|
2039
|
-
target_table_id: targetTableId
|
|
2040
|
-
};
|
|
2041
|
-
}
|
|
2042
|
-
async function awaitTargetTableId(id, wait, options) {
|
|
2043
|
-
try {
|
|
2044
|
-
return linkedTableId(await pollUntil(async (signal) => get(id, {
|
|
2045
|
-
...options,
|
|
2046
|
-
signal
|
|
2047
|
-
}), (transform) => linkedTableId(transform) !== null, wait));
|
|
2048
|
-
} catch (error) {
|
|
2049
|
-
if (error instanceof TimeoutError) return null;
|
|
2050
|
-
throw error;
|
|
2051
|
-
}
|
|
2052
|
-
}
|
|
2053
|
-
return {
|
|
2054
|
-
list,
|
|
2055
|
-
get,
|
|
2056
|
-
create,
|
|
2057
|
-
update,
|
|
2058
|
-
delete: remove,
|
|
2059
|
-
deleteTable,
|
|
2060
|
-
dependencies,
|
|
2061
|
-
cancel,
|
|
2062
|
-
getRun,
|
|
2063
|
-
runPages,
|
|
2064
|
-
run
|
|
2065
|
-
};
|
|
2066
|
-
}
|
|
2067
|
-
function linkedTableId(transform) {
|
|
2068
|
-
return transform.target_table_id ?? transform.table?.id ?? null;
|
|
2069
|
-
}
|
|
2070
|
-
//#endregion
|
|
2071
|
-
//#region ../client/src/resources/transform-tag.ts
|
|
2072
|
-
const TransformTagApiList = z.array(TransformTag);
|
|
2073
|
-
function transformTagResource(transport) {
|
|
2074
|
-
/** List every transform tag the caller can see, built-in tags included. */
|
|
2075
|
-
async function list(options = {}) {
|
|
2076
|
-
return {
|
|
2077
|
-
data: await transport.requestParsed(TransformTagApiList, "/api/transform-tag", { ...options }),
|
|
2078
|
-
total: null
|
|
2079
|
-
};
|
|
2080
|
-
}
|
|
2081
|
-
/** Create a transform tag, the label a transform job matches transforms on. */
|
|
2082
|
-
async function create(params, options = {}) {
|
|
2083
|
-
return transport.requestParsed(TransformTag, "/api/transform-tag", {
|
|
2084
|
-
...options,
|
|
2085
|
-
method: "POST",
|
|
2086
|
-
body: params
|
|
2087
|
-
});
|
|
2088
|
-
}
|
|
2089
|
-
/** Rename a transform tag by id. */
|
|
2090
|
-
async function update(id, params, options = {}) {
|
|
2091
|
-
return transport.requestParsed(TransformTag, `/api/transform-tag/${id}`, {
|
|
2092
|
-
...options,
|
|
2093
|
-
method: "PUT",
|
|
2094
|
-
body: params
|
|
2095
|
-
});
|
|
2096
|
-
}
|
|
2097
|
-
/** Delete a transform tag by id, detaching it from every transform and job carrying it. */
|
|
2098
|
-
async function remove(id, options = {}) {
|
|
2099
|
-
await transport.requestRaw(`/api/transform-tag/${id}`, {
|
|
2100
|
-
...options,
|
|
2101
|
-
method: "DELETE",
|
|
2102
|
-
expectContentType: "binary"
|
|
2103
|
-
});
|
|
2104
|
-
}
|
|
2105
|
-
return {
|
|
2106
|
-
list,
|
|
2107
|
-
create,
|
|
2108
|
-
update,
|
|
2109
|
-
delete: remove
|
|
2110
|
-
};
|
|
2111
|
-
}
|
|
2112
|
-
//#endregion
|
|
2113
|
-
//#region ../client/src/resources/upload.ts
|
|
2114
|
-
const UPLOAD_TABLE_ID_HEADER = "metabase-table-id";
|
|
2115
|
-
function uploadResource(transport) {
|
|
2116
|
-
/**
|
|
2117
|
-
* Create a table and model populated with the values from the attached CSV. Returns the model ID
|
|
2118
|
-
* if successful.
|
|
2119
|
-
*
|
|
2120
|
-
* The file may be at most 50 MB; larger uploads are rejected with a 413 response.
|
|
2121
|
-
*/
|
|
2122
|
-
async function createFromCsv(file, params, options = {}) {
|
|
2123
|
-
const form = buildCsvFormData(file);
|
|
2124
|
-
form.append("collection_id", params.collection_id);
|
|
2125
|
-
const response = await transport.requestRaw("/api/upload/csv", {
|
|
2126
|
-
...options,
|
|
2127
|
-
method: "POST",
|
|
2128
|
-
body: form,
|
|
2129
|
-
expectContentType: "binary"
|
|
2130
|
-
});
|
|
2131
|
-
return parseCreateUploadResult(await response.text(), response.headers);
|
|
2132
|
-
}
|
|
2133
|
-
return { createFromCsv };
|
|
2134
|
-
}
|
|
2135
|
-
function parseCreateUploadResult(bodyText, headers) {
|
|
2136
|
-
return UploadResult.parse({
|
|
2137
|
-
model_id: parseResponseInteger(bodyText, "response body"),
|
|
2138
|
-
table_id: parseResponseInteger(headers.get(UPLOAD_TABLE_ID_HEADER), `${UPLOAD_TABLE_ID_HEADER} header`)
|
|
2139
|
-
});
|
|
2140
|
-
}
|
|
2141
|
-
function parseResponseInteger(value, source) {
|
|
2142
|
-
const trimmed = value?.trim() ?? "";
|
|
2143
|
-
if (trimmed === "") throw new ResponseShapeError(`upload succeeded but the ${source} was empty`, {
|
|
2144
|
-
kind: "decoded",
|
|
2145
|
-
source,
|
|
2146
|
-
value
|
|
2147
|
-
});
|
|
2148
|
-
const parsed = Number(trimmed);
|
|
2149
|
-
if (!Number.isInteger(parsed)) throw new ResponseShapeError(`upload succeeded but the ${source} was not an integer: ${JSON.stringify(trimmed)}`, {
|
|
2150
|
-
kind: "decoded",
|
|
2151
|
-
source,
|
|
2152
|
-
value
|
|
2153
|
-
});
|
|
2154
|
-
return parsed;
|
|
2155
|
-
}
|
|
2156
|
-
//#endregion
|
|
2157
|
-
//#region ../client/src/domain/user.ts
|
|
2158
|
-
const CurrentUser = z.object({
|
|
2159
|
-
id: z.number().int(),
|
|
2160
|
-
email: z.email(),
|
|
2161
|
-
common_name: z.string(),
|
|
2162
|
-
is_superuser: z.boolean()
|
|
2163
|
-
}).loose();
|
|
2164
|
-
CurrentUser.pick({
|
|
2165
|
-
id: true,
|
|
2166
|
-
email: true,
|
|
2167
|
-
common_name: true,
|
|
2168
|
-
is_superuser: true
|
|
2169
|
-
}).strip();
|
|
2170
|
-
//#endregion
|
|
2171
|
-
//#region ../client/src/resources/user.ts
|
|
2172
|
-
function userResource(transport) {
|
|
2173
|
-
/** Get the user the request's credentials authenticate as. */
|
|
2174
|
-
async function current(options = {}) {
|
|
2175
|
-
return transport.requestParsed(CurrentUser, "/api/user/current", { ...options });
|
|
2176
|
-
}
|
|
2177
|
-
return { current };
|
|
2178
|
-
}
|
|
2179
|
-
//#endregion
|
|
2180
|
-
//#region ../client/src/client.ts
|
|
2181
|
-
var client_exports = /* @__PURE__ */ __exportAll({ createClient: () => createClient });
|
|
2182
|
-
function createClient(config, options) {
|
|
2183
|
-
const transport = createTransport(config, options);
|
|
2184
|
-
return {
|
|
2185
|
-
card: cardResource(transport),
|
|
2186
|
-
collection: collectionResource(transport),
|
|
2187
|
-
contentTranslation: contentTranslationResource(transport),
|
|
2188
|
-
dashboard: dashboardResource(transport),
|
|
2189
|
-
database: databaseResource(transport),
|
|
2190
|
-
dataset: datasetResource(transport),
|
|
2191
|
-
document: documentResource(transport),
|
|
2192
|
-
eidTranslation: eidTranslationResource(transport),
|
|
2193
|
-
field: fieldResource(transport),
|
|
2194
|
-
gitSync: gitSyncResource(transport),
|
|
2195
|
-
library: libraryResource(transport),
|
|
2196
|
-
measure: measureResource(transport),
|
|
2197
|
-
notification: notificationResource(transport),
|
|
2198
|
-
pulse: pulseResource(transport),
|
|
2199
|
-
search: searchResource(transport),
|
|
2200
|
-
segment: segmentResource(transport),
|
|
2201
|
-
setting: settingResource(transport),
|
|
2202
|
-
setup: setupResource(transport),
|
|
2203
|
-
snippet: snippetResource(transport),
|
|
2204
|
-
table: tableResource(transport),
|
|
2205
|
-
timeline: timelineResource(transport),
|
|
2206
|
-
timelineEvent: timelineEventResource(transport),
|
|
2207
|
-
transform: transformResource(transport),
|
|
2208
|
-
transformJob: transformJobResource(transport),
|
|
2209
|
-
transformTag: transformTagResource(transport),
|
|
2210
|
-
upload: uploadResource(transport),
|
|
2211
|
-
user: userResource(transport),
|
|
2212
|
-
requestParsed: transport.requestParsed,
|
|
2213
|
-
requestRaw: transport.requestRaw,
|
|
2214
|
-
requestStream: transport.requestStream
|
|
2215
|
-
};
|
|
2216
|
-
}
|
|
2217
|
-
//#endregion
|
|
2218
|
-
export { createClient as n, client_exports as t };
|