@metabase/cli 0.1.0-alpha.workspaces-commands.818a8f1 → 0.1.0
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 +0 -237
- package/dist/{archive-BPG5c88Y.mjs → archive-CsWeHXle.mjs} +4 -5
- package/dist/{auth--Hpjwlaf.mjs → auth-BF7IjZIH.mjs} +3 -3
- package/dist/{body-DwU2s6Pg.mjs → body-Dv9hQ0Qk.mjs} +2 -2
- package/dist/{branches-BbcoJXfp.mjs → branches-BujtceGr.mjs} +4 -5
- package/dist/{cancel-task-BDas45YO.mjs → cancel-task-CT2xUMRg.mjs} +4 -5
- package/dist/card-_Ta7zdYe.mjs +19 -0
- package/dist/cli.mjs +13 -17
- package/dist/{create-DpnjQvPw.mjs → create-B8ektf-R.mjs} +6 -7
- package/dist/{create-_UOeEXAj.mjs → create-CI2Cunq5.mjs} +6 -7
- package/dist/{create-CwVcoq0O.mjs → create-DdbU3TLX.mjs} +6 -7
- package/dist/{create-branch-sDttBORB.mjs → create-branch-goZBTNnr.mjs} +4 -5
- package/dist/{current-task-BGt1mqaX.mjs → current-task-DBjRNCFq.mjs} +4 -5
- package/dist/{db-Dm2u2ISJ.mjs → db-DMghzgb6.mjs} +2 -2
- package/dist/{delete-DRBTgyus.mjs → delete-8vGU35r3.mjs} +5 -6
- package/dist/{delete-DUC_stoL.mjs → delete-B27KLF5X.mjs} +5 -6
- package/dist/{delete-runtime-inOVw3IX.mjs → delete-runtime-Byr60cR3.mjs} +2 -4
- package/dist/{delete-table-9Is631O_.mjs → delete-table-BNaJ_gA4.mjs} +5 -6
- package/dist/{dirty-CLjHbz6J.mjs → dirty-aNUuph4I.mjs} +4 -5
- package/dist/{export-D2Anfu3p.mjs → export-QDkuuzSE.mjs} +5 -6
- package/dist/{field-Dhs2AND3.mjs → field-DaYo_90x.mjs} +1 -1
- package/dist/{get-DhIoNeOp.mjs → get-BGBIzMKY.mjs} +4 -5
- package/dist/{get-CAVVmdMX.mjs → get-COXHplHP.mjs} +4 -5
- package/dist/{get-CAPLfawI.mjs → get-Cl8-IauC.mjs} +4 -5
- package/dist/{get-DDWpubE8.mjs → get-Cwpj7lDe.mjs} +5 -6
- package/dist/{get-BHJA78zg.mjs → get-DI_IJvgk.mjs} +4 -5
- package/dist/{get-2po1uv9i.mjs → get-Dh_acl8q.mjs} +4 -5
- package/dist/{get-qPOsuTPw.mjs → get-i6LWOByV.mjs} +4 -5
- package/dist/{has-remote-changes-DAL5jetW.mjs → has-remote-changes-hjKoQuRy.mjs} +4 -5
- package/dist/{import-CUMxUfSF.mjs → import-HJsSKRYx.mjs} +5 -6
- package/dist/{input-BNqSFl38.mjs → input-Dojr-RTw.mjs} +1 -1
- package/dist/{is-dirty-B10S6MG0.mjs → is-dirty-1Qy7hiHB.mjs} +2 -3
- package/dist/is-dirty-DpKn9HJp.mjs +8 -0
- package/dist/{key-CyhOpgWt.mjs → key-DBxPSFwi.mjs} +1 -1
- package/dist/{license-DtsGJi3l.mjs → license-MoWse3ZI.mjs} +3 -3
- package/dist/{list-Y7iGsOfE.mjs → list-Bk6RsbJl.mjs} +3 -4
- package/dist/{list-DeFGwhhJ.mjs → list-C4Ajrw8f.mjs} +3 -4
- package/dist/{list-C5MGydGU.mjs → list-C8tdLOH5.mjs} +3 -4
- package/dist/{list-evtQS7jl.mjs → list-CBSBHtK-.mjs} +3 -4
- package/dist/{list-qetY9OIN.mjs → list-CWt3fqrZ.mjs} +3 -4
- package/dist/{list-OBx5B3gd.mjs → list-C_PRdL5e.mjs} +5 -6
- package/dist/{login-Dqw9ZtCx.mjs → login-C9WTwNn6.mjs} +4 -5
- package/dist/{logout-DwYJ5OUi.mjs → logout-oLszGCOg.mjs} +3 -4
- package/dist/{package-t8dKf4m_.mjs → package-BGfw4ZWJ.mjs} +1 -2
- package/dist/parse-id-BhmmfyCP.mjs +14 -0
- package/dist/{poll-D2sXM5rc.mjs → poll-ILanYysl.mjs} +1 -1
- package/dist/{poll-task-Byiunmaj.mjs → poll-task-DbpsiQhl.mjs} +2 -2
- package/dist/{prompt-fXeNtj0M.mjs → prompt-DpT8yAVy.mjs} +1 -1
- package/dist/{query-BnGVGeM3.mjs → query-PihYi-UZ.mjs} +4 -5
- package/dist/{remove-Bx48o-0S.mjs → remove-B2hVYn1v.mjs} +3 -4
- package/dist/{run-D4NgvaRh.mjs → run-C2so6Qp6.mjs} +27 -11
- package/dist/{runtime-DUgFfYkN.mjs → runtime-C9CEZhcn.mjs} +335 -203
- package/dist/{search-4wKx5ug2.mjs → search-CopOytXY.mjs} +4 -5
- package/dist/{set-BZnCRL4c.mjs → set-BcF7M1GQ.mjs} +4 -5
- package/dist/{set-DCjrmTFm.mjs → set-CbibegpA.mjs} +6 -7
- package/dist/{setting-C4vQSqer.mjs → setting-U3NtBMFo.mjs} +3 -3
- package/dist/{stash-ZZkmW_V7.mjs → stash-DOBbYozC.mjs} +5 -6
- package/dist/{status-DezF-PIM.mjs → status-Buf1ZbNR.mjs} +5 -6
- package/dist/{status-JH6BZppo.mjs → status-CUcs8XBH.mjs} +2 -3
- package/dist/{status-9KAPIpX8.mjs → status-D1F5XHae.mjs} +2 -3
- package/dist/sync-BPyGXfUk.mjs +26 -0
- package/dist/{table-BvAr2ixC.mjs → table-Cfk7oSvw.mjs} +1 -1
- package/dist/{table-D-Mb5Nvw.mjs → table-D7nJt7JO.mjs} +2 -2
- package/dist/transform-UbyewMxY.mjs +21 -0
- package/dist/transform-job-CrYkr-Ma.mjs +19 -0
- package/dist/{update-DxKlQ0hP.mjs → update-CL8tRbxr.mjs} +7 -8
- package/dist/{update-CDtm71m2.mjs → update-DU2oU2j-.mjs} +7 -8
- package/dist/{wait-Cj_8wu4y.mjs → wait-Bugr9eXD.mjs} +5 -6
- package/package.json +1 -2
- package/dist/api-key-D9XxErQn.mjs +0 -13
- package/dist/card-D4zZSPUb.mjs +0 -19
- package/dist/create-Bd_U1zWU.mjs +0 -124
- package/dist/create-CCzsCZMm.mjs +0 -47
- package/dist/credentials-C0xKke5D.mjs +0 -84
- package/dist/database-4V1iiPEx.mjs +0 -17
- package/dist/deprovision-BAMzZc6f.mjs +0 -60
- package/dist/docker-QWVMG2gl.mjs +0 -605
- package/dist/eid-BNhutC1U.mjs +0 -13
- package/dist/flag-pair-CWvvzDJ_.mjs +0 -17
- package/dist/is-dirty-CUuq-aB6.mjs +0 -9
- package/dist/list-B8s7Qnzk.mjs +0 -31
- package/dist/logs-B_lrY7Js.mjs +0 -57
- package/dist/parse-id-C1prc9US.mjs +0 -12
- package/dist/provision-DC4_HWZD.mjs +0 -80
- package/dist/ps-1bZKIwWh.mjs +0 -9
- package/dist/ps-BiOrecEe.mjs +0 -78
- package/dist/remove-DecoZzNd.mjs +0 -97
- package/dist/render-DlBijc5i.mjs +0 -179
- package/dist/setup-Dqh9hN6l.mjs +0 -70
- package/dist/start-xXQypG5L.mjs +0 -324
- package/dist/stop-br-ZOnve.mjs +0 -80
- package/dist/sync-C7VOWD00.mjs +0 -26
- package/dist/transform-CqxZwhGs.mjs +0 -21
- package/dist/transform-job-HjbqjEoP.mjs +0 -19
- package/dist/translate-DJxDVAE4.mjs +0 -110
- package/dist/update-DYVeVjk2.mjs +0 -76
- package/dist/url-DP88YHNo.mjs +0 -53
- package/dist/wait-DwZN3ZwR.mjs +0 -19
- package/dist/wait-flags-CjW4ogUJ.mjs +0 -35
- package/dist/workspace-CbwR0vX_.mjs +0 -24
- package/dist/workspace-Dr9lWU3D.mjs +0 -72
- package/dist/workspace-credentials-q5RRFMT8.mjs +0 -139
- /package/dist/{body-flags-7oqLhu5j.mjs → body-flags-BUA9XV1u.mjs} +0 -0
- /package/dist/{card-C31pGtBZ.mjs → card-CsXk8T6A.mjs} +0 -0
- /package/dist/{database-BTX5qbSv.mjs → database-PA9Goi25.mjs} +0 -0
- /package/dist/{field-QwBMAWsq.mjs → field-C8IVs6rp.mjs} +0 -0
- /package/dist/{manifest-wzEFG0JB.mjs → manifest-CAdjQYH8.mjs} +0 -0
- /package/dist/{setting-DM7pm7yh.mjs → setting-26ckqHAP.mjs} +0 -0
- /package/dist/{transform-DfVkUttP.mjs → transform-B5uRpg1G.mjs} +0 -0
- /package/dist/{transform-job-DuB_OjhO.mjs → transform-job-C7QXWTVE.mjs} +0 -0
|
@@ -1,13 +1,14 @@
|
|
|
1
|
-
import { package_default } from "./package-
|
|
1
|
+
import { package_default } from "./package-BGfw4ZWJ.mjs";
|
|
2
2
|
import { setMetabaseAugment } from "./command-augment-D9pI9Vbh.mjs";
|
|
3
3
|
import { defineCommand } from "citty";
|
|
4
4
|
import { ZodError, z } from "zod";
|
|
5
|
-
import { isCancel } from "@clack/prompts";
|
|
6
5
|
import { promises } from "node:fs";
|
|
6
|
+
import { homedir } from "node:os";
|
|
7
7
|
import { dirname, join } from "node:path";
|
|
8
8
|
import { Entry } from "@napi-rs/keyring";
|
|
9
|
-
import {
|
|
9
|
+
import { isCancel } from "@clack/prompts";
|
|
10
10
|
import { setTimeout } from "node:timers/promises";
|
|
11
|
+
import Table from "cli-table3";
|
|
11
12
|
|
|
12
13
|
//#region src/core/errors.ts
|
|
13
14
|
var MetabaseError = class extends Error {
|
|
@@ -137,99 +138,6 @@ function parseJsonResult(input, schema, opts = {}) {
|
|
|
137
138
|
};
|
|
138
139
|
}
|
|
139
140
|
|
|
140
|
-
//#endregion
|
|
141
|
-
//#region src/output/types.ts
|
|
142
|
-
const DEFAULT_MAX_BYTES = 65536;
|
|
143
|
-
function listEnvelopeSchema(item) {
|
|
144
|
-
return z.object({
|
|
145
|
-
data: z.array(item),
|
|
146
|
-
returned: z.number().int().nonnegative(),
|
|
147
|
-
total: z.number().int().nonnegative().optional(),
|
|
148
|
-
limit: z.number().int().nonnegative().optional(),
|
|
149
|
-
truncated: z.object({
|
|
150
|
-
reason: z.literal("max_bytes"),
|
|
151
|
-
bytes: z.number().int().nonnegative()
|
|
152
|
-
}).optional()
|
|
153
|
-
});
|
|
154
|
-
}
|
|
155
|
-
function wrapList(items) {
|
|
156
|
-
return {
|
|
157
|
-
data: items,
|
|
158
|
-
returned: items.length,
|
|
159
|
-
total: items.length
|
|
160
|
-
};
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
//#endregion
|
|
164
|
-
//#region src/commands/flags.ts
|
|
165
|
-
const outputFlags = {
|
|
166
|
-
format: {
|
|
167
|
-
type: "string",
|
|
168
|
-
description: "auto | json | text",
|
|
169
|
-
default: "auto"
|
|
170
|
-
},
|
|
171
|
-
json: {
|
|
172
|
-
type: "boolean",
|
|
173
|
-
description: "Shorthand for --format json"
|
|
174
|
-
},
|
|
175
|
-
full: {
|
|
176
|
-
type: "boolean",
|
|
177
|
-
description: "Return the full object (default: compact)"
|
|
178
|
-
},
|
|
179
|
-
fields: {
|
|
180
|
-
type: "string",
|
|
181
|
-
description: "Dot-paths, comma separated (mutually exclusive with --full)"
|
|
182
|
-
},
|
|
183
|
-
maxBytes: {
|
|
184
|
-
type: "string",
|
|
185
|
-
description: "Output size cap; 0 disables",
|
|
186
|
-
default: String(DEFAULT_MAX_BYTES),
|
|
187
|
-
alias: "max-bytes"
|
|
188
|
-
}
|
|
189
|
-
};
|
|
190
|
-
const profileFlag = { profile: {
|
|
191
|
-
type: "string",
|
|
192
|
-
description: "Named profile (default: 'default')"
|
|
193
|
-
} };
|
|
194
|
-
const connectionFlags = {
|
|
195
|
-
url: {
|
|
196
|
-
type: "string",
|
|
197
|
-
description: "Metabase URL"
|
|
198
|
-
},
|
|
199
|
-
apiKey: {
|
|
200
|
-
type: "string",
|
|
201
|
-
description: "API key",
|
|
202
|
-
alias: "api-key"
|
|
203
|
-
}
|
|
204
|
-
};
|
|
205
|
-
|
|
206
|
-
//#endregion
|
|
207
|
-
//#region src/commands/parse-integer.ts
|
|
208
|
-
const INTEGER_PATTERN = /^-?\d+$/;
|
|
209
|
-
function parseInteger(value, options) {
|
|
210
|
-
const trimmed = value.trim();
|
|
211
|
-
if (!INTEGER_PATTERN.test(trimmed)) throw new ConfigError(`invalid ${options.name}: "${value}" (expected integer)`);
|
|
212
|
-
const parsed = Number.parseInt(trimmed, 10);
|
|
213
|
-
if (parsed < options.min) throw new ConfigError(`invalid ${options.name}: ${parsed} (must be ≥ ${options.min})`);
|
|
214
|
-
return parsed;
|
|
215
|
-
}
|
|
216
|
-
function parseOptionalInteger(value, options) {
|
|
217
|
-
if (value === void 0 || value === "") return null;
|
|
218
|
-
return parseInteger(value, options);
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
//#endregion
|
|
222
|
-
//#region src/core/paths.ts
|
|
223
|
-
const APP_DIR_NAME = "metabase-cli";
|
|
224
|
-
function configDir() {
|
|
225
|
-
if (process.platform === "win32") {
|
|
226
|
-
const appData = process.env["APPDATA"] ?? join(homedir(), "AppData", "Roaming");
|
|
227
|
-
return join(appData, APP_DIR_NAME);
|
|
228
|
-
}
|
|
229
|
-
const xdg = process.env["XDG_CONFIG_HOME"] ?? join(homedir(), ".config");
|
|
230
|
-
return join(xdg, APP_DIR_NAME);
|
|
231
|
-
}
|
|
232
|
-
|
|
233
141
|
//#endregion
|
|
234
142
|
//#region src/core/auth/storage.ts
|
|
235
143
|
const CredentialsFileSchema = z.record(z.string(), z.string());
|
|
@@ -243,6 +151,14 @@ const account = {
|
|
|
243
151
|
profileApiKey: (profile) => `profile:${profile}:apiKey`,
|
|
244
152
|
license: "license"
|
|
245
153
|
};
|
|
154
|
+
function configDir() {
|
|
155
|
+
if (process.platform === "win32") {
|
|
156
|
+
const appData = process.env["APPDATA"] ?? join(homedir(), "AppData", "Roaming");
|
|
157
|
+
return join(appData, "metabase-cli");
|
|
158
|
+
}
|
|
159
|
+
const xdg = process.env["XDG_CONFIG_HOME"] ?? join(homedir(), ".config");
|
|
160
|
+
return join(xdg, "metabase-cli");
|
|
161
|
+
}
|
|
246
162
|
function fallbackFilePath() {
|
|
247
163
|
return join(configDir(), CREDENTIALS_FILE);
|
|
248
164
|
}
|
|
@@ -372,9 +288,6 @@ async function clearProfile(name = DEFAULT_PROFILE) {
|
|
|
372
288
|
const removedKey = await credentials.remove(account.profileApiKey(name));
|
|
373
289
|
return removedUrl || removedKey;
|
|
374
290
|
}
|
|
375
|
-
async function readLicense() {
|
|
376
|
-
return credentials.read(account.license);
|
|
377
|
-
}
|
|
378
291
|
async function writeLicense(token) {
|
|
379
292
|
return credentials.set(account.license, token);
|
|
380
293
|
}
|
|
@@ -382,82 +295,6 @@ async function clearLicense() {
|
|
|
382
295
|
return credentials.remove(account.license);
|
|
383
296
|
}
|
|
384
297
|
|
|
385
|
-
//#endregion
|
|
386
|
-
//#region src/core/url.ts
|
|
387
|
-
function normalizeUrl(input) {
|
|
388
|
-
const trimmed = input.trim().replace(/\/+$/, "");
|
|
389
|
-
if (!/^https?:\/\//i.test(trimmed)) throw new Error("URL must start with http:// or https://");
|
|
390
|
-
return trimmed;
|
|
391
|
-
}
|
|
392
|
-
function originOnly(input) {
|
|
393
|
-
const parsed = new URL(input);
|
|
394
|
-
parsed.username = "";
|
|
395
|
-
parsed.password = "";
|
|
396
|
-
return parsed.origin;
|
|
397
|
-
}
|
|
398
|
-
function localUrl(port) {
|
|
399
|
-
return `http://localhost:${port}`;
|
|
400
|
-
}
|
|
401
|
-
|
|
402
|
-
//#endregion
|
|
403
|
-
//#region src/core/config.ts
|
|
404
|
-
const ENV_URL = "METABASE_URL";
|
|
405
|
-
const ENV_API_KEY = "METABASE_API_KEY";
|
|
406
|
-
const ENV_PROFILE = "METABASE_PROFILE";
|
|
407
|
-
const ENV_LICENSE_TOKEN = "METABASE_LICENSE_TOKEN";
|
|
408
|
-
function resolveProfileName(profileFlag$1) {
|
|
409
|
-
return profileFlag$1 || process.env[ENV_PROFILE] || DEFAULT_PROFILE;
|
|
410
|
-
}
|
|
411
|
-
function readEnvCredentials() {
|
|
412
|
-
return {
|
|
413
|
-
url: process.env[ENV_URL] ?? null,
|
|
414
|
-
apiKey: process.env[ENV_API_KEY] ?? null
|
|
415
|
-
};
|
|
416
|
-
}
|
|
417
|
-
function readEnvLicenseToken() {
|
|
418
|
-
return process.env[ENV_LICENSE_TOKEN] ?? null;
|
|
419
|
-
}
|
|
420
|
-
async function resolveConfig(flags) {
|
|
421
|
-
const profile = resolveProfileName(flags.profile);
|
|
422
|
-
const env = readEnvCredentials();
|
|
423
|
-
const flagUrl = flags.url;
|
|
424
|
-
const flagKey = flags.apiKey;
|
|
425
|
-
const needsStored = !flagUrl && !env.url || !flagKey && !env.apiKey;
|
|
426
|
-
const stored = needsStored ? await readProfile(profile) : null;
|
|
427
|
-
const urlField = pickField(flagUrl, env.url, stored?.url);
|
|
428
|
-
const keyField = pickField(flagKey, env.apiKey, stored?.apiKey);
|
|
429
|
-
if (urlField === null || keyField === null) throw new ConfigError(`Not authenticated for profile "${profile}". Run \`metabase auth login\`, set ${ENV_URL}/${ENV_API_KEY}, or pass --url/--api-key.`);
|
|
430
|
-
return {
|
|
431
|
-
url: normalizeUrl(urlField.value),
|
|
432
|
-
apiKey: keyField.value,
|
|
433
|
-
profile,
|
|
434
|
-
source: urlField.source === keyField.source ? urlField.source : "mixed"
|
|
435
|
-
};
|
|
436
|
-
}
|
|
437
|
-
async function resolveLicenseToken(flags) {
|
|
438
|
-
const flag = flags.token;
|
|
439
|
-
const env = readEnvLicenseToken();
|
|
440
|
-
const stored = !flag && !env ? await readLicense() : null;
|
|
441
|
-
const value = flag ?? env ?? stored;
|
|
442
|
-
if (!value) throw new ConfigError(`No license token. Pass --token, set ${ENV_LICENSE_TOKEN}, or store one with \`metabase license set\`.`);
|
|
443
|
-
return value;
|
|
444
|
-
}
|
|
445
|
-
function pickField(flag, env, stored) {
|
|
446
|
-
if (flag) return {
|
|
447
|
-
value: flag,
|
|
448
|
-
source: "flag"
|
|
449
|
-
};
|
|
450
|
-
if (env) return {
|
|
451
|
-
value: env,
|
|
452
|
-
source: "env"
|
|
453
|
-
};
|
|
454
|
-
if (stored) return {
|
|
455
|
-
value: stored,
|
|
456
|
-
source: "stored"
|
|
457
|
-
};
|
|
458
|
-
return null;
|
|
459
|
-
}
|
|
460
|
-
|
|
461
298
|
//#endregion
|
|
462
299
|
//#region src/runtime/signal.ts
|
|
463
300
|
function createProcessAbortHandler() {
|
|
@@ -825,6 +662,312 @@ async function readBodyForError(response) {
|
|
|
825
662
|
}
|
|
826
663
|
}
|
|
827
664
|
|
|
665
|
+
//#endregion
|
|
666
|
+
//#region src/core/url.ts
|
|
667
|
+
function normalizeUrl(input) {
|
|
668
|
+
const trimmed = input.trim().replace(/\/+$/, "");
|
|
669
|
+
if (!/^https?:\/\//i.test(trimmed)) throw new Error("URL must start with http:// or https://");
|
|
670
|
+
return trimmed;
|
|
671
|
+
}
|
|
672
|
+
function originOnly(input) {
|
|
673
|
+
const parsed = new URL(input);
|
|
674
|
+
parsed.username = "";
|
|
675
|
+
parsed.password = "";
|
|
676
|
+
return parsed.origin;
|
|
677
|
+
}
|
|
678
|
+
|
|
679
|
+
//#endregion
|
|
680
|
+
//#region src/core/config.ts
|
|
681
|
+
const ENV_URL = "METABASE_URL";
|
|
682
|
+
const ENV_API_KEY = "METABASE_API_KEY";
|
|
683
|
+
const ENV_PROFILE = "METABASE_PROFILE";
|
|
684
|
+
const ENV_LICENSE_TOKEN = "METABASE_LICENSE_TOKEN";
|
|
685
|
+
function resolveProfileName(profileFlag$1) {
|
|
686
|
+
return profileFlag$1 || process.env[ENV_PROFILE] || DEFAULT_PROFILE;
|
|
687
|
+
}
|
|
688
|
+
function readEnvCredentials() {
|
|
689
|
+
return {
|
|
690
|
+
url: process.env[ENV_URL] ?? null,
|
|
691
|
+
apiKey: process.env[ENV_API_KEY] ?? null
|
|
692
|
+
};
|
|
693
|
+
}
|
|
694
|
+
function readEnvLicenseToken() {
|
|
695
|
+
return process.env[ENV_LICENSE_TOKEN] ?? null;
|
|
696
|
+
}
|
|
697
|
+
async function resolveConfig(flags) {
|
|
698
|
+
const profile = resolveProfileName(flags.profile);
|
|
699
|
+
const env = readEnvCredentials();
|
|
700
|
+
const flagUrl = flags.url;
|
|
701
|
+
const flagKey = flags.apiKey;
|
|
702
|
+
const needsStored = !flagUrl && !env.url || !flagKey && !env.apiKey;
|
|
703
|
+
const stored = needsStored ? await readProfile(profile) : null;
|
|
704
|
+
const urlField = pickField(flagUrl, env.url, stored?.url);
|
|
705
|
+
const keyField = pickField(flagKey, env.apiKey, stored?.apiKey);
|
|
706
|
+
if (urlField === null || keyField === null) throw new ConfigError(`Not authenticated for profile "${profile}". Run \`metabase auth login\`, set ${ENV_URL}/${ENV_API_KEY}, or pass --url/--api-key.`);
|
|
707
|
+
return {
|
|
708
|
+
url: normalizeUrl(urlField.value),
|
|
709
|
+
apiKey: keyField.value,
|
|
710
|
+
profile,
|
|
711
|
+
source: urlField.source === keyField.source ? urlField.source : "mixed"
|
|
712
|
+
};
|
|
713
|
+
}
|
|
714
|
+
function pickField(flag, env, stored) {
|
|
715
|
+
if (flag) return {
|
|
716
|
+
value: flag,
|
|
717
|
+
source: "flag"
|
|
718
|
+
};
|
|
719
|
+
if (env) return {
|
|
720
|
+
value: env,
|
|
721
|
+
source: "env"
|
|
722
|
+
};
|
|
723
|
+
if (stored) return {
|
|
724
|
+
value: stored,
|
|
725
|
+
source: "stored"
|
|
726
|
+
};
|
|
727
|
+
return null;
|
|
728
|
+
}
|
|
729
|
+
|
|
730
|
+
//#endregion
|
|
731
|
+
//#region src/output/notice.ts
|
|
732
|
+
function warn(message) {
|
|
733
|
+
process.stderr.write(message + "\n");
|
|
734
|
+
}
|
|
735
|
+
function listTruncationNotice(bytes) {
|
|
736
|
+
return `… cut at ${bytes} bytes; rerun with --max-bytes 0`;
|
|
737
|
+
}
|
|
738
|
+
function itemOversizeNotice(bytes) {
|
|
739
|
+
return `… item is ${bytes} bytes (exceeds --max-bytes); narrow with --fields, or pass --max-bytes 0`;
|
|
740
|
+
}
|
|
741
|
+
|
|
742
|
+
//#endregion
|
|
743
|
+
//#region src/output/cap.ts
|
|
744
|
+
function capListEnvelope(envelope, maxBytes) {
|
|
745
|
+
if (maxBytes <= 0) return envelope;
|
|
746
|
+
const fullBytes = jsonByteLength(envelope);
|
|
747
|
+
if (fullBytes <= maxBytes) return envelope;
|
|
748
|
+
let lo = 0;
|
|
749
|
+
let hi = envelope.data.length;
|
|
750
|
+
while (lo < hi) {
|
|
751
|
+
const mid = Math.ceil((lo + hi) / 2);
|
|
752
|
+
if (jsonByteLength(truncate(envelope, mid, fullBytes)) <= maxBytes) lo = mid;
|
|
753
|
+
else hi = mid - 1;
|
|
754
|
+
}
|
|
755
|
+
return truncate(envelope, lo, fullBytes);
|
|
756
|
+
}
|
|
757
|
+
function truncate(envelope, count, originalBytes) {
|
|
758
|
+
return {
|
|
759
|
+
...envelope,
|
|
760
|
+
data: envelope.data.slice(0, count),
|
|
761
|
+
returned: count,
|
|
762
|
+
truncated: {
|
|
763
|
+
reason: "max_bytes",
|
|
764
|
+
bytes: originalBytes
|
|
765
|
+
}
|
|
766
|
+
};
|
|
767
|
+
}
|
|
768
|
+
function jsonByteLength(value) {
|
|
769
|
+
return Buffer.byteLength(JSON.stringify(value), "utf8");
|
|
770
|
+
}
|
|
771
|
+
|
|
772
|
+
//#endregion
|
|
773
|
+
//#region src/output/projection.ts
|
|
774
|
+
function applyProjection(value, view, full, fields) {
|
|
775
|
+
if (fields !== void 0) {
|
|
776
|
+
if (fields.length === 0) throw new ConfigError("--fields requires at least one path");
|
|
777
|
+
return projectFields(value, fields);
|
|
778
|
+
}
|
|
779
|
+
if (full) return value;
|
|
780
|
+
const parsed = view.compactPick.safeParse(value);
|
|
781
|
+
if (parsed.success) return parsed.data;
|
|
782
|
+
throw new ConfigError(`compact projection failed: ${parsed.error.message}`);
|
|
783
|
+
}
|
|
784
|
+
function projectFields(value, fields) {
|
|
785
|
+
const out = {};
|
|
786
|
+
for (const path of fields) {
|
|
787
|
+
if (path.length === 0) throw new ConfigError(`empty field path`);
|
|
788
|
+
const parts = path.split(".");
|
|
789
|
+
if (parts.some((part) => part.length === 0)) throw new ConfigError(`invalid field path: "${path}"`);
|
|
790
|
+
setPath(out, parts, pickPath(value, parts));
|
|
791
|
+
}
|
|
792
|
+
return out;
|
|
793
|
+
}
|
|
794
|
+
function pickPath(value, parts) {
|
|
795
|
+
let cursor = value;
|
|
796
|
+
for (const part of parts) {
|
|
797
|
+
if (!isPlainObject(cursor) || !Object.hasOwn(cursor, part)) throw new ConfigError(`unknown field path: "${parts.join(".")}"`);
|
|
798
|
+
cursor = Reflect.get(cursor, part);
|
|
799
|
+
}
|
|
800
|
+
return cursor;
|
|
801
|
+
}
|
|
802
|
+
function setPath(target, parts, value) {
|
|
803
|
+
let cursor = target;
|
|
804
|
+
const lastIndex = parts.length - 1;
|
|
805
|
+
for (const [index, part] of parts.entries()) {
|
|
806
|
+
if (index === lastIndex) {
|
|
807
|
+
cursor[part] = value;
|
|
808
|
+
return;
|
|
809
|
+
}
|
|
810
|
+
const existing = cursor[part];
|
|
811
|
+
if (isPlainObject(existing)) cursor = existing;
|
|
812
|
+
else {
|
|
813
|
+
const next = {};
|
|
814
|
+
cursor[part] = next;
|
|
815
|
+
cursor = next;
|
|
816
|
+
}
|
|
817
|
+
}
|
|
818
|
+
}
|
|
819
|
+
function isPlainObject(value) {
|
|
820
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
821
|
+
}
|
|
822
|
+
|
|
823
|
+
//#endregion
|
|
824
|
+
//#region src/output/table.ts
|
|
825
|
+
function renderTable(rows, columns) {
|
|
826
|
+
const head = columns.map((column) => column.label ?? column.key);
|
|
827
|
+
const widths = columns.map((column) => column.width ?? null);
|
|
828
|
+
const hasWidth = widths.some((width) => width !== null);
|
|
829
|
+
const table = new Table(hasWidth ? {
|
|
830
|
+
head,
|
|
831
|
+
colWidths: widths
|
|
832
|
+
} : { head });
|
|
833
|
+
for (const row of rows) table.push(columns.map((column) => formatCell(row, column)));
|
|
834
|
+
return table.toString();
|
|
835
|
+
}
|
|
836
|
+
function formatCell(row, column) {
|
|
837
|
+
const value = row[column.key];
|
|
838
|
+
if (column.format !== void 0) return column.format(value);
|
|
839
|
+
return formatScalar(value);
|
|
840
|
+
}
|
|
841
|
+
function formatScalar(value) {
|
|
842
|
+
if (value === null || value === void 0) return "";
|
|
843
|
+
if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") return String(value);
|
|
844
|
+
return JSON.stringify(value);
|
|
845
|
+
}
|
|
846
|
+
|
|
847
|
+
//#endregion
|
|
848
|
+
//#region src/output/render.ts
|
|
849
|
+
function renderItem(item, view, opts) {
|
|
850
|
+
const projected = applyProjection(item, view, opts.full, opts.fields);
|
|
851
|
+
const body = renderItemBody(item, view, projected, opts) + "\n";
|
|
852
|
+
process.stdout.write(body);
|
|
853
|
+
emitItemOversizeNotice(body, opts.maxBytes);
|
|
854
|
+
}
|
|
855
|
+
function renderList(envelope, view, opts) {
|
|
856
|
+
if (opts.format === "json" || opts.fields !== void 0) {
|
|
857
|
+
renderJsonEnvelope(envelope, view, opts);
|
|
858
|
+
return;
|
|
859
|
+
}
|
|
860
|
+
if (envelope.data.length === 0) {
|
|
861
|
+
process.stdout.write("(no results)\n");
|
|
862
|
+
return;
|
|
863
|
+
}
|
|
864
|
+
const capped = capListEnvelope(envelope, opts.maxBytes);
|
|
865
|
+
process.stdout.write(renderTable(capped.data, view.tableColumns) + "\n");
|
|
866
|
+
if (capped.truncated !== void 0) warn(listTruncationNotice(capped.truncated.bytes));
|
|
867
|
+
}
|
|
868
|
+
function renderJsonEnvelope(envelope, view, opts) {
|
|
869
|
+
const projectedItems = envelope.data.map((item) => applyProjection(item, view, opts.full, opts.fields));
|
|
870
|
+
const projectedEnvelope = {
|
|
871
|
+
...envelope,
|
|
872
|
+
data: projectedItems
|
|
873
|
+
};
|
|
874
|
+
const capped = capListEnvelope(projectedEnvelope, opts.maxBytes);
|
|
875
|
+
process.stdout.write(JSON.stringify(capped, null, 2) + "\n");
|
|
876
|
+
if (capped.truncated !== void 0) warn(listTruncationNotice(capped.truncated.bytes));
|
|
877
|
+
}
|
|
878
|
+
function renderItemBody(item, view, projected, opts) {
|
|
879
|
+
if (opts.format === "json" || opts.fields !== void 0) return JSON.stringify(projected, null, 2);
|
|
880
|
+
if (!opts.full) return renderKeyValueLines(columnPairs(item, view.tableColumns));
|
|
881
|
+
return renderKeyValueLines(objectPairs(projected));
|
|
882
|
+
}
|
|
883
|
+
function columnPairs(item, columns) {
|
|
884
|
+
return columns.map((column) => [column.label ?? column.key, formatCell(item, column)]);
|
|
885
|
+
}
|
|
886
|
+
function objectPairs(value) {
|
|
887
|
+
if (!isPlainObject(value)) {
|
|
888
|
+
const scalar = formatScalar(value);
|
|
889
|
+
return scalar === "" ? [] : [["", scalar]];
|
|
890
|
+
}
|
|
891
|
+
return Object.entries(value).map(([key, raw]) => [key, formatScalar(raw)]);
|
|
892
|
+
}
|
|
893
|
+
function renderKeyValueLines(pairs) {
|
|
894
|
+
if (pairs.length === 0) return "";
|
|
895
|
+
const padding = Math.max(...pairs.map(([label]) => label.length));
|
|
896
|
+
return pairs.map(([label, value]) => `${label.padEnd(padding)} ${value}`).join("\n");
|
|
897
|
+
}
|
|
898
|
+
function emitItemOversizeNotice(body, maxBytes) {
|
|
899
|
+
if (maxBytes <= 0) return;
|
|
900
|
+
const bytes = Buffer.byteLength(body, "utf8");
|
|
901
|
+
if (bytes <= maxBytes) return;
|
|
902
|
+
warn(itemOversizeNotice(bytes));
|
|
903
|
+
}
|
|
904
|
+
|
|
905
|
+
//#endregion
|
|
906
|
+
//#region src/output/types.ts
|
|
907
|
+
const DEFAULT_MAX_BYTES = 65536;
|
|
908
|
+
function listEnvelopeSchema(item) {
|
|
909
|
+
return z.object({
|
|
910
|
+
data: z.array(item),
|
|
911
|
+
returned: z.number().int().nonnegative(),
|
|
912
|
+
total: z.number().int().nonnegative().optional(),
|
|
913
|
+
limit: z.number().int().nonnegative().optional(),
|
|
914
|
+
truncated: z.object({
|
|
915
|
+
reason: z.literal("max_bytes"),
|
|
916
|
+
bytes: z.number().int().nonnegative()
|
|
917
|
+
}).optional()
|
|
918
|
+
});
|
|
919
|
+
}
|
|
920
|
+
function wrapList(items) {
|
|
921
|
+
return {
|
|
922
|
+
data: items,
|
|
923
|
+
returned: items.length,
|
|
924
|
+
total: items.length
|
|
925
|
+
};
|
|
926
|
+
}
|
|
927
|
+
|
|
928
|
+
//#endregion
|
|
929
|
+
//#region src/commands/flags.ts
|
|
930
|
+
const outputFlags = {
|
|
931
|
+
format: {
|
|
932
|
+
type: "string",
|
|
933
|
+
description: "auto | json | text",
|
|
934
|
+
default: "auto"
|
|
935
|
+
},
|
|
936
|
+
json: {
|
|
937
|
+
type: "boolean",
|
|
938
|
+
description: "Shorthand for --format json"
|
|
939
|
+
},
|
|
940
|
+
full: {
|
|
941
|
+
type: "boolean",
|
|
942
|
+
description: "Return the full object (default: compact)"
|
|
943
|
+
},
|
|
944
|
+
fields: {
|
|
945
|
+
type: "string",
|
|
946
|
+
description: "Dot-paths, comma separated (mutually exclusive with --full)"
|
|
947
|
+
},
|
|
948
|
+
maxBytes: {
|
|
949
|
+
type: "string",
|
|
950
|
+
description: "Output size cap; 0 disables",
|
|
951
|
+
default: String(DEFAULT_MAX_BYTES),
|
|
952
|
+
alias: "max-bytes"
|
|
953
|
+
}
|
|
954
|
+
};
|
|
955
|
+
const profileFlag = { profile: {
|
|
956
|
+
type: "string",
|
|
957
|
+
description: "Named profile (default: 'default')"
|
|
958
|
+
} };
|
|
959
|
+
const connectionFlags = {
|
|
960
|
+
url: {
|
|
961
|
+
type: "string",
|
|
962
|
+
description: "Metabase URL"
|
|
963
|
+
},
|
|
964
|
+
apiKey: {
|
|
965
|
+
type: "string",
|
|
966
|
+
description: "API key",
|
|
967
|
+
alias: "api-key"
|
|
968
|
+
}
|
|
969
|
+
};
|
|
970
|
+
|
|
828
971
|
//#endregion
|
|
829
972
|
//#region src/output/error.ts
|
|
830
973
|
function reportError(error) {
|
|
@@ -845,14 +988,9 @@ function resolveFormat({ json, format, isTty }) {
|
|
|
845
988
|
return isTty ? "text" : "json";
|
|
846
989
|
}
|
|
847
990
|
|
|
848
|
-
//#endregion
|
|
849
|
-
//#region src/runtime/csv.ts
|
|
850
|
-
function parseCsv(raw) {
|
|
851
|
-
return raw.split(",").map((part) => part.trim()).filter((part) => part.length > 0);
|
|
852
|
-
}
|
|
853
|
-
|
|
854
991
|
//#endregion
|
|
855
992
|
//#region src/commands/context.ts
|
|
993
|
+
const INTEGER_PATTERN = /^-?\d+$/;
|
|
856
994
|
function resolveCommonFlags(args, options = {}) {
|
|
857
995
|
const isTty = options.isTty ?? Boolean(process.stdout.isTTY);
|
|
858
996
|
const fields = parseFields(args.fields);
|
|
@@ -874,14 +1012,15 @@ function resolveCommonFlags(args, options = {}) {
|
|
|
874
1012
|
}
|
|
875
1013
|
function parseFields(value) {
|
|
876
1014
|
if (value === void 0 || value === "") return void 0;
|
|
877
|
-
const parts =
|
|
1015
|
+
const parts = value.split(",").map((part) => part.trim()).filter((part) => part.length > 0);
|
|
878
1016
|
return parts.length > 0 ? parts : void 0;
|
|
879
1017
|
}
|
|
880
1018
|
function parseMaxBytes(value) {
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
});
|
|
1019
|
+
const raw = value ?? String(DEFAULT_MAX_BYTES);
|
|
1020
|
+
if (!INTEGER_PATTERN.test(raw)) throw new ConfigError(`invalid --max-bytes value: "${raw}" (expected non-negative integer)`);
|
|
1021
|
+
const parsed = Number.parseInt(raw, 10);
|
|
1022
|
+
if (parsed < 0) throw new ConfigError(`invalid --max-bytes value: ${parsed} (must be non-negative)`);
|
|
1023
|
+
return parsed;
|
|
885
1024
|
}
|
|
886
1025
|
|
|
887
1026
|
//#endregion
|
|
@@ -893,27 +1032,20 @@ function defineMetabaseCommand(def) {
|
|
|
893
1032
|
async run({ args }) {
|
|
894
1033
|
try {
|
|
895
1034
|
const ctx = resolveCommonFlags(pickCommonArgs(args));
|
|
896
|
-
let
|
|
897
|
-
let cachedClient = null;
|
|
898
|
-
const getResolvedConfig = async () => {
|
|
899
|
-
if (cachedConfig === null) cachedConfig = await resolveConfig(buildConfigFlags(ctx));
|
|
900
|
-
return cachedConfig;
|
|
901
|
-
};
|
|
1035
|
+
let cached = null;
|
|
902
1036
|
const getClient = async () => {
|
|
903
|
-
if (
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
return cachedClient;
|
|
1037
|
+
if (cached) return cached;
|
|
1038
|
+
const resolved = await resolveConfig(buildConfigFlags(ctx));
|
|
1039
|
+
cached = createClient({
|
|
1040
|
+
url: resolved.url,
|
|
1041
|
+
apiKey: resolved.apiKey
|
|
1042
|
+
});
|
|
1043
|
+
return cached;
|
|
911
1044
|
};
|
|
912
1045
|
await def.run({
|
|
913
1046
|
args,
|
|
914
1047
|
ctx,
|
|
915
|
-
getClient
|
|
916
|
-
getResolvedConfig
|
|
1048
|
+
getClient
|
|
917
1049
|
});
|
|
918
1050
|
} catch (error) {
|
|
919
1051
|
reportError(error);
|
|
@@ -947,4 +1079,4 @@ function buildConfigFlags(ctx) {
|
|
|
947
1079
|
}
|
|
948
1080
|
|
|
949
1081
|
//#endregion
|
|
950
|
-
export { AbortError, ConfigError, HttpError, MetabaseError, TimeoutError,
|
|
1082
|
+
export { AbortError, ConfigError, HttpError, MetabaseError, TimeoutError, account, clearLicense, clearProfile, combineAborts, connectionFlags, createClient, credentials, defineMetabaseCommand, errorMessage, isNotFoundError, listEnvelopeSchema, normalizeUrl, originOnly, outputFlags, parseJson, profileFlag, readEnvCredentials, readEnvLicenseToken, renderItem, renderList, resolveProfileName, throwIfAborted, warn, wrapList, writeLicense, writeProfile };
|
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
import "./package-
|
|
1
|
+
import "./package-BGfw4ZWJ.mjs";
|
|
2
2
|
import "./command-augment-D9pI9Vbh.mjs";
|
|
3
|
-
import { renderList } from "./
|
|
4
|
-
import {
|
|
5
|
-
import { parseId } from "./parse-id-C1prc9US.mjs";
|
|
3
|
+
import { ConfigError, connectionFlags, defineMetabaseCommand, listEnvelopeSchema, outputFlags, profileFlag, renderList } from "./runtime-C9CEZhcn.mjs";
|
|
4
|
+
import { parseId } from "./parse-id-BhmmfyCP.mjs";
|
|
6
5
|
import { z } from "zod";
|
|
7
6
|
|
|
8
7
|
//#region src/domain/search.ts
|
|
@@ -154,7 +153,7 @@ function nonEmpty(value) {
|
|
|
154
153
|
}
|
|
155
154
|
function parseModels(raw) {
|
|
156
155
|
if (raw === void 0 || raw === "") return void 0;
|
|
157
|
-
const parts =
|
|
156
|
+
const parts = raw.split(",").map((part) => part.trim()).filter((part) => part.length > 0);
|
|
158
157
|
if (parts.length === 0) return void 0;
|
|
159
158
|
const accepted = [];
|
|
160
159
|
const rejected = [];
|
|
@@ -1,9 +1,8 @@
|
|
|
1
|
-
import "./package-
|
|
1
|
+
import "./package-BGfw4ZWJ.mjs";
|
|
2
2
|
import "./command-augment-D9pI9Vbh.mjs";
|
|
3
|
-
import { renderItem, warn } from "./
|
|
4
|
-
import {
|
|
5
|
-
import { readInput } from "./input-
|
|
6
|
-
import { promptPassword } from "./prompt-fXeNtj0M.mjs";
|
|
3
|
+
import { ConfigError, defineMetabaseCommand, outputFlags, readEnvLicenseToken, renderItem, warn, writeLicense } from "./runtime-C9CEZhcn.mjs";
|
|
4
|
+
import { promptPassword } from "./prompt-DpT8yAVy.mjs";
|
|
5
|
+
import { readInput } from "./input-Dojr-RTw.mjs";
|
|
7
6
|
import { z } from "zod";
|
|
8
7
|
|
|
9
8
|
//#region src/commands/license/set.ts
|
|
@@ -1,11 +1,10 @@
|
|
|
1
|
-
import "./package-
|
|
1
|
+
import "./package-BGfw4ZWJ.mjs";
|
|
2
2
|
import "./command-augment-D9pI9Vbh.mjs";
|
|
3
|
-
import { renderItem } from "./
|
|
4
|
-
import
|
|
5
|
-
import "./
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import { parseSettingKey } from "./key-CyhOpgWt.mjs";
|
|
3
|
+
import { connectionFlags, defineMetabaseCommand, outputFlags, profileFlag, renderItem } from "./runtime-C9CEZhcn.mjs";
|
|
4
|
+
import "./input-Dojr-RTw.mjs";
|
|
5
|
+
import { readBody } from "./body-Dv9hQ0Qk.mjs";
|
|
6
|
+
import { SettingValue, settingValueView } from "./setting-26ckqHAP.mjs";
|
|
7
|
+
import { parseSettingKey } from "./key-DBxPSFwi.mjs";
|
|
9
8
|
import { z } from "zod";
|
|
10
9
|
|
|
11
10
|
//#region src/commands/setting/set.ts
|
|
@@ -8,9 +8,9 @@ var setting_default = defineCommand({
|
|
|
8
8
|
alias: "settings"
|
|
9
9
|
},
|
|
10
10
|
subCommands: {
|
|
11
|
-
list: () => import("./list-
|
|
12
|
-
get: () => import("./get-
|
|
13
|
-
set: () => import("./set-
|
|
11
|
+
list: () => import("./list-Bk6RsbJl.mjs").then((m) => m.default),
|
|
12
|
+
get: () => import("./get-COXHplHP.mjs").then((m) => m.default),
|
|
13
|
+
set: () => import("./set-CbibegpA.mjs").then((m) => m.default)
|
|
14
14
|
}
|
|
15
15
|
});
|
|
16
16
|
|