@metabase/client 0.0.0-stage → 0.1.1
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/CHANGELOG.md +28 -0
- package/LICENSE +661 -0
- package/README.md +490 -2
- package/dist/api-key-DJeN1-7G.d.ts +46 -0
- package/dist/auth/credential.d.ts +2 -0
- package/dist/auth/credential.js +61 -0
- package/dist/auth/oauth-login.d.ts +2 -0
- package/dist/auth/oauth-login.js +2 -0
- package/dist/auth/oauth-session.d.ts +2 -0
- package/dist/auth/oauth-session.js +31 -0
- package/dist/card-BxBzr5Uj.d.ts +1392 -0
- package/dist/card-DN0sLkCG.d.ts +33 -0
- package/dist/client-DdXLlH1B.d.ts +3380 -0
- package/dist/client.d.ts +2 -0
- package/dist/client.js +99 -0
- package/dist/collection-DGnTvD6R.d.ts +294 -0
- package/dist/collection-fFahL-ub.d.ts +53 -0
- package/dist/content-translation-zfUkE_OG.d.ts +8 -0
- package/dist/credential-6aOEGqMH.d.ts +30 -0
- package/dist/cron-DThzerR6.d.ts +9 -0
- package/dist/csv-upload--K35QedP.d.ts +8 -0
- package/dist/dashboard-CM7RmNeE.d.ts +38 -0
- package/dist/dashboard-DtLXVgtf.d.ts +978 -0
- package/dist/data-action-CkXVrOUH.d.ts +97 -0
- package/dist/data-app-CqP5_fpB.d.ts +76 -0
- package/dist/database-B0JNZjDN.d.ts +27 -0
- package/dist/database-BxqDmfcj.d.ts +997 -0
- package/dist/dataset-BBNGPVec.d.ts +4144 -0
- package/dist/dataset-BUirJ1rO.d.ts +23 -0
- package/dist/dependency-CzpXmeu7.d.ts +299 -0
- package/dist/dependency-arB8Cr2H.d.ts +879 -0
- package/dist/document-tLd6pYWe.d.ts +115 -0
- package/dist/domain/api-key.d.ts +2 -0
- package/dist/domain/api-key.js +31 -0
- package/dist/domain/card.d.ts +2 -0
- package/dist/domain/card.js +140 -0
- package/dist/domain/collection.d.ts +2 -0
- package/dist/domain/collection.js +137 -0
- package/dist/domain/content-translation.d.ts +2 -0
- package/dist/domain/content-translation.js +5 -0
- package/dist/domain/cron.d.ts +2 -0
- package/dist/domain/cron.js +5 -0
- package/dist/domain/dashboard.d.ts +2 -0
- package/dist/domain/dashboard.js +211 -0
- package/dist/domain/data-action.d.ts +2 -0
- package/dist/domain/data-action.js +91 -0
- package/dist/domain/data-app.d.ts +2 -0
- package/dist/domain/data-app.js +52 -0
- package/dist/domain/database.d.ts +2 -0
- package/dist/domain/database.js +56 -0
- package/dist/domain/dataset.d.ts +2 -0
- package/dist/domain/dataset.js +56 -0
- package/dist/domain/dependency.d.ts +2 -0
- package/dist/domain/dependency.js +168 -0
- package/dist/domain/document.d.ts +2 -0
- package/dist/domain/document.js +94 -0
- package/dist/domain/eid-translation.d.ts +2 -0
- package/dist/domain/eid-translation.js +36 -0
- package/dist/domain/embedding.d.ts +2 -0
- package/dist/domain/embedding.js +9 -0
- package/dist/domain/erd.d.ts +2 -0
- package/dist/domain/erd.js +45 -0
- package/dist/domain/field.d.ts +2 -0
- package/dist/domain/field.js +274 -0
- package/dist/domain/git-sync.d.ts +2 -0
- package/dist/domain/git-sync.js +147 -0
- package/dist/domain/glossary.d.ts +2 -0
- package/dist/domain/glossary.js +30 -0
- package/dist/domain/library.d.ts +2 -0
- package/dist/domain/library.js +89 -0
- package/dist/domain/measure.d.ts +2 -0
- package/dist/domain/measure.js +43 -0
- package/dist/domain/metric.d.ts +2 -0
- package/dist/domain/metric.js +139 -0
- package/dist/domain/moderation-review.d.ts +2 -0
- package/dist/domain/moderation-review.js +31 -0
- package/dist/domain/notification.d.ts +2 -0
- package/dist/domain/notification.js +143 -0
- package/dist/domain/parameter.d.ts +2 -0
- package/dist/domain/parameter.js +109 -0
- package/dist/domain/permission.d.ts +2 -0
- package/dist/domain/permission.js +36 -0
- package/dist/domain/pulse.d.ts +2 -0
- package/dist/domain/pulse.js +140 -0
- package/dist/domain/query.d.ts +2 -0
- package/dist/domain/query.js +13 -0
- package/dist/domain/replacement.d.ts +2 -0
- package/dist/domain/replacement.js +93 -0
- package/dist/domain/revision.d.ts +2 -0
- package/dist/domain/revision.js +90 -0
- package/dist/domain/search.d.ts +2 -0
- package/dist/domain/search.js +63 -0
- package/dist/domain/segment.d.ts +2 -0
- package/dist/domain/segment.js +46 -0
- package/dist/domain/session-properties.d.ts +2 -0
- package/dist/domain/session-properties.js +14 -0
- package/dist/domain/setting.d.ts +2 -0
- package/dist/domain/setting.js +22 -0
- package/dist/domain/setup.d.ts +2 -0
- package/dist/domain/setup.js +21 -0
- package/dist/domain/snippet.d.ts +2 -0
- package/dist/domain/snippet.js +38 -0
- package/dist/domain/table.d.ts +2 -0
- package/dist/domain/table.js +187 -0
- package/dist/domain/text.d.ts +5 -0
- package/dist/domain/text.js +6 -0
- package/dist/domain/timeline.d.ts +2 -0
- package/dist/domain/timeline.js +97 -0
- package/dist/domain/transform-dag-run.d.ts +2 -0
- package/dist/domain/transform-dag-run.js +19 -0
- package/dist/domain/transform-inspector.d.ts +2 -0
- package/dist/domain/transform-inspector.js +142 -0
- package/dist/domain/transform-job.d.ts +2 -0
- package/dist/domain/transform-job.js +115 -0
- package/dist/domain/transform-python.d.ts +2 -0
- package/dist/domain/transform-python.js +51 -0
- package/dist/domain/transform-tag.d.ts +2 -0
- package/dist/domain/transform-tag.js +17 -0
- package/dist/domain/transform-test.d.ts +2 -0
- package/dist/domain/transform-test.js +176 -0
- package/dist/domain/transform.d.ts +2 -0
- package/dist/domain/transform.js +304 -0
- package/dist/domain/upload.d.ts +2 -0
- package/dist/domain/upload.js +13 -0
- package/dist/domain/user.d.ts +2 -0
- package/dist/domain/user.js +16 -0
- package/dist/eid-translation-CH6NPWd-.d.ts +143 -0
- package/dist/embedding-oU3gqfgX.d.ts +10 -0
- package/dist/erd-BdeFEeSy.d.ts +842 -0
- package/dist/erd-CbV7xvAc.d.ts +51 -0
- package/dist/errors-DdMlaXqq.js +330 -0
- package/dist/errors.d.ts +2 -0
- package/dist/errors.js +189 -0
- package/dist/features-SMSfJhB6.d.ts +295 -0
- package/dist/field-D1Pfk-0S.d.ts +50 -0
- package/dist/field-p9Rme2zB.d.ts +2549 -0
- package/dist/git-sync-BTf1aYHr.d.ts +205 -0
- package/dist/git-sync-C99SVdJ9.d.ts +258 -0
- package/dist/glossary-CHK3elPj.d.ts +35 -0
- package/dist/glossary-DFvnz-E5.d.ts +15 -0
- package/dist/http/errors.d.ts +2 -0
- package/dist/http/errors.js +2 -0
- package/dist/http/oauth.d.ts +2 -0
- package/dist/http/oauth.js +201 -0
- package/dist/http/retry.d.ts +19 -0
- package/dist/http/retry.js +33 -0
- package/dist/http/transport.d.ts +2 -0
- package/dist/http/transport.js +2 -0
- package/dist/index.d.ts +62 -0
- package/dist/index.js +64 -0
- package/dist/input-gate-registry-Dai7SfXb.js +14 -0
- package/dist/input-gates-DwKoTJVQ.d.ts +28 -0
- package/dist/json-BksZpXDC.d.ts +19 -0
- package/dist/json-pointer.d.ts +5 -0
- package/dist/json-pointer.js +10 -0
- package/dist/json.d.ts +2 -0
- package/dist/json.js +44 -0
- package/dist/known-range-DTOBgTEC.d.ts +7 -0
- package/dist/library-B9pEq7qP.d.ts +230 -0
- package/dist/list-BT_bBm9Z.d.ts +7 -0
- package/dist/list.d.ts +2 -0
- package/dist/list.js +1 -0
- package/dist/measure-CgH14YQZ.d.ts +44 -0
- package/dist/measure-lPz8qnwz.d.ts +108 -0
- package/dist/metric-DcYloqOQ.d.ts +2655 -0
- package/dist/moderation-review-B4RUTZ6_.d.ts +56 -0
- package/dist/network-error-5g4U1iul.js +62 -0
- package/dist/notification-Cp5GJErS.d.ts +22 -0
- package/dist/notification-D1MThyKE.d.ts +443 -0
- package/dist/oauth-C4ordeoJ.d.ts +59 -0
- package/dist/oauth-login-CJsT_3EE.d.ts +19 -0
- package/dist/oauth-login-D734Jvbq.js +179 -0
- package/dist/oauth-session-BlIlcd8Q.d.ts +6 -0
- package/dist/paginate-COuL0Gzl.d.ts +24 -0
- package/dist/paginate.d.ts +2 -0
- package/dist/paginate.js +49 -0
- package/dist/parameter-ak-J-IOj.d.ts +190 -0
- package/dist/permission-BnCQw5Kp.d.ts +149 -0
- package/dist/poll-CIwnee7h.d.ts +15 -0
- package/dist/poll.d.ts +2 -0
- package/dist/poll.js +47 -0
- package/dist/predicates.d.ts +10 -0
- package/dist/predicates.js +18 -0
- package/dist/pulse-0LG3K6qO.d.ts +598 -0
- package/dist/pulse-BzKmz3Yn.d.ts +18 -0
- package/dist/query-Xsin530u.d.ts +23 -0
- package/dist/refusal-B9aeHMc9.js +130 -0
- package/dist/replacement-BGyggp-G.d.ts +2467 -0
- package/dist/replacement-CVebCuNp.d.ts +128 -0
- package/dist/requirement-check-glU7wqhQ.d.ts +17 -0
- package/dist/requirements-Dx_ZVzl7.d.ts +227 -0
- package/dist/resources/api-key.d.ts +11 -0
- package/dist/resources/api-key.js +35 -0
- package/dist/resources/card.d.ts +2 -0
- package/dist/resources/card.js +103 -0
- package/dist/resources/collection.d.ts +2 -0
- package/dist/resources/collection.js +134 -0
- package/dist/resources/content-translation.d.ts +11 -0
- package/dist/resources/content-translation.js +27 -0
- package/dist/resources/csv-upload.d.ts +2 -0
- package/dist/resources/csv-upload.js +9 -0
- package/dist/resources/dashboard.d.ts +2 -0
- package/dist/resources/dashboard.js +221 -0
- package/dist/resources/data-action.d.ts +60 -0
- package/dist/resources/data-action.js +79 -0
- package/dist/resources/data-app.d.ts +112 -0
- package/dist/resources/data-app.js +75 -0
- package/dist/resources/database.d.ts +2 -0
- package/dist/resources/database.js +103 -0
- package/dist/resources/dataset.d.ts +2 -0
- package/dist/resources/dataset.js +81 -0
- package/dist/resources/dependency.d.ts +2 -0
- package/dist/resources/dependency.js +156 -0
- package/dist/resources/document.d.ts +55 -0
- package/dist/resources/document.js +60 -0
- package/dist/resources/eid-translation.d.ts +8 -0
- package/dist/resources/eid-translation.js +19 -0
- package/dist/resources/erd.d.ts +2 -0
- package/dist/resources/erd.js +26 -0
- package/dist/resources/field.d.ts +2 -0
- package/dist/resources/field.js +99 -0
- package/dist/resources/git-sync.d.ts +2 -0
- package/dist/resources/git-sync.js +362 -0
- package/dist/resources/glossary.d.ts +2 -0
- package/dist/resources/glossary.js +51 -0
- package/dist/resources/library.d.ts +85 -0
- package/dist/resources/library.js +90 -0
- package/dist/resources/measure.d.ts +2 -0
- package/dist/resources/measure.js +57 -0
- package/dist/resources/metric.d.ts +2 -0
- package/dist/resources/metric.js +50 -0
- package/dist/resources/moderation-review.d.ts +23 -0
- package/dist/resources/moderation-review.js +24 -0
- package/dist/resources/notification.d.ts +2 -0
- package/dist/resources/notification.js +93 -0
- package/dist/resources/optional-parsed.d.ts +7 -0
- package/dist/resources/optional-parsed.js +14 -0
- package/dist/resources/permission.d.ts +10 -0
- package/dist/resources/permission.js +31 -0
- package/dist/resources/pivot-export.d.ts +10 -0
- package/dist/resources/pivot-export.js +16 -0
- package/dist/resources/pulse.d.ts +2 -0
- package/dist/resources/pulse.js +76 -0
- package/dist/resources/replacement.d.ts +2 -0
- package/dist/resources/replacement.js +82 -0
- package/dist/resources/request-body.d.ts +9 -0
- package/dist/resources/request-body.js +13 -0
- package/dist/resources/revision.d.ts +70 -0
- package/dist/resources/revision.js +46 -0
- package/dist/resources/search.d.ts +2 -0
- package/dist/resources/search.js +78 -0
- package/dist/resources/segment.d.ts +2 -0
- package/dist/resources/segment.js +55 -0
- package/dist/resources/setting.d.ts +11 -0
- package/dist/resources/setting.js +43 -0
- package/dist/resources/setup.d.ts +8 -0
- package/dist/resources/setup.js +18 -0
- package/dist/resources/snippet.d.ts +2 -0
- package/dist/resources/snippet.js +52 -0
- package/dist/resources/table.d.ts +2 -0
- package/dist/resources/table.js +274 -0
- package/dist/resources/timeline-event.d.ts +12 -0
- package/dist/resources/timeline-event.js +51 -0
- package/dist/resources/timeline.d.ts +2 -0
- package/dist/resources/timeline.js +82 -0
- package/dist/resources/transform-dag-run.d.ts +22 -0
- package/dist/resources/transform-dag-run.js +32 -0
- package/dist/resources/transform-inspector.d.ts +214 -0
- package/dist/resources/transform-inspector.js +47 -0
- package/dist/resources/transform-job.d.ts +2 -0
- package/dist/resources/transform-job.js +90 -0
- package/dist/resources/transform-python.d.ts +59 -0
- package/dist/resources/transform-python.js +57 -0
- package/dist/resources/transform-tag.d.ts +35 -0
- package/dist/resources/transform-tag.js +47 -0
- package/dist/resources/transform-test.d.ts +2 -0
- package/dist/resources/transform-test.js +75 -0
- package/dist/resources/transform.d.ts +2 -0
- package/dist/resources/transform.js +227 -0
- package/dist/resources/upload.d.ts +2 -0
- package/dist/resources/upload.js +48 -0
- package/dist/resources/user.d.ts +8 -0
- package/dist/resources/user.js +11 -0
- package/dist/revision-Dyl-8p7d.d.ts +106 -0
- package/dist/search-Cm5IxKss.d.ts +92 -0
- package/dist/search-Cten2h0I.d.ts +26 -0
- package/dist/segment-CbAgVO-5.d.ts +47 -0
- package/dist/segment-DQLX6r1E.d.ts +16 -0
- package/dist/session-properties-COtlxAcK.d.ts +15 -0
- package/dist/setting-DXuQGXGF.d.ts +25 -0
- package/dist/setup-JqcJ2unJ.d.ts +26 -0
- package/dist/signal.d.ts +8 -0
- package/dist/signal.js +25 -0
- package/dist/snippet-C_Ilx7tR.d.ts +41 -0
- package/dist/snippet-Djn0rL21.d.ts +16 -0
- package/dist/table-CDZbLNow.d.ts +176 -0
- package/dist/table-Od6uvDVW.d.ts +3234 -0
- package/dist/tag-qzjGGci8.d.ts +48 -0
- package/dist/timeline-BK45hy-h.d.ts +218 -0
- package/dist/timeline-BTs6fuRp.d.ts +21 -0
- package/dist/transform-C5thnJwW.d.ts +559 -0
- package/dist/transform-WASQAXeA.d.ts +652 -0
- package/dist/transform-dag-run-BgZwv1yx.d.ts +49 -0
- package/dist/transform-inspector-CMCh8WKV.d.ts +374 -0
- package/dist/transform-job-D8jTQtdX.d.ts +98 -0
- package/dist/transform-job-DmTwKxhc.d.ts +237 -0
- package/dist/transform-python-DtL3xxMj.d.ts +101 -0
- package/dist/transform-tag-C6j5EUkX.d.ts +25 -0
- package/dist/transform-test-CR_i54IV.d.ts +412 -0
- package/dist/transform-test-CeMzDpUC.d.ts +346 -0
- package/dist/transport-BsXqRujn.d.ts +476 -0
- package/dist/transport-HP7cyo9N.js +397 -0
- package/dist/upload-B5YjVkSW.d.ts +12 -0
- package/dist/upload-UPfZFdbH.d.ts +22 -0
- package/dist/url-CI0pxHOc.d.ts +7 -0
- package/dist/url.d.ts +2 -0
- package/dist/url.js +34 -0
- package/dist/user-Sqqv7rqh.d.ts +18 -0
- package/dist/version/capability-error.d.ts +2 -0
- package/dist/version/capability-error.js +42 -0
- package/dist/version/features.d.ts +2 -0
- package/dist/version/features.js +171 -0
- package/dist/version/input-gates.d.ts +2 -0
- package/dist/version/input-gates.js +13 -0
- package/dist/version/known-range.d.ts +2 -0
- package/dist/version/known-range.js +7 -0
- package/dist/version/probe.d.ts +2 -0
- package/dist/version/probe.js +30 -0
- package/dist/version/profile.d.ts +2 -0
- package/dist/version/profile.js +64 -0
- package/dist/version/requirement-check.d.ts +2 -0
- package/dist/version/requirement-check.js +62 -0
- package/dist/version/requirements.d.ts +2 -0
- package/dist/version/requirements.js +229 -0
- package/dist/version/tag.d.ts +2 -0
- package/dist/version/tag.js +52 -0
- package/package.json +66 -4
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { TableSelectors } from "../domain/table.js";
|
|
2
|
+
import { Collection } from "../domain/collection.js";
|
|
3
|
+
import { t as explainer } from "../refusal-B9aeHMc9.js";
|
|
4
|
+
import { listCollectionsAs } from "./collection.js";
|
|
5
|
+
import { parseRequestBody } from "./request-body.js";
|
|
6
|
+
import { LibraryCollectionInfo, LibraryPublishTablesInput, libraryWireSchema, toLibrary } from "../domain/library.js";
|
|
7
|
+
import { z } from "zod";
|
|
8
|
+
//#region src/resources/library.ts
|
|
9
|
+
const LIBRARY_ROOT_PATH = "/api/ee/library/";
|
|
10
|
+
const PUBLISH_TABLES_PATH = "/api/ee/data-studio/table/publish-tables";
|
|
11
|
+
const UNPUBLISH_TABLES_PATH = "/api/ee/data-studio/table/unpublish-tables";
|
|
12
|
+
const LIBRARY_DATA_TYPE = "library-data";
|
|
13
|
+
const PublishTablesResponse = z.object({ target_collection: Collection.nullable() });
|
|
14
|
+
function libraryResource(transport) {
|
|
15
|
+
const { explain } = explainer(transport, "library");
|
|
16
|
+
/** Get the Library root and its child collections, or `null` on an instance that has none. */
|
|
17
|
+
async function get(options = {}) {
|
|
18
|
+
const { features } = await transport.server(options);
|
|
19
|
+
const wire = await transport.requestParsed(libraryWireSchema(features), LIBRARY_ROOT_PATH, { ...options });
|
|
20
|
+
if (wire === null) return null;
|
|
21
|
+
return toLibrary(wire, await libraryListing(options));
|
|
22
|
+
}
|
|
23
|
+
async function libraryListing(options) {
|
|
24
|
+
const data = await listCollectionsAs(transport, LibraryCollectionInfo, options);
|
|
25
|
+
const byId = /* @__PURE__ */ new Map();
|
|
26
|
+
for (const collection of data) if (typeof collection.id === "number") byId.set(collection.id, collection);
|
|
27
|
+
return byId;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Create the Library subtree (its Data and Metrics collections). Metabase takes no body, rejects
|
|
31
|
+
* a second create with a 400, and answers the bare root collection without its
|
|
32
|
+
* `effective_children` — so an existing Library short-circuits the call and a fresh one comes
|
|
33
|
+
* back from a refetch, which together make this idempotent.
|
|
34
|
+
*/
|
|
35
|
+
async function create(options = {}) {
|
|
36
|
+
const existing = await get(options);
|
|
37
|
+
if (existing !== null) return existing;
|
|
38
|
+
await transport.requestRaw(LIBRARY_ROOT_PATH, {
|
|
39
|
+
...options,
|
|
40
|
+
method: "POST"
|
|
41
|
+
});
|
|
42
|
+
const created = await get(options);
|
|
43
|
+
if (created === null) throw new Error(`Library was not created after POST ${LIBRARY_ROOT_PATH}`);
|
|
44
|
+
return created;
|
|
45
|
+
}
|
|
46
|
+
/** The id of the Library's Data collection, creating the Library first when it does not exist. */
|
|
47
|
+
async function ensureDataCollectionId(options = {}) {
|
|
48
|
+
const data = (await create(options)).effective_children.find((child) => child.type === LIBRARY_DATA_TYPE);
|
|
49
|
+
if (data === void 0) throw new Error("Library has no Data collection to publish into");
|
|
50
|
+
if (typeof data.id !== "number") throw new Error(`Library Data collection has a non-numeric id ${String(data.id)}`);
|
|
51
|
+
return data.id;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Publish tables — and every upstream table they depend on — into a collection, so they lead the
|
|
55
|
+
* data pickers and rank up in search. Answers the collection they landed in. The endpoint
|
|
56
|
+
* answers the same whether or not the selectors matched a table, so a body that does not match
|
|
57
|
+
* `LibraryPublishTablesInput` is refused before any request.
|
|
58
|
+
*/
|
|
59
|
+
async function publishTables(params, options = {}) {
|
|
60
|
+
const body = parseRequestBody(LibraryPublishTablesInput, params, "tables to publish");
|
|
61
|
+
return (await transport.requestParsed(PublishTablesResponse, PUBLISH_TABLES_PATH, {
|
|
62
|
+
...options,
|
|
63
|
+
method: "POST",
|
|
64
|
+
body
|
|
65
|
+
})).target_collection;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Clear the Library collection from tables, and recursively from every downstream table that
|
|
69
|
+
* depends on them. The endpoint answers no JSON body, whether or not the selectors matched a
|
|
70
|
+
* table, so selectors that do not match `TableSelectors` are refused before any request.
|
|
71
|
+
*/
|
|
72
|
+
async function unpublishTables(params, options = {}) {
|
|
73
|
+
const body = parseRequestBody(TableSelectors, params, "table selectors");
|
|
74
|
+
await transport.requestRaw(UNPUBLISH_TABLES_PATH, {
|
|
75
|
+
...options,
|
|
76
|
+
method: "POST",
|
|
77
|
+
body,
|
|
78
|
+
expectContentType: "binary"
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
return {
|
|
82
|
+
get: explain("get", get),
|
|
83
|
+
create: explain("create", create),
|
|
84
|
+
ensureDataCollectionId: explain("ensureDataCollectionId", ensureDataCollectionId),
|
|
85
|
+
publishTables: explain("publishTables", publishTables),
|
|
86
|
+
unpublishTables: explain("unpublishTables", unpublishTables)
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
//#endregion
|
|
90
|
+
export { libraryResource };
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { t as explainer } from "../refusal-B9aeHMc9.js";
|
|
2
|
+
import { Measure } from "../domain/measure.js";
|
|
3
|
+
import { z } from "zod";
|
|
4
|
+
//#region src/resources/measure.ts
|
|
5
|
+
const MeasureApiList = z.array(Measure);
|
|
6
|
+
function measureResource(transport) {
|
|
7
|
+
const { explain } = explainer(transport, "measure");
|
|
8
|
+
/** List measures. */
|
|
9
|
+
async function list(options = {}) {
|
|
10
|
+
return {
|
|
11
|
+
data: await transport.requestParsed(MeasureApiList, "/api/measure", { ...options }),
|
|
12
|
+
total: null
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
/** Get one measure by id. */
|
|
16
|
+
async function get(id, options = {}) {
|
|
17
|
+
return transport.requestParsed(Measure, `/api/measure/${id}`, { ...options });
|
|
18
|
+
}
|
|
19
|
+
/** Create a measure — a saved aggregation tied to a table — from a full measure body. */
|
|
20
|
+
async function create(params, options = {}) {
|
|
21
|
+
return transport.requestParsed(Measure, "/api/measure", {
|
|
22
|
+
...options,
|
|
23
|
+
method: "POST",
|
|
24
|
+
body: params
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Update a measure by id, patching only the fields the body carries. `revision_message` is
|
|
29
|
+
* required and lands in the audit log.
|
|
30
|
+
*/
|
|
31
|
+
async function update(id, params, options = {}) {
|
|
32
|
+
return transport.requestParsed(Measure, `/api/measure/${id}`, {
|
|
33
|
+
...options,
|
|
34
|
+
method: "PUT",
|
|
35
|
+
body: params
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Archive (soft-delete) a measure by id. Metabase models this as an update, not its own endpoint,
|
|
40
|
+
* so it carries the same required `revision_message`.
|
|
41
|
+
*/
|
|
42
|
+
async function archive(id, params, options = {}) {
|
|
43
|
+
return update(id, {
|
|
44
|
+
archived: true,
|
|
45
|
+
revision_message: params.revision_message
|
|
46
|
+
}, options);
|
|
47
|
+
}
|
|
48
|
+
return {
|
|
49
|
+
list: explain("list", list),
|
|
50
|
+
get: explain("get", get),
|
|
51
|
+
create: explain("create", create),
|
|
52
|
+
update: explain("update", update),
|
|
53
|
+
archive: explain("archive", archive)
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
//#endregion
|
|
57
|
+
export { measureResource };
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { CardQueryResult } from "../domain/card.js";
|
|
2
|
+
import { t as explainer } from "../refusal-B9aeHMc9.js";
|
|
3
|
+
import { MetricBreakoutValues, MetricDimensionListing } from "../domain/metric.js";
|
|
4
|
+
//#region src/resources/metric.ts
|
|
5
|
+
function metricResource(transport) {
|
|
6
|
+
const { explain } = explainer(transport, "metric");
|
|
7
|
+
/**
|
|
8
|
+
* Run a metric definition and return the query result envelope: one metric or measure, or an
|
|
9
|
+
* arithmetic expression over several, each leaf filtered and projected on its own `lib/uuid`.
|
|
10
|
+
*/
|
|
11
|
+
async function query(definition, options = {}) {
|
|
12
|
+
return transport.requestParsed(CardQueryResult, "/api/metric/dataset", {
|
|
13
|
+
...options,
|
|
14
|
+
method: "POST",
|
|
15
|
+
body: { definition }
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Fetch the distinct values of a definition's breakout dimension, with that column's metadata.
|
|
20
|
+
* Takes the same definition `query` does.
|
|
21
|
+
*/
|
|
22
|
+
async function breakoutValues(definition, options = {}) {
|
|
23
|
+
return transport.requestParsed(MetricBreakoutValues, "/api/metric/breakout-values", {
|
|
24
|
+
...options,
|
|
25
|
+
method: "POST",
|
|
26
|
+
body: { definition }
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* List a metric's curated dimensions and, under `with-addable`, the columns still available to
|
|
31
|
+
* add, grouped by source table. `query` filters both by a name substring.
|
|
32
|
+
*/
|
|
33
|
+
async function dimensions(id, params = {}, options = {}) {
|
|
34
|
+
return transport.requestParsed(MetricDimensionListing, `/api/metric/${id}/dimension`, {
|
|
35
|
+
...options,
|
|
36
|
+
query: {
|
|
37
|
+
query: params.query,
|
|
38
|
+
"with-addable": params["with-addable"],
|
|
39
|
+
"include-orphaned": params["include-orphaned"]
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
return {
|
|
44
|
+
query: explain("query", query),
|
|
45
|
+
breakoutValues: explain("breakoutValues", breakoutValues),
|
|
46
|
+
dimensions: explain("dimensions", dimensions)
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
//#endregion
|
|
50
|
+
export { metricResource };
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { f as RequestOptions, h as Transport } from "../transport-BsXqRujn.js";
|
|
2
|
+
//#region src/resources/moderation-review.d.ts
|
|
3
|
+
declare function moderationReviewResource(transport: Transport): {
|
|
4
|
+
create: (params: {
|
|
5
|
+
moderated_item_id: number;
|
|
6
|
+
moderated_item_type: "card" | "dashboard";
|
|
7
|
+
status?: "verified" | null | undefined;
|
|
8
|
+
text?: string | null | undefined;
|
|
9
|
+
}, options?: RequestOptions | undefined) => Promise<{
|
|
10
|
+
[x: string]: unknown;
|
|
11
|
+
id: number;
|
|
12
|
+
moderated_item_id: number;
|
|
13
|
+
moderated_item_type: "card" | "dashboard";
|
|
14
|
+
moderator_id: number;
|
|
15
|
+
status: "verified" | null;
|
|
16
|
+
text: string | null;
|
|
17
|
+
most_recent: boolean;
|
|
18
|
+
created_at: string;
|
|
19
|
+
updated_at: string;
|
|
20
|
+
}>;
|
|
21
|
+
};
|
|
22
|
+
//#endregion
|
|
23
|
+
export { moderationReviewResource };
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { ModerationReview, ModerationReviewCreateInput } from "../domain/moderation-review.js";
|
|
2
|
+
import { t as explainer } from "../refusal-B9aeHMc9.js";
|
|
3
|
+
import { parseRequestBody } from "./request-body.js";
|
|
4
|
+
//#region src/resources/moderation-review.ts
|
|
5
|
+
function moderationReviewResource(transport) {
|
|
6
|
+
const { explain } = explainer(transport, "moderationReview");
|
|
7
|
+
/**
|
|
8
|
+
* Create a moderation review on a card or dashboard. `status: "verified"` marks the item
|
|
9
|
+
* verified, `null` or an absent status records a note that leaves it unverified. The new review
|
|
10
|
+
* becomes the item's most recent one; the server keeps the ten newest per item. Admins only.
|
|
11
|
+
* A body that does not match `ModerationReviewCreateInput` is refused before any request.
|
|
12
|
+
*/
|
|
13
|
+
async function create(params, options = {}) {
|
|
14
|
+
const body = parseRequestBody(ModerationReviewCreateInput, params, "moderation review");
|
|
15
|
+
return transport.requestParsed(ModerationReview, "/api/moderation-review", {
|
|
16
|
+
...options,
|
|
17
|
+
method: "POST",
|
|
18
|
+
body
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
return { create: explain("create", create) };
|
|
22
|
+
}
|
|
23
|
+
//#endregion
|
|
24
|
+
export { moderationReviewResource };
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { ConfigError } from "../errors.js";
|
|
2
|
+
import { AnyNotification, CARD_PAYLOAD_TYPE, Notification, NotificationCardPayload } from "../domain/notification.js";
|
|
3
|
+
import { z } from "zod";
|
|
4
|
+
//#region src/resources/notification.ts
|
|
5
|
+
const NotificationApiList = z.array(Notification);
|
|
6
|
+
function assertCardAlert(notification) {
|
|
7
|
+
if (notification.payload_type !== "notification/card") throw new ConfigError(`notification ${notification.id} is a ${notification.payload_type}, not a question alert — this operation accepts card alerts only`);
|
|
8
|
+
return notification;
|
|
9
|
+
}
|
|
10
|
+
function mergeAlertUpdate(current, patch) {
|
|
11
|
+
return Notification.parse({
|
|
12
|
+
...current,
|
|
13
|
+
...patch,
|
|
14
|
+
id: current.id,
|
|
15
|
+
payload: patch.payload === void 0 ? current.payload : mergePayload(current, patch.payload)
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
function mergePayload(current, patch) {
|
|
19
|
+
if (current.payload === null) throw new ConfigError(`alert ${current.id} has lost its card payload — it can be archived, but not patched`);
|
|
20
|
+
return NotificationCardPayload.parse({
|
|
21
|
+
...current.payload,
|
|
22
|
+
...patch
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
function notificationResource(transport) {
|
|
26
|
+
/**
|
|
27
|
+
* List question alerts, optionally narrowed by the card they watch, their creator, or a
|
|
28
|
+
* recipient. `/api/notification` also serves Metabase's internal system-event notifications, so
|
|
29
|
+
* the request pins the card payload type.
|
|
30
|
+
*/
|
|
31
|
+
async function list(params = {}, options = {}) {
|
|
32
|
+
return {
|
|
33
|
+
data: await transport.requestParsed(NotificationApiList, "/api/notification", {
|
|
34
|
+
...options,
|
|
35
|
+
query: {
|
|
36
|
+
payload_type: CARD_PAYLOAD_TYPE,
|
|
37
|
+
card_id: params.card_id,
|
|
38
|
+
creator_id: params.creator_id,
|
|
39
|
+
recipient_id: params.recipient_id,
|
|
40
|
+
include_inactive: params.include_inactive
|
|
41
|
+
}
|
|
42
|
+
}),
|
|
43
|
+
total: null
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
/** Get one question alert by id, refusing an id that names a system-event notification. */
|
|
47
|
+
async function get(id, options = {}) {
|
|
48
|
+
return assertCardAlert(await transport.requestParsed(AnyNotification, `/api/notification/${id}`, { ...options }));
|
|
49
|
+
}
|
|
50
|
+
/** Create a question alert — its card payload, schedules and handlers — from a full body. */
|
|
51
|
+
async function create(params, options = {}) {
|
|
52
|
+
return transport.requestParsed(Notification, "/api/notification", {
|
|
53
|
+
...options,
|
|
54
|
+
method: "POST",
|
|
55
|
+
body: params
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
/** Update a question alert by id, merging the patch over the stored notification. */
|
|
59
|
+
async function update(id, params, options = {}) {
|
|
60
|
+
const current = await get(id, options);
|
|
61
|
+
return transport.requestParsed(Notification, `/api/notification/${id}`, {
|
|
62
|
+
...options,
|
|
63
|
+
method: "PUT",
|
|
64
|
+
body: mergeAlertUpdate(current, params)
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
/** Archive a question alert by id, stopping every delivery. Metabase models this as an update. */
|
|
68
|
+
async function archive(id, options = {}) {
|
|
69
|
+
return update(id, { active: false }, options);
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Send a question alert now, off-schedule, to every handler on it. The server answers with no
|
|
73
|
+
* body.
|
|
74
|
+
*/
|
|
75
|
+
async function send(id, options = {}) {
|
|
76
|
+
await get(id, options);
|
|
77
|
+
await transport.requestRaw(`/api/notification/${id}/send`, {
|
|
78
|
+
...options,
|
|
79
|
+
method: "POST",
|
|
80
|
+
expectContentType: "binary"
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
return {
|
|
84
|
+
list,
|
|
85
|
+
get,
|
|
86
|
+
create,
|
|
87
|
+
update,
|
|
88
|
+
archive,
|
|
89
|
+
send
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
//#endregion
|
|
93
|
+
export { assertCardAlert, mergeAlertUpdate, notificationResource };
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { f as RequestOptions, g as TransportRequestOptions, h as Transport } from "../transport-BsXqRujn.js";
|
|
2
|
+
import { ZodType } from "zod";
|
|
3
|
+
//#region src/resources/optional-parsed.d.ts
|
|
4
|
+
type OptionalParsedOptions = RequestOptions & Pick<TransportRequestOptions, "query">;
|
|
5
|
+
declare function fetchOptionalParsed<T>(client: Transport, path: string, schema: ZodType<T>, options?: OptionalParsedOptions): Promise<T | null>;
|
|
6
|
+
//#endregion
|
|
7
|
+
export { OptionalParsedOptions, fetchOptionalParsed };
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { parseJsonOrPlain } from "../json.js";
|
|
2
|
+
//#region src/resources/optional-parsed.ts
|
|
3
|
+
const NO_CONTENT_STATUS = 204;
|
|
4
|
+
async function fetchOptionalParsed(client, path, schema, options = {}) {
|
|
5
|
+
const response = await client.requestRaw(path, {
|
|
6
|
+
...options,
|
|
7
|
+
method: "GET",
|
|
8
|
+
expectContentType: "binary"
|
|
9
|
+
});
|
|
10
|
+
if (response.status === NO_CONTENT_STATUS) return null;
|
|
11
|
+
return parseJsonOrPlain(await response.text(), response.headers.get("content-type"), schema, { source: response.url });
|
|
12
|
+
}
|
|
13
|
+
//#endregion
|
|
14
|
+
export { fetchOptionalParsed };
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { f as RequestOptions, h as Transport } from "../transport-BsXqRujn.js";
|
|
2
|
+
import { a as PermissionsGraph } from "../permission-BnCQw5Kp.js";
|
|
3
|
+
//#region src/resources/permission.d.ts
|
|
4
|
+
declare function permissionResource(transport: Transport): {
|
|
5
|
+
graph: (options?: RequestOptions) => Promise<PermissionsGraph>;
|
|
6
|
+
databaseGraph: (id: number, options?: RequestOptions) => Promise<PermissionsGraph>;
|
|
7
|
+
groupGraph: (id: number, options?: RequestOptions) => Promise<PermissionsGraph>;
|
|
8
|
+
};
|
|
9
|
+
//#endregion
|
|
10
|
+
export { permissionResource };
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { PermissionsGraph } from "../domain/permission.js";
|
|
2
|
+
//#region src/resources/permission.ts
|
|
3
|
+
function permissionResource(transport) {
|
|
4
|
+
/**
|
|
5
|
+
* Get the data permissions of every group on every database, keyed by group id then database
|
|
6
|
+
* id. Admin only. One read of the whole `data_permissions` table, so prefer `databaseGraph` when
|
|
7
|
+
* one database is the question.
|
|
8
|
+
*/
|
|
9
|
+
async function graph(options = {}) {
|
|
10
|
+
return transport.requestParsed(PermissionsGraph, "/api/permissions/graph", { ...options });
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Get the data permissions of every group on one database. Admin only. The read is filtered to
|
|
14
|
+
* that database, so this is the cheapest way to learn which groups can query a table: look the
|
|
15
|
+
* group up under the database and read `view-data` and `create-queries` down to the table id.
|
|
16
|
+
*/
|
|
17
|
+
async function databaseGraph(id, options = {}) {
|
|
18
|
+
return transport.requestParsed(PermissionsGraph, `/api/permissions/graph/db/${id}`, { ...options });
|
|
19
|
+
}
|
|
20
|
+
/** Get the data permissions of one group on every database. Admin only. */
|
|
21
|
+
async function groupGraph(id, options = {}) {
|
|
22
|
+
return transport.requestParsed(PermissionsGraph, `/api/permissions/graph/group/${id}`, { ...options });
|
|
23
|
+
}
|
|
24
|
+
return {
|
|
25
|
+
graph,
|
|
26
|
+
databaseGraph,
|
|
27
|
+
groupGraph
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
//#endregion
|
|
31
|
+
export { permissionResource };
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { f as RequestOptions, h as Transport } from "../transport-BsXqRujn.js";
|
|
2
|
+
import { n as ExportFormat } from "../query-Xsin530u.js";
|
|
3
|
+
//#region src/resources/pivot-export.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* Refuse a pivoted export the server would answer with plain rows: a JSON export keeps only the
|
|
6
|
+
* ungrouped rows, and an admin can turn pivoted CSV and XLSX exports off.
|
|
7
|
+
*/
|
|
8
|
+
declare function assertPivotedExport(transport: Transport, format: ExportFormat, options: RequestOptions): Promise<void>;
|
|
9
|
+
//#endregion
|
|
10
|
+
export { assertPivotedExport };
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { SessionProperties } from "../domain/session-properties.js";
|
|
2
|
+
import { ConfigError } from "../errors.js";
|
|
3
|
+
import { PivotExportFormat } from "../domain/query.js";
|
|
4
|
+
import { z } from "zod";
|
|
5
|
+
//#region src/resources/pivot-export.ts
|
|
6
|
+
const PivotedExportsProperty = SessionProperties.extend({ "enable-pivoted-exports": z.boolean() });
|
|
7
|
+
/**
|
|
8
|
+
* Refuse a pivoted export the server would answer with plain rows: a JSON export keeps only the
|
|
9
|
+
* ungrouped rows, and an admin can turn pivoted CSV and XLSX exports off.
|
|
10
|
+
*/
|
|
11
|
+
async function assertPivotedExport(transport, format, options) {
|
|
12
|
+
if (!PivotExportFormat.safeParse(format).success) throw new ConfigError(`a ${format} export cannot be pivoted; only ${PivotExportFormat.options.join(" and ")} can`);
|
|
13
|
+
if (!(await transport.probe(PivotedExportsProperty, 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");
|
|
14
|
+
}
|
|
15
|
+
//#endregion
|
|
16
|
+
export { assertPivotedExport };
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { gateTriggered } from "../version/input-gates.js";
|
|
2
|
+
import { Pulse, SUBSCRIPTION_FILTERS_GATE } from "../domain/pulse.js";
|
|
3
|
+
import { z } from "zod";
|
|
4
|
+
//#region src/resources/pulse.ts
|
|
5
|
+
const PulseApiList = z.array(Pulse);
|
|
6
|
+
function mergePulseUpdate(current, patch) {
|
|
7
|
+
return {
|
|
8
|
+
...patch,
|
|
9
|
+
archived: patch.archived ?? current.archived,
|
|
10
|
+
skip_if_empty: patch.skip_if_empty ?? current.skip_if_empty
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
function pulseResource(transport) {
|
|
14
|
+
/** List dashboard subscriptions, optionally narrowed to one dashboard or to the archived ones. */
|
|
15
|
+
async function list(params = {}, options = {}) {
|
|
16
|
+
return {
|
|
17
|
+
data: await transport.requestParsed(PulseApiList, "/api/pulse", {
|
|
18
|
+
...options,
|
|
19
|
+
query: {
|
|
20
|
+
dashboard_id: params.dashboard_id,
|
|
21
|
+
archived: params.archived
|
|
22
|
+
}
|
|
23
|
+
}),
|
|
24
|
+
total: null
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
/** Get one dashboard subscription by id. */
|
|
28
|
+
async function get(id, options = {}) {
|
|
29
|
+
return transport.requestParsed(Pulse, `/api/pulse/${id}`, { ...options });
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Create a dashboard subscription — its cards and its delivery channels — from a full body.
|
|
33
|
+
* Non-empty `parameters` need the `dashboard_subscription_filters` premium feature, and are
|
|
34
|
+
* refused before the wire without it.
|
|
35
|
+
*/
|
|
36
|
+
async function create(params, options = {}) {
|
|
37
|
+
await requireSubscriptionFilters(params.parameters, options);
|
|
38
|
+
return transport.requestParsed(Pulse, "/api/pulse", {
|
|
39
|
+
...options,
|
|
40
|
+
method: "POST",
|
|
41
|
+
body: params
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Update a dashboard subscription by id, carrying the server-defaulted flags forward. Non-empty
|
|
46
|
+
* `parameters` are refused as on `create`.
|
|
47
|
+
*/
|
|
48
|
+
async function update(id, params, options = {}) {
|
|
49
|
+
await requireSubscriptionFilters(params.parameters, options);
|
|
50
|
+
const current = await get(id, options);
|
|
51
|
+
return transport.requestParsed(Pulse, `/api/pulse/${id}`, {
|
|
52
|
+
...options,
|
|
53
|
+
method: "PUT",
|
|
54
|
+
body: mergePulseUpdate(current, params)
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Archive a dashboard subscription by id, stopping every delivery. Metabase models this as an
|
|
59
|
+
* update, and disables each of the subscription's channels as a side effect.
|
|
60
|
+
*/
|
|
61
|
+
async function archive(id, options = {}) {
|
|
62
|
+
return update(id, { archived: true }, options);
|
|
63
|
+
}
|
|
64
|
+
async function requireSubscriptionFilters(parameters, options) {
|
|
65
|
+
if (gateTriggered(SUBSCRIPTION_FILTERS_GATE, parameters)) await transport.requireFeatures([SUBSCRIPTION_FILTERS_GATE.feature], options);
|
|
66
|
+
}
|
|
67
|
+
return {
|
|
68
|
+
list,
|
|
69
|
+
get,
|
|
70
|
+
create,
|
|
71
|
+
update,
|
|
72
|
+
archive
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
//#endregion
|
|
76
|
+
export { mergePulseUpdate, pulseResource };
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { t as explainer } from "../refusal-B9aeHMc9.js";
|
|
2
|
+
import { ReplacementCheck, ReplacementRun, ReplacementRunStarted } from "../domain/replacement.js";
|
|
3
|
+
import { z } from "zod";
|
|
4
|
+
//#region src/resources/replacement.ts
|
|
5
|
+
const ReplacementApiRunList = z.array(ReplacementRun);
|
|
6
|
+
const CancelRunResponse = z.object({ success: z.literal(true) });
|
|
7
|
+
function replacementResource(transport) {
|
|
8
|
+
const { explain } = explainer(transport, "replacement");
|
|
9
|
+
/**
|
|
10
|
+
* Check whether every usage of a source entity could be rewritten to read a target entity
|
|
11
|
+
* instead: the two must share a database, the target must not depend on the source, every source
|
|
12
|
+
* column must exist on the target with a compatible type, and a table source must not be joined
|
|
13
|
+
* implicitly or sandboxed. Admins only.
|
|
14
|
+
*/
|
|
15
|
+
async function checkReplaceSource(params, options = {}) {
|
|
16
|
+
return transport.requestParsed(ReplacementCheck, "/api/ee/replacement/check-replace-source", {
|
|
17
|
+
...options,
|
|
18
|
+
method: "POST",
|
|
19
|
+
body: params
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Rewrite every usage of a source entity to read a target entity, in the background. Runs the
|
|
24
|
+
* same check as `checkReplaceSource` first and refuses with a 400 when it fails, and with a 409
|
|
25
|
+
* while another replacement is running. Admins only.
|
|
26
|
+
*/
|
|
27
|
+
async function replaceSource(params, options = {}) {
|
|
28
|
+
return transport.requestParsed(ReplacementRunStarted, "/api/ee/replacement/replace-source", {
|
|
29
|
+
...options,
|
|
30
|
+
method: "POST",
|
|
31
|
+
body: params
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Create a transform from a model's query, run it, and rewrite every usage of the model to read
|
|
36
|
+
* the transform's output table, in the background; the model becomes a saved question. A failed
|
|
37
|
+
* transform run leaves the model as it was; a failed rewrite keeps the transform and its table
|
|
38
|
+
* as well, since other queries may already read them. Refuses with a 409 while another
|
|
39
|
+
* replacement is running. Admins only.
|
|
40
|
+
*/
|
|
41
|
+
async function replaceModelWithTransform(params, options = {}) {
|
|
42
|
+
return transport.requestParsed(ReplacementRunStarted, "/api/ee/replacement/replace-model-with-transform", {
|
|
43
|
+
...options,
|
|
44
|
+
method: "POST",
|
|
45
|
+
body: params
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* List replacement runs, newest first. `is-active: true` keeps only the run in progress,
|
|
50
|
+
* `false` only the ended ones. Admins only.
|
|
51
|
+
*/
|
|
52
|
+
async function listRuns(params = {}, options = {}) {
|
|
53
|
+
return {
|
|
54
|
+
data: await transport.requestParsed(ReplacementApiRunList, "/api/ee/replacement/runs", {
|
|
55
|
+
...options,
|
|
56
|
+
query: { "is-active": params["is-active"] }
|
|
57
|
+
}),
|
|
58
|
+
total: null
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
/** Get one replacement run by id, with its status and progress. Admins only. */
|
|
62
|
+
async function getRun(id, options = {}) {
|
|
63
|
+
return transport.requestParsed(ReplacementRun, `/api/ee/replacement/runs/${id}`, { ...options });
|
|
64
|
+
}
|
|
65
|
+
/** Cancel the replacement in progress. Refuses with a 409 once the run has ended. Admins only. */
|
|
66
|
+
async function cancelRun(id, options = {}) {
|
|
67
|
+
await transport.requestParsed(CancelRunResponse, `/api/ee/replacement/runs/${id}/cancel`, {
|
|
68
|
+
...options,
|
|
69
|
+
method: "POST"
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
return {
|
|
73
|
+
checkReplaceSource: explain("checkReplaceSource", checkReplaceSource),
|
|
74
|
+
replaceSource: explain("replaceSource", replaceSource),
|
|
75
|
+
replaceModelWithTransform: explain("replaceModelWithTransform", replaceModelWithTransform),
|
|
76
|
+
listRuns: explain("listRuns", listRuns),
|
|
77
|
+
getRun: explain("getRun", getRun),
|
|
78
|
+
cancelRun: explain("cancelRun", cancelRun)
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
//#endregion
|
|
82
|
+
export { replacementResource };
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
//#region src/resources/request-body.d.ts
|
|
3
|
+
/**
|
|
4
|
+
* Parse the body a caller hands a method, refusing one that does not match `schema` before any
|
|
5
|
+
* request. `what` names the body in the refusal.
|
|
6
|
+
*/
|
|
7
|
+
declare function parseRequestBody<T>(schema: z.ZodType<T>, value: unknown, what: string): T;
|
|
8
|
+
//#endregion
|
|
9
|
+
export { parseRequestBody };
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { ConfigError, formatZodIssue } from "../errors.js";
|
|
2
|
+
//#region src/resources/request-body.ts
|
|
3
|
+
/**
|
|
4
|
+
* Parse the body a caller hands a method, refusing one that does not match `schema` before any
|
|
5
|
+
* request. `what` names the body in the refusal.
|
|
6
|
+
*/
|
|
7
|
+
function parseRequestBody(schema, value, what) {
|
|
8
|
+
const parsed = schema.safeParse(value);
|
|
9
|
+
if (!parsed.success) throw new ConfigError(`invalid ${what}: ${parsed.error.issues.map(formatZodIssue).join("; ")}`);
|
|
10
|
+
return parsed.data;
|
|
11
|
+
}
|
|
12
|
+
//#endregion
|
|
13
|
+
export { parseRequestBody };
|