@metabase/cli 0.3.2-alpha.fix-transform-test-ee-path.8ac2a7a → 0.4.0-alpha.release-65-integration-branch.31ca6bb
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-B_-eMU_k.mjs → add-collection-B-Kczwcj.mjs} +5 -5
- package/dist/{alert-Dalin_DD.mjs → alert-Ne0ivd5m.mjs} +7 -7
- package/dist/{alerts-DpBgrjPI.mjs → alerts-Fakzg9iP.mjs} +6 -6
- package/dist/{append-C1JNVALm.mjs → append-DCDVqPmR.mjs} +4 -4
- package/dist/archive-55sDfnHf.mjs +32 -0
- package/dist/{archive-CdKf_Eqq.mjs → archive-BNJit8eD.mjs} +3 -3
- package/dist/{archive-DckxlWBt.mjs → archive-BbNqts-V.mjs} +3 -3
- package/dist/{archive-B51prFgS.mjs → archive-C93UR4Uc.mjs} +3 -3
- package/dist/{archive-CISXgZAI.mjs → archive-CGmvQht4.mjs} +5 -5
- package/dist/{archive-cAdUa1-2.mjs → archive-CL8wqAzm.mjs} +3 -3
- package/dist/{archive-DVHxeDKS.mjs → archive-CSdktxvW.mjs} +5 -5
- package/dist/{archive-CicPYX27.mjs → archive-CpCSY4RT.mjs} +5 -5
- package/dist/{archive-CwITzj_j.mjs → archive-DCCkQTjQ.mjs} +5 -5
- package/dist/{archive-BkITQyWW.mjs → archive-DCE087yD.mjs} +4 -4
- package/dist/{archive-DA3OiLEE.mjs → archive-DEef7eB8.mjs} +3 -3
- package/dist/{archive-52ZHbFDm2.mjs → archive-DIZu7o4C.mjs} +4 -4
- package/dist/{auth-A96JOCQx.mjs → auth-Bx4QQhqt.mjs} +5 -5
- package/dist/body-CB2eDFFb.mjs +17 -0
- package/dist/branch-flag-pFQPNYKr.mjs +9 -0
- package/dist/{branches-CbcwWYL9.mjs → branches-B6ilUG-7.mjs} +3 -3
- package/dist/breaking-Dg3-8yDF.mjs +36 -0
- package/dist/broken-BNBD4Eo3.mjs +37 -0
- package/dist/bulk-discard-values-DfKXuZpR.mjs +49 -0
- package/dist/bulk-edit-oUCfDQ_M.mjs +53 -0
- package/dist/bulk-rescan-values-B8pNlXUH.mjs +28 -0
- package/dist/bulk-sync-schema-tRp7jBJt.mjs +28 -0
- package/dist/{cancel-DpDcVY7M.mjs → cancel-Bl4BMkwI.mjs} +3 -3
- package/dist/{cancel-task-B4RDvIYb.mjs → cancel-task-CWWo7vLf.mjs} +4 -4
- package/dist/card-CQD4D8mw.mjs +25 -0
- package/dist/{card-CEkp1mcI.mjs → card-CQNUT9pm.mjs} +1 -1
- package/dist/{card-voh1k4hl.mjs → card-P5mBknsl.mjs} +3 -11
- package/dist/{cards-BC0JX8Yg.mjs → cards-BIUYdSIR.mjs} +6 -6
- package/dist/cli.mjs +420 -111
- package/dist/{client-ClL6gf7G.mjs → client-BHIFvEg2.mjs} +863 -316
- package/dist/{collection-DYM0p3Xl.mjs → collection-BG3Ksea-.mjs} +1 -1
- package/dist/collection-CuaTd10G.mjs +21 -0
- package/dist/{collection-BxdPxD38.mjs → collection-D3KXhvnc.mjs} +7 -5
- package/dist/{collection-namespace-Dv0l-V9K.mjs → collection-namespace-ZQePD67z.mjs} +2 -2
- package/dist/{content-translation-BXIXL4eW.mjs → content-translation-BRdNdAmn.mjs} +3 -3
- package/dist/copy-BMEaYmTb.mjs +55 -0
- package/dist/copy-CbDfVZRC.mjs +36 -0
- package/dist/copy-flags-anRhAvB5.mjs +32 -0
- package/dist/{create-Dhai9zAt.mjs → create-5cDaZcRL.mjs} +3 -3
- package/dist/{create-DWFJdyIr.mjs → create-BEN-2XFK.mjs} +3 -3
- package/dist/create-BJG630xB.mjs +48 -0
- package/dist/{create-NCKHHdov.mjs → create-BTQB1lqX.mjs} +4 -4
- package/dist/{create-kZIIEN2Y.mjs → create-C3TmU1Bi.mjs} +6 -6
- package/dist/create-C7O9tPL2.mjs +34 -0
- package/dist/{create-BVNhtAgF.mjs → create-C8hsOv_D.mjs} +6 -6
- package/dist/{create-D--Z1S3p2.mjs → create-CBSsW8Hm.mjs} +6 -6
- package/dist/{create-BcsVwXgS2.mjs → create-CG6WWY6k.mjs} +4 -4
- package/dist/{create--fiwuTWc.mjs → create-D2Shlb7t.mjs} +3 -3
- package/dist/{create-DmN2gFc4.mjs → create-DVEqry26.mjs} +4 -4
- package/dist/{create-YetX69Re.mjs → create-D_pNX7d0.mjs} +3 -3
- package/dist/{create-Za1EskpV.mjs → create-R0Q-nRlq.mjs} +4 -4
- package/dist/{create-Bryrkb9g.mjs → create-SqmOf6WQ.mjs} +6 -6
- package/dist/{create-branch-CseVn3lp.mjs → create-branch-Cb3CWojg.mjs} +4 -4
- package/dist/{create-BbjSOTN-.mjs → create-c2zR9y4J.mjs} +4 -4
- package/dist/{create-CHr8MPPq.mjs → create-xt4ff6fP.mjs} +3 -3
- package/dist/{create-B9qXQ_wV.mjs → create-zpJIRn9j.mjs} +5 -5
- package/dist/{csv-DNzesu8y.mjs → csv-CRNOhy4X.mjs} +4 -4
- package/dist/{current-task-DRTKZcP9.mjs → current-task-DFo1ZJ51.mjs} +4 -4
- package/dist/dashboard-D11YAa7I.mjs +35 -0
- package/dist/{dashboard-D0hwTC-f.mjs → dashboard-Phz3XpRM.mjs} +2 -1
- package/dist/{dashboard-DgK81azj.mjs → dashboard-XSTr9QCr.mjs} +6 -2
- package/dist/data-action-BiHjjVjc.mjs +24 -0
- package/dist/data-action-DZxVB_hD.mjs +85 -0
- package/dist/data-action-R9qxJDPA.mjs +40 -0
- package/dist/database-BT7DVgSr.mjs +45 -0
- package/dist/{database-C3E9PZSx.mjs → database-Kq2AL5jH.mjs} +1 -1
- package/dist/dataset-BmvCxGoE.mjs +66 -0
- package/dist/{db-BDijt81U.mjs → db-C8lj73Dz.mjs} +7 -7
- package/dist/delete-09O7BTNw.mjs +44 -0
- package/dist/{delete-wFsy80db.mjs → delete-CYgNpHl7.mjs} +4 -4
- package/dist/{delete-BudvZkvK.mjs → delete-D_ZNoYVv.mjs} +4 -4
- package/dist/{delete--15it-A8.mjs → delete-HWeQtc4M.mjs} +4 -4
- package/dist/delete-I4eFpsed.mjs +44 -0
- package/dist/{delete-Dc8E5YwZ.mjs → delete-My8TX-B2.mjs} +4 -4
- package/dist/{delete-BxjJ66BS.mjs → delete-qwdN0N7e.mjs} +4 -4
- package/dist/delete-runtime-BbmRg_in.mjs +55 -0
- package/dist/{delete-table-5AQpn8OB.mjs → delete-table-BCvjX7bh.mjs} +4 -4
- package/dist/{dependencies-C1ogC3BV.mjs → dependencies-BAE4YPXX.mjs} +5 -5
- package/dist/dependency-CIam7zmr.mjs +15 -0
- package/dist/dependency-DzLH3J8P.mjs +165 -0
- package/dist/dependency-zElFM-os.mjs +111 -0
- package/dist/dependents-Dv6tLdSs.mjs +52 -0
- package/dist/{dirty-CSLDYO-K.mjs → dirty-CZORg0i0.mjs} +5 -5
- package/dist/discard-values-DKnP-JHr.mjs +55 -0
- package/dist/{document-CA0Q6lqu.mjs → document-C18b5rM6.mjs} +1 -1
- package/dist/{document-BHpLJbKU.mjs → document-DFCj1Az_.mjs} +2 -1
- package/dist/document-uxz96Lah.mjs +20 -0
- package/dist/{download-Ddap1OAo.mjs → download-BImtTll0.mjs} +2 -2
- package/dist/{eid-HnrWhPoe.mjs → eid-D0FxhT9H.mjs} +11 -10
- package/dist/entity-DWp9WJbU.mjs +20 -0
- package/dist/entry-flags-3sDWwa90.mjs +42 -0
- package/dist/{events-CXqetjcS.mjs → events-BzCjVA3-.mjs} +4 -4
- package/dist/execute-BhHbkBqf.mjs +45 -0
- package/dist/export-CjqjDnaZ.mjs +74 -0
- package/dist/export-flags-BETJHNcw.mjs +81 -0
- package/dist/export-preflight-DzvIP6TB.mjs +35 -0
- package/dist/{field-CcN4oZy6.mjs → field-5nivEfd6.mjs} +33 -3
- package/dist/field-fBpiGiqr.mjs +21 -0
- package/dist/field-wmN6raOG.mjs +128 -0
- package/dist/{fields-DxHxuxwO.mjs → fields-C-au1eLO.mjs} +6 -6
- package/dist/filter-flags-BIFcA2TT.mjs +72 -0
- package/dist/fks-83QIm8xb.mjs +36 -0
- package/dist/{get-CDnmpfHQ.mjs → get-BMHbEGbr.mjs} +4 -4
- package/dist/{get-BiPclcIP.mjs → get-BTCOzSkl.mjs} +3 -3
- package/dist/{get-DmKtPNOy.mjs → get-BawLhSwW.mjs} +3 -3
- package/dist/{get-BcoJ9Aha.mjs → get-BjqqFG2m.mjs} +3 -3
- package/dist/{get-C3cuZNeW.mjs → get-C-R_Fdsi.mjs} +3 -3
- package/dist/{get-H6kInHIx.mjs → get-C73V2KsB.mjs} +5 -5
- package/dist/{get-BGLvyOO3.mjs → get-C9sq2boy.mjs} +5 -5
- package/dist/{get-B2pj2q3X.mjs → get-Cggv6yLC.mjs} +4 -4
- package/dist/{get-CxUQyhte.mjs → get-CkXc0Xld.mjs} +5 -5
- package/dist/{get-BF2vdF3W.mjs → get-CqNEVAX_2.mjs} +3 -3
- package/dist/{get-Dtre5jzh.mjs → get-D7h7uH4k.mjs} +5 -5
- package/dist/get-DGmE5fmp.mjs +31 -0
- package/dist/{get-D_x-ENFe.mjs → get-DTTsPd-c.mjs} +5 -5
- package/dist/{get-DW7mCaGe.mjs → get-DXBXhPrU.mjs} +5 -5
- package/dist/{get-CE9_4Q7E.mjs → get-D_v1IAL1.mjs} +3 -3
- package/dist/{get-eJilYnHk.mjs → get-DkzO3G5p.mjs} +5 -5
- package/dist/{get-DjlQhgD4.mjs → get-Dvr_69L7.mjs} +3 -3
- package/dist/get-NOMvMvYJ.mjs +36 -0
- package/dist/{get-C_tdSMwW2.mjs → get-YPDWhgm_2.mjs} +4 -4
- package/dist/{get-b0CoPz5B.mjs → get-Z36_0HX_.mjs} +4 -4
- package/dist/{get-run-BE1HtJDW.mjs → get-run-v1QHn-Mx.mjs} +4 -4
- package/dist/{git-sync-BwBRmEhE.mjs → git-sync-COokpYgc.mjs} +12 -3
- package/dist/git-sync-DspFahwV.mjs +165 -0
- package/dist/git-sync-VAqASCQ5.mjs +29 -0
- package/dist/glossary-BlNCrYbw.mjs +30 -0
- package/dist/glossary-Brnk2PBi.mjs +14 -0
- package/dist/glossary-LmZWwCNP.mjs +21 -0
- package/dist/graph-B6OliqnW.mjs +34 -0
- package/dist/{group-YQQ5GIcP.mjs → group-bpD_KcjA.mjs} +1 -1
- package/dist/{has-remote-changes-Cj1KhBOT.mjs → has-remote-changes-iTRCU9j0.mjs} +4 -4
- package/dist/{import-DLb9VN4l.mjs → import-CdSs5CtT.mjs} +19 -8
- package/dist/{input-D5tQEfqN.mjs → input-D8qW-KtR.mjs} +6 -2
- package/dist/{is-dirty-BxtgV2xF.mjs → is-dirty-B5fj9NeS.mjs} +2 -2
- package/dist/{items-DLUYc5-z.mjs → items-BxWnNEh7.mjs} +8 -8
- package/dist/{key-PYetuQ13.mjs → key-BynJSK9u.mjs} +1 -1
- package/dist/{library-BNSxXOpc.mjs → library-BHHgurW0.mjs} +5 -5
- package/dist/{library-PGCfm0UA.mjs → library-BOv5SY24.mjs} +1 -1
- package/dist/{library-BPIzb3K_.mjs → library-Ck0EK5bi.mjs} +4 -2
- package/dist/{list-cIMww2Me.mjs → list-BPMOLrwn.mjs} +5 -5
- package/dist/{list-jhQSgh6i.mjs → list-BTcEm4td.mjs} +3 -3
- package/dist/{list-M8J10Ozk.mjs → list-BTgAbqeS.mjs} +4 -4
- package/dist/{list-CERbeLbQ.mjs → list-Bop1NTbU.mjs} +6 -6
- package/dist/{list-BQnOEB3W.mjs → list-By9XJRiv.mjs} +3 -3
- package/dist/list-CNC-XHbN.mjs +35 -0
- package/dist/{list-CX9qZ-bx.mjs → list-CPWgBkPa.mjs} +4 -4
- package/dist/{list-C5mS_ehX.mjs → list-Cpa0Se7M.mjs} +5 -5
- package/dist/list-DA9KsA0o.mjs +101 -0
- package/dist/{list-Dat8QNcf.mjs → list-DE9gYY3I.mjs} +3 -3
- package/dist/{list-COLpwXW4.mjs → list-DFJt2-fY.mjs} +4 -4
- package/dist/{list-CBLxhaNZ.mjs → list-DUcnAb1h.mjs} +3 -3
- package/dist/{list-CehE6KBV.mjs → list-DW4-u7eO.mjs} +5 -5
- package/dist/{list-CQbiSx26.mjs → list-DbXnSL2x.mjs} +5 -5
- package/dist/list-DgsM9YQX.mjs +28 -0
- package/dist/{list-Sd7jGZoX.mjs → list-Dzzt6Yee.mjs} +3 -3
- package/dist/{list-BUz6KOfw.mjs → list-ZHLsjxXg.mjs} +6 -6
- package/dist/{list-CzRzCbCY.mjs → list-e7yvJYMw.mjs} +3 -3
- package/dist/{list-B1soS8QW.mjs → list-hN_Tu2T6.mjs} +6 -6
- package/dist/{list-BcP1DTJH.mjs → list-zyKxxNvn.mjs} +3 -3
- package/dist/{login-BfLqBfCd.mjs → login-B7nGQDZK.mjs} +6 -6
- package/dist/{logout-BpRXB3Ze.mjs → logout-pZffAh1G.mjs} +2 -2
- package/dist/{measure-Ds8O5Evr.mjs → measure-AtnrCTCC.mjs} +6 -6
- package/dist/moderation-review-BdqEH6N1.mjs +31 -0
- package/dist/{notification-DVrLkjFT.mjs → notification-DOYdl0ao.mjs} +1 -1
- package/dist/{parameter-values-DhrkLXoN.mjs → parameter-values-CxTkEjCs.mjs} +3 -3
- package/dist/{parse-enum-Dc0dMZ3P.mjs → parse-enum-CLIXMsd8.mjs} +1 -1
- package/dist/parse-id-7ja3HUdB.mjs +13 -0
- package/dist/{parse-ref-DTDld_LJ.mjs → parse-ref-Cw5fa4FI.mjs} +1 -1
- package/dist/parse-text-T0lTXzTZ.mjs +11 -0
- package/dist/{path-_GHFrTLx.mjs → path-DM4vyihl.mjs} +4 -4
- package/dist/{poll-KLl4Eq8Y.mjs → poll-Dz4tUm2f.mjs} +2 -2
- package/dist/{preflight-BpYtF0IU.mjs → preflight-DaZ2z2C1.mjs} +3 -3
- package/dist/{process-CLtOWKBn.mjs → process-D0HdqZ3r.mjs} +1 -1
- package/dist/{publish-D-7Zlmuk.mjs → publish-C0HCL04a.mjs} +4 -4
- package/dist/{pulse-x0gFxWfG.mjs → pulse-D1uh8UIU.mjs} +1 -1
- package/dist/{query-B1CZztxs.mjs → query-BC-C6efK.mjs} +14 -33
- package/dist/query-BKtMP5eH.mjs +13 -0
- package/dist/query-CAFPlqfi.mjs +329 -0
- package/dist/remapping-CgA6UJGU.mjs +53 -0
- package/dist/{remove-collection-C4saCFxz.mjs → remove-collection-DoctJa9g.mjs} +5 -5
- package/dist/{render-6O_eF-P1.mjs → render-Bvm9mta6.mjs} +2 -2
- package/dist/{replace-BuR4f2Ai.mjs → replace-CaFJd9fO.mjs} +4 -4
- package/dist/rescan-values-7VOGCLMe.mjs +32 -0
- package/dist/{rescan-values-CNOiiWQ5.mjs → rescan-values-sJRwcHsk.mjs} +5 -5
- package/dist/{run-DijA_BXt.mjs → run-COHDQ5J4.mjs} +3 -3
- package/dist/{run-QEUbWNm7.mjs → run-RXpFlDAB.mjs} +7 -7
- package/dist/{runs-BSlhVeDO.mjs → runs-CUYdCKiE.mjs} +5 -5
- package/dist/{runtime-Dtb93zKy.mjs → runtime-B8RtMb4B.mjs} +21 -82
- package/dist/{schema-tables-BE3rEb6I.mjs → schema-tables-CO5qyZBe.mjs} +6 -6
- package/dist/{schemas-yDjBiwlH.mjs → schemas-CzHHgDdF.mjs} +4 -4
- package/dist/search-BWb052_b.mjs +131 -0
- package/dist/search-Cc9vHNae.mjs +85 -0
- package/dist/{segment-Cm6zQjJW.mjs → segment-C_rsUkHK.mjs} +6 -6
- package/dist/{send-kC8oerkT.mjs → send-C-3bkpni.mjs} +3 -3
- package/dist/{set-tFhPkxrL.mjs → set-BDkT37OT.mjs} +4 -4
- package/dist/{set-active-lDKhAlij.mjs → set-active-CDJTfQEc.mjs} +3 -3
- package/dist/set-sensitivity-DVrINHde.mjs +57 -0
- package/dist/{setting-DrJXCaFE.mjs → setting-CoLzd08x.mjs} +4 -4
- package/dist/{setup-BWY9M0iR.mjs → setup-C4F4XYbU.mjs} +3 -3
- package/dist/{signal-Csom0mt5.mjs → signal-CxWeLszu.mjs} +1 -1
- package/dist/{skill-list-CCes8pKe.mjs → skill-list-BgihWuPf.mjs} +2 -2
- package/dist/{skills-DE9ej5Rg.mjs → skills-4qDjKRSk.mjs} +2 -2
- package/dist/{skills-DPRN2384.mjs → skills-BWEFRpUj.mjs} +3 -3
- package/dist/snippet-CYd8D9SK.mjs +19 -0
- package/dist/{stash-C9oDvQ9P.mjs → stash-CZ1x0rox.mjs} +6 -6
- package/dist/{status-DSdXmNC3.mjs → status-BM6eYW7I.mjs} +3 -3
- package/dist/{status-CkpujA26.mjs → status-gqpPZvue.mjs} +7 -7
- package/dist/{subscription-DKOKoHRG.mjs → subscription-pSuO241O.mjs} +6 -6
- package/dist/{subscriptions-C5SyJL4B.mjs → subscriptions-n5zJ9rYZ.mjs} +6 -6
- package/dist/{summary-DTPgXsc0.mjs → summary-DvIf2EiO.mjs} +5 -5
- package/dist/sync-schema-Cc21crxQ.mjs +32 -0
- package/dist/{sync-schema-DKKkNSR7.mjs → sync-schema-D1t8rhdQ.mjs} +6 -6
- package/dist/sync-task-CXFoqlpF.mjs +53 -0
- package/dist/{table-DfuY0N8e.mjs → table-Ci6bhZkb.mjs} +35 -12
- package/dist/table-CxvaDiIZ.mjs +155 -0
- package/dist/table-Dc0dLfyg.mjs +26 -0
- package/dist/table-selector-flags-BVZvnhUa.mjs +42 -0
- package/dist/text-DaNkPRwt.mjs +6 -0
- package/dist/timeline-BqU5sOb6.mjs +21 -0
- package/dist/{timeline-event-n4Lzet7l.mjs → timeline-event-jn1SOKd4.mjs} +6 -6
- package/dist/transform-BUIlFqpv.mjs +28 -0
- package/dist/{transform-CtqB1WYo.mjs → transform-CNBIV7No.mjs} +1 -1
- package/dist/transform-job-DsbY9mme.mjs +22 -0
- package/dist/{transform-tag-D6NXqWaX.mjs → transform-tag-C0jzV6Dk.mjs} +5 -5
- package/dist/{transforms-O4NtXqFz.mjs → transforms-DwTy_Quh.mjs} +5 -5
- package/dist/tree-p2j6IVy-.mjs +34 -0
- package/dist/{unpublish-DvWefKJi.mjs → unpublish-B-961jX1.mjs} +3 -3
- package/dist/unreferenced-Dxy-aYI7.mjs +36 -0
- package/dist/{update-DXmZuJho.mjs → update-BFYRBbRu.mjs} +6 -6
- package/dist/{update-xEegxIyH.mjs → update-BGeaPntx.mjs} +5 -5
- package/dist/{update-Bah7N8QX.mjs → update-BnIEN390.mjs} +5 -5
- package/dist/{update-To6A1Ugu.mjs → update-CALlEgIC.mjs} +4 -4
- package/dist/{update-76nzOc71.mjs → update-CHkVN69L.mjs} +13 -8
- package/dist/{update-AJ2JmwDl.mjs → update-CKqL9PmU.mjs} +5 -5
- package/dist/{update-DmgRIp7o.mjs → update-CYGYUCFQ.mjs} +4 -4
- package/dist/update-CuQy2g51.mjs +52 -0
- package/dist/{update-DOdcflLH.mjs → update-D4TGE6FS.mjs} +7 -7
- package/dist/{update-H_fdjugs.mjs → update-D7xi-0bU.mjs} +4 -4
- package/dist/{update-2KIpYgyj.mjs → update-DK77vtFF.mjs} +6 -6
- package/dist/{update-7oKvP1HC.mjs → update-DKDQTlnV.mjs} +5 -5
- package/dist/update-DXxJHC8y.mjs +41 -0
- package/dist/update-DiJK0uRG.mjs +181 -0
- package/dist/{update-CGJvIS-l.mjs → update-MD1Kwq1P.mjs} +4 -4
- package/dist/{update-dashcard-DjT5QOkL.mjs → update-dashcard-DuTjOh14.mjs} +6 -6
- package/dist/{update-D7dG7H-z.mjs → update-hvO4VpfZ.mjs} +7 -7
- package/dist/{update-DV54H3L5.mjs → update-qDZvnwvf.mjs} +7 -7
- package/dist/{update-BB6Go_RX.mjs → update-tltXCUwR.mjs} +4 -4
- package/dist/{upgrade-CuJx9fX4.mjs → upgrade-Ca-Ss5jb.mjs} +4 -4
- package/dist/{upload-DOO94rCQ.mjs → upload-C2fhpKkP.mjs} +2 -2
- package/dist/upload-Dw7mVr9u.mjs +13 -0
- package/dist/{upload-CboARPZm.mjs → upload-t6dkccqn.mjs} +3 -3
- package/dist/{uuid-InwZlrpQ.mjs → uuid-BMlJZT8z.mjs} +2 -2
- package/dist/{validate-D6-Vg_kn.mjs → validate-D7e110oU.mjs} +1 -1
- package/dist/{validate-query-B90KYPQr.mjs → validate-query-BzbZmenf.mjs} +7 -3
- package/dist/{values-CsZLk1Ls.mjs → values-CXN4xTTh.mjs} +5 -5
- package/dist/verify-CPVfwKSu.mjs +38 -0
- package/dist/verify-flags-CMpRkMPa.mjs +58 -0
- package/dist/verify-k-JB-k3D.mjs +38 -0
- package/dist/{verify-DrGjZwBM.mjs → verify-t-CEmvoG.mjs} +3 -3
- package/dist/{wait-BmzdarP9.mjs → wait-KSkq7kKW.mjs} +6 -6
- package/dist/{wait-flags-CiJGrTCT.mjs → wait-flags-KX7NHdj4.mjs} +2 -2
- package/dist/{window-DSb1tqSe.mjs → window-CI_QD04s.mjs} +1 -1
- package/package.json +1 -1
- package/skill-data/core/SKILL.md +24 -23
- package/skill-data/dashboard/SKILL.md +1 -1
- package/skill-data/data-action/SKILL.md +125 -0
- package/skill-data/document/SKILL.md +12 -1
- package/skill-data/git-sync/SKILL.md +61 -9
- package/skill-data/mbql/SKILL.md +5 -0
- package/skill-data/metadata/SKILL.md +36 -6
- package/skill-data/native-sql/SKILL.md +1 -1
- package/skill-data/transform/SKILL.md +1 -63
- package/dist/body-CshgcV6U.mjs +0 -17
- package/dist/card-CefVYtF7.mjs +0 -24
- package/dist/collection-Be5AHVWP.mjs +0 -20
- package/dist/create-DiJ8bUb-.mjs +0 -34
- package/dist/dashboard-CMw13KXM.mjs +0 -33
- package/dist/database-JtHTqSpq.mjs +0 -26
- package/dist/delete-Bsdwqh7H.mjs +0 -44
- package/dist/delete-runtime-BKEzJn22.mjs +0 -49
- package/dist/document-BGzVip5_.mjs +0 -19
- package/dist/export-IFZdgYZ2.mjs +0 -63
- package/dist/field-BJ6HoLRd.mjs +0 -18
- package/dist/field-fDtIrY6D.mjs +0 -80
- package/dist/get-i0KInCw9.mjs +0 -32
- package/dist/get-jofVjU6e.mjs +0 -31
- package/dist/git-sync-TjX1r_wF.mjs +0 -136
- package/dist/git-sync-xKC1sqC4.mjs +0 -28
- package/dist/list-Cuhf2lKL.mjs +0 -35
- package/dist/list-D-SyhKFw.mjs +0 -34
- package/dist/parse-id-DtM6q9HU.mjs +0 -10
- package/dist/query-CxESKMve.mjs +0 -114
- package/dist/query-result-E4Q-Gra6.mjs +0 -15
- package/dist/run-FmRruANb.mjs +0 -64
- package/dist/search-CR_xNArA.mjs +0 -97
- package/dist/selectors-C-vgMcGK.mjs +0 -35
- package/dist/snippet-DWHTSo9c.mjs +0 -19
- package/dist/sync-task-BtDnTXCP.mjs +0 -38
- package/dist/table-C6h4tIRw.mjs +0 -37
- package/dist/table-I8NXSdUC.mjs +0 -18
- package/dist/timeline-B_ESH-6W.mjs +0 -21
- package/dist/transform-BNuNiH9d.mjs +0 -28
- package/dist/transform-job-B7yc6dfH.mjs +0 -22
- package/dist/transform-test-BjjCQ2xm.mjs +0 -169
- package/dist/transform-test-C1Oqtfb-.mjs +0 -16
- package/dist/transform-test-gzDcbypy.mjs +0 -25
- package/dist/transport-CyVo29u7.mjs +0 -313
- package/dist/tree-CuyF116R.mjs +0 -26
- package/dist/update-l3PyNQKG.mjs +0 -41
- package/dist/upload-2YFFBSln.mjs +0 -13
- package/skill-data/transform-test-plan/SKILL.md +0 -171
- package/skill-data/transform-test-plan/references/checklist.md +0 -81
- package/skill-data/transform-test-plan/references/checks.md +0 -263
|
@@ -1,22 +1,28 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { at as ConfigError, ct as NetworkError, ft as ValidationError, lt as ResponseShapeError, mt as formatZodIssue, n as methodRequirements, ot as InternalError, pt as errorMessage, ut as TimeoutError } from "./cli.mjs";
|
|
2
2
|
import { n as Notification, r as NotificationCardPayload, t as CARD_PAYLOAD_TYPE } from "./notification-DaA4bBHW.mjs";
|
|
3
|
-
import { H as
|
|
4
|
-
import { n as
|
|
5
|
-
import {
|
|
3
|
+
import { $ as CapabilityError, B as assertCredentialHeaderSafe, G as normalizeUrl, H as credentialSecrets, I as isRetryableStatus, J as checkFeatures, L as JSON_CONTENT_TYPE, M as buildNetworkError, N as isConnectionClosed, P as HttpError, Q as probeServer, R as parseJson, V as credentialAuthHeader, X as createServerProfile, Z as PROBE_PATH, z as parseJsonOrPlain } from "./runtime-B8RtMb4B.mjs";
|
|
4
|
+
import { n as throwIfAborted, r as untilAborted, t as combineAborts } from "./signal-CxWeLszu.mjs";
|
|
5
|
+
import { f as FieldWithDataSensitivity, h as fieldRemappedValueSchema, m as fieldDetailSchema, n as FieldBaseType, o as FieldSearchMatches, s as FieldSemanticType, u as FieldValues } from "./field-5nivEfd6.mjs";
|
|
6
6
|
import { a as TemporalUnit, r as ParameterValues } from "./parameter-Celg0wZa.mjs";
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import { t as
|
|
7
|
+
import { r as PivotExportFormat, t as DatasetQuery } from "./query-BKtMP5eH.mjs";
|
|
8
|
+
import { a as CardQueryResult, t as Card } from "./card-P5mBknsl.mjs";
|
|
9
|
+
import { b as TableVisibilityType, p as TableQueryMetadata, s as TableDataLayerTier, t as Table, u as TableForeignKey, v as TableSelectors } from "./table-Ci6bhZkb.mjs";
|
|
10
|
+
import { t as Database } from "./database-BT7DVgSr.mjs";
|
|
10
11
|
import { t as Snippet } from "./snippet-CyKAgIZl.mjs";
|
|
11
|
-
import {
|
|
12
|
+
import { o as compiledQuerySchema, r as QueryMetadata } from "./dataset-BmvCxGoE.mjs";
|
|
13
|
+
import { c as CollectionItem, m as CollectionTreeNode, r as Collection } from "./collection-D3KXhvnc.mjs";
|
|
12
14
|
import { t as ContentTranslationUploadResult } from "./content-translation-BrHOrmj9.mjs";
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
15
|
+
import { l as Dashcard, o as DashboardDetail, r as DashboardCopy, t as Dashboard } from "./dashboard-Phz3XpRM.mjs";
|
|
16
|
+
import { a as DataActionExecuteResult, s as dataActionSchema } from "./data-action-DZxVB_hD.mjs";
|
|
17
|
+
import { r as pollUntil } from "./poll-Dz4tUm2f.mjs";
|
|
18
|
+
import { i as DependencyEntity, s as DependencyGraph, t as BreakingSource, u as DependencyNode } from "./dependency-DzLH3J8P.mjs";
|
|
19
|
+
import { t as Document } from "./document-DFCj1Az_.mjs";
|
|
16
20
|
import { i as EidTranslateResult } from "./eid-translation-zEHtr5Oc.mjs";
|
|
17
|
-
import { c as
|
|
18
|
-
import {
|
|
21
|
+
import { c as SyncRemoteChanges, d as SyncTask, i as SyncExportPreflight, l as SyncSettingsUpdateResult, m as isSyncTaskTerminal, n as SyncDirtyItem, t as SyncBranchCreated } from "./git-sync-COokpYgc.mjs";
|
|
22
|
+
import { t as Glossary } from "./glossary-BlNCrYbw.mjs";
|
|
23
|
+
import { a as libraryWireSchema, i as LibraryPublishTablesInput, n as LibraryCollectionInfo, o as toLibrary } from "./library-Ck0EK5bi.mjs";
|
|
19
24
|
import { t as Measure } from "./measure-CtfjqJFP.mjs";
|
|
25
|
+
import { r as ModerationReviewCreateInput, t as ModerationReview } from "./moderation-review-BdqEH6N1.mjs";
|
|
20
26
|
import { t as Pulse } from "./pulse-Dz0ocv0l.mjs";
|
|
21
27
|
import { a as TransformDagTransform, d as TransformTarget, g as transformRowSchema, h as transformDetailSchema, i as TransformDagRunResult, l as TransformRunSummary, m as isTransformRunTerminal, o as TransformRun, p as isTransformRunFailed, u as TransformSourceTableEntry } from "./transform-DiW7bREn.mjs";
|
|
22
28
|
import { r as SearchResult } from "./search-BAXg-EJw.mjs";
|
|
@@ -26,9 +32,9 @@ import { n as SetupResult } from "./setup-CO7QV-ao.mjs";
|
|
|
26
32
|
import { i as TimelineEvent, t as Timeline } from "./timeline-CCSU2qOS.mjs";
|
|
27
33
|
import { c as transformJobSchema, n as TransformJobActiveResult, s as transformJobRunResultSchema } from "./transform-job-CCguL6LP.mjs";
|
|
28
34
|
import { t as TransformTag } from "./transform-tag-CcElGp3C.mjs";
|
|
29
|
-
import { i as TransformTestRunResult, t as TransformTest } from "./transform-test-BjjCQ2xm.mjs";
|
|
30
35
|
import { t as UploadResult } from "./upload-DAtxBBms.mjs";
|
|
31
36
|
import { z } from "zod";
|
|
37
|
+
import { setTimeout } from "node:timers/promises";
|
|
32
38
|
//#region \0rolldown/runtime.js
|
|
33
39
|
var __defProp = Object.defineProperty;
|
|
34
40
|
var __exportAll = (all, no_symbols) => {
|
|
@@ -41,43 +47,324 @@ var __exportAll = (all, no_symbols) => {
|
|
|
41
47
|
return target;
|
|
42
48
|
};
|
|
43
49
|
//#endregion
|
|
44
|
-
//#region ../client/src/
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
50
|
+
//#region ../client/src/http/response-shape.ts
|
|
51
|
+
async function parseJsonResponse(text, schema, context) {
|
|
52
|
+
try {
|
|
53
|
+
return parseJson(text, schema, { source: context.url });
|
|
54
|
+
} catch (error) {
|
|
55
|
+
if (error instanceof ValidationError) throw ResponseShapeError.fromZodIssues({
|
|
56
|
+
kind: "zod",
|
|
57
|
+
method: context.method,
|
|
58
|
+
url: context.url,
|
|
59
|
+
status: context.status,
|
|
60
|
+
zodIssues: error.developerDetail.zodIssues,
|
|
61
|
+
serverTag: await context.getServerTag(),
|
|
62
|
+
serverSkew: context.serverSkew
|
|
63
|
+
});
|
|
64
|
+
throw error;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
//#endregion
|
|
68
|
+
//#region ../client/src/http/retry.ts
|
|
69
|
+
const BASE_DELAY_MS = 250;
|
|
70
|
+
const MAX_DELAY_MS = 8e3;
|
|
71
|
+
const MS_PER_SECOND = 1e3;
|
|
72
|
+
function backoffDelay({ attempt, retryAfterHeader }) {
|
|
73
|
+
const fromHeader = parseRetryAfter(retryAfterHeader);
|
|
74
|
+
if (fromHeader !== null) return fromHeader;
|
|
75
|
+
return Math.min(MAX_DELAY_MS, BASE_DELAY_MS * 2 ** attempt);
|
|
76
|
+
}
|
|
77
|
+
function parseRetryAfter(header) {
|
|
78
|
+
if (!header) return null;
|
|
79
|
+
const numeric = Number(header);
|
|
80
|
+
if (Number.isFinite(numeric) && numeric >= 0) return Math.round(numeric * MS_PER_SECOND);
|
|
81
|
+
const dateMs = Date.parse(header);
|
|
82
|
+
if (Number.isFinite(dateMs)) return Math.max(0, dateMs - Date.now());
|
|
83
|
+
return null;
|
|
84
|
+
}
|
|
85
|
+
function sleep(ms, signal) {
|
|
86
|
+
return setTimeout(ms, void 0, { signal });
|
|
87
|
+
}
|
|
88
|
+
async function runWithRetries(attempt, signal) {
|
|
89
|
+
let attemptIndex = 0;
|
|
90
|
+
while (true) {
|
|
91
|
+
const outcome = await attempt(attemptIndex);
|
|
92
|
+
if (outcome.kind === "success") return outcome.response;
|
|
93
|
+
await sleep(outcome.delayMs, signal);
|
|
94
|
+
attemptIndex += 1;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
//#endregion
|
|
98
|
+
//#region ../client/src/http/transport.ts
|
|
99
|
+
const UNAUTHORIZED_STATUS = 401;
|
|
100
|
+
const DEFAULT_TIMEOUT_MS = 3e4;
|
|
101
|
+
const OCTET_STREAM_CONTENT_TYPE = "application/octet-stream";
|
|
102
|
+
const TEXT_CONTENT_TYPE_PREFIX = "text/";
|
|
103
|
+
const ERROR_BODY_BYTE_CAP = 64 * 1024;
|
|
104
|
+
const IDEMPOTENT_METHODS = /* @__PURE__ */ new Set([
|
|
105
|
+
"GET",
|
|
106
|
+
"HEAD",
|
|
107
|
+
"OPTIONS"
|
|
54
108
|
]);
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
const
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
109
|
+
function createTransport(config, options) {
|
|
110
|
+
const baseUrl = normalizeUrl(config.url);
|
|
111
|
+
assertCredentialHeaderSafe(config.credential);
|
|
112
|
+
const fetchImpl = options.fetchImpl ?? globalThis.fetch.bind(globalThis);
|
|
113
|
+
let settledProfile = options.server ?? null;
|
|
114
|
+
const getServerTag = options.getServerTag ?? (async () => tagOf(settledProfile));
|
|
115
|
+
const serverSkew = () => settledProfile === null ? null : settledProfile.skew;
|
|
116
|
+
const refreshCredential = options.refreshCredential;
|
|
117
|
+
let credential = config.credential;
|
|
118
|
+
const knownSecrets = new Set(credentialSecrets(credential));
|
|
119
|
+
const redactionContext = { knownSecrets };
|
|
120
|
+
let refreshInFlight = null;
|
|
121
|
+
function tryRefreshCredential() {
|
|
122
|
+
const refresh = refreshCredential;
|
|
123
|
+
if (credential.kind !== "oauth" || refresh === void 0) return Promise.resolve(false);
|
|
124
|
+
refreshInFlight ??= refreshOnce(refresh).finally(() => {
|
|
125
|
+
refreshInFlight = null;
|
|
126
|
+
});
|
|
127
|
+
return refreshInFlight;
|
|
128
|
+
}
|
|
129
|
+
async function refreshOnce(refresh) {
|
|
130
|
+
const next = await refresh();
|
|
131
|
+
if (next === null) return false;
|
|
132
|
+
credential = next;
|
|
133
|
+
for (const secret of credentialSecrets(next)) knownSecrets.add(secret);
|
|
134
|
+
return true;
|
|
135
|
+
}
|
|
136
|
+
async function attemptOnce(prepared, attempt) {
|
|
137
|
+
const hasRetriesLeft = attempt < prepared.retries;
|
|
138
|
+
const timeoutSignal = AbortSignal.timeout(prepared.timeoutMs);
|
|
139
|
+
const combined = combineAborts(timeoutSignal, prepared.cancelSignal);
|
|
140
|
+
let response;
|
|
141
|
+
try {
|
|
142
|
+
response = await fetchImpl(prepared.url, {
|
|
143
|
+
method: prepared.method,
|
|
144
|
+
headers: prepared.headers,
|
|
145
|
+
body: prepared.body,
|
|
146
|
+
signal: combined
|
|
147
|
+
});
|
|
148
|
+
} catch (error) {
|
|
149
|
+
throwIfAborted(prepared.cancelSignal);
|
|
150
|
+
const isStaleSocketFirstTry = attempt === 0 && isConnectionClosed(error);
|
|
151
|
+
if (prepared.idempotent && (hasRetriesLeft || isStaleSocketFirstTry)) return {
|
|
152
|
+
kind: "retry",
|
|
153
|
+
delayMs: backoffDelay({ attempt })
|
|
154
|
+
};
|
|
155
|
+
if (timeoutSignal.aborted) throw new TimeoutError(`Request timed out after ${prepared.timeoutMs}ms`, {
|
|
156
|
+
kind: "http",
|
|
157
|
+
method: prepared.method,
|
|
158
|
+
url: prepared.url,
|
|
159
|
+
timeoutMs: prepared.timeoutMs
|
|
160
|
+
});
|
|
161
|
+
throw buildNetworkError(error, prepared.method, prepared.url);
|
|
162
|
+
}
|
|
163
|
+
const canRetryStatus = hasRetriesLeft && prepared.idempotent;
|
|
164
|
+
if (!response.ok && isRetryableStatus(response.status) && canRetryStatus) {
|
|
165
|
+
const retryAfter = response.headers.get("Retry-After");
|
|
166
|
+
response.body?.cancel().catch(() => void 0);
|
|
167
|
+
return {
|
|
168
|
+
kind: "retry",
|
|
169
|
+
delayMs: backoffDelay({
|
|
170
|
+
attempt,
|
|
171
|
+
retryAfterHeader: retryAfter
|
|
172
|
+
})
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
if (!response.ok) {
|
|
176
|
+
const rawBody = await readBodyForError(response);
|
|
177
|
+
const serverTag = await getServerTag();
|
|
178
|
+
throw new HttpError({
|
|
179
|
+
status: response.status,
|
|
180
|
+
statusText: response.statusText,
|
|
181
|
+
method: prepared.method,
|
|
182
|
+
url: prepared.url,
|
|
183
|
+
responseHeaders: response.headers,
|
|
184
|
+
rawBody,
|
|
185
|
+
serverTag,
|
|
186
|
+
redactionContext
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
assertContentType(response, prepared);
|
|
190
|
+
return {
|
|
191
|
+
kind: "success",
|
|
192
|
+
response
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
async function executeRaw(prepared) {
|
|
196
|
+
try {
|
|
197
|
+
return await runWithRetries((attempt) => attemptOnce(prepared, attempt), prepared.cancelSignal);
|
|
198
|
+
} catch (error) {
|
|
199
|
+
throwIfAborted(prepared.cancelSignal);
|
|
200
|
+
throw error;
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
async function executeWithAuthRefresh(path, opts) {
|
|
204
|
+
const prepared = prepare(path, opts);
|
|
205
|
+
try {
|
|
206
|
+
return {
|
|
207
|
+
response: await executeRaw(prepared),
|
|
208
|
+
prepared
|
|
209
|
+
};
|
|
210
|
+
} catch (error) {
|
|
211
|
+
if (error instanceof HttpError && error.status === UNAUTHORIZED_STATUS) {
|
|
212
|
+
if (await tryRefreshCredential()) {
|
|
213
|
+
const retried = prepare(path, opts);
|
|
214
|
+
return {
|
|
215
|
+
response: await executeRaw(retried),
|
|
216
|
+
prepared: retried
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
throw error;
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
function prepare(path, opts = {}) {
|
|
224
|
+
const method = opts.method ?? "GET";
|
|
225
|
+
const expectContentType = opts.expectContentType ?? "json";
|
|
226
|
+
const url = buildUrl(baseUrl, path, opts.query);
|
|
227
|
+
const headers = new Headers();
|
|
228
|
+
const auth = credentialAuthHeader(credential);
|
|
229
|
+
headers.set(auth.name, auth.value);
|
|
230
|
+
headers.set("accept", acceptHeader(expectContentType));
|
|
231
|
+
headers.set("user-agent", options.userAgent);
|
|
232
|
+
let body = null;
|
|
233
|
+
if (opts.body !== void 0 && opts.body !== null) if (typeof opts.body === "string" || opts.body instanceof URLSearchParams) body = opts.body;
|
|
234
|
+
else if (opts.body instanceof FormData || opts.body instanceof ReadableStream) body = opts.body;
|
|
235
|
+
else if (opts.body instanceof Uint8Array) {
|
|
236
|
+
body = opts.body;
|
|
237
|
+
headers.set("content-type", OCTET_STREAM_CONTENT_TYPE);
|
|
238
|
+
} else {
|
|
239
|
+
body = JSON.stringify(opts.body);
|
|
240
|
+
headers.set("content-type", JSON_CONTENT_TYPE);
|
|
241
|
+
}
|
|
242
|
+
return {
|
|
243
|
+
url,
|
|
244
|
+
method,
|
|
245
|
+
headers,
|
|
246
|
+
body,
|
|
247
|
+
expectContentType,
|
|
248
|
+
retries: opts.retries ?? 3,
|
|
249
|
+
idempotent: opts.idempotent ?? IDEMPOTENT_METHODS.has(method),
|
|
250
|
+
timeoutMs: opts.timeoutMs ?? DEFAULT_TIMEOUT_MS,
|
|
251
|
+
cancelSignal: combineAborts(opts.signal, options.signal)
|
|
252
|
+
};
|
|
253
|
+
}
|
|
254
|
+
let serverProfile = options.server === void 0 ? null : Promise.resolve(options.server);
|
|
255
|
+
async function server(wait = {}) {
|
|
256
|
+
throwIfAborted(wait.signal);
|
|
257
|
+
if (serverProfile === null) {
|
|
258
|
+
const probe = probeServer(transport).then((info) => {
|
|
259
|
+
settledProfile = createServerProfile(info);
|
|
260
|
+
return settledProfile;
|
|
261
|
+
});
|
|
262
|
+
probe.catch(() => {
|
|
263
|
+
serverProfile = null;
|
|
264
|
+
});
|
|
265
|
+
serverProfile = probe;
|
|
266
|
+
}
|
|
267
|
+
return untilAborted(serverProfile, wait.signal);
|
|
268
|
+
}
|
|
269
|
+
const enforceRequirements = options.enforceRequirements ?? true;
|
|
270
|
+
async function requireFeatures(features, wait = {}) {
|
|
271
|
+
if (!enforceRequirements || features.length === 0) return;
|
|
272
|
+
const failure = checkFeatures(features, await server(wait));
|
|
273
|
+
if (failure !== null) throw new CapabilityError(failure);
|
|
274
|
+
}
|
|
275
|
+
async function requireMethod(key, wait = {}) {
|
|
276
|
+
return requireFeatures(methodRequirements(key), wait);
|
|
277
|
+
}
|
|
278
|
+
const transport = {
|
|
279
|
+
server,
|
|
280
|
+
require: requireMethod,
|
|
281
|
+
requireFeatures,
|
|
282
|
+
async requestRaw(path, opts) {
|
|
283
|
+
return (await executeWithAuthRefresh(path, opts ?? {})).response;
|
|
284
|
+
},
|
|
285
|
+
async requestParsed(schema, path, opts) {
|
|
286
|
+
const { response, prepared } = await executeWithAuthRefresh(path, {
|
|
287
|
+
...opts,
|
|
288
|
+
expectContentType: "json"
|
|
289
|
+
});
|
|
290
|
+
return parseJsonResponse(await response.text(), schema, {
|
|
291
|
+
method: prepared.method,
|
|
292
|
+
url: prepared.url,
|
|
293
|
+
status: response.status,
|
|
294
|
+
getServerTag,
|
|
295
|
+
serverSkew: serverSkew()
|
|
296
|
+
});
|
|
297
|
+
},
|
|
298
|
+
async requestStream(path, opts) {
|
|
299
|
+
const { response, prepared } = await executeWithAuthRefresh(path, {
|
|
300
|
+
...opts,
|
|
301
|
+
expectContentType: opts?.expectContentType ?? "binary"
|
|
302
|
+
});
|
|
303
|
+
if (!response.body) throw new NetworkError("Response had no body to stream", {
|
|
304
|
+
method: prepared.method,
|
|
305
|
+
url: prepared.url,
|
|
306
|
+
cause: "missing body"
|
|
307
|
+
});
|
|
308
|
+
return response.body;
|
|
309
|
+
}
|
|
310
|
+
};
|
|
311
|
+
return transport;
|
|
312
|
+
}
|
|
313
|
+
function tagOf(profile) {
|
|
314
|
+
return profile === null ? null : profile.version.tag;
|
|
315
|
+
}
|
|
316
|
+
function buildUrl(baseUrl, path, query) {
|
|
317
|
+
const normalizedPath = path.startsWith("/") ? path : `/${path}`;
|
|
318
|
+
const target = new URL(baseUrl + normalizedPath);
|
|
319
|
+
if (query) for (const [key, value] of Object.entries(query)) {
|
|
320
|
+
if (value === void 0) continue;
|
|
321
|
+
if (Array.isArray(value)) for (const entry of value) target.searchParams.append(key, String(entry));
|
|
322
|
+
else target.searchParams.append(key, String(value));
|
|
323
|
+
}
|
|
324
|
+
return target.toString();
|
|
325
|
+
}
|
|
326
|
+
function acceptHeader(expected) {
|
|
327
|
+
if (expected === "json") return JSON_CONTENT_TYPE;
|
|
328
|
+
if (expected === "text") return "text/*";
|
|
329
|
+
return "*/*";
|
|
330
|
+
}
|
|
331
|
+
function assertContentType(response, prepared) {
|
|
332
|
+
if (prepared.expectContentType === "binary") return;
|
|
333
|
+
const contentType = response.headers.get("content-type");
|
|
334
|
+
if (contentType === null) throwContentTypeMismatch(response, prepared, prepared.expectContentType);
|
|
335
|
+
if (prepared.expectContentType === "json" && !contentType.includes("application/json")) throwContentTypeMismatch(response, prepared, "json");
|
|
336
|
+
if (prepared.expectContentType === "text" && !contentType.startsWith(TEXT_CONTENT_TYPE_PREFIX)) throwContentTypeMismatch(response, prepared, "text");
|
|
337
|
+
}
|
|
338
|
+
function throwContentTypeMismatch(response, prepared, expected) {
|
|
339
|
+
const actual = response.headers.get("content-type") ?? "no content-type";
|
|
340
|
+
throw new HttpError({
|
|
341
|
+
status: response.status,
|
|
342
|
+
statusText: response.statusText,
|
|
343
|
+
method: prepared.method,
|
|
344
|
+
url: prepared.url,
|
|
345
|
+
responseHeaders: response.headers,
|
|
346
|
+
rawBody: null,
|
|
347
|
+
overrideUserMessage: `Expected ${expected} response but got ${actual}`
|
|
348
|
+
});
|
|
349
|
+
}
|
|
350
|
+
async function readBodyForError(response) {
|
|
351
|
+
try {
|
|
352
|
+
return Buffer.from(await response.arrayBuffer()).subarray(0, ERROR_BODY_BYTE_CAP).toString("utf8");
|
|
353
|
+
} catch (error) {
|
|
354
|
+
return `[body read failed: ${errorMessage(error)}]`;
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
//#endregion
|
|
358
|
+
//#region ../client/src/resources/pivot-export.ts
|
|
359
|
+
const PivotedExportsSetting = z.object({ "enable-pivoted-exports": z.boolean() });
|
|
360
|
+
/**
|
|
361
|
+
* Refuse a pivoted export the server would answer with plain rows: a JSON export keeps only the
|
|
362
|
+
* ungrouped rows, and an admin can turn pivoted CSV and XLSX exports off.
|
|
363
|
+
*/
|
|
364
|
+
async function assertPivotedExport(transport, format, options) {
|
|
365
|
+
if (!PivotExportFormat.safeParse(format).success) throw new ConfigError(`a ${format} export cannot be pivoted; only ${PivotExportFormat.options.join(" and ")} can`);
|
|
366
|
+
if (!(await transport.requestParsed(PivotedExportsSetting, "/api/session/properties", { ...options }))["enable-pivoted-exports"]) throw new ConfigError("the server has pivoted exports turned off (the enable-pivoted-exports setting), so it would export the plain rows");
|
|
367
|
+
}
|
|
81
368
|
//#endregion
|
|
82
369
|
//#region ../client/src/resources/card.ts
|
|
83
370
|
const CardApiList = z.array(Card);
|
|
@@ -134,15 +421,22 @@ function cardResource(transport) {
|
|
|
134
421
|
});
|
|
135
422
|
}
|
|
136
423
|
/**
|
|
137
|
-
* Run a
|
|
138
|
-
* form-encoded body and answers bytes, so a caller
|
|
424
|
+
* Run the query associated with a Card, and return its results as a file in the specified
|
|
425
|
+
* format. Unlike `query`, this endpoint takes a form-encoded body and answers bytes, so a caller
|
|
426
|
+
* consumes the stream rather than a value. A pivot the server would answer with plain rows (a
|
|
427
|
+
* JSON export, or pivoted exports turned off) is refused. `csv_include_bom` opens a CSV with a
|
|
428
|
+
* UTF-8 byte order mark; a server without it drops the key silently, so asking for one is refused
|
|
429
|
+
* there before the wire.
|
|
139
430
|
*/
|
|
140
431
|
async function exportQuery(id, format, params, options = {}) {
|
|
141
432
|
await transport.require("card.exportQuery", options);
|
|
433
|
+
await transport.requireFeatures(params.csv_include_bom ? ["exportCsvByteOrderMark"] : [], options);
|
|
434
|
+
if (params.pivot_results) await assertPivotedExport(transport, format, options);
|
|
142
435
|
const body = new URLSearchParams({
|
|
143
436
|
parameters: JSON.stringify(params.parameters),
|
|
144
437
|
format_rows: String(params.format_rows),
|
|
145
|
-
pivot_results: String(params.pivot_results)
|
|
438
|
+
pivot_results: String(params.pivot_results),
|
|
439
|
+
csv_include_bom: String(params.csv_include_bom)
|
|
146
440
|
});
|
|
147
441
|
return transport.requestStream(`/api/card/${id}/query/${format}`, {
|
|
148
442
|
...options,
|
|
@@ -226,20 +520,20 @@ function refPath(ref) {
|
|
|
226
520
|
return encodeURIComponent(ref);
|
|
227
521
|
}
|
|
228
522
|
/**
|
|
229
|
-
* List
|
|
230
|
-
* projection. `Collection` pins `type`, `namespace` and `authority_level`
|
|
231
|
-
* consumer reading a few fields off every collection on the instance narrows
|
|
232
|
-
* carrying a server value outside those sets then costs nothing to a caller
|
|
233
|
-
* field.
|
|
523
|
+
* List every collection the caller can read, the Library and its children among them, parsing each
|
|
524
|
+
* through the caller's own projection. `Collection` pins `type`, `namespace` and `authority_level`
|
|
525
|
+
* to closed enums, so a consumer reading a few fields off every collection on the instance narrows
|
|
526
|
+
* here: one collection carrying a server value outside those sets then costs nothing to a caller
|
|
527
|
+
* that never reads the field.
|
|
234
528
|
*/
|
|
235
|
-
async function
|
|
236
|
-
return transport.requestParsed(z.array(schema), "/api/collection", {
|
|
237
|
-
...options,
|
|
238
|
-
query: { "include-library": true }
|
|
239
|
-
});
|
|
529
|
+
async function listCollectionsAs(transport, schema, options = {}) {
|
|
530
|
+
return transport.requestParsed(z.array(schema), "/api/collection", { ...options });
|
|
240
531
|
}
|
|
241
532
|
function collectionResource(transport) {
|
|
242
|
-
/**
|
|
533
|
+
/**
|
|
534
|
+
* List collections. `filter` picks a server-side preset: everything, archived, or personal. Every
|
|
535
|
+
* preset includes the Library collections that match it.
|
|
536
|
+
*/
|
|
243
537
|
async function list(params = {}, options = {}) {
|
|
244
538
|
await transport.require("collection.list", options);
|
|
245
539
|
return {
|
|
@@ -250,18 +544,6 @@ function collectionResource(transport) {
|
|
|
250
544
|
total: null
|
|
251
545
|
};
|
|
252
546
|
}
|
|
253
|
-
/**
|
|
254
|
-
* List collections including the Library and its children, which the plain listing omits.
|
|
255
|
-
* The Library's own children carry neither `type` nor `is_remote_synced`, so this is where a
|
|
256
|
-
* caller resolves both.
|
|
257
|
-
*/
|
|
258
|
-
async function listWithLibrary(options = {}) {
|
|
259
|
-
await transport.require("collection.listWithLibrary", options);
|
|
260
|
-
return {
|
|
261
|
-
data: await listCollectionsWithLibrary(transport, Collection, options),
|
|
262
|
-
total: null
|
|
263
|
-
};
|
|
264
|
-
}
|
|
265
547
|
/** Get one collection by id, entity id, or the `root`/`trash` alias. */
|
|
266
548
|
async function get(ref, options = {}) {
|
|
267
549
|
await transport.require("collection.get", options);
|
|
@@ -276,7 +558,11 @@ function collectionResource(transport) {
|
|
|
276
558
|
body: params
|
|
277
559
|
});
|
|
278
560
|
}
|
|
279
|
-
/**
|
|
561
|
+
/**
|
|
562
|
+
* Update a collection, patching the fields the body carries. The server reads an absent
|
|
563
|
+
* `archived` as `false`, so a patch without it restores an archived collection, and a patch that
|
|
564
|
+
* moves a collection into the trash ignores `parent_id`.
|
|
565
|
+
*/
|
|
280
566
|
async function update(ref, params, options = {}) {
|
|
281
567
|
await transport.require("collection.update", options);
|
|
282
568
|
return transport.requestParsed(Collection, `/api/collection/${refPath(ref)}`, {
|
|
@@ -309,16 +595,18 @@ function collectionResource(transport) {
|
|
|
309
595
|
});
|
|
310
596
|
}
|
|
311
597
|
/** Fetch the collection hierarchy as a forest of nested nodes. */
|
|
312
|
-
async function tree(options = {}) {
|
|
598
|
+
async function tree(params = {}, options = {}) {
|
|
313
599
|
await transport.require("collection.tree", options);
|
|
314
600
|
return {
|
|
315
|
-
data: await transport.requestParsed(CollectionTreeApiList, "/api/collection/tree", {
|
|
601
|
+
data: await transport.requestParsed(CollectionTreeApiList, "/api/collection/tree", {
|
|
602
|
+
...options,
|
|
603
|
+
query: { "include-library": params["include-library"] }
|
|
604
|
+
}),
|
|
316
605
|
total: null
|
|
317
606
|
};
|
|
318
607
|
}
|
|
319
608
|
return {
|
|
320
609
|
list,
|
|
321
|
-
listWithLibrary,
|
|
322
610
|
get,
|
|
323
611
|
create,
|
|
324
612
|
update,
|
|
@@ -407,9 +695,13 @@ function dashboardResource(transport) {
|
|
|
407
695
|
}
|
|
408
696
|
/**
|
|
409
697
|
* Copy a dashboard, with its tabs and dashcards, into `collection_id` (root when absent). A deep
|
|
410
|
-
* copy duplicates
|
|
411
|
-
*
|
|
412
|
-
*
|
|
698
|
+
* copy duplicates its questions and metrics and references its models. With `is_deep_copy`
|
|
699
|
+
* false or absent the copy references every card, and a dashboard holding unarchived dashboard
|
|
700
|
+
* questions is refused. Archived cards, cards the caller cannot read, and every card on a
|
|
701
|
+
* dashcard whose main card the caller cannot read are left out and reported as `uncopied`, once
|
|
702
|
+
* per dashcard they sat on. A left-out main card takes its dashcard with it; a left-out series
|
|
703
|
+
* card stays on a dashcard whose main card is referenced and is dropped from one whose main card
|
|
704
|
+
* is duplicated. Action, link and placeholder dashcards are not copied.
|
|
413
705
|
*/
|
|
414
706
|
async function copy(id, params = {}, options = {}) {
|
|
415
707
|
await transport.require("dashboard.copy", options);
|
|
@@ -548,6 +840,81 @@ function stripEntityId(dashcard) {
|
|
|
548
840
|
};
|
|
549
841
|
}
|
|
550
842
|
//#endregion
|
|
843
|
+
//#region ../client/src/resources/data-action.ts
|
|
844
|
+
function dataActionResource(transport) {
|
|
845
|
+
async function readSchema(options) {
|
|
846
|
+
const { features } = await transport.server(options);
|
|
847
|
+
return dataActionSchema(features);
|
|
848
|
+
}
|
|
849
|
+
/** List the unarchived data actions the caller can see. `GET /api/action` answers a bare array. */
|
|
850
|
+
async function list(options = {}) {
|
|
851
|
+
await transport.require("dataAction.list", options);
|
|
852
|
+
const schema = await readSchema(options);
|
|
853
|
+
return {
|
|
854
|
+
data: await transport.requestParsed(z.array(schema), "/api/action", { ...options }),
|
|
855
|
+
total: null
|
|
856
|
+
};
|
|
857
|
+
}
|
|
858
|
+
/** Get one unarchived data action by id. */
|
|
859
|
+
async function get(id, options = {}) {
|
|
860
|
+
await transport.require("dataAction.get", options);
|
|
861
|
+
const schema = await readSchema(options);
|
|
862
|
+
return transport.requestParsed(schema, `/api/action/${id}`, { ...options });
|
|
863
|
+
}
|
|
864
|
+
/** Create a data action — a parameterized native query that writes to a database — in a collection. */
|
|
865
|
+
async function create(params, options = {}) {
|
|
866
|
+
await transport.require("dataAction.create", options);
|
|
867
|
+
const schema = await readSchema(options);
|
|
868
|
+
return transport.requestParsed(schema, "/api/action", {
|
|
869
|
+
...options,
|
|
870
|
+
method: "POST",
|
|
871
|
+
body: params
|
|
872
|
+
});
|
|
873
|
+
}
|
|
874
|
+
/** Update a data action by id, patching only the fields the body carries. */
|
|
875
|
+
async function update(id, params, options = {}) {
|
|
876
|
+
await transport.require("dataAction.update", options);
|
|
877
|
+
const schema = await readSchema(options);
|
|
878
|
+
return transport.requestParsed(schema, `/api/action/${id}`, {
|
|
879
|
+
...options,
|
|
880
|
+
method: "PUT",
|
|
881
|
+
body: params
|
|
882
|
+
});
|
|
883
|
+
}
|
|
884
|
+
/** Archive (soft-delete) a data action by id. Metabase models this as an update, not its own endpoint. */
|
|
885
|
+
async function archive(id, options = {}) {
|
|
886
|
+
await transport.require("dataAction.archive", options);
|
|
887
|
+
return update(id, { archived: true }, options);
|
|
888
|
+
}
|
|
889
|
+
/** Delete a data action by id, removing it and the dashboard buttons that run it. */
|
|
890
|
+
async function remove(id, options = {}) {
|
|
891
|
+
await transport.require("dataAction.delete", options);
|
|
892
|
+
await transport.requestRaw(`/api/action/${id}`, {
|
|
893
|
+
...options,
|
|
894
|
+
method: "DELETE",
|
|
895
|
+
expectContentType: "binary"
|
|
896
|
+
});
|
|
897
|
+
}
|
|
898
|
+
/** Execute a data action by id with parameter values keyed by parameter id. */
|
|
899
|
+
async function execute(id, params, options = {}) {
|
|
900
|
+
await transport.require("dataAction.execute", options);
|
|
901
|
+
return transport.requestParsed(DataActionExecuteResult, `/api/action/${id}/execute`, {
|
|
902
|
+
...options,
|
|
903
|
+
method: "POST",
|
|
904
|
+
body: params
|
|
905
|
+
});
|
|
906
|
+
}
|
|
907
|
+
return {
|
|
908
|
+
list,
|
|
909
|
+
get,
|
|
910
|
+
create,
|
|
911
|
+
update,
|
|
912
|
+
archive,
|
|
913
|
+
delete: remove,
|
|
914
|
+
execute
|
|
915
|
+
};
|
|
916
|
+
}
|
|
917
|
+
//#endregion
|
|
551
918
|
//#region ../client/src/resources/database.ts
|
|
552
919
|
const DatabaseApiList = z.object({
|
|
553
920
|
data: z.array(Database),
|
|
@@ -663,7 +1030,8 @@ function datasetResource(transport) {
|
|
|
663
1030
|
*/
|
|
664
1031
|
async function native(datasetQuery, params = {}, options = {}) {
|
|
665
1032
|
await transport.require("dataset.native", options);
|
|
666
|
-
|
|
1033
|
+
const { features } = await transport.server(options);
|
|
1034
|
+
return transport.requestParsed(compiledQuerySchema(features), "/api/dataset/native", {
|
|
667
1035
|
...options,
|
|
668
1036
|
method: "POST",
|
|
669
1037
|
body: {
|
|
@@ -686,18 +1054,33 @@ function datasetResource(transport) {
|
|
|
686
1054
|
});
|
|
687
1055
|
}
|
|
688
1056
|
/**
|
|
689
|
-
*
|
|
690
|
-
* bytes, so a caller consumes the stream rather than a value.
|
|
1057
|
+
* Execute a query and download the result data as a file in the specified format. Unlike
|
|
1058
|
+
* `query`, this endpoint answers bytes, so a caller consumes the stream rather than a value.
|
|
1059
|
+
* `visualization_settings` drive `format_rows` column formatting and, through
|
|
1060
|
+
* `pivot_table.column_split`, the layout `pivot_results` lays the rows out in. The server only
|
|
1061
|
+
* computes that layout for a query it runs as a pivot, which it reads from the query's own
|
|
1062
|
+
* `was-pivot`, so `pivot_results` sets it. A pivot the server would answer with plain rows (a
|
|
1063
|
+
* JSON export, or pivoted exports turned off) is refused. `csv_include_bom` opens a CSV with a
|
|
1064
|
+
* UTF-8 byte order mark; a server without it drops the key silently, so asking for one is refused
|
|
1065
|
+
* there before the wire.
|
|
691
1066
|
*/
|
|
692
1067
|
async function exportQuery(format, params, options = {}) {
|
|
693
1068
|
await transport.require("dataset.exportQuery", options);
|
|
1069
|
+
await transport.requireFeatures(params.csv_include_bom ? ["exportCsvByteOrderMark"] : [], options);
|
|
1070
|
+
if (params.pivot_results) await assertPivotedExport(transport, format, options);
|
|
1071
|
+
const exported = params.pivot_results ? {
|
|
1072
|
+
...params.query,
|
|
1073
|
+
"was-pivot": true
|
|
1074
|
+
} : params.query;
|
|
694
1075
|
return transport.requestStream(`/api/dataset/${format}`, {
|
|
695
1076
|
...options,
|
|
696
1077
|
method: "POST",
|
|
697
1078
|
body: {
|
|
698
|
-
query:
|
|
1079
|
+
query: exported,
|
|
1080
|
+
visualization_settings: params.visualization_settings,
|
|
699
1081
|
format_rows: params.format_rows,
|
|
700
|
-
pivot_results: params.pivot_results
|
|
1082
|
+
pivot_results: params.pivot_results,
|
|
1083
|
+
csv_include_bom: params.csv_include_bom
|
|
701
1084
|
}
|
|
702
1085
|
});
|
|
703
1086
|
}
|
|
@@ -709,133 +1092,18 @@ function datasetResource(transport) {
|
|
|
709
1092
|
};
|
|
710
1093
|
}
|
|
711
1094
|
//#endregion
|
|
712
|
-
//#region ../client/src/domain/dependency.ts
|
|
713
|
-
const DependencyType = z.enum([
|
|
714
|
-
"table",
|
|
715
|
-
"card",
|
|
716
|
-
"snippet",
|
|
717
|
-
"transform",
|
|
718
|
-
"dashboard",
|
|
719
|
-
"document",
|
|
720
|
-
"sandbox",
|
|
721
|
-
"segment",
|
|
722
|
-
"measure"
|
|
723
|
-
]);
|
|
724
|
-
const DependencyUsageType = z.enum([
|
|
725
|
-
"table",
|
|
726
|
-
"snippet",
|
|
727
|
-
"transform",
|
|
728
|
-
"dashboard",
|
|
729
|
-
"document",
|
|
730
|
-
"sandbox",
|
|
731
|
-
"segment",
|
|
732
|
-
"question",
|
|
733
|
-
"model",
|
|
734
|
-
"metric",
|
|
735
|
-
"measure"
|
|
736
|
-
]);
|
|
737
|
-
const DependencyFindingErrorType = z.enum([
|
|
738
|
-
"missing-column",
|
|
739
|
-
"missing-table-alias",
|
|
740
|
-
"missing-table",
|
|
741
|
-
"missing-card",
|
|
742
|
-
"duplicate-column",
|
|
743
|
-
"syntax-error",
|
|
744
|
-
"validation-exception-error"
|
|
745
|
-
]);
|
|
746
|
-
const DependencyErrorSourceType = z.enum([
|
|
747
|
-
"table",
|
|
748
|
-
"card",
|
|
749
|
-
"transform"
|
|
750
|
-
]);
|
|
751
|
-
z.enum([
|
|
752
|
-
"name",
|
|
753
|
-
"location",
|
|
754
|
-
"view-count"
|
|
755
|
-
]);
|
|
756
|
-
z.enum([
|
|
757
|
-
"name",
|
|
758
|
-
"location",
|
|
759
|
-
"dependents-with-errors",
|
|
760
|
-
"dependents-errors"
|
|
761
|
-
]);
|
|
762
|
-
const DependencyCollectionRef = z.object({
|
|
763
|
-
id: CollectionId,
|
|
764
|
-
name: z.string(),
|
|
765
|
-
authority_level: CollectionAuthorityLevel.nullable(),
|
|
766
|
-
is_personal: z.boolean().optional()
|
|
767
|
-
}).loose();
|
|
768
|
-
const DependencyContainerRef = z.object({
|
|
769
|
-
id: z.number().int(),
|
|
770
|
-
name: z.string()
|
|
771
|
-
}).loose();
|
|
772
|
-
const DependencyEntityData = z.object({
|
|
773
|
-
name: z.string().nullable().optional(),
|
|
774
|
-
display_name: z.string().nullable().optional(),
|
|
775
|
-
description: z.string().nullable().optional(),
|
|
776
|
-
type: CardType.nullable().optional(),
|
|
777
|
-
display: z.string().nullable().optional(),
|
|
778
|
-
database_id: z.number().int().nullable().optional(),
|
|
779
|
-
db_id: z.number().int().nullable().optional(),
|
|
780
|
-
schema: z.string().nullable().optional(),
|
|
781
|
-
collection_id: CollectionId.nullable().optional(),
|
|
782
|
-
collection: DependencyCollectionRef.nullable().optional(),
|
|
783
|
-
dashboard_id: z.number().int().nullable().optional(),
|
|
784
|
-
dashboard: DependencyContainerRef.nullable().optional(),
|
|
785
|
-
document_id: z.number().int().nullable().optional(),
|
|
786
|
-
document: DependencyContainerRef.nullable().optional(),
|
|
787
|
-
table_id: z.number().int().nullable().optional(),
|
|
788
|
-
view_count: z.number().int().nullable().optional()
|
|
789
|
-
}).loose();
|
|
790
|
-
const DependencyEntity = z.object({
|
|
791
|
-
id: z.number().int(),
|
|
792
|
-
type: DependencyType,
|
|
793
|
-
data: DependencyEntityData
|
|
794
|
-
}).loose();
|
|
795
|
-
const DependencyNode = DependencyEntity.extend({ dependents_count: z.partialRecord(DependencyUsageType, z.number().int()).nullable() });
|
|
796
|
-
const DependencyFindingError = z.object({
|
|
797
|
-
id: z.number().int(),
|
|
798
|
-
analyzed_entity_type: DependencyType,
|
|
799
|
-
analyzed_entity_id: z.number().int(),
|
|
800
|
-
error_type: DependencyFindingErrorType,
|
|
801
|
-
error_detail: z.string().nullable().optional(),
|
|
802
|
-
source_entity_type: DependencyErrorSourceType.nullable().optional(),
|
|
803
|
-
source_entity_id: z.number().int().nullable().optional()
|
|
804
|
-
}).loose();
|
|
805
|
-
const BreakingSource = DependencyNode.extend({ dependents_errors: z.array(DependencyFindingError).nullable().optional() });
|
|
806
|
-
const DependencyEdge = z.object({
|
|
807
|
-
from_entity_type: DependencyType,
|
|
808
|
-
from_entity_id: z.number().int(),
|
|
809
|
-
to_entity_type: DependencyType,
|
|
810
|
-
to_entity_id: z.number().int()
|
|
811
|
-
}).loose();
|
|
812
|
-
const DependencyGraph = z.object({
|
|
813
|
-
nodes: z.array(DependencyNode),
|
|
814
|
-
edges: z.array(DependencyEdge)
|
|
815
|
-
}).loose();
|
|
816
|
-
//#endregion
|
|
817
1095
|
//#region ../client/src/resources/dependency.ts
|
|
818
1096
|
const DependencyNodeApiList = z.array(DependencyNode);
|
|
819
1097
|
const DependencyEntityApiList = z.array(DependencyEntity);
|
|
820
|
-
const RENAMED_FILTERS = [
|
|
821
|
-
"dependent-types",
|
|
822
|
-
"dependent-card-types",
|
|
823
|
-
"card-types",
|
|
824
|
-
"include-personal-collections",
|
|
825
|
-
"sort-column",
|
|
826
|
-
"sort-direction"
|
|
827
|
-
];
|
|
828
|
-
function filterFeatures(params) {
|
|
829
|
-
return RENAMED_FILTERS.some((key) => params[key] !== void 0) ? ["dependencyKebabCaseFilters"] : [];
|
|
830
|
-
}
|
|
831
1098
|
function dependencyResource(transport) {
|
|
832
1099
|
/**
|
|
833
1100
|
* The upstream dependency graph of one entity. `nodes` holds the starting entity plus every
|
|
834
1101
|
* entity it depends on, directly or transitively; each edge runs from the dependent to what it
|
|
835
|
-
* depends on.
|
|
1102
|
+
* depends on. A measure starts a graph only on a server with `measureDependencyGraph`.
|
|
836
1103
|
*/
|
|
837
1104
|
async function graph(type, id, options = {}) {
|
|
838
1105
|
await transport.require("dependency.graph", options);
|
|
1106
|
+
if (type === "measure") await transport.requireFeatures(["measureDependencyGraph"], options);
|
|
839
1107
|
return transport.requestParsed(DependencyGraph, "/api/ee/dependencies/graph", {
|
|
840
1108
|
...options,
|
|
841
1109
|
query: {
|
|
@@ -852,7 +1120,6 @@ function dependencyResource(transport) {
|
|
|
852
1120
|
*/
|
|
853
1121
|
async function dependents(type, id, params = {}, options = {}) {
|
|
854
1122
|
await transport.require("dependency.dependents", options);
|
|
855
|
-
await transport.requireFeatures(filterFeatures(params), options);
|
|
856
1123
|
return {
|
|
857
1124
|
data: await transport.requestParsed(DependencyNodeApiList, "/api/ee/dependencies/graph/dependents", {
|
|
858
1125
|
...options,
|
|
@@ -879,7 +1146,6 @@ function dependencyResource(transport) {
|
|
|
879
1146
|
*/
|
|
880
1147
|
async function broken(type, id, params = {}, options = {}) {
|
|
881
1148
|
await transport.require("dependency.broken", options);
|
|
882
|
-
await transport.requireFeatures(filterFeatures(params), options);
|
|
883
1149
|
return {
|
|
884
1150
|
data: await transport.requestParsed(DependencyEntityApiList, "/api/ee/dependencies/graph/broken", {
|
|
885
1151
|
...options,
|
|
@@ -897,15 +1163,23 @@ function dependencyResource(transport) {
|
|
|
897
1163
|
};
|
|
898
1164
|
}
|
|
899
1165
|
/**
|
|
900
|
-
* Walk the entities
|
|
901
|
-
*
|
|
1166
|
+
* Walk the entities that no readable, unarchived dependent depends on, one page at a time: an
|
|
1167
|
+
* entity used only by archived content, or by content the caller cannot read, is listed. `types`
|
|
1168
|
+
* and `card-types` narrow which kinds are listed, `query` matches against names and locations,
|
|
902
1169
|
* `include-personal-collections` admits content in personal collections, and `sort-column` /
|
|
903
|
-
* `sort-direction` order the result.
|
|
904
|
-
*
|
|
1170
|
+
* `sort-direction` order the result. A `query` leaves sandboxes out, since they have no name or
|
|
1171
|
+
* location to match, so sandboxes alone with a `query` answer one empty page without a request.
|
|
1172
|
+
* This endpoint pages on the server, so the caller consumes pages and decides how far to pull.
|
|
905
1173
|
*/
|
|
906
1174
|
async function* unreferencedPages(params = {}, options = {}) {
|
|
907
1175
|
await transport.require("dependency.unreferencedPages", options);
|
|
908
|
-
|
|
1176
|
+
if (queryLeavesNoKind(params)) {
|
|
1177
|
+
yield {
|
|
1178
|
+
items: [],
|
|
1179
|
+
total: 0
|
|
1180
|
+
};
|
|
1181
|
+
return;
|
|
1182
|
+
}
|
|
909
1183
|
yield* paginatePages(transport, "/api/ee/dependencies/graph/unreferenced", DependencyNode, {
|
|
910
1184
|
query: itemListQuery(params),
|
|
911
1185
|
...options.offset !== void 0 && { offset: options.offset },
|
|
@@ -923,7 +1197,13 @@ function dependencyResource(transport) {
|
|
|
923
1197
|
*/
|
|
924
1198
|
async function* breakingPages(params = {}, options = {}) {
|
|
925
1199
|
await transport.require("dependency.breakingPages", options);
|
|
926
|
-
|
|
1200
|
+
if (queryLeavesNoKind(params)) {
|
|
1201
|
+
yield {
|
|
1202
|
+
items: [],
|
|
1203
|
+
total: 0
|
|
1204
|
+
};
|
|
1205
|
+
return;
|
|
1206
|
+
}
|
|
927
1207
|
yield* paginatePages(transport, "/api/ee/dependencies/graph/breaking", BreakingSource, {
|
|
928
1208
|
query: itemListQuery(params),
|
|
929
1209
|
...options.offset !== void 0 && { offset: options.offset },
|
|
@@ -940,9 +1220,14 @@ function dependencyResource(transport) {
|
|
|
940
1220
|
breakingPages
|
|
941
1221
|
};
|
|
942
1222
|
}
|
|
1223
|
+
function queryLeavesNoKind(params) {
|
|
1224
|
+
const { query, types } = params;
|
|
1225
|
+
if (query === void 0 || types === void 0 || types.length === 0) return false;
|
|
1226
|
+
return types.every((type) => type === "sandbox");
|
|
1227
|
+
}
|
|
943
1228
|
function itemListQuery(params) {
|
|
944
1229
|
return {
|
|
945
|
-
types: params.types,
|
|
1230
|
+
types: params.types === void 0 ? void 0 : [...new Set(params.types)],
|
|
946
1231
|
"card-types": params["card-types"],
|
|
947
1232
|
query: params.query,
|
|
948
1233
|
"include-personal-collections": params["include-personal-collections"],
|
|
@@ -1109,21 +1394,39 @@ async function fetchOptionalParsed(client, path, schema, options = {}) {
|
|
|
1109
1394
|
//#region ../client/src/resources/field.ts
|
|
1110
1395
|
const FieldApiSummary = z.tuple([z.tuple([z.literal("count"), z.number().int()]), z.tuple([z.literal("distincts"), z.number().int()])]);
|
|
1111
1396
|
function fieldResource(transport) {
|
|
1112
|
-
/**
|
|
1397
|
+
/**
|
|
1398
|
+
* Get one field by id. A server that labels data sensitivity answers `data_sensitivity`, `null`
|
|
1399
|
+
* for an unlabelled field; any other answers the field without the key (`hasDataSensitivity`).
|
|
1400
|
+
*/
|
|
1113
1401
|
async function get(id, options = {}) {
|
|
1114
1402
|
await transport.require("field.get", options);
|
|
1115
|
-
|
|
1403
|
+
const { features } = await transport.server(options);
|
|
1404
|
+
return transport.requestParsed(fieldDetailSchema(features), `/api/field/${id}`, { ...options });
|
|
1116
1405
|
}
|
|
1117
1406
|
/**
|
|
1118
1407
|
* Update a field by id, patching only the fields the body carries. A `data_sensitivity` label is
|
|
1119
1408
|
* a person's call the server's classifier never overwrites, and `null` withdraws it so the
|
|
1120
1409
|
* classifier's own applies again; a server without the column would drop the key silently, so
|
|
1121
|
-
* the label is refused there before the wire.
|
|
1410
|
+
* the label is refused there before the wire. Answers the field the way `get` does.
|
|
1122
1411
|
*/
|
|
1123
1412
|
async function update(id, params, options = {}) {
|
|
1124
1413
|
await transport.require("field.update", options);
|
|
1125
1414
|
await transport.requireFeatures(params.data_sensitivity === void 0 ? [] : ["fieldDataSensitivity"], options);
|
|
1126
|
-
|
|
1415
|
+
const { features } = await transport.server(options);
|
|
1416
|
+
return transport.requestParsed(fieldDetailSchema(features), `/api/field/${id}`, {
|
|
1417
|
+
...options,
|
|
1418
|
+
method: "PUT",
|
|
1419
|
+
body: params
|
|
1420
|
+
});
|
|
1421
|
+
}
|
|
1422
|
+
/**
|
|
1423
|
+
* Label a field's data sensitivity by hand. A person's label is never overwritten by the server's
|
|
1424
|
+
* classifier; `null` withdraws it, so whatever label the classifier wrote shows again. Answers
|
|
1425
|
+
* the field with the label it now carries.
|
|
1426
|
+
*/
|
|
1427
|
+
async function setDataSensitivity(id, params, options = {}) {
|
|
1428
|
+
await transport.require("field.setDataSensitivity", options);
|
|
1429
|
+
return transport.requestParsed(FieldWithDataSensitivity, `/api/field/${id}`, {
|
|
1127
1430
|
...options,
|
|
1128
1431
|
method: "PUT",
|
|
1129
1432
|
body: params
|
|
@@ -1131,8 +1434,11 @@ function fieldResource(transport) {
|
|
|
1131
1434
|
}
|
|
1132
1435
|
/**
|
|
1133
1436
|
* Search the values of `searchId` that contain `value`, case-insensitively, answering the
|
|
1134
|
-
* matching values of `id` paired with them
|
|
1135
|
-
* points at
|
|
1437
|
+
* matching values of `id` paired with them, ordered by value, at most `limit` of them. An FK on
|
|
1438
|
+
* either side is followed to the PK it points at, and a field that resolves to the same field as
|
|
1439
|
+
* `searchId` answers each value alone. Without `value`, the first `limit` values. A field with
|
|
1440
|
+
* custom display values answers every mapped value with its display value instead, matching
|
|
1441
|
+
* `value` against the display value, ignoring both `searchId` and `limit`.
|
|
1136
1442
|
*/
|
|
1137
1443
|
async function search(id, searchId, params, options = {}) {
|
|
1138
1444
|
await transport.require("field.search", options);
|
|
@@ -1146,11 +1452,13 @@ function fieldResource(transport) {
|
|
|
1146
1452
|
}
|
|
1147
1453
|
/**
|
|
1148
1454
|
* The value of `remappedId` on the one row where `id` equals `value`, as `[value, remapped]`,
|
|
1149
|
-
* or `null` when no row matches.
|
|
1455
|
+
* or `null` when no row matches. For a numeric field the server reads the leading number of
|
|
1456
|
+
* `value` and ignores any text after it, refusing only a `value` that has none.
|
|
1150
1457
|
*/
|
|
1151
1458
|
async function remapping(id, remappedId, params, options = {}) {
|
|
1152
1459
|
await transport.require("field.remapping", options);
|
|
1153
|
-
|
|
1460
|
+
const { features } = await transport.server(options);
|
|
1461
|
+
return fetchOptionalParsed(transport, `/api/field/${id}/remapping/${remappedId}`, fieldRemappedValueSchema(features, id === remappedId), {
|
|
1154
1462
|
...options,
|
|
1155
1463
|
query: { value: params.value }
|
|
1156
1464
|
});
|
|
@@ -1173,6 +1481,7 @@ function fieldResource(transport) {
|
|
|
1173
1481
|
return {
|
|
1174
1482
|
get,
|
|
1175
1483
|
update,
|
|
1484
|
+
setDataSensitivity,
|
|
1176
1485
|
search,
|
|
1177
1486
|
remapping,
|
|
1178
1487
|
summary,
|
|
@@ -1204,6 +1513,7 @@ const SyncStashStarted = z.object({
|
|
|
1204
1513
|
task_id: z.number().int().positive()
|
|
1205
1514
|
});
|
|
1206
1515
|
const RemoteSyncSetting = z.string().nullable();
|
|
1516
|
+
const RemoteSyncBranchProperty = z.object({ "remote-sync-branch": z.string().nullable().optional() });
|
|
1207
1517
|
const FORBIDDEN_STATUS = 403;
|
|
1208
1518
|
const UNREGISTERED_STATUS = 404;
|
|
1209
1519
|
function isRemoteUnreadable(error) {
|
|
@@ -1251,16 +1561,24 @@ function gitSyncResource(transport) {
|
|
|
1251
1561
|
/**
|
|
1252
1562
|
* Import content from the remote into Metabase. The endpoint queues a task and returns at once;
|
|
1253
1563
|
* pass `wait` to poll that task until it reaches a terminal status. A server already up to date
|
|
1254
|
-
* answers no task id, and there is then nothing to poll.
|
|
1564
|
+
* answers no task id, and there is then nothing to poll. A server that guards the tracked branch
|
|
1565
|
+
* refuses with 409 when `expected_branch` disagrees with the setting; left out, it is the tracked
|
|
1566
|
+
* branch as read just before the request. `merge` folds the remote's changes into local content
|
|
1567
|
+
* by a three-way merge and keeps un-pushed local changes, where a plain import refuses on a dirty
|
|
1568
|
+
* instance.
|
|
1255
1569
|
*/
|
|
1256
1570
|
async function importFromRemote(params = {}, options = {}) {
|
|
1257
1571
|
await transport.require("gitSync.import", options);
|
|
1572
|
+
await requireMerge(params.merge, options);
|
|
1573
|
+
const expectedBranch = await guardedBranch(params.expected_branch, options);
|
|
1258
1574
|
const started = await transport.requestParsed(SyncImportStarted, "/api/ee/remote-sync/import", {
|
|
1259
1575
|
...options,
|
|
1260
1576
|
method: "POST",
|
|
1261
1577
|
body: {
|
|
1262
1578
|
branch: params.branch,
|
|
1263
|
-
force: params.force
|
|
1579
|
+
force: params.force,
|
|
1580
|
+
merge: params.merge,
|
|
1581
|
+
expected_branch: expectedBranch
|
|
1264
1582
|
}
|
|
1265
1583
|
});
|
|
1266
1584
|
const message = started.message ?? null;
|
|
@@ -1274,19 +1592,36 @@ function gitSyncResource(transport) {
|
|
|
1274
1592
|
final: await settle(params.wait, options)
|
|
1275
1593
|
};
|
|
1276
1594
|
}
|
|
1595
|
+
async function requireMerge(merge, options) {
|
|
1596
|
+
if (merge === true) await transport.requireFeatures(["remoteSyncMerge"], options);
|
|
1597
|
+
}
|
|
1598
|
+
async function guardedBranch(given, options) {
|
|
1599
|
+
if (given !== void 0) return given;
|
|
1600
|
+
const { features } = await transport.server(options);
|
|
1601
|
+
if (!features.remoteSyncBranchGuard) return;
|
|
1602
|
+
return trackedBranch(options);
|
|
1603
|
+
}
|
|
1277
1604
|
/**
|
|
1278
1605
|
* Export Metabase's content to the remote. The endpoint queues a task and returns at once; pass
|
|
1279
|
-
* `wait` to poll that task until it reaches a terminal status.
|
|
1606
|
+
* `wait` to poll that task until it reaches a terminal status. A server that guards the tracked
|
|
1607
|
+
* branch refuses with 409 when `branch` is not the tracked one; left out, it is the tracked branch
|
|
1608
|
+
* as read just before the request there, and the server's own default elsewhere. When the remote
|
|
1609
|
+
* has moved past the last sync, a plain export ends in a `conflict` task where `merge` is
|
|
1610
|
+
* available, and is refused with 400 before any task elsewhere; `merge` folds the remote's changes
|
|
1611
|
+
* in by a three-way merge instead, and `force` overwrites them.
|
|
1280
1612
|
*/
|
|
1281
1613
|
async function exportToRemote(params = {}, options = {}) {
|
|
1282
1614
|
await transport.require("gitSync.export", options);
|
|
1615
|
+
await requireMerge(params.merge, options);
|
|
1616
|
+
const branchName = await guardedBranch(params.branch, options);
|
|
1283
1617
|
const started = await transport.requestParsed(SyncExportStarted, "/api/ee/remote-sync/export", {
|
|
1284
1618
|
...options,
|
|
1285
1619
|
method: "POST",
|
|
1286
1620
|
body: {
|
|
1287
|
-
branch:
|
|
1621
|
+
branch: branchName,
|
|
1288
1622
|
message: params.message,
|
|
1289
|
-
force: params.force
|
|
1623
|
+
force: params.force,
|
|
1624
|
+
merge: params.merge
|
|
1290
1625
|
}
|
|
1291
1626
|
});
|
|
1292
1627
|
if (params.wait === void 0) return {
|
|
@@ -1371,7 +1706,7 @@ function gitSyncResource(transport) {
|
|
|
1371
1706
|
async function syncedCollections(options = {}) {
|
|
1372
1707
|
await transport.require("gitSync.syncedCollections", options);
|
|
1373
1708
|
return {
|
|
1374
|
-
data: (await
|
|
1709
|
+
data: (await listCollectionsAs(transport, SyncScopeCollection, options)).filter((entry) => entry.is_remote_synced === true),
|
|
1375
1710
|
total: null
|
|
1376
1711
|
};
|
|
1377
1712
|
}
|
|
@@ -1387,17 +1722,22 @@ function gitSyncResource(transport) {
|
|
|
1387
1722
|
}
|
|
1388
1723
|
}
|
|
1389
1724
|
/**
|
|
1390
|
-
* The branch git-sync tracks, or null when none is configured
|
|
1391
|
-
* the server has no remote-sync module
|
|
1725
|
+
* The branch git-sync tracks, or null when none is configured. Refuses when the caller may not
|
|
1726
|
+
* read the setting (it is admin-only) or the server has no remote-sync module, rather than
|
|
1727
|
+
* reading either as unset.
|
|
1392
1728
|
*/
|
|
1393
1729
|
async function branch(options = {}) {
|
|
1394
1730
|
await transport.require("gitSync.branch", options);
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1731
|
+
const tracked = (await transport.requestParsed(RemoteSyncBranchProperty, PROBE_PATH, { ...options }))["remote-sync-branch"];
|
|
1732
|
+
if (tracked === void 0) throw new ConfigError("the remote-sync-branch setting is not readable: it is visible to admins only, and absent on a server without the remote-sync module");
|
|
1733
|
+
return tracked;
|
|
1734
|
+
}
|
|
1735
|
+
/** The branch git-sync tracks, refused when none is configured or the caller may not read it. */
|
|
1736
|
+
async function trackedBranch(options = {}) {
|
|
1737
|
+
await transport.require("gitSync.trackedBranch", options);
|
|
1738
|
+
const tracked = await branch(options);
|
|
1739
|
+
if (tracked === null) throw new ConfigError("git-sync tracks no branch: the remote-sync-branch setting is unset");
|
|
1740
|
+
return tracked;
|
|
1401
1741
|
}
|
|
1402
1742
|
/**
|
|
1403
1743
|
* Poll the current task until it reaches a terminal status. A server with no task at all
|
|
@@ -1429,36 +1769,11 @@ function gitSyncResource(transport) {
|
|
|
1429
1769
|
syncedCollections,
|
|
1430
1770
|
remoteUrl,
|
|
1431
1771
|
branch,
|
|
1772
|
+
trackedBranch,
|
|
1432
1773
|
waitForTask
|
|
1433
1774
|
};
|
|
1434
1775
|
}
|
|
1435
1776
|
//#endregion
|
|
1436
|
-
//#region ../client/src/domain/glossary.ts
|
|
1437
|
-
const GlossaryCreator = z.object({
|
|
1438
|
-
id: z.number().int(),
|
|
1439
|
-
email: z.string(),
|
|
1440
|
-
first_name: z.string().nullable(),
|
|
1441
|
-
last_name: z.string().nullable()
|
|
1442
|
-
}).loose();
|
|
1443
|
-
const Glossary = z.object({
|
|
1444
|
-
id: z.number().int(),
|
|
1445
|
-
term: z.string(),
|
|
1446
|
-
definition: z.string(),
|
|
1447
|
-
creator_id: z.number().int(),
|
|
1448
|
-
creator: GlossaryCreator,
|
|
1449
|
-
created_at: z.string(),
|
|
1450
|
-
updated_at: z.string()
|
|
1451
|
-
}).loose();
|
|
1452
|
-
Glossary.pick({
|
|
1453
|
-
id: true,
|
|
1454
|
-
term: true,
|
|
1455
|
-
definition: true
|
|
1456
|
-
}).strip();
|
|
1457
|
-
z.object({
|
|
1458
|
-
term: z.string().min(1),
|
|
1459
|
-
definition: z.string().min(1)
|
|
1460
|
-
}).strict();
|
|
1461
|
-
//#endregion
|
|
1462
1777
|
//#region ../client/src/resources/glossary.ts
|
|
1463
1778
|
const GlossaryApiList = z.object({ data: z.array(Glossary) }).loose();
|
|
1464
1779
|
function glossaryResource(transport) {
|
|
@@ -1511,6 +1826,17 @@ function glossaryResource(transport) {
|
|
|
1511
1826
|
};
|
|
1512
1827
|
}
|
|
1513
1828
|
//#endregion
|
|
1829
|
+
//#region ../client/src/resources/request-body.ts
|
|
1830
|
+
/**
|
|
1831
|
+
* Parse the body a caller hands a method, refusing one that does not match `schema` before any
|
|
1832
|
+
* request. `what` names the body in the refusal.
|
|
1833
|
+
*/
|
|
1834
|
+
function parseRequestBody(schema, value, what) {
|
|
1835
|
+
const parsed = schema.safeParse(value);
|
|
1836
|
+
if (!parsed.success) throw new ConfigError(`invalid ${what}: ${parsed.error.issues.map(formatZodIssue).join("; ")}`);
|
|
1837
|
+
return parsed.data;
|
|
1838
|
+
}
|
|
1839
|
+
//#endregion
|
|
1514
1840
|
//#region ../client/src/resources/library.ts
|
|
1515
1841
|
const LIBRARY_ROOT_PATH = "/api/ee/library/";
|
|
1516
1842
|
const PUBLISH_TABLES_PATH = "/api/ee/data-studio/table/publish-tables";
|
|
@@ -1527,7 +1853,7 @@ function libraryResource(transport) {
|
|
|
1527
1853
|
return toLibrary(wire, await libraryListing(options));
|
|
1528
1854
|
}
|
|
1529
1855
|
async function libraryListing(options) {
|
|
1530
|
-
const data = await
|
|
1856
|
+
const data = await listCollectionsAs(transport, LibraryCollectionInfo, options);
|
|
1531
1857
|
const byId = /* @__PURE__ */ new Map();
|
|
1532
1858
|
for (const collection of data) if (typeof collection.id === "number") byId.set(collection.id, collection);
|
|
1533
1859
|
return byId;
|
|
@@ -1560,26 +1886,31 @@ function libraryResource(transport) {
|
|
|
1560
1886
|
}
|
|
1561
1887
|
/**
|
|
1562
1888
|
* Publish tables — and every upstream table they depend on — into a collection, so they lead the
|
|
1563
|
-
* data pickers and rank up in search. Answers the collection they landed in.
|
|
1889
|
+
* data pickers and rank up in search. Answers the collection they landed in. The endpoint
|
|
1890
|
+
* answers the same whether or not the selectors matched a table, so a body that does not match
|
|
1891
|
+
* `LibraryPublishTablesInput` is refused before any request.
|
|
1564
1892
|
*/
|
|
1565
1893
|
async function publishTables(params, options = {}) {
|
|
1566
1894
|
await transport.require("library.publishTables", options);
|
|
1895
|
+
const body = parseRequestBody(LibraryPublishTablesInput, params, "tables to publish");
|
|
1567
1896
|
return (await transport.requestParsed(PublishTablesResponse, PUBLISH_TABLES_PATH, {
|
|
1568
1897
|
...options,
|
|
1569
1898
|
method: "POST",
|
|
1570
|
-
body
|
|
1899
|
+
body
|
|
1571
1900
|
})).target_collection;
|
|
1572
1901
|
}
|
|
1573
1902
|
/**
|
|
1574
1903
|
* Clear the Library collection from tables, and recursively from every downstream table that
|
|
1575
|
-
* depends on them. The endpoint answers no JSON body
|
|
1904
|
+
* depends on them. The endpoint answers no JSON body, whether or not the selectors matched a
|
|
1905
|
+
* table, so selectors that do not match `TableSelectors` are refused before any request.
|
|
1576
1906
|
*/
|
|
1577
1907
|
async function unpublishTables(params, options = {}) {
|
|
1578
1908
|
await transport.require("library.unpublishTables", options);
|
|
1909
|
+
const body = parseRequestBody(TableSelectors, params, "table selectors");
|
|
1579
1910
|
await transport.requestRaw(UNPUBLISH_TABLES_PATH, {
|
|
1580
1911
|
...options,
|
|
1581
1912
|
method: "POST",
|
|
1582
|
-
body
|
|
1913
|
+
body,
|
|
1583
1914
|
expectContentType: "binary"
|
|
1584
1915
|
});
|
|
1585
1916
|
}
|
|
@@ -1832,48 +2163,21 @@ function metricResource(transport) {
|
|
|
1832
2163
|
};
|
|
1833
2164
|
}
|
|
1834
2165
|
//#endregion
|
|
1835
|
-
//#region ../client/src/domain/moderation-review.ts
|
|
1836
|
-
const ModeratedItemType = z.enum(["card", "dashboard"]);
|
|
1837
|
-
const ModerationStatus = z.enum(["verified"]);
|
|
1838
|
-
const ModerationReview = z.object({
|
|
1839
|
-
id: z.number().int(),
|
|
1840
|
-
moderated_item_id: z.number().int(),
|
|
1841
|
-
moderated_item_type: ModeratedItemType,
|
|
1842
|
-
moderator_id: z.number().int(),
|
|
1843
|
-
status: ModerationStatus.nullable(),
|
|
1844
|
-
text: z.string().nullable(),
|
|
1845
|
-
most_recent: z.boolean(),
|
|
1846
|
-
created_at: z.string(),
|
|
1847
|
-
updated_at: z.string()
|
|
1848
|
-
}).loose();
|
|
1849
|
-
ModerationReview.pick({
|
|
1850
|
-
id: true,
|
|
1851
|
-
moderated_item_id: true,
|
|
1852
|
-
moderated_item_type: true,
|
|
1853
|
-
status: true,
|
|
1854
|
-
text: true,
|
|
1855
|
-
most_recent: true
|
|
1856
|
-
}).strip();
|
|
1857
|
-
z.object({
|
|
1858
|
-
moderated_item_id: z.number().int().positive(),
|
|
1859
|
-
moderated_item_type: ModeratedItemType,
|
|
1860
|
-
status: ModerationStatus.nullable().optional(),
|
|
1861
|
-
text: z.string().nullable().optional()
|
|
1862
|
-
}).strict();
|
|
1863
|
-
//#endregion
|
|
1864
2166
|
//#region ../client/src/resources/moderation-review.ts
|
|
1865
2167
|
function moderationReviewResource(transport) {
|
|
1866
2168
|
/**
|
|
1867
2169
|
* Create a moderation review on a card or dashboard. `status: "verified"` marks the item
|
|
1868
2170
|
* verified, `null` or an absent status records a note that leaves it unverified. The new review
|
|
1869
2171
|
* becomes the item's most recent one; the server keeps the ten newest per item. Admins only.
|
|
2172
|
+
* A body that does not match `ModerationReviewCreateInput` is refused before any request.
|
|
1870
2173
|
*/
|
|
1871
2174
|
async function create(params, options = {}) {
|
|
1872
2175
|
await transport.require("moderationReview.create", options);
|
|
2176
|
+
const body = parseRequestBody(ModerationReviewCreateInput, params, "moderation review");
|
|
1873
2177
|
return transport.requestParsed(ModerationReview, "/api/moderation-review", {
|
|
1874
2178
|
...options,
|
|
1875
2179
|
method: "POST",
|
|
1876
|
-
body
|
|
2180
|
+
body
|
|
1877
2181
|
});
|
|
1878
2182
|
}
|
|
1879
2183
|
return { create };
|
|
@@ -2394,8 +2698,10 @@ function searchResource(transport) {
|
|
|
2394
2698
|
* may match, `archived` swaps the active set for the archived one, `table_db_id` restricts to
|
|
2395
2699
|
* items on one database, `verified` to verified content, `collection` to one collection and its
|
|
2396
2700
|
* descendants, `created_by` to items created by any of those users, `search_native_query` also
|
|
2397
|
-
* matches
|
|
2398
|
-
*
|
|
2701
|
+
* matches native query text but narrows to the models that carry one (cards, models, metrics,
|
|
2702
|
+
* actions, transforms), `include_metadata` attaches each card's `result_metadata`,
|
|
2703
|
+
* `include_dashboard_questions` also matches questions saved into a dashboard (excluded by
|
|
2704
|
+
* default), and `limit`/`offset` are the window the server applies before ranking hydration.
|
|
2399
2705
|
*/
|
|
2400
2706
|
async function query(params = {}, options = {}) {
|
|
2401
2707
|
await transport.require("search.query", options);
|
|
@@ -2412,7 +2718,8 @@ function searchResource(transport) {
|
|
|
2412
2718
|
collection: params.collection,
|
|
2413
2719
|
created_by: params.created_by,
|
|
2414
2720
|
search_native_query: params.search_native_query,
|
|
2415
|
-
include_metadata: params.include_metadata
|
|
2721
|
+
include_metadata: params.include_metadata,
|
|
2722
|
+
include_dashboard_questions: params.include_dashboard_questions
|
|
2416
2723
|
}
|
|
2417
2724
|
});
|
|
2418
2725
|
return {
|
|
@@ -2596,14 +2903,18 @@ function snippetResource(transport) {
|
|
|
2596
2903
|
const TableApiList = z.array(Table);
|
|
2597
2904
|
const TableApiFks = z.array(TableForeignKey);
|
|
2598
2905
|
const SyncSchemaResponse = z.object({ status: z.literal("ok") });
|
|
2599
|
-
const
|
|
2906
|
+
const FieldValuesResponse = z.object({ status: z.literal("success") });
|
|
2600
2907
|
const BulkEditResponse = z.object({});
|
|
2601
2908
|
const BULK_EDIT_PATH = "/api/data-studio/table/edit";
|
|
2909
|
+
const BULK_SYNC_SCHEMA_PATH = "/api/data-studio/table/sync-schema";
|
|
2910
|
+
const BULK_RESCAN_VALUES_PATH = "/api/data-studio/table/rescan-values";
|
|
2911
|
+
const BULK_DISCARD_VALUES_PATH = "/api/data-studio/table/discard-values";
|
|
2602
2912
|
const LIST_PARAM_FEATURES = [
|
|
2603
2913
|
["can-query", "tableListAccessFilters"],
|
|
2604
2914
|
["can-write", "tableListAccessFilters"],
|
|
2605
2915
|
["include-transform-targets", "tableListTransformTargets"],
|
|
2606
|
-
["unused-only", "tableUnusedFilter"]
|
|
2916
|
+
["unused-only", "tableUnusedFilter"],
|
|
2917
|
+
["published-only", "tableListPublishedFilter"]
|
|
2607
2918
|
];
|
|
2608
2919
|
function listParamFeatures(params) {
|
|
2609
2920
|
return LIST_PARAM_FEATURES.filter(([param]) => params[param] !== void 0).map(([, feature]) => feature);
|
|
@@ -2617,7 +2928,7 @@ function tableResource(transport) {
|
|
|
2617
2928
|
* List every table the caller can see, across all databases. `term` matches names and display
|
|
2618
2929
|
* names; `can-query` and `can-write` keep only the tables the caller may query or edit the
|
|
2619
2930
|
* metadata of; `include-transform-targets` adds tables a transform writes to; `unused-only` keeps
|
|
2620
|
-
* tables nothing depends on.
|
|
2931
|
+
* tables nothing depends on; `published-only` keeps tables published to the library.
|
|
2621
2932
|
*/
|
|
2622
2933
|
async function list(params = {}, options = {}) {
|
|
2623
2934
|
await transport.require("table.list", options);
|
|
@@ -2635,6 +2946,7 @@ function tableResource(transport) {
|
|
|
2635
2946
|
"owner-email": params["owner-email"],
|
|
2636
2947
|
"orphan-only": params["orphan-only"],
|
|
2637
2948
|
"unused-only": params["unused-only"],
|
|
2949
|
+
"published-only": params["published-only"],
|
|
2638
2950
|
"can-query": params["can-query"],
|
|
2639
2951
|
"can-write": params["can-write"],
|
|
2640
2952
|
"include-transform-targets": params["include-transform-targets"]
|
|
@@ -2684,38 +2996,107 @@ function tableResource(transport) {
|
|
|
2684
2996
|
};
|
|
2685
2997
|
}
|
|
2686
2998
|
/**
|
|
2687
|
-
* Trigger a
|
|
2688
|
-
*
|
|
2999
|
+
* Trigger a sync of this table: its columns, their fingerprints and its cached field values. It
|
|
3000
|
+
* never discovers new tables. The sync runs after the call returns; a warehouse the server cannot
|
|
3001
|
+
* connect to is a 422.
|
|
2689
3002
|
*/
|
|
2690
3003
|
async function syncSchema(id, options = {}) {
|
|
2691
3004
|
await transport.require("table.syncSchema", options);
|
|
2692
|
-
|
|
2693
|
-
|
|
2694
|
-
|
|
2695
|
-
|
|
3005
|
+
return {
|
|
3006
|
+
id,
|
|
3007
|
+
status: (await transport.requestParsed(SyncSchemaResponse, `/api/table/${id}/sync_schema`, {
|
|
3008
|
+
...options,
|
|
3009
|
+
method: "POST"
|
|
3010
|
+
})).status
|
|
3011
|
+
};
|
|
2696
3012
|
}
|
|
2697
3013
|
/**
|
|
2698
|
-
* Trigger an update of the field values of every eligible field of this table
|
|
2699
|
-
* after the call returns.
|
|
3014
|
+
* Trigger an update of the field values of every eligible field of this table that already has a
|
|
3015
|
+
* cached set. The scan runs after the call returns.
|
|
2700
3016
|
*/
|
|
2701
3017
|
async function rescanValues(id, options = {}) {
|
|
2702
3018
|
await transport.require("table.rescanValues", options);
|
|
2703
|
-
|
|
2704
|
-
|
|
2705
|
-
|
|
2706
|
-
|
|
3019
|
+
return {
|
|
3020
|
+
id,
|
|
3021
|
+
status: (await transport.requestParsed(FieldValuesResponse, `/api/table/${id}/rescan_values`, {
|
|
3022
|
+
...options,
|
|
3023
|
+
method: "POST"
|
|
3024
|
+
})).status
|
|
3025
|
+
};
|
|
3026
|
+
}
|
|
3027
|
+
/**
|
|
3028
|
+
* Discard the cached field values of every field of this table, custom display values included.
|
|
3029
|
+
* No scan recreates a discarded set; the server rebuilds it, without the display values, the next
|
|
3030
|
+
* time the field's values are read.
|
|
3031
|
+
*/
|
|
3032
|
+
async function discardValues(id, options = {}) {
|
|
3033
|
+
await transport.require("table.discardValues", options);
|
|
3034
|
+
return {
|
|
3035
|
+
id,
|
|
3036
|
+
status: (await transport.requestParsed(FieldValuesResponse, `/api/table/${id}/discard_values`, {
|
|
3037
|
+
...options,
|
|
3038
|
+
method: "POST"
|
|
3039
|
+
})).status
|
|
3040
|
+
};
|
|
2707
3041
|
}
|
|
2708
3042
|
/**
|
|
2709
3043
|
* Set the same metadata on every table the selectors pick out. A table leaving the `hidden` data
|
|
2710
|
-
* layer is re-synced after the call returns.
|
|
3044
|
+
* layer is re-synced after the call returns. The server answers the same whether or not the
|
|
3045
|
+
* selectors matched a table.
|
|
2711
3046
|
*/
|
|
2712
3047
|
async function bulkEdit(params, options = {}) {
|
|
2713
3048
|
await transport.require("table.bulkEdit", options);
|
|
3049
|
+
await requireDataAuthorityNull(params.data_authority, options);
|
|
2714
3050
|
await transport.requestParsed(BulkEditResponse, BULK_EDIT_PATH, {
|
|
2715
3051
|
...options,
|
|
2716
3052
|
method: "POST",
|
|
2717
3053
|
body: params
|
|
2718
3054
|
});
|
|
3055
|
+
return {
|
|
3056
|
+
accepted: true,
|
|
3057
|
+
...params
|
|
3058
|
+
};
|
|
3059
|
+
}
|
|
3060
|
+
async function requireDataAuthorityNull(value, options) {
|
|
3061
|
+
if (value === null) await transport.requireFeatures(["tableUserValueWithdrawal"], options);
|
|
3062
|
+
}
|
|
3063
|
+
async function postSelection(path, selectors, options) {
|
|
3064
|
+
const body = parseRequestBody(TableSelectors, selectors, "table selectors");
|
|
3065
|
+
await transport.requestRaw(path, {
|
|
3066
|
+
...options,
|
|
3067
|
+
method: "POST",
|
|
3068
|
+
body,
|
|
3069
|
+
expectContentType: "binary"
|
|
3070
|
+
});
|
|
3071
|
+
return {
|
|
3072
|
+
accepted: true,
|
|
3073
|
+
...body
|
|
3074
|
+
};
|
|
3075
|
+
}
|
|
3076
|
+
/**
|
|
3077
|
+
* Trigger a sync of every table the selectors pick out: its columns, their fingerprints and its
|
|
3078
|
+
* cached field values. Every database behind them must answer a connection test first, or the
|
|
3079
|
+
* call is a 422; the syncs run after it returns.
|
|
3080
|
+
*/
|
|
3081
|
+
async function bulkSyncSchema(selectors, options = {}) {
|
|
3082
|
+
await transport.require("table.bulkSyncSchema", options);
|
|
3083
|
+
return postSelection(BULK_SYNC_SCHEMA_PATH, selectors, options);
|
|
3084
|
+
}
|
|
3085
|
+
/**
|
|
3086
|
+
* Trigger a field-values rescan of every table the selectors pick out, refreshing the sets that
|
|
3087
|
+
* are already cached. The scans run after the call returns.
|
|
3088
|
+
*/
|
|
3089
|
+
async function bulkRescanValues(selectors, options = {}) {
|
|
3090
|
+
await transport.require("table.bulkRescanValues", options);
|
|
3091
|
+
return postSelection(BULK_RESCAN_VALUES_PATH, selectors, options);
|
|
3092
|
+
}
|
|
3093
|
+
/**
|
|
3094
|
+
* Discard the cached field values of every table the selectors pick out, custom display values
|
|
3095
|
+
* included. No scan recreates a discarded set.
|
|
3096
|
+
*/
|
|
3097
|
+
async function bulkDiscardValues(selectors, options = {}) {
|
|
3098
|
+
await transport.require("table.bulkDiscardValues", options);
|
|
3099
|
+
return postSelection(BULK_DISCARD_VALUES_PATH, selectors, options);
|
|
2719
3100
|
}
|
|
2720
3101
|
async function updateFromCsv(id, action, file, options) {
|
|
2721
3102
|
await transport.requestRaw(`/api/table/${id}/${UPLOAD_UPDATE_PATHS[action]}`, {
|
|
@@ -2757,7 +3138,11 @@ function tableResource(transport) {
|
|
|
2757
3138
|
fks,
|
|
2758
3139
|
syncSchema,
|
|
2759
3140
|
rescanValues,
|
|
3141
|
+
discardValues,
|
|
2760
3142
|
bulkEdit,
|
|
3143
|
+
bulkSyncSchema,
|
|
3144
|
+
bulkRescanValues,
|
|
3145
|
+
bulkDiscardValues,
|
|
2761
3146
|
appendCsv,
|
|
2762
3147
|
replaceCsv
|
|
2763
3148
|
};
|
|
@@ -3584,6 +3969,167 @@ function transformTagResource(transport) {
|
|
|
3584
3969
|
};
|
|
3585
3970
|
}
|
|
3586
3971
|
//#endregion
|
|
3972
|
+
//#region ../client/src/domain/transform-test.ts
|
|
3973
|
+
const TransformTestTable = z.object({
|
|
3974
|
+
schema: z.string().min(1).nullable().optional(),
|
|
3975
|
+
name: z.string().min(1)
|
|
3976
|
+
}).loose();
|
|
3977
|
+
const TransformTestColumn = z.object({
|
|
3978
|
+
name: z.string().min(1),
|
|
3979
|
+
cast_type: z.string().min(1)
|
|
3980
|
+
}).loose();
|
|
3981
|
+
const TransformTestCell = z.union([
|
|
3982
|
+
z.boolean(),
|
|
3983
|
+
z.number(),
|
|
3984
|
+
z.string(),
|
|
3985
|
+
z.null()
|
|
3986
|
+
]);
|
|
3987
|
+
const TransformTestRow = z.record(z.string(), TransformTestCell);
|
|
3988
|
+
const TransformTestSqlInput = z.object({
|
|
3989
|
+
table: TransformTestTable,
|
|
3990
|
+
format: z.literal("sql"),
|
|
3991
|
+
sql: z.string().min(1)
|
|
3992
|
+
}).loose();
|
|
3993
|
+
const TransformTestRowsInput = z.object({
|
|
3994
|
+
table: TransformTestTable,
|
|
3995
|
+
format: z.literal("rows"),
|
|
3996
|
+
columns: z.array(TransformTestColumn).min(1),
|
|
3997
|
+
rows: z.array(TransformTestRow)
|
|
3998
|
+
}).loose();
|
|
3999
|
+
const TransformTestInput = z.discriminatedUnion("format", [TransformTestSqlInput, TransformTestRowsInput]);
|
|
4000
|
+
const TransformTestEqualsSqlExpectation = z.object({
|
|
4001
|
+
type: z.literal("equals"),
|
|
4002
|
+
name: z.string().min(1),
|
|
4003
|
+
format: z.literal("sql"),
|
|
4004
|
+
sql: z.string().min(1)
|
|
4005
|
+
}).loose();
|
|
4006
|
+
const TransformTestEqualsRowsExpectation = z.object({
|
|
4007
|
+
type: z.literal("equals"),
|
|
4008
|
+
name: z.string().min(1),
|
|
4009
|
+
format: z.literal("rows"),
|
|
4010
|
+
columns: z.array(TransformTestColumn).min(1),
|
|
4011
|
+
rows: z.array(TransformTestRow)
|
|
4012
|
+
}).loose();
|
|
4013
|
+
const TransformTestEqualsExpectation = z.discriminatedUnion("format", [TransformTestEqualsSqlExpectation, TransformTestEqualsRowsExpectation]);
|
|
4014
|
+
const TransformTestEmptyExpectation = z.object({
|
|
4015
|
+
type: z.literal("empty"),
|
|
4016
|
+
name: z.string().min(1),
|
|
4017
|
+
sql: z.string().min(1)
|
|
4018
|
+
}).loose();
|
|
4019
|
+
const TransformTestExpectation = z.discriminatedUnion("type", [TransformTestEqualsExpectation, TransformTestEmptyExpectation]);
|
|
4020
|
+
const TransformTest = z.object({
|
|
4021
|
+
id: z.number().int(),
|
|
4022
|
+
entity_id: z.string(),
|
|
4023
|
+
transform_id: z.number().int(),
|
|
4024
|
+
creator_id: z.number().int(),
|
|
4025
|
+
name: z.string(),
|
|
4026
|
+
description: z.string().nullable(),
|
|
4027
|
+
inputs: z.array(TransformTestInput),
|
|
4028
|
+
expectations: z.array(TransformTestExpectation),
|
|
4029
|
+
created_at: z.string(),
|
|
4030
|
+
updated_at: z.string()
|
|
4031
|
+
}).loose();
|
|
4032
|
+
TransformTest.pick({
|
|
4033
|
+
id: true,
|
|
4034
|
+
transform_id: true,
|
|
4035
|
+
name: true,
|
|
4036
|
+
description: true
|
|
4037
|
+
}).strip();
|
|
4038
|
+
z.object({
|
|
4039
|
+
transform_id: z.number().int().positive(),
|
|
4040
|
+
name: z.string().min(1),
|
|
4041
|
+
description: z.string().nullable().optional(),
|
|
4042
|
+
inputs: z.array(TransformTestInput),
|
|
4043
|
+
expectations: z.array(TransformTestExpectation)
|
|
4044
|
+
}).loose();
|
|
4045
|
+
z.object({
|
|
4046
|
+
transform_id: z.number().int().positive().optional(),
|
|
4047
|
+
name: z.string().min(1).optional(),
|
|
4048
|
+
description: z.string().nullable().optional(),
|
|
4049
|
+
inputs: z.array(TransformTestInput).optional(),
|
|
4050
|
+
expectations: z.array(TransformTestExpectation).optional()
|
|
4051
|
+
}).loose();
|
|
4052
|
+
const TransformTestResultColumn = z.object({
|
|
4053
|
+
name: z.string(),
|
|
4054
|
+
database_type: z.string()
|
|
4055
|
+
}).loose();
|
|
4056
|
+
const TransformTestExpectationError = z.object({
|
|
4057
|
+
type: z.string(),
|
|
4058
|
+
message: z.string()
|
|
4059
|
+
}).loose();
|
|
4060
|
+
const TransformTestCellMismatch = z.object({
|
|
4061
|
+
column: z.string(),
|
|
4062
|
+
expected: TransformTestCell,
|
|
4063
|
+
actual: TransformTestCell
|
|
4064
|
+
}).loose();
|
|
4065
|
+
const TransformTestRowCounts = z.object({
|
|
4066
|
+
actual: z.number().int(),
|
|
4067
|
+
expected: z.number().int()
|
|
4068
|
+
}).loose();
|
|
4069
|
+
const TransformTestEqualsFindings = z.object({
|
|
4070
|
+
name: z.string(),
|
|
4071
|
+
type: z.literal("equals"),
|
|
4072
|
+
status: z.enum(["passed", "failed"]),
|
|
4073
|
+
columns: z.array(TransformTestResultColumn),
|
|
4074
|
+
"row-counts": TransformTestRowCounts,
|
|
4075
|
+
"extra-rows": z.array(TransformTestRow),
|
|
4076
|
+
"missing-rows": z.array(TransformTestRow),
|
|
4077
|
+
"cell-mismatches": z.array(TransformTestCellMismatch),
|
|
4078
|
+
truncated: z.number().int()
|
|
4079
|
+
}).loose();
|
|
4080
|
+
const TransformTestEqualsError = z.object({
|
|
4081
|
+
name: z.string(),
|
|
4082
|
+
type: z.literal("equals"),
|
|
4083
|
+
status: z.literal("error"),
|
|
4084
|
+
error: TransformTestExpectationError
|
|
4085
|
+
}).loose();
|
|
4086
|
+
const TransformTestEqualsResult = z.discriminatedUnion("status", [TransformTestEqualsFindings, TransformTestEqualsError]);
|
|
4087
|
+
const TransformTestEmptyPassed = z.object({
|
|
4088
|
+
name: z.string(),
|
|
4089
|
+
type: z.literal("empty"),
|
|
4090
|
+
status: z.literal("passed")
|
|
4091
|
+
}).loose();
|
|
4092
|
+
const TransformTestEmptyFailed = z.object({
|
|
4093
|
+
name: z.string(),
|
|
4094
|
+
type: z.literal("empty"),
|
|
4095
|
+
status: z.literal("failed"),
|
|
4096
|
+
columns: z.array(TransformTestResultColumn),
|
|
4097
|
+
sample: z.array(TransformTestRow),
|
|
4098
|
+
truncated: z.number().int()
|
|
4099
|
+
}).loose();
|
|
4100
|
+
const TransformTestEmptyError = z.object({
|
|
4101
|
+
name: z.string(),
|
|
4102
|
+
type: z.literal("empty"),
|
|
4103
|
+
status: z.literal("error"),
|
|
4104
|
+
error: TransformTestExpectationError
|
|
4105
|
+
}).loose();
|
|
4106
|
+
const TransformTestEmptyResult = z.discriminatedUnion("status", [
|
|
4107
|
+
TransformTestEmptyPassed,
|
|
4108
|
+
TransformTestEmptyFailed,
|
|
4109
|
+
TransformTestEmptyError
|
|
4110
|
+
]);
|
|
4111
|
+
const TransformTestExpectationResult = z.discriminatedUnion("type", [TransformTestEqualsResult, TransformTestEmptyResult]);
|
|
4112
|
+
const TransformTestRunResult = z.object({
|
|
4113
|
+
status: z.enum(["passed", "failed"]),
|
|
4114
|
+
expectations: z.array(TransformTestExpectationResult),
|
|
4115
|
+
tables: z.record(z.string(), z.string())
|
|
4116
|
+
}).loose();
|
|
4117
|
+
z.enum([
|
|
4118
|
+
"transform-test.unknown-column",
|
|
4119
|
+
"transform-test.ambiguous-column",
|
|
4120
|
+
"transform-test.missing-inputs",
|
|
4121
|
+
"transform-test.unused-inputs",
|
|
4122
|
+
"transform-test.duplicate-input-table",
|
|
4123
|
+
"transform-test.unparseable-source",
|
|
4124
|
+
"transform-test.unremapped-reference",
|
|
4125
|
+
"transform-test.unsupported-transform",
|
|
4126
|
+
"transform-test.unsupported-driver",
|
|
4127
|
+
"transform-test.transform-failed",
|
|
4128
|
+
"transform-test.setup-failed",
|
|
4129
|
+
"transform-test.expectation-failed",
|
|
4130
|
+
"transform-test.unsupported-format"
|
|
4131
|
+
]);
|
|
4132
|
+
//#endregion
|
|
3587
4133
|
//#region ../client/src/resources/transform-test.ts
|
|
3588
4134
|
const TransformTestApiList = z.array(TransformTest);
|
|
3589
4135
|
function transformTestResource(transport) {
|
|
@@ -3738,6 +4284,7 @@ function createClient(config, options) {
|
|
|
3738
4284
|
collection: collectionResource(transport),
|
|
3739
4285
|
contentTranslation: contentTranslationResource(transport),
|
|
3740
4286
|
dashboard: dashboardResource(transport),
|
|
4287
|
+
dataAction: dataActionResource(transport),
|
|
3741
4288
|
database: databaseResource(transport),
|
|
3742
4289
|
dataset: datasetResource(transport),
|
|
3743
4290
|
dependency: dependencyResource(transport),
|