@metabase/cli 0.1.0 → 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/README.md +972 -57
- package/dist/add-collection--zwkmE1S.mjs +11 -0
- package/dist/add-collection-B1qe0D1U.mjs +54 -0
- package/dist/api-key-gzCbKDjL.mjs +13 -0
- package/dist/archive-CitmlD1e.mjs +39 -0
- package/dist/{archive-CsWeHXle.mjs → archive-CnhWegtR.mjs} +7 -4
- package/dist/archive-DQjBOXnx.mjs +44 -0
- package/dist/archive-Ni8-lQ1Y.mjs +44 -0
- package/dist/auth-BPjsrFxM.mjs +19 -0
- package/dist/{body-Dv9hQ0Qk.mjs → body-DRBgxS6-.mjs} +3 -2
- package/dist/{branches-BujtceGr.mjs → branches-C5Jcw8wu.mjs} +8 -6
- package/dist/cancel-Ca3r7Y6v.mjs +56 -0
- package/dist/{cancel-task-CT2xUMRg.mjs → cancel-task-C1-8vDKS.mjs} +9 -7
- package/dist/card-BGAy3eIb.mjs +20 -0
- package/dist/{card-CsXk8T6A.mjs → card-CAEZWixN.mjs} +34 -15
- package/dist/cards-CILfMPUP.mjs +37 -0
- package/dist/cli.mjs +33 -14
- package/dist/collection-B3sPXRLs.mjs +163 -0
- package/dist/collection-D8cnCB98.mjs +19 -0
- package/dist/create-3Z6rm-4O.mjs +44 -0
- package/dist/create-BsY5RrVY.mjs +44 -0
- package/dist/create-C4OCclBD.mjs +48 -0
- package/dist/create-COsD7Vzm.mjs +48 -0
- package/dist/create-CP8ou91U.mjs +125 -0
- package/dist/create-CeIi_QLj.mjs +66 -0
- package/dist/create-CqNw6PmR.mjs +50 -0
- package/dist/create-DE_5NrFy.mjs +48 -0
- package/dist/{create-B8ektf-R.mjs → create-MEhhhgMC.mjs} +8 -6
- package/dist/create-QxDmleKJ.mjs +48 -0
- package/dist/{create-branch-goZBTNnr.mjs → create-branch-CKMYaAHk.mjs} +9 -7
- package/dist/credentials-CwRKvdP2.mjs +85 -0
- package/dist/{current-task-DBjRNCFq.mjs → current-task-Dutjys16.mjs} +9 -7
- package/dist/dashboard-B4fVp392.mjs +20 -0
- package/dist/dashboard-CnMD04PQ.mjs +163 -0
- package/dist/database-BMTb0CzV.mjs +17 -0
- package/dist/database-Dvkfy3JM.mjs +51 -0
- package/dist/db-ACuuaEok.mjs +22 -0
- package/dist/{delete-8vGU35r3.mjs → delete-BMQZuVXZ.mjs} +7 -5
- package/dist/{delete-B27KLF5X.mjs → delete-BvcA4jPj.mjs} +7 -5
- package/dist/{delete-runtime-Byr60cR3.mjs → delete-runtime-BMzvfj_B.mjs} +4 -4
- package/dist/{delete-table-BNaJ_gA4.mjs → delete-table-DUPjHKk4.mjs} +7 -5
- package/dist/deprovision-Bsc1S15j.mjs +61 -0
- package/dist/{dirty-aNUuph4I.mjs → dirty-CXcdoUhY.mjs} +8 -6
- package/dist/docker-D-ieBsP7.mjs +612 -0
- package/dist/eid-pvOsEMPZ.mjs +13 -0
- package/dist/{export-QDkuuzSE.mjs → export-BjGhLEOi.mjs} +30 -23
- package/dist/field-BI2bt8e9.mjs +18 -0
- package/dist/field-DciLbuv-.mjs +276 -0
- package/dist/fields-Do8HHm_T.mjs +38 -0
- package/dist/flag-pair-DtR1AiBQ.mjs +17 -0
- package/dist/{get-BGBIzMKY.mjs → get-BGFGWkH0.mjs} +6 -4
- package/dist/get-BmE_VHdl.mjs +36 -0
- package/dist/{get-DI_IJvgk.mjs → get-C7sshmqF.mjs} +6 -4
- package/dist/get-CObKBj2J.mjs +36 -0
- package/dist/get-Cq5U_Eep.mjs +40 -0
- package/dist/get-D4GUJBiX.mjs +41 -0
- package/dist/{get-COXHplHP.mjs → get-DFrsi77F.mjs} +7 -5
- package/dist/get-DczxeETg.mjs +53 -0
- package/dist/{get-Cl8-IauC.mjs → get-DeQa3ThJ.mjs} +7 -4
- package/dist/get-DhZ_dGUb.mjs +36 -0
- package/dist/{get-i6LWOByV.mjs → get-DzCVafyO.mjs} +6 -4
- package/dist/get-YCnVqq-z.mjs +49 -0
- package/dist/get-run-CTyW29s3.mjs +36 -0
- package/dist/git-sync-BOmT8HEU.mjs +28 -0
- package/dist/{has-remote-changes-hjKoQuRy.mjs → has-remote-changes-xX8vMVsX.mjs} +8 -6
- package/dist/{import-HJsSKRYx.mjs → import-CaAUNtXz.mjs} +11 -9
- package/dist/{input-Dojr-RTw.mjs → input-ikCiip6x.mjs} +2 -1
- package/dist/is-dirty-CPu-xqkW.mjs +10 -0
- package/dist/{is-dirty-1Qy7hiHB.mjs → is-dirty-mgxEwEk4.mjs} +5 -4
- package/dist/items-Cg67tdto.mjs +77 -0
- package/dist/{key-DBxPSFwi.mjs → key-NDEARu2L.mjs} +1 -1
- package/dist/{license-MoWse3ZI.mjs → license-CwKzVMD0.mjs} +3 -3
- package/dist/list-BqdNQ1nU.mjs +47 -0
- package/dist/list-BwGdD45N.mjs +32 -0
- package/dist/list-CfOVsAZz.mjs +55 -0
- package/dist/list-CpyNn1Zn.mjs +32 -0
- package/dist/list-CwwOoGLK.mjs +40 -0
- package/dist/{list-C_PRdL5e.mjs → list-DD8CQx8l.mjs} +7 -5
- package/dist/{list-Bk6RsbJl.mjs → list-DL-RWpIE.mjs} +5 -3
- package/dist/list-DLlq3FyS.mjs +61 -0
- package/dist/list-DdQ4jmUQ.mjs +52 -0
- package/dist/{list-C4Ajrw8f.mjs → list-DshbLoqR.mjs} +6 -3
- package/dist/{list-C8tdLOH5.mjs → list-DzTMpoBs.mjs} +5 -3
- package/dist/list-JgRtCzz3.mjs +32 -0
- package/dist/{list-CWt3fqrZ.mjs → list-WzgJcwB5.mjs} +5 -3
- package/dist/{login-C9WTwNn6.mjs → login-DJnmR2wX.mjs} +14 -5
- package/dist/{logout-oLszGCOg.mjs → logout-BMe_1Zp8.mjs} +7 -6
- package/dist/logs-CQxKJ3HG.mjs +58 -0
- package/dist/{manifest-CAdjQYH8.mjs → manifest-Dv5B9Blc.mjs} +3 -7
- package/dist/measure-BEQfnLdN.mjs +67 -0
- package/dist/measure-BGyYbtqO.mjs +19 -0
- package/dist/metadata-CLIALntn.mjs +37 -0
- package/dist/metadata-T-fNUWg_.mjs +38 -0
- package/dist/{package-BGfw4ZWJ.mjs → package-DBsS7a5x.mjs} +7 -1
- package/dist/paginate-CTSfuYiF.mjs +49 -0
- package/dist/parse-id-BUOZQqjp.mjs +12 -0
- package/dist/parse-ref-DGvh4aDn.mjs +17 -0
- package/dist/parse-schemas-BnW4T1_I.mjs +12 -0
- package/dist/{poll-ILanYysl.mjs → poll-DMmmZWvi.mjs} +2 -1
- package/dist/{poll-task-DbpsiQhl.mjs → poll-task-2Ckiwp8U.mjs} +8 -7
- package/dist/predicates-DiIiS3k7.mjs +153 -0
- package/dist/preflight-CC_g6EWU.mjs +91 -0
- package/dist/{prompt-DpT8yAVy.mjs → prompt-Bf3DQ-qE.mjs} +1 -1
- package/dist/provision-BUgWJWAV.mjs +77 -0
- package/dist/ps-BUNHygf-.mjs +10 -0
- package/dist/ps-Yv0JjLVN.mjs +78 -0
- package/dist/{query-PihYi-UZ.mjs → query-CzfbuG8a.mjs} +38 -13
- package/dist/query-UIebHmbT.mjs +90 -0
- package/dist/remove-BAUbcwuF.mjs +98 -0
- package/dist/{remove-B2hVYn1v.mjs → remove-CN2PNGTR.mjs} +6 -5
- package/dist/remove-collection-C6NxEh53.mjs +38 -0
- package/dist/render-DXv-D6fU.mjs +182 -0
- package/dist/rescan-values-CcB4F9qa.mjs +43 -0
- package/dist/revision-message-flag-CWQbKhdl.mjs +11 -0
- package/dist/{run-C2so6Qp6.mjs → run-BjXZtu_6.mjs} +27 -36
- package/dist/runs-CXx7l1NY.mjs +54 -0
- package/dist/{runtime-C9CEZhcn.mjs → runtime-D7jihh81.mjs} +425 -442
- package/dist/schema-tables-BCJT2DM_.mjs +45 -0
- package/dist/schemas-DlNpbn4H.mjs +47 -0
- package/dist/{search-CopOytXY.mjs → search-Dt-6mdHZ.mjs} +6 -19
- package/dist/segment-BMrUBz94.mjs +70 -0
- package/dist/segment-C52QNnSs.mjs +19 -0
- package/dist/{set-BcF7M1GQ.mjs → set-DCESWpi3.mjs} +6 -4
- package/dist/{set-CbibegpA.mjs → set-L7cuHjVZ.mjs} +8 -6
- package/dist/{setting-U3NtBMFo.mjs → setting-DysGAuYS.mjs} +3 -3
- package/dist/setup-_ypJDPAY.mjs +71 -0
- package/dist/snippet-Dw0Sjzkr.mjs +64 -0
- package/dist/snippet-vb3G9R8a.mjs +19 -0
- package/dist/start-BokXnb0V.mjs +350 -0
- package/dist/{stash-DOBbYozC.mjs → stash-CaGX6PfX.mjs} +9 -7
- package/dist/{status-Buf1ZbNR.mjs → status-BaX9vedb.mjs} +10 -8
- package/dist/{status-CUcs8XBH.mjs → status-CyecXzN4.mjs} +4 -2
- package/dist/{status-D1F5XHae.mjs → status-RpVyPEty.mjs} +4 -2
- package/dist/stop-BRuF_Cg1.mjs +81 -0
- package/dist/summary-CpEOiOlZ.mjs +41 -0
- package/dist/sync-schema-4Cl4h8Jn.mjs +43 -0
- package/dist/table-BeMWuvzO.mjs +19 -0
- package/dist/{table-Cfk7oSvw.mjs → table-jljEqZ0R.mjs} +22 -9
- package/dist/transform-DwRc-w6y.mjs +24 -0
- package/dist/{transform-B5uRpg1G.mjs → transform-IEX4Mx3X.mjs} +56 -2
- package/dist/transform-job-BigWrctt.mjs +19 -0
- package/dist/{transform-job-C7QXWTVE.mjs → transform-job-Csr86muI.mjs} +7 -0
- package/dist/translate-DqLlXXUx.mjs +111 -0
- package/dist/tree-BT24nkLM.mjs +32 -0
- package/dist/update-BCXKQi2n.mjs +52 -0
- package/dist/{update-CL8tRbxr.mjs → update-BXbLmC2b.mjs} +9 -7
- package/dist/update-C1Frz9GR.mjs +52 -0
- package/dist/update-C5goGhNr.mjs +56 -0
- package/dist/update-CCOyB0iT.mjs +73 -0
- package/dist/update-D04NMueX.mjs +59 -0
- package/dist/update-D6WVtNV1.mjs +57 -0
- package/dist/update-DFR46LsB.mjs +56 -0
- package/dist/update-DyLItrpV.mjs +56 -0
- package/dist/update-dashcard-av0_PYeg.mjs +71 -0
- package/dist/update-mrgvQF4i.mjs +51 -0
- package/dist/url-x4wn_l3k.mjs +54 -0
- package/dist/uuid-BZHbti8B.mjs +47 -0
- package/dist/validate-DCYx6jdL.mjs +1496 -0
- package/dist/validate-query-B07oGG4K.mjs +37 -0
- package/dist/values-Be6i0Fs9.mjs +36 -0
- package/dist/{wait-Bugr9eXD.mjs → wait-BMqQD8k_.mjs} +10 -8
- package/dist/wait-CWizX_sR.mjs +19 -0
- package/dist/wait-flags-DO3ar2tf.mjs +35 -0
- package/dist/workspace-CG1xyJ86.mjs +24 -0
- package/dist/workspace-DVuqKJGG.mjs +72 -0
- package/dist/workspace-credentials-B6BL-X0d.mjs +139 -0
- package/package.json +7 -1
- package/dist/auth-BF7IjZIH.mjs +0 -18
- package/dist/card-_Ta7zdYe.mjs +0 -19
- package/dist/create-CI2Cunq5.mjs +0 -38
- package/dist/create-DdbU3TLX.mjs +0 -42
- package/dist/database-PA9Goi25.mjs +0 -33
- package/dist/db-DMghzgb6.mjs +0 -17
- package/dist/field-C8IVs6rp.mjs +0 -76
- package/dist/field-DaYo_90x.mjs +0 -13
- package/dist/get-Cwpj7lDe.mjs +0 -35
- package/dist/get-Dh_acl8q.mjs +0 -34
- package/dist/is-dirty-DpKn9HJp.mjs +0 -8
- package/dist/list-CBSBHtK-.mjs +0 -38
- package/dist/parse-id-BhmmfyCP.mjs +0 -14
- package/dist/sync-BPyGXfUk.mjs +0 -26
- package/dist/table-D7nJt7JO.mjs +0 -16
- package/dist/transform-UbyewMxY.mjs +0 -21
- package/dist/transform-job-CrYkr-Ma.mjs +0 -19
- package/dist/update-DU2oU2j-.mjs +0 -49
- /package/dist/{body-flags-BUA9XV1u.mjs → body-flags-BK7J6Daz.mjs} +0 -0
- /package/dist/{setting-26ckqHAP.mjs → setting-CTaAeMci.mjs} +0 -0
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import { ZodError, core } from "zod";
|
|
2
|
+
import { isCancel } from "@clack/prompts";
|
|
3
|
+
|
|
4
|
+
//#region src/core/json-pointer.ts
|
|
5
|
+
function escapeJsonPointerSegment(key) {
|
|
6
|
+
if (typeof key === "number") return String(key);
|
|
7
|
+
const segment = typeof key === "symbol" ? key.toString() : key;
|
|
8
|
+
return segment.replaceAll("~", "~0").replaceAll("/", "~1");
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
//#endregion
|
|
12
|
+
//#region src/core/errors.ts
|
|
13
|
+
const VERBOSE_ENV = "METABASE_VERBOSE";
|
|
14
|
+
var MetabaseError = class extends Error {
|
|
15
|
+
get userMessage() {
|
|
16
|
+
return this.message;
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
var NetworkError = class extends MetabaseError {
|
|
20
|
+
category = "network";
|
|
21
|
+
isRetryable = true;
|
|
22
|
+
exitCode = 1;
|
|
23
|
+
developerDetail;
|
|
24
|
+
constructor(message, developerDetail) {
|
|
25
|
+
super(message);
|
|
26
|
+
this.name = "NetworkError";
|
|
27
|
+
this.developerDetail = developerDetail;
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
var TimeoutError = class extends MetabaseError {
|
|
31
|
+
category = "timeout";
|
|
32
|
+
isRetryable = true;
|
|
33
|
+
exitCode = 1;
|
|
34
|
+
developerDetail;
|
|
35
|
+
constructor(message, developerDetail) {
|
|
36
|
+
super(message);
|
|
37
|
+
this.name = "TimeoutError";
|
|
38
|
+
this.developerDetail = developerDetail;
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
var ValidationError = class extends MetabaseError {
|
|
42
|
+
category = "validation";
|
|
43
|
+
isRetryable = false;
|
|
44
|
+
exitCode = 1;
|
|
45
|
+
developerDetail;
|
|
46
|
+
constructor(message, developerDetail) {
|
|
47
|
+
super(message);
|
|
48
|
+
this.name = "ValidationError";
|
|
49
|
+
this.developerDetail = developerDetail;
|
|
50
|
+
}
|
|
51
|
+
get userMessage() {
|
|
52
|
+
const issues = this.developerDetail.zodIssues;
|
|
53
|
+
if (issues.length === 0) return this.message;
|
|
54
|
+
return `${this.message}\n${formatZodIssueList(issues)}`;
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
const MAX_ISSUES_PRINTED = 10;
|
|
58
|
+
function formatZodIssueList(issues) {
|
|
59
|
+
const head = issues.slice(0, MAX_ISSUES_PRINTED).map(formatZodIssueLine);
|
|
60
|
+
const overflow = issues.length - MAX_ISSUES_PRINTED;
|
|
61
|
+
if (overflow > 0) head.push(` ... and ${overflow} more`);
|
|
62
|
+
return head.join("\n");
|
|
63
|
+
}
|
|
64
|
+
function formatZodIssueLine(issue) {
|
|
65
|
+
return ` ${formatZodIssuePointer(issue.path)}: ${issue.message}`;
|
|
66
|
+
}
|
|
67
|
+
function formatZodIssuePointer(path) {
|
|
68
|
+
if (path.length === 0) return "/";
|
|
69
|
+
return path.map((key) => `/${escapeJsonPointerSegment(key)}`).join("");
|
|
70
|
+
}
|
|
71
|
+
var ConfigError = class extends MetabaseError {
|
|
72
|
+
category = "config";
|
|
73
|
+
isRetryable = false;
|
|
74
|
+
exitCode = 2;
|
|
75
|
+
developerDetail = null;
|
|
76
|
+
constructor(message) {
|
|
77
|
+
super(message);
|
|
78
|
+
this.name = "ConfigError";
|
|
79
|
+
}
|
|
80
|
+
};
|
|
81
|
+
var AbortError = class extends MetabaseError {
|
|
82
|
+
category = "abort";
|
|
83
|
+
isRetryable = false;
|
|
84
|
+
exitCode = 130;
|
|
85
|
+
developerDetail = null;
|
|
86
|
+
constructor(message = "aborted") {
|
|
87
|
+
super(message);
|
|
88
|
+
this.name = "AbortError";
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
var ChainedRequestError = class extends MetabaseError {
|
|
92
|
+
cause;
|
|
93
|
+
constructor(message, cause) {
|
|
94
|
+
super(message);
|
|
95
|
+
this.name = "ChainedRequestError";
|
|
96
|
+
this.cause = cause;
|
|
97
|
+
}
|
|
98
|
+
get category() {
|
|
99
|
+
return this.cause.category;
|
|
100
|
+
}
|
|
101
|
+
get isRetryable() {
|
|
102
|
+
return this.cause.isRetryable;
|
|
103
|
+
}
|
|
104
|
+
get exitCode() {
|
|
105
|
+
return this.cause.exitCode;
|
|
106
|
+
}
|
|
107
|
+
get developerDetail() {
|
|
108
|
+
return this.cause.developerDetail;
|
|
109
|
+
}
|
|
110
|
+
};
|
|
111
|
+
var UnknownError = class extends MetabaseError {
|
|
112
|
+
category = "unknown";
|
|
113
|
+
isRetryable = false;
|
|
114
|
+
exitCode = 1;
|
|
115
|
+
developerDetail;
|
|
116
|
+
constructor(input) {
|
|
117
|
+
super(input.originalMessage);
|
|
118
|
+
this.name = "UnknownError";
|
|
119
|
+
this.developerDetail = input;
|
|
120
|
+
}
|
|
121
|
+
};
|
|
122
|
+
function toMetabaseError(error) {
|
|
123
|
+
if (error instanceof MetabaseError) return error;
|
|
124
|
+
if (isCancel(error)) return new AbortError();
|
|
125
|
+
if (error instanceof ZodError) return new ConfigError(error.issues.map(formatZodIssue).join("; "));
|
|
126
|
+
if (error instanceof Error) return new UnknownError({
|
|
127
|
+
originalMessage: error.message,
|
|
128
|
+
stack: error.stack ?? null
|
|
129
|
+
});
|
|
130
|
+
return new UnknownError({
|
|
131
|
+
originalMessage: String(error),
|
|
132
|
+
stack: null
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
function formatZodIssue(issue) {
|
|
136
|
+
const path = core.toDotPath(issue.path);
|
|
137
|
+
return path === "" ? issue.message : `${path}: ${issue.message}`;
|
|
138
|
+
}
|
|
139
|
+
function isNotFoundError(value) {
|
|
140
|
+
return value instanceof Error && "code" in value && value.code === "ENOENT";
|
|
141
|
+
}
|
|
142
|
+
function errorMessage(value) {
|
|
143
|
+
return value instanceof Error ? value.message : String(value);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
//#endregion
|
|
147
|
+
//#region src/runtime/predicates.ts
|
|
148
|
+
function isPlainObject(value) {
|
|
149
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
//#endregion
|
|
153
|
+
export { AbortError, ChainedRequestError, ConfigError, MetabaseError, NetworkError, TimeoutError, VERBOSE_ENV, ValidationError, errorMessage, escapeJsonPointerSegment, isNotFoundError, isPlainObject, toMetabaseError };
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { writeJson } from "./render-DXv-D6fU.mjs";
|
|
2
|
+
import { ChainedRequestError, ConfigError, MetabaseError } from "./predicates-DiIiS3k7.mjs";
|
|
3
|
+
import { HttpError } from "./runtime-D7jihh81.mjs";
|
|
4
|
+
import { Card } from "./card-CAEZWixN.mjs";
|
|
5
|
+
import { z } from "zod";
|
|
6
|
+
|
|
7
|
+
//#region src/commands/dashboard/preflight.ts
|
|
8
|
+
const PreflightDashcard = z.looseObject({ card_id: z.number().int().nullable().optional() });
|
|
9
|
+
function collectDashcardCardReferences(dashcards) {
|
|
10
|
+
if (dashcards === void 0) return [];
|
|
11
|
+
const refs = [];
|
|
12
|
+
dashcards.forEach((dashcard, index) => {
|
|
13
|
+
const parsed = PreflightDashcard.safeParse(dashcard);
|
|
14
|
+
if (!parsed.success) return;
|
|
15
|
+
const cardId = parsed.data.card_id;
|
|
16
|
+
if (typeof cardId === "number" && cardId > 0) refs.push({
|
|
17
|
+
cardId,
|
|
18
|
+
path: `/dashcards/${index}/card_id`
|
|
19
|
+
});
|
|
20
|
+
});
|
|
21
|
+
return refs;
|
|
22
|
+
}
|
|
23
|
+
async function preflightDashcardCardReferences(client, dashcards) {
|
|
24
|
+
const references = collectDashcardCardReferences(dashcards);
|
|
25
|
+
if (references.length === 0) return;
|
|
26
|
+
const grouped = new Map();
|
|
27
|
+
for (const ref of references) {
|
|
28
|
+
const list = grouped.get(ref.cardId);
|
|
29
|
+
if (list === void 0) grouped.set(ref.cardId, [ref]);
|
|
30
|
+
else list.push(ref);
|
|
31
|
+
}
|
|
32
|
+
const checks = await Promise.all(Array.from(grouped.entries()).map(async ([cardId, refs]) => ({
|
|
33
|
+
refs,
|
|
34
|
+
result: await classifyCardReference(client, cardId)
|
|
35
|
+
})));
|
|
36
|
+
const errors = [];
|
|
37
|
+
for (const check of checks) {
|
|
38
|
+
if (check.result.status === "ok") continue;
|
|
39
|
+
for (const ref of check.refs) errors.push({
|
|
40
|
+
path: ref.path,
|
|
41
|
+
message: check.result.message
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
if (errors.length === 0) return;
|
|
45
|
+
const outcome = {
|
|
46
|
+
ok: false,
|
|
47
|
+
errors
|
|
48
|
+
};
|
|
49
|
+
writeJson(outcome);
|
|
50
|
+
throw new ConfigError(`dashboard card-reference pre-flight failed: ${errors.length} error(s) — fix the dashcard card_id values listed above`);
|
|
51
|
+
}
|
|
52
|
+
function wrapChainedDashboardWriteError(error, dashboardId) {
|
|
53
|
+
if (!(error instanceof MetabaseError)) return error;
|
|
54
|
+
const prefix = `dashboard ${dashboardId} created but follow-up PUT /api/dashboard/${dashboardId} failed`;
|
|
55
|
+
const suffix = "dashcards not applied";
|
|
56
|
+
const message = `${prefix}: ${error.userMessage}; ${suffix}`;
|
|
57
|
+
if (error instanceof HttpError) return new HttpError({
|
|
58
|
+
status: error.status,
|
|
59
|
+
statusText: error.developerDetail.statusText,
|
|
60
|
+
method: error.developerDetail.method,
|
|
61
|
+
url: error.developerDetail.url,
|
|
62
|
+
responseHeaders: error.developerDetail.responseHeaders,
|
|
63
|
+
rawBody: error.developerDetail.body,
|
|
64
|
+
overrideUserMessage: message
|
|
65
|
+
});
|
|
66
|
+
return new ChainedRequestError(message, error);
|
|
67
|
+
}
|
|
68
|
+
async function classifyCardReference(client, cardId) {
|
|
69
|
+
try {
|
|
70
|
+
const card = await client.requestParsed(Card, `/api/card/${cardId}`);
|
|
71
|
+
if (card.archived) return {
|
|
72
|
+
status: "error",
|
|
73
|
+
message: `card ${cardId} is archived`
|
|
74
|
+
};
|
|
75
|
+
return { status: "ok" };
|
|
76
|
+
} catch (error) {
|
|
77
|
+
if (!(error instanceof HttpError)) throw error;
|
|
78
|
+
if (error.status === 404) return {
|
|
79
|
+
status: "error",
|
|
80
|
+
message: `card ${cardId} not found`
|
|
81
|
+
};
|
|
82
|
+
if (error.status === 401 || error.status === 403) return {
|
|
83
|
+
status: "error",
|
|
84
|
+
message: `card ${cardId} is not readable: ${error.userMessage}`
|
|
85
|
+
};
|
|
86
|
+
throw error;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
//#endregion
|
|
91
|
+
export { preflightDashcardCardReferences, wrapChainedDashboardWriteError };
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import "./package-DBsS7a5x.mjs";
|
|
2
|
+
import "./command-augment-D9pI9Vbh.mjs";
|
|
3
|
+
import { renderItem } from "./render-DXv-D6fU.mjs";
|
|
4
|
+
import { ConfigError } from "./predicates-DiIiS3k7.mjs";
|
|
5
|
+
import "./input-ikCiip6x.mjs";
|
|
6
|
+
import { connectionFlags, defineMetabaseCommand, outputFlags, profileFlag } from "./runtime-D7jihh81.mjs";
|
|
7
|
+
import { readBody } from "./body-DRBgxS6-.mjs";
|
|
8
|
+
import { bodyInputFlags } from "./body-flags-BK7J6Daz.mjs";
|
|
9
|
+
import { parseId } from "./parse-id-BUOZQqjp.mjs";
|
|
10
|
+
import "./poll-DMmmZWvi.mjs";
|
|
11
|
+
import { parseWaitFlags, waitFlags } from "./wait-flags-DO3ar2tf.mjs";
|
|
12
|
+
import { Workspace, WorkspaceProvisionInput, workspaceView } from "./workspace-DVuqKJGG.mjs";
|
|
13
|
+
import { waitForDatabaseProvisioned } from "./wait-CWizX_sR.mjs";
|
|
14
|
+
import { parseSchemasCsv } from "./parse-schemas-BnW4T1_I.mjs";
|
|
15
|
+
|
|
16
|
+
//#region src/commands/workspace/database/provision.ts
|
|
17
|
+
var provision_default = defineMetabaseCommand({
|
|
18
|
+
meta: {
|
|
19
|
+
name: "provision",
|
|
20
|
+
description: "Provision a database into a workspace"
|
|
21
|
+
},
|
|
22
|
+
args: {
|
|
23
|
+
...outputFlags,
|
|
24
|
+
...profileFlag,
|
|
25
|
+
...connectionFlags,
|
|
26
|
+
...bodyInputFlags,
|
|
27
|
+
...waitFlags,
|
|
28
|
+
"database-id": {
|
|
29
|
+
type: "string",
|
|
30
|
+
description: "Database id (alternative to --body / --file)"
|
|
31
|
+
},
|
|
32
|
+
schemas: {
|
|
33
|
+
type: "string",
|
|
34
|
+
description: "Comma-separated input schemas (alternative to --body / --file)"
|
|
35
|
+
},
|
|
36
|
+
id: {
|
|
37
|
+
type: "positional",
|
|
38
|
+
description: "Workspace id",
|
|
39
|
+
required: true
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
outputSchema: Workspace,
|
|
43
|
+
examples: [
|
|
44
|
+
"metabase workspace database provision 1 --database-id 5 --schemas analytics,github",
|
|
45
|
+
"metabase workspace database provision 1 --database-id 5 --schemas analytics --wait",
|
|
46
|
+
"metabase workspace database provision 1 --file provision.json"
|
|
47
|
+
],
|
|
48
|
+
async run({ args, ctx, getClient }) {
|
|
49
|
+
const workspaceId = parseId(args.id);
|
|
50
|
+
const databaseIdFlag = args["database-id"];
|
|
51
|
+
const schemasFlag = args.schemas;
|
|
52
|
+
const wait = parseWaitFlags(args);
|
|
53
|
+
let body;
|
|
54
|
+
if (databaseIdFlag !== void 0 && databaseIdFlag !== "") {
|
|
55
|
+
const databaseId = parseId(databaseIdFlag, "--database-id");
|
|
56
|
+
if (schemasFlag === void 0 || schemasFlag === "") throw new ConfigError("--schemas is required when using --database-id");
|
|
57
|
+
const input_schemas = parseSchemasCsv(schemasFlag);
|
|
58
|
+
body = WorkspaceProvisionInput.parse({
|
|
59
|
+
database_id: databaseId,
|
|
60
|
+
input_schemas
|
|
61
|
+
});
|
|
62
|
+
} else body = await readBody({
|
|
63
|
+
flag: args.body,
|
|
64
|
+
file: args.file
|
|
65
|
+
}, WorkspaceProvisionInput);
|
|
66
|
+
const client = await getClient();
|
|
67
|
+
const initial = await client.requestParsed(Workspace, `/api/ee/workspace-manager/${workspaceId}/database`, {
|
|
68
|
+
method: "POST",
|
|
69
|
+
body
|
|
70
|
+
});
|
|
71
|
+
const final = wait.enabled ? await waitForDatabaseProvisioned(client, workspaceId, body.database_id, wait.schedule) : initial;
|
|
72
|
+
renderItem(final, workspaceView, ctx);
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
//#endregion
|
|
77
|
+
export { provision_default as default };
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import "./package-DBsS7a5x.mjs";
|
|
2
|
+
import "./command-augment-D9pI9Vbh.mjs";
|
|
3
|
+
import "./render-DXv-D6fU.mjs";
|
|
4
|
+
import "./predicates-DiIiS3k7.mjs";
|
|
5
|
+
import "./runtime-D7jihh81.mjs";
|
|
6
|
+
import "./poll-DMmmZWvi.mjs";
|
|
7
|
+
import "./docker-D-ieBsP7.mjs";
|
|
8
|
+
import { LocalWorkspace, LocalWorkspaceCompact, LocalWorkspaceListEnvelope, LocalWorkspaceState, localWorkspaceView, ps_default } from "./ps-Yv0JjLVN.mjs";
|
|
9
|
+
|
|
10
|
+
export { ps_default as default };
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { renderList } from "./render-DXv-D6fU.mjs";
|
|
2
|
+
import { defineMetabaseCommand, listEnvelopeSchema, localUrl, outputFlags, wrapList } from "./runtime-D7jihh81.mjs";
|
|
3
|
+
import { CONTAINER_STATES, checkDockerReady, listWorkspaceContainers } from "./docker-D-ieBsP7.mjs";
|
|
4
|
+
import { z } from "zod";
|
|
5
|
+
|
|
6
|
+
//#region src/commands/workspace/ps.ts
|
|
7
|
+
const LocalWorkspaceState = z.enum(CONTAINER_STATES);
|
|
8
|
+
const LocalWorkspace = z.object({
|
|
9
|
+
workspace_id: z.number().int().positive(),
|
|
10
|
+
workspace_name: z.string(),
|
|
11
|
+
container_name: z.string(),
|
|
12
|
+
state: LocalWorkspaceState,
|
|
13
|
+
status: z.string(),
|
|
14
|
+
image: z.string(),
|
|
15
|
+
profile: z.string().nullable(),
|
|
16
|
+
parent_url: z.string().nullable(),
|
|
17
|
+
host_port: z.number().int().positive().nullable(),
|
|
18
|
+
url: z.string().nullable()
|
|
19
|
+
});
|
|
20
|
+
const LocalWorkspaceCompact = LocalWorkspace.pick({
|
|
21
|
+
workspace_id: true,
|
|
22
|
+
workspace_name: true,
|
|
23
|
+
state: true,
|
|
24
|
+
url: true
|
|
25
|
+
}).strip();
|
|
26
|
+
const localWorkspaceView = {
|
|
27
|
+
compactPick: LocalWorkspaceCompact,
|
|
28
|
+
tableColumns: [
|
|
29
|
+
{
|
|
30
|
+
key: "workspace_id",
|
|
31
|
+
label: "ID"
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
key: "workspace_name",
|
|
35
|
+
label: "Name"
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
key: "state",
|
|
39
|
+
label: "State"
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
key: "url",
|
|
43
|
+
label: "URL",
|
|
44
|
+
format: (value) => typeof value === "string" ? value : "—"
|
|
45
|
+
}
|
|
46
|
+
]
|
|
47
|
+
};
|
|
48
|
+
const LocalWorkspaceListEnvelope = listEnvelopeSchema(LocalWorkspaceCompact);
|
|
49
|
+
var ps_default = defineMetabaseCommand({
|
|
50
|
+
meta: {
|
|
51
|
+
name: "ps",
|
|
52
|
+
description: "List workspaces with a local container (running or stopped)"
|
|
53
|
+
},
|
|
54
|
+
args: { ...outputFlags },
|
|
55
|
+
outputSchema: LocalWorkspaceListEnvelope,
|
|
56
|
+
examples: ["metabase workspace ps", "metabase workspace ps --json"],
|
|
57
|
+
async run({ ctx }) {
|
|
58
|
+
await checkDockerReady();
|
|
59
|
+
const summaries = await listWorkspaceContainers();
|
|
60
|
+
const items = summaries.map((summary) => ({
|
|
61
|
+
workspace_id: summary.workspaceId,
|
|
62
|
+
workspace_name: summary.workspaceName,
|
|
63
|
+
container_name: summary.name,
|
|
64
|
+
state: summary.state,
|
|
65
|
+
status: summary.status,
|
|
66
|
+
image: summary.image,
|
|
67
|
+
profile: summary.profile,
|
|
68
|
+
parent_url: summary.parentUrl,
|
|
69
|
+
host_port: summary.hostPort,
|
|
70
|
+
url: summary.hostPort !== null && summary.state === "running" ? localUrl(summary.hostPort) : null
|
|
71
|
+
}));
|
|
72
|
+
items.sort((a, b) => a.workspace_id - b.workspace_id);
|
|
73
|
+
renderList(wrapList(items), localWorkspaceView, ctx);
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
//#endregion
|
|
78
|
+
export { LocalWorkspace, LocalWorkspaceCompact, LocalWorkspaceListEnvelope, LocalWorkspaceState, localWorkspaceView, ps_default };
|
|
@@ -1,8 +1,11 @@
|
|
|
1
|
-
import "./package-
|
|
1
|
+
import "./package-DBsS7a5x.mjs";
|
|
2
2
|
import "./command-augment-D9pI9Vbh.mjs";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
3
|
+
import { renderItem } from "./render-DXv-D6fU.mjs";
|
|
4
|
+
import { ConfigError } from "./predicates-DiIiS3k7.mjs";
|
|
5
|
+
import { connectionFlags, defineMetabaseCommand, outputFlags, parseJson, profileFlag } from "./runtime-D7jihh81.mjs";
|
|
6
|
+
import { parseId } from "./parse-id-BUOZQqjp.mjs";
|
|
7
|
+
import "./field-DciLbuv-.mjs";
|
|
8
|
+
import { CardQueryResult, cardQueryView } from "./card-CAEZWixN.mjs";
|
|
6
9
|
import { z } from "zod";
|
|
7
10
|
import { Writable } from "node:stream";
|
|
8
11
|
|
|
@@ -13,12 +16,16 @@ async function pipeToStdout(stream) {
|
|
|
13
16
|
|
|
14
17
|
//#endregion
|
|
15
18
|
//#region src/commands/card/query.ts
|
|
16
|
-
const ExportFormat = z.enum([
|
|
19
|
+
const ExportFormat = z.enum([
|
|
20
|
+
"csv",
|
|
21
|
+
"json",
|
|
22
|
+
"xlsx"
|
|
23
|
+
]);
|
|
17
24
|
const QueryParameters = z.array(z.unknown());
|
|
18
25
|
var query_default = defineMetabaseCommand({
|
|
19
26
|
meta: {
|
|
20
27
|
name: "query",
|
|
21
|
-
description: "Run a saved card and return results (json envelope, CSV
|
|
28
|
+
description: "Run a saved card and return results (json envelope, or stream CSV/JSON/XLSX via --export-format)"
|
|
22
29
|
},
|
|
23
30
|
args: {
|
|
24
31
|
...outputFlags,
|
|
@@ -39,7 +46,17 @@ var query_default = defineMetabaseCommand({
|
|
|
39
46
|
},
|
|
40
47
|
limit: {
|
|
41
48
|
type: "string",
|
|
42
|
-
description: "Cap rows kept in the JSON envelope (no effect on
|
|
49
|
+
description: "Cap rows kept in the JSON envelope (no effect on streamed exports)"
|
|
50
|
+
},
|
|
51
|
+
"format-rows": {
|
|
52
|
+
type: "boolean",
|
|
53
|
+
description: "Streamed exports only: apply visualization-settings formatting to values (default false)",
|
|
54
|
+
default: false
|
|
55
|
+
},
|
|
56
|
+
"pivot-results": {
|
|
57
|
+
type: "boolean",
|
|
58
|
+
description: "Streamed exports only: emit the pivoted output for pivot questions (default false)",
|
|
59
|
+
default: false
|
|
43
60
|
}
|
|
44
61
|
},
|
|
45
62
|
outputSchema: CardQueryResult,
|
|
@@ -55,8 +72,12 @@ var query_default = defineMetabaseCommand({
|
|
|
55
72
|
const client = await getClient();
|
|
56
73
|
const exportFormatRaw = args["export-format"];
|
|
57
74
|
if (exportFormatRaw !== void 0 && exportFormatRaw !== "") {
|
|
58
|
-
|
|
59
|
-
|
|
75
|
+
await streamExport(client, id, {
|
|
76
|
+
format: parseExportFormat(exportFormatRaw),
|
|
77
|
+
parameters,
|
|
78
|
+
formatRows: args["format-rows"],
|
|
79
|
+
pivotResults: args["pivot-results"]
|
|
80
|
+
});
|
|
60
81
|
return;
|
|
61
82
|
}
|
|
62
83
|
const result = await client.requestParsed(CardQueryResult, `/api/card/${id}/query`, {
|
|
@@ -77,7 +98,7 @@ function parseExportFormat(raw) {
|
|
|
77
98
|
return result.data;
|
|
78
99
|
}
|
|
79
100
|
function applyLimit(result, limit) {
|
|
80
|
-
if (limit === null || result.
|
|
101
|
+
if (limit === null || result.data === void 0 || result.data.rows.length <= limit) return result;
|
|
81
102
|
return {
|
|
82
103
|
...result,
|
|
83
104
|
data: {
|
|
@@ -86,9 +107,13 @@ function applyLimit(result, limit) {
|
|
|
86
107
|
}
|
|
87
108
|
};
|
|
88
109
|
}
|
|
89
|
-
async function streamExport(client, id,
|
|
90
|
-
const body = new URLSearchParams({
|
|
91
|
-
|
|
110
|
+
async function streamExport(client, id, options) {
|
|
111
|
+
const body = new URLSearchParams({
|
|
112
|
+
parameters: JSON.stringify(options.parameters),
|
|
113
|
+
format_rows: String(options.formatRows),
|
|
114
|
+
pivot_results: String(options.pivotResults)
|
|
115
|
+
});
|
|
116
|
+
const stream = await client.requestStream(`/api/card/${id}/query/${options.format}`, {
|
|
92
117
|
method: "POST",
|
|
93
118
|
body
|
|
94
119
|
});
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import "./package-DBsS7a5x.mjs";
|
|
2
|
+
import "./command-augment-D9pI9Vbh.mjs";
|
|
3
|
+
import { renderItem, writeJson } from "./render-DXv-D6fU.mjs";
|
|
4
|
+
import { ConfigError } from "./predicates-DiIiS3k7.mjs";
|
|
5
|
+
import "./input-ikCiip6x.mjs";
|
|
6
|
+
import { connectionFlags, defineMetabaseCommand, outputFlags, profileFlag } from "./runtime-D7jihh81.mjs";
|
|
7
|
+
import { readBody } from "./body-DRBgxS6-.mjs";
|
|
8
|
+
import { bodyInputFlags } from "./body-flags-BK7J6Daz.mjs";
|
|
9
|
+
import "./field-DciLbuv-.mjs";
|
|
10
|
+
import { CardQueryResult, cardQueryView } from "./card-CAEZWixN.mjs";
|
|
11
|
+
import { assertNotLegacyEnvelopeWrappingMbql5, getQuerySchemaBundle, isMbql5Query, validateQuery } from "./validate-DCYx6jdL.mjs";
|
|
12
|
+
import { skipValidateFlag } from "./validate-query-B07oGG4K.mjs";
|
|
13
|
+
import { z } from "zod";
|
|
14
|
+
|
|
15
|
+
//#region src/commands/query.ts
|
|
16
|
+
const QueryBody = z.unknown();
|
|
17
|
+
const QUERY_ENDPOINT = "/api/dataset";
|
|
18
|
+
var query_default = defineMetabaseCommand({
|
|
19
|
+
meta: {
|
|
20
|
+
name: "query",
|
|
21
|
+
description: "Run an MBQL 5 query (validates against the bundled schema first); --print-schema emits the schema for agent discovery, --dry-run validates without sending. Any non-MBQL 5 body — legacy MBQL 4 ({type:\"query\", …}), legacy native ({type:\"native\", …}), or any other non-{lib/type:\"mbql/query\"} shape — skips pre-flight automatically and is normalized server-side by lib-be/normalize-query. The bundled schema only models MBQL 5. Every clause options object carries a `lib/uuid` (UUID v4); mint these via `metabase uuid` — never author them by hand."
|
|
22
|
+
},
|
|
23
|
+
args: {
|
|
24
|
+
...outputFlags,
|
|
25
|
+
...profileFlag,
|
|
26
|
+
...connectionFlags,
|
|
27
|
+
...bodyInputFlags,
|
|
28
|
+
"dry-run": {
|
|
29
|
+
type: "boolean",
|
|
30
|
+
description: "Validate the body and exit without sending the query"
|
|
31
|
+
},
|
|
32
|
+
"print-schema": {
|
|
33
|
+
type: "boolean",
|
|
34
|
+
description: "Emit the bundled MBQL 5 query JSON Schema and exit; no body required"
|
|
35
|
+
},
|
|
36
|
+
...skipValidateFlag
|
|
37
|
+
},
|
|
38
|
+
outputSchema: CardQueryResult,
|
|
39
|
+
examples: [
|
|
40
|
+
"metabase query --print-schema",
|
|
41
|
+
"cat q.json | metabase query --dry-run",
|
|
42
|
+
"metabase query --file q.json",
|
|
43
|
+
"metabase query --file q.json --skip-validate"
|
|
44
|
+
],
|
|
45
|
+
async run({ args, ctx, getClient }) {
|
|
46
|
+
if (args["print-schema"] === true) {
|
|
47
|
+
writeJson(getQuerySchemaBundle());
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
const dryRun = args["dry-run"] === true;
|
|
51
|
+
const explicitSkip = args["skip-validate"] === true;
|
|
52
|
+
if (dryRun && explicitSkip) throw new ConfigError("--skip-validate cannot be combined with --dry-run");
|
|
53
|
+
const body = await readBody({
|
|
54
|
+
flag: args.body,
|
|
55
|
+
file: args.file
|
|
56
|
+
}, QueryBody);
|
|
57
|
+
if (!explicitSkip) assertNotLegacyEnvelopeWrappingMbql5(body, {
|
|
58
|
+
contextLabel: "query",
|
|
59
|
+
bodyNoun: "the body"
|
|
60
|
+
});
|
|
61
|
+
const skipValidation = explicitSkip || !isMbql5Query(body);
|
|
62
|
+
if (!skipValidation) {
|
|
63
|
+
const outcome = validateQuery(body);
|
|
64
|
+
if (!outcome.ok) {
|
|
65
|
+
writeJson(outcome);
|
|
66
|
+
const hint = dryRun ? "" : " — pass --dry-run to validate without sending";
|
|
67
|
+
throw new ConfigError(`validation failed: ${outcome.errors.length} error(s)${hint}`);
|
|
68
|
+
}
|
|
69
|
+
if (dryRun) {
|
|
70
|
+
writeJson(outcome);
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
} else if (dryRun) {
|
|
74
|
+
writeJson({
|
|
75
|
+
ok: true,
|
|
76
|
+
errors: []
|
|
77
|
+
});
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
const client = await getClient();
|
|
81
|
+
const queryResult = await client.requestParsed(CardQueryResult, QUERY_ENDPOINT, {
|
|
82
|
+
method: "POST",
|
|
83
|
+
body
|
|
84
|
+
});
|
|
85
|
+
renderItem(queryResult, cardQueryView, ctx);
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
//#endregion
|
|
90
|
+
export { query_default as default };
|