@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.
Files changed (187) hide show
  1. package/README.md +972 -57
  2. package/dist/add-collection--zwkmE1S.mjs +11 -0
  3. package/dist/add-collection-B1qe0D1U.mjs +54 -0
  4. package/dist/api-key-gzCbKDjL.mjs +13 -0
  5. package/dist/archive-CitmlD1e.mjs +39 -0
  6. package/dist/{archive-CsWeHXle.mjs → archive-CnhWegtR.mjs} +7 -4
  7. package/dist/archive-DQjBOXnx.mjs +44 -0
  8. package/dist/archive-Ni8-lQ1Y.mjs +44 -0
  9. package/dist/auth-BPjsrFxM.mjs +19 -0
  10. package/dist/{body-Dv9hQ0Qk.mjs → body-DRBgxS6-.mjs} +3 -2
  11. package/dist/{branches-BujtceGr.mjs → branches-C5Jcw8wu.mjs} +8 -6
  12. package/dist/cancel-Ca3r7Y6v.mjs +56 -0
  13. package/dist/{cancel-task-CT2xUMRg.mjs → cancel-task-C1-8vDKS.mjs} +9 -7
  14. package/dist/card-BGAy3eIb.mjs +20 -0
  15. package/dist/{card-CsXk8T6A.mjs → card-CAEZWixN.mjs} +34 -15
  16. package/dist/cards-CILfMPUP.mjs +37 -0
  17. package/dist/cli.mjs +33 -14
  18. package/dist/collection-B3sPXRLs.mjs +163 -0
  19. package/dist/collection-D8cnCB98.mjs +19 -0
  20. package/dist/create-3Z6rm-4O.mjs +44 -0
  21. package/dist/create-BsY5RrVY.mjs +44 -0
  22. package/dist/create-C4OCclBD.mjs +48 -0
  23. package/dist/create-COsD7Vzm.mjs +48 -0
  24. package/dist/create-CP8ou91U.mjs +125 -0
  25. package/dist/create-CeIi_QLj.mjs +66 -0
  26. package/dist/create-CqNw6PmR.mjs +50 -0
  27. package/dist/create-DE_5NrFy.mjs +48 -0
  28. package/dist/{create-B8ektf-R.mjs → create-MEhhhgMC.mjs} +8 -6
  29. package/dist/create-QxDmleKJ.mjs +48 -0
  30. package/dist/{create-branch-goZBTNnr.mjs → create-branch-CKMYaAHk.mjs} +9 -7
  31. package/dist/credentials-CwRKvdP2.mjs +85 -0
  32. package/dist/{current-task-DBjRNCFq.mjs → current-task-Dutjys16.mjs} +9 -7
  33. package/dist/dashboard-B4fVp392.mjs +20 -0
  34. package/dist/dashboard-CnMD04PQ.mjs +163 -0
  35. package/dist/database-BMTb0CzV.mjs +17 -0
  36. package/dist/database-Dvkfy3JM.mjs +51 -0
  37. package/dist/db-ACuuaEok.mjs +22 -0
  38. package/dist/{delete-8vGU35r3.mjs → delete-BMQZuVXZ.mjs} +7 -5
  39. package/dist/{delete-B27KLF5X.mjs → delete-BvcA4jPj.mjs} +7 -5
  40. package/dist/{delete-runtime-Byr60cR3.mjs → delete-runtime-BMzvfj_B.mjs} +4 -4
  41. package/dist/{delete-table-BNaJ_gA4.mjs → delete-table-DUPjHKk4.mjs} +7 -5
  42. package/dist/deprovision-Bsc1S15j.mjs +61 -0
  43. package/dist/{dirty-aNUuph4I.mjs → dirty-CXcdoUhY.mjs} +8 -6
  44. package/dist/docker-D-ieBsP7.mjs +612 -0
  45. package/dist/eid-pvOsEMPZ.mjs +13 -0
  46. package/dist/{export-QDkuuzSE.mjs → export-BjGhLEOi.mjs} +30 -23
  47. package/dist/field-BI2bt8e9.mjs +18 -0
  48. package/dist/field-DciLbuv-.mjs +276 -0
  49. package/dist/fields-Do8HHm_T.mjs +38 -0
  50. package/dist/flag-pair-DtR1AiBQ.mjs +17 -0
  51. package/dist/{get-BGBIzMKY.mjs → get-BGFGWkH0.mjs} +6 -4
  52. package/dist/get-BmE_VHdl.mjs +36 -0
  53. package/dist/{get-DI_IJvgk.mjs → get-C7sshmqF.mjs} +6 -4
  54. package/dist/get-CObKBj2J.mjs +36 -0
  55. package/dist/get-Cq5U_Eep.mjs +40 -0
  56. package/dist/get-D4GUJBiX.mjs +41 -0
  57. package/dist/{get-COXHplHP.mjs → get-DFrsi77F.mjs} +7 -5
  58. package/dist/get-DczxeETg.mjs +53 -0
  59. package/dist/{get-Cl8-IauC.mjs → get-DeQa3ThJ.mjs} +7 -4
  60. package/dist/get-DhZ_dGUb.mjs +36 -0
  61. package/dist/{get-i6LWOByV.mjs → get-DzCVafyO.mjs} +6 -4
  62. package/dist/get-YCnVqq-z.mjs +49 -0
  63. package/dist/get-run-CTyW29s3.mjs +36 -0
  64. package/dist/git-sync-BOmT8HEU.mjs +28 -0
  65. package/dist/{has-remote-changes-hjKoQuRy.mjs → has-remote-changes-xX8vMVsX.mjs} +8 -6
  66. package/dist/{import-HJsSKRYx.mjs → import-CaAUNtXz.mjs} +11 -9
  67. package/dist/{input-Dojr-RTw.mjs → input-ikCiip6x.mjs} +2 -1
  68. package/dist/is-dirty-CPu-xqkW.mjs +10 -0
  69. package/dist/{is-dirty-1Qy7hiHB.mjs → is-dirty-mgxEwEk4.mjs} +5 -4
  70. package/dist/items-Cg67tdto.mjs +77 -0
  71. package/dist/{key-DBxPSFwi.mjs → key-NDEARu2L.mjs} +1 -1
  72. package/dist/{license-MoWse3ZI.mjs → license-CwKzVMD0.mjs} +3 -3
  73. package/dist/list-BqdNQ1nU.mjs +47 -0
  74. package/dist/list-BwGdD45N.mjs +32 -0
  75. package/dist/list-CfOVsAZz.mjs +55 -0
  76. package/dist/list-CpyNn1Zn.mjs +32 -0
  77. package/dist/list-CwwOoGLK.mjs +40 -0
  78. package/dist/{list-C_PRdL5e.mjs → list-DD8CQx8l.mjs} +7 -5
  79. package/dist/{list-Bk6RsbJl.mjs → list-DL-RWpIE.mjs} +5 -3
  80. package/dist/list-DLlq3FyS.mjs +61 -0
  81. package/dist/list-DdQ4jmUQ.mjs +52 -0
  82. package/dist/{list-C4Ajrw8f.mjs → list-DshbLoqR.mjs} +6 -3
  83. package/dist/{list-C8tdLOH5.mjs → list-DzTMpoBs.mjs} +5 -3
  84. package/dist/list-JgRtCzz3.mjs +32 -0
  85. package/dist/{list-CWt3fqrZ.mjs → list-WzgJcwB5.mjs} +5 -3
  86. package/dist/{login-C9WTwNn6.mjs → login-DJnmR2wX.mjs} +14 -5
  87. package/dist/{logout-oLszGCOg.mjs → logout-BMe_1Zp8.mjs} +7 -6
  88. package/dist/logs-CQxKJ3HG.mjs +58 -0
  89. package/dist/{manifest-CAdjQYH8.mjs → manifest-Dv5B9Blc.mjs} +3 -7
  90. package/dist/measure-BEQfnLdN.mjs +67 -0
  91. package/dist/measure-BGyYbtqO.mjs +19 -0
  92. package/dist/metadata-CLIALntn.mjs +37 -0
  93. package/dist/metadata-T-fNUWg_.mjs +38 -0
  94. package/dist/{package-BGfw4ZWJ.mjs → package-DBsS7a5x.mjs} +7 -1
  95. package/dist/paginate-CTSfuYiF.mjs +49 -0
  96. package/dist/parse-id-BUOZQqjp.mjs +12 -0
  97. package/dist/parse-ref-DGvh4aDn.mjs +17 -0
  98. package/dist/parse-schemas-BnW4T1_I.mjs +12 -0
  99. package/dist/{poll-ILanYysl.mjs → poll-DMmmZWvi.mjs} +2 -1
  100. package/dist/{poll-task-DbpsiQhl.mjs → poll-task-2Ckiwp8U.mjs} +8 -7
  101. package/dist/predicates-DiIiS3k7.mjs +153 -0
  102. package/dist/preflight-CC_g6EWU.mjs +91 -0
  103. package/dist/{prompt-DpT8yAVy.mjs → prompt-Bf3DQ-qE.mjs} +1 -1
  104. package/dist/provision-BUgWJWAV.mjs +77 -0
  105. package/dist/ps-BUNHygf-.mjs +10 -0
  106. package/dist/ps-Yv0JjLVN.mjs +78 -0
  107. package/dist/{query-PihYi-UZ.mjs → query-CzfbuG8a.mjs} +38 -13
  108. package/dist/query-UIebHmbT.mjs +90 -0
  109. package/dist/remove-BAUbcwuF.mjs +98 -0
  110. package/dist/{remove-B2hVYn1v.mjs → remove-CN2PNGTR.mjs} +6 -5
  111. package/dist/remove-collection-C6NxEh53.mjs +38 -0
  112. package/dist/render-DXv-D6fU.mjs +182 -0
  113. package/dist/rescan-values-CcB4F9qa.mjs +43 -0
  114. package/dist/revision-message-flag-CWQbKhdl.mjs +11 -0
  115. package/dist/{run-C2so6Qp6.mjs → run-BjXZtu_6.mjs} +27 -36
  116. package/dist/runs-CXx7l1NY.mjs +54 -0
  117. package/dist/{runtime-C9CEZhcn.mjs → runtime-D7jihh81.mjs} +425 -442
  118. package/dist/schema-tables-BCJT2DM_.mjs +45 -0
  119. package/dist/schemas-DlNpbn4H.mjs +47 -0
  120. package/dist/{search-CopOytXY.mjs → search-Dt-6mdHZ.mjs} +6 -19
  121. package/dist/segment-BMrUBz94.mjs +70 -0
  122. package/dist/segment-C52QNnSs.mjs +19 -0
  123. package/dist/{set-BcF7M1GQ.mjs → set-DCESWpi3.mjs} +6 -4
  124. package/dist/{set-CbibegpA.mjs → set-L7cuHjVZ.mjs} +8 -6
  125. package/dist/{setting-U3NtBMFo.mjs → setting-DysGAuYS.mjs} +3 -3
  126. package/dist/setup-_ypJDPAY.mjs +71 -0
  127. package/dist/snippet-Dw0Sjzkr.mjs +64 -0
  128. package/dist/snippet-vb3G9R8a.mjs +19 -0
  129. package/dist/start-BokXnb0V.mjs +350 -0
  130. package/dist/{stash-DOBbYozC.mjs → stash-CaGX6PfX.mjs} +9 -7
  131. package/dist/{status-Buf1ZbNR.mjs → status-BaX9vedb.mjs} +10 -8
  132. package/dist/{status-CUcs8XBH.mjs → status-CyecXzN4.mjs} +4 -2
  133. package/dist/{status-D1F5XHae.mjs → status-RpVyPEty.mjs} +4 -2
  134. package/dist/stop-BRuF_Cg1.mjs +81 -0
  135. package/dist/summary-CpEOiOlZ.mjs +41 -0
  136. package/dist/sync-schema-4Cl4h8Jn.mjs +43 -0
  137. package/dist/table-BeMWuvzO.mjs +19 -0
  138. package/dist/{table-Cfk7oSvw.mjs → table-jljEqZ0R.mjs} +22 -9
  139. package/dist/transform-DwRc-w6y.mjs +24 -0
  140. package/dist/{transform-B5uRpg1G.mjs → transform-IEX4Mx3X.mjs} +56 -2
  141. package/dist/transform-job-BigWrctt.mjs +19 -0
  142. package/dist/{transform-job-C7QXWTVE.mjs → transform-job-Csr86muI.mjs} +7 -0
  143. package/dist/translate-DqLlXXUx.mjs +111 -0
  144. package/dist/tree-BT24nkLM.mjs +32 -0
  145. package/dist/update-BCXKQi2n.mjs +52 -0
  146. package/dist/{update-CL8tRbxr.mjs → update-BXbLmC2b.mjs} +9 -7
  147. package/dist/update-C1Frz9GR.mjs +52 -0
  148. package/dist/update-C5goGhNr.mjs +56 -0
  149. package/dist/update-CCOyB0iT.mjs +73 -0
  150. package/dist/update-D04NMueX.mjs +59 -0
  151. package/dist/update-D6WVtNV1.mjs +57 -0
  152. package/dist/update-DFR46LsB.mjs +56 -0
  153. package/dist/update-DyLItrpV.mjs +56 -0
  154. package/dist/update-dashcard-av0_PYeg.mjs +71 -0
  155. package/dist/update-mrgvQF4i.mjs +51 -0
  156. package/dist/url-x4wn_l3k.mjs +54 -0
  157. package/dist/uuid-BZHbti8B.mjs +47 -0
  158. package/dist/validate-DCYx6jdL.mjs +1496 -0
  159. package/dist/validate-query-B07oGG4K.mjs +37 -0
  160. package/dist/values-Be6i0Fs9.mjs +36 -0
  161. package/dist/{wait-Bugr9eXD.mjs → wait-BMqQD8k_.mjs} +10 -8
  162. package/dist/wait-CWizX_sR.mjs +19 -0
  163. package/dist/wait-flags-DO3ar2tf.mjs +35 -0
  164. package/dist/workspace-CG1xyJ86.mjs +24 -0
  165. package/dist/workspace-DVuqKJGG.mjs +72 -0
  166. package/dist/workspace-credentials-B6BL-X0d.mjs +139 -0
  167. package/package.json +7 -1
  168. package/dist/auth-BF7IjZIH.mjs +0 -18
  169. package/dist/card-_Ta7zdYe.mjs +0 -19
  170. package/dist/create-CI2Cunq5.mjs +0 -38
  171. package/dist/create-DdbU3TLX.mjs +0 -42
  172. package/dist/database-PA9Goi25.mjs +0 -33
  173. package/dist/db-DMghzgb6.mjs +0 -17
  174. package/dist/field-C8IVs6rp.mjs +0 -76
  175. package/dist/field-DaYo_90x.mjs +0 -13
  176. package/dist/get-Cwpj7lDe.mjs +0 -35
  177. package/dist/get-Dh_acl8q.mjs +0 -34
  178. package/dist/is-dirty-DpKn9HJp.mjs +0 -8
  179. package/dist/list-CBSBHtK-.mjs +0 -38
  180. package/dist/parse-id-BhmmfyCP.mjs +0 -14
  181. package/dist/sync-BPyGXfUk.mjs +0 -26
  182. package/dist/table-D7nJt7JO.mjs +0 -16
  183. package/dist/transform-UbyewMxY.mjs +0 -21
  184. package/dist/transform-job-CrYkr-Ma.mjs +0 -19
  185. package/dist/update-DU2oU2j-.mjs +0 -49
  186. /package/dist/{body-flags-BUA9XV1u.mjs → body-flags-BK7J6Daz.mjs} +0 -0
  187. /package/dist/{setting-26ckqHAP.mjs → setting-CTaAeMci.mjs} +0 -0
@@ -0,0 +1,37 @@
1
+ import { writeJson } from "./render-DXv-D6fU.mjs";
2
+ import { ConfigError } from "./predicates-DiIiS3k7.mjs";
3
+ import { assertNotLegacyEnvelopeWrappingMbql5, isMbql5Query, validateQuery } from "./validate-DCYx6jdL.mjs";
4
+
5
+ //#region src/commands/validate-query.ts
6
+ const skipValidateFlag = { "skip-validate": {
7
+ type: "boolean",
8
+ description: "Skip the local MBQL 5 pre-flight validation; let the server be the authority. Use only when the bundled schema disagrees with what the server accepts."
9
+ } };
10
+ const CARD_DATASET_QUERY_LABELS = {
11
+ contextLabel: "card.dataset_query validation failed",
12
+ bodyNoun: "dataset_query"
13
+ };
14
+ const TRANSFORM_SOURCE_QUERY_LABELS = {
15
+ contextLabel: "transform.source.query validation failed",
16
+ bodyNoun: "source.query"
17
+ };
18
+ const MEASURE_DEFINITION_LABELS = {
19
+ contextLabel: "measure.definition validation failed",
20
+ bodyNoun: "definition"
21
+ };
22
+ const SEGMENT_DEFINITION_LABELS = {
23
+ contextLabel: "segment.definition validation failed",
24
+ bodyNoun: "definition"
25
+ };
26
+ function preflightMbql5Query(query, labels, options) {
27
+ if (options.skip) return;
28
+ assertNotLegacyEnvelopeWrappingMbql5(query, labels);
29
+ if (!isMbql5Query(query)) return;
30
+ const outcome = validateQuery(query);
31
+ if (outcome.ok) return;
32
+ writeJson(outcome);
33
+ throw new ConfigError(`${labels.contextLabel}: ${outcome.errors.length} error(s) — pass valid MBQL 5 or use the legacy format`);
34
+ }
35
+
36
+ //#endregion
37
+ export { CARD_DATASET_QUERY_LABELS, MEASURE_DEFINITION_LABELS, SEGMENT_DEFINITION_LABELS, TRANSFORM_SOURCE_QUERY_LABELS, preflightMbql5Query, skipValidateFlag };
@@ -0,0 +1,36 @@
1
+ import "./package-DBsS7a5x.mjs";
2
+ import "./command-augment-D9pI9Vbh.mjs";
3
+ import { renderItem } from "./render-DXv-D6fU.mjs";
4
+ import "./predicates-DiIiS3k7.mjs";
5
+ import { connectionFlags, defineMetabaseCommand, outputFlags, profileFlag } from "./runtime-D7jihh81.mjs";
6
+ import { parseId } from "./parse-id-BUOZQqjp.mjs";
7
+ import { FieldValues, fieldValuesView } from "./field-DciLbuv-.mjs";
8
+
9
+ //#region src/commands/field/values.ts
10
+ var values_default = defineMetabaseCommand({
11
+ meta: {
12
+ name: "values",
13
+ description: "Fetch the cached distinct values for a field (FieldValues list)"
14
+ },
15
+ args: {
16
+ ...outputFlags,
17
+ ...profileFlag,
18
+ ...connectionFlags,
19
+ id: {
20
+ type: "positional",
21
+ description: "Field id",
22
+ required: true
23
+ }
24
+ },
25
+ outputSchema: FieldValues,
26
+ examples: ["metabase field values 100", "metabase field values 100 --json"],
27
+ async run({ args, ctx, getClient }) {
28
+ const id = parseId(args.id);
29
+ const client = await getClient();
30
+ const values = await client.requestParsed(FieldValues, `/api/field/${id}/values`);
31
+ renderItem(values, fieldValuesView, ctx);
32
+ }
33
+ });
34
+
35
+ //#endregion
36
+ export { values_default as default };
@@ -1,16 +1,18 @@
1
- import "./package-BGfw4ZWJ.mjs";
1
+ import "./package-DBsS7a5x.mjs";
2
2
  import "./command-augment-D9pI9Vbh.mjs";
3
- import { connectionFlags, defineMetabaseCommand, outputFlags, profileFlag, renderItem } from "./runtime-C9CEZhcn.mjs";
4
- import { parseId } from "./parse-id-BhmmfyCP.mjs";
5
- import { SyncTaskOrIdle, pollSyncTask, syncTaskIdleView, syncTaskView, throwIfFailedTask } from "./poll-task-DbpsiQhl.mjs";
6
- import { DEFAULT_INTERVAL_MS, DEFAULT_TIMEOUT_MS } from "./poll-ILanYysl.mjs";
3
+ import { renderItem } from "./render-DXv-D6fU.mjs";
4
+ import "./predicates-DiIiS3k7.mjs";
5
+ import { connectionFlags, defineMetabaseCommand, outputFlags, profileFlag } from "./runtime-D7jihh81.mjs";
6
+ import { parseId } from "./parse-id-BUOZQqjp.mjs";
7
+ import { SyncTaskOrIdle, pollSyncTask, syncTaskIdleView, syncTaskView, throwIfFailedTask } from "./poll-task-2Ckiwp8U.mjs";
8
+ import { DEFAULT_INTERVAL_MS, DEFAULT_TIMEOUT_MS } from "./poll-DMmmZWvi.mjs";
7
9
 
8
- //#region src/commands/sync/wait.ts
10
+ //#region src/commands/git-sync/wait.ts
9
11
  const WaitResult = SyncTaskOrIdle;
10
12
  var wait_default = defineMetabaseCommand({
11
13
  meta: {
12
14
  name: "wait",
13
- description: "Poll the current sync task until it reaches a terminal status"
15
+ description: "Poll the current git-sync task until it reaches a terminal status"
14
16
  },
15
17
  args: {
16
18
  ...outputFlags,
@@ -28,7 +30,7 @@ var wait_default = defineMetabaseCommand({
28
30
  }
29
31
  },
30
32
  outputSchema: WaitResult,
31
- examples: ["metabase sync wait", "metabase sync wait --timeout 300000 --json"],
33
+ examples: ["metabase git-sync wait", "metabase git-sync wait --timeout 300000 --json"],
32
34
  async run({ args, ctx, getClient }) {
33
35
  const timeoutMs = parseId(args.timeout, "timeout");
34
36
  const intervalMs = parseId(args.interval, "interval");
@@ -0,0 +1,19 @@
1
+ import { pollUntil } from "./poll-DMmmZWvi.mjs";
2
+ import { Workspace } from "./workspace-DVuqKJGG.mjs";
3
+
4
+ //#region src/commands/workspace/database/wait.ts
5
+ async function waitForDatabaseProvisioned(client, workspaceId, databaseId, schedule) {
6
+ return pollUntil(() => client.requestParsed(Workspace, `/api/ee/workspace-manager/${workspaceId}`), (workspace) => {
7
+ const entry = workspace.databases?.find((row) => row.database_id === databaseId);
8
+ return entry !== void 0 && entry.status === "provisioned";
9
+ }, schedule);
10
+ }
11
+ async function waitForDatabaseGone(client, workspaceId, databaseId, schedule) {
12
+ await pollUntil(() => client.requestParsed(Workspace, `/api/ee/workspace-manager/${workspaceId}`), (workspace) => {
13
+ const entry = workspace.databases?.find((row) => row.database_id === databaseId);
14
+ return entry === void 0;
15
+ }, schedule);
16
+ }
17
+
18
+ //#endregion
19
+ export { waitForDatabaseGone, waitForDatabaseProvisioned };
@@ -0,0 +1,35 @@
1
+ import { parseId } from "./parse-id-BUOZQqjp.mjs";
2
+ import { DEFAULT_INTERVAL_MS, DEFAULT_TIMEOUT_MS } from "./poll-DMmmZWvi.mjs";
3
+
4
+ //#region src/commands/wait-flags.ts
5
+ const waitFlags = {
6
+ wait: {
7
+ type: "boolean",
8
+ description: "Poll until the operation reaches a terminal state",
9
+ default: false
10
+ },
11
+ timeout: {
12
+ type: "string",
13
+ description: "Polling timeout in ms (used with --wait)",
14
+ default: String(DEFAULT_TIMEOUT_MS)
15
+ },
16
+ interval: {
17
+ type: "string",
18
+ description: "Polling interval in ms (used with --wait)",
19
+ default: String(DEFAULT_INTERVAL_MS)
20
+ }
21
+ };
22
+ function parseWaitFlags(args) {
23
+ const interval = args.interval ?? String(DEFAULT_INTERVAL_MS);
24
+ const timeout = args.timeout ?? String(DEFAULT_TIMEOUT_MS);
25
+ return {
26
+ enabled: args.wait === true,
27
+ schedule: {
28
+ intervalMs: parseId(interval, "interval"),
29
+ timeoutMs: parseId(timeout, "timeout")
30
+ }
31
+ };
32
+ }
33
+
34
+ //#endregion
35
+ export { parseWaitFlags, waitFlags };
@@ -0,0 +1,24 @@
1
+ import { defineCommand } from "citty";
2
+
3
+ //#region src/commands/workspace/index.ts
4
+ var workspace_default = defineCommand({
5
+ meta: {
6
+ name: "workspace",
7
+ description: "Manage Metabase workspaces (workspace-manager)"
8
+ },
9
+ subCommands: {
10
+ list: () => import("./list-CpyNn1Zn.mjs").then((mod) => mod.default),
11
+ create: () => import("./create-C4OCclBD.mjs").then((mod) => mod.default),
12
+ database: () => import("./database-BMTb0CzV.mjs").then((mod) => mod.default),
13
+ start: () => import("./start-BokXnb0V.mjs").then((mod) => mod.default),
14
+ stop: () => import("./stop-BRuF_Cg1.mjs").then((mod) => mod.default),
15
+ remove: () => import("./remove-BAUbcwuF.mjs").then((mod) => mod.default),
16
+ logs: () => import("./logs-CQxKJ3HG.mjs").then((mod) => mod.default),
17
+ url: () => import("./url-x4wn_l3k.mjs").then((mod) => mod.default),
18
+ credentials: () => import("./credentials-CwRKvdP2.mjs").then((mod) => mod.default),
19
+ ps: () => import("./ps-BUNHygf-.mjs").then((mod) => mod.default)
20
+ }
21
+ });
22
+
23
+ //#endregion
24
+ export { workspace_default as default };
@@ -0,0 +1,72 @@
1
+ import { z } from "zod";
2
+
3
+ //#region src/domain/workspace.ts
4
+ const WorkspaceDatabaseStatus = z.enum([
5
+ "unprovisioned",
6
+ "provisioning",
7
+ "provisioned",
8
+ "deprovisioning"
9
+ ]);
10
+ const WorkspaceDatabase = z.object({
11
+ database_id: z.number().int(),
12
+ output_namespace: z.string(),
13
+ input_schemas: z.array(z.string().min(1)),
14
+ status: WorkspaceDatabaseStatus
15
+ }).loose();
16
+ const WorkspaceCreator = z.object({
17
+ id: z.number().int(),
18
+ first_name: z.string().nullable(),
19
+ last_name: z.string().nullable(),
20
+ email: z.string(),
21
+ common_name: z.string().nullable().optional()
22
+ }).loose();
23
+ const Workspace = z.object({
24
+ id: z.number().int(),
25
+ name: z.string(),
26
+ creator: WorkspaceCreator.nullable(),
27
+ created_at: z.string(),
28
+ updated_at: z.string(),
29
+ databases: z.array(WorkspaceDatabase).optional()
30
+ }).loose();
31
+ const WorkspaceCompact = Workspace.pick({
32
+ id: true,
33
+ name: true,
34
+ databases: true
35
+ }).strip();
36
+ const WorkspaceDatabaseList = z.array(WorkspaceDatabase);
37
+ const workspaceView = {
38
+ compactPick: WorkspaceCompact,
39
+ tableColumns: [
40
+ {
41
+ key: "id",
42
+ label: "ID"
43
+ },
44
+ {
45
+ key: "name",
46
+ label: "Name"
47
+ },
48
+ {
49
+ key: "databases",
50
+ label: "Databases",
51
+ format: (value) => formatDatabases(value)
52
+ }
53
+ ]
54
+ };
55
+ const WorkspaceCreateInput = z.object({ name: z.string().min(1) }).loose();
56
+ const WorkspaceProvisionInput = z.object({
57
+ database_id: z.number().int().positive(),
58
+ input_schemas: z.array(z.string().min(1)).min(1)
59
+ }).loose();
60
+ const WorkspaceUpdateDatabaseInput = z.object({ input_schemas: z.array(z.string().min(1)).min(1) }).loose();
61
+ function formatDatabases(value) {
62
+ if (value === void 0) return "";
63
+ const parsed = WorkspaceDatabaseList.safeParse(value);
64
+ if (!parsed.success || parsed.data.length === 0) return "(none)";
65
+ return parsed.data.map((entry) => {
66
+ const schemas = entry.input_schemas.length === 0 ? "" : ` [${entry.input_schemas.join(", ")}]`;
67
+ return `${entry.database_id} (${entry.status})${schemas}`;
68
+ }).join("; ");
69
+ }
70
+
71
+ //#endregion
72
+ export { Workspace, WorkspaceCompact, WorkspaceCreateInput, WorkspaceProvisionInput, WorkspaceUpdateDatabaseInput, workspaceView };
@@ -0,0 +1,139 @@
1
+ import { ConfigError, ValidationError, errorMessage } from "./predicates-DiIiS3k7.mjs";
2
+ import { z } from "zod";
3
+ import { randomBytes } from "node:crypto";
4
+ import { YAMLParseError, parse, stringify } from "yaml";
5
+
6
+ //#region src/runtime/yaml.ts
7
+ function parseYaml(input, schema, opts = {}) {
8
+ const result = parseYamlResult(input, schema, opts);
9
+ if (!result.ok) throw result.error;
10
+ return result.value;
11
+ }
12
+ function parseYamlResult(input, schema, opts = {}) {
13
+ const sourcePrefix = opts.source ? `${opts.source}: ` : "";
14
+ let raw;
15
+ try {
16
+ raw = parse(input);
17
+ } catch (error) {
18
+ if (error instanceof YAMLParseError) return {
19
+ ok: false,
20
+ error: new ConfigError(`${sourcePrefix}invalid YAML: ${error.message}`)
21
+ };
22
+ return {
23
+ ok: false,
24
+ error: new ConfigError(`${sourcePrefix}invalid YAML: ${errorMessage(error)}`)
25
+ };
26
+ }
27
+ const parsed = schema.safeParse(raw);
28
+ if (!parsed.success) return {
29
+ ok: false,
30
+ error: new ValidationError(`${sourcePrefix}value did not match expected schema`, {
31
+ source: opts.source ?? "<input>",
32
+ zodIssues: parsed.error.issues
33
+ })
34
+ };
35
+ return {
36
+ ok: true,
37
+ value: parsed.data
38
+ };
39
+ }
40
+ function stringifyYaml(value) {
41
+ return stringify(value, { lineWidth: 0 });
42
+ }
43
+
44
+ //#endregion
45
+ //#region src/core/workspace-credentials.ts
46
+ const API_KEY_NAME = "Workspace API Key";
47
+ const API_KEY_GROUP = "admin";
48
+ const PASSWORD_BYTE_LENGTH = 18;
49
+ const API_KEY_BYTE_LENGTH = 32;
50
+ const WorkspaceCredentials = z.object({
51
+ workspace_id: z.number().int().positive(),
52
+ user: z.object({
53
+ first_name: z.string().min(1),
54
+ last_name: z.string().min(1),
55
+ password: z.string().min(1),
56
+ email: z.string().min(1)
57
+ }),
58
+ api_key: z.object({
59
+ name: z.string().min(1),
60
+ group: z.enum(["admin", "all-users"]),
61
+ creator: z.string().min(1),
62
+ key: z.string().regex(/^mb_[A-Za-z0-9+/=]+$/)
63
+ })
64
+ });
65
+ function generateWorkspaceCredentials(workspaceId) {
66
+ const email = `workspace-${workspaceId}@workspace.local`;
67
+ return {
68
+ workspace_id: workspaceId,
69
+ user: {
70
+ first_name: "Workspace",
71
+ last_name: "Admin",
72
+ password: randomBase64Url(PASSWORD_BYTE_LENGTH),
73
+ email
74
+ },
75
+ api_key: {
76
+ name: API_KEY_NAME,
77
+ group: API_KEY_GROUP,
78
+ creator: email,
79
+ key: `mb_${randomBytes(API_KEY_BYTE_LENGTH).toString("base64")}`
80
+ }
81
+ };
82
+ }
83
+ const credentialsJsonEncoder = new TextEncoder();
84
+ function buildCredentialsJson(credentials) {
85
+ return credentialsJsonEncoder.encode(`${JSON.stringify(credentials, null, 2)}\n`);
86
+ }
87
+ const ConfigEnvelopeShape = z.object({
88
+ version: z.number().int(),
89
+ config: z.looseObject({})
90
+ }).loose();
91
+ function injectCredentialsIntoConfig(yamlInput, credentials) {
92
+ const envelope = parseYaml(yamlInput, ConfigEnvelopeShape, { source: "config.yml" });
93
+ if ("users" in envelope.config || "api-keys" in envelope.config) throw new ConfigError("config.yml already declares users or api-keys — refusing to overwrite parent-supplied credentials");
94
+ const merged = {
95
+ ...envelope,
96
+ config: {
97
+ ...envelope.config,
98
+ users: [credentials.user],
99
+ "api-keys": [credentials.api_key]
100
+ }
101
+ };
102
+ return stringifyYaml(merged);
103
+ }
104
+ const REPO_SYNC_MODES = ["read-write", "read-only"];
105
+ const RepoSyncMode = z.enum(REPO_SYNC_MODES);
106
+ const ConfigEnvelopeWithSettingsShape = z.object({
107
+ version: z.number().int(),
108
+ config: z.object({ settings: z.looseObject({}).optional() }).loose()
109
+ }).loose();
110
+ const REMOTE_SYNC_KEYS = [
111
+ "remote-sync-url",
112
+ "remote-sync-branch",
113
+ "remote-sync-type"
114
+ ];
115
+ function injectRepoSettingsIntoConfig(yamlInput, repo) {
116
+ const envelope = parseYaml(yamlInput, ConfigEnvelopeWithSettingsShape, { source: "config.yml" });
117
+ const existingSettings = envelope.config.settings ?? {};
118
+ const conflicts = REMOTE_SYNC_KEYS.filter((key) => key in existingSettings);
119
+ if (conflicts.length > 0) throw new ConfigError(`config.yml already declares remote-sync settings (${conflicts.join(", ")}) — refusing to overwrite parent-supplied values`);
120
+ const merged = {
121
+ ...envelope,
122
+ config: {
123
+ ...envelope.config,
124
+ settings: {
125
+ ...existingSettings,
126
+ "remote-sync-url": repo.url,
127
+ "remote-sync-branch": repo.branch,
128
+ "remote-sync-type": repo.mode
129
+ }
130
+ }
131
+ };
132
+ return stringifyYaml(merged);
133
+ }
134
+ function randomBase64Url(byteLength) {
135
+ return randomBytes(byteLength).toString("base64url");
136
+ }
137
+
138
+ //#endregion
139
+ export { REPO_SYNC_MODES, RepoSyncMode, WorkspaceCredentials, buildCredentialsJson, generateWorkspaceCredentials, injectCredentialsIntoConfig, injectRepoSettingsIntoConfig };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@metabase/cli",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "Metabase CLI",
5
5
  "license": "AGPL-3.0",
6
6
  "repository": {
@@ -35,19 +35,25 @@
35
35
  "lint:fix": "oxlint --fix",
36
36
  "format": "oxfmt",
37
37
  "format:check": "oxfmt --check",
38
+ "sync:representations": "bun run scripts/sync-representations.ts",
38
39
  "prepublishOnly": "tsdown && publint"
39
40
  },
40
41
  "dependencies": {
41
42
  "@clack/prompts": "^0.8.2",
42
43
  "@napi-rs/keyring": "^1.3.0",
44
+ "ajv": "^8.17.1",
45
+ "ajv-formats": "^3.0.1",
43
46
  "citty": "^0.2.2",
44
47
  "cli-table3": "^0.6.5",
48
+ "yaml": "^2.8.4",
45
49
  "zod": "^4.0.0"
46
50
  },
47
51
  "devDependencies": {
52
+ "@types/js-yaml": "^4.0.9",
48
53
  "@types/node": "^22.10.0",
49
54
  "execa": "^9.5.2",
50
55
  "fast-check": "^4.7.0",
56
+ "js-yaml": "^4.1.0",
51
57
  "oxfmt": "^0.47.0",
52
58
  "oxlint": "^1.62.0",
53
59
  "publint": "^0.3.0",
@@ -1,18 +0,0 @@
1
- import { defineCommand } from "citty";
2
-
3
- //#region src/commands/auth/index.ts
4
- var auth_default = defineCommand({
5
- meta: {
6
- name: "auth",
7
- description: "Authenticate against a Metabase instance"
8
- },
9
- default: "login",
10
- subCommands: {
11
- login: () => import("./login-C9WTwNn6.mjs").then((m) => m.default),
12
- status: () => import("./status-CUcs8XBH.mjs").then((m) => m.default),
13
- logout: () => import("./logout-oLszGCOg.mjs").then((m) => m.default)
14
- }
15
- });
16
-
17
- //#endregion
18
- export { auth_default as default };
@@ -1,19 +0,0 @@
1
- import { defineCommand } from "citty";
2
-
3
- //#region src/commands/card/index.ts
4
- var card_default = defineCommand({
5
- meta: {
6
- name: "card",
7
- description: "Manage Metabase cards (questions, models, metrics)"
8
- },
9
- subCommands: {
10
- list: () => import("./list-C4Ajrw8f.mjs").then((mod) => mod.default),
11
- get: () => import("./get-Cl8-IauC.mjs").then((mod) => mod.default),
12
- query: () => import("./query-PihYi-UZ.mjs").then((mod) => mod.default),
13
- create: () => import("./create-DdbU3TLX.mjs").then((mod) => mod.default),
14
- archive: () => import("./archive-CsWeHXle.mjs").then((mod) => mod.default)
15
- }
16
- });
17
-
18
- //#endregion
19
- export { card_default as default };
@@ -1,38 +0,0 @@
1
- import "./package-BGfw4ZWJ.mjs";
2
- import "./command-augment-D9pI9Vbh.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 { bodyInputFlags } from "./body-flags-BUA9XV1u.mjs";
7
- import { Transform, TransformCreateInput, transformView } from "./transform-B5uRpg1G.mjs";
8
-
9
- //#region src/commands/transform/create.ts
10
- var create_default = defineMetabaseCommand({
11
- meta: {
12
- name: "create",
13
- description: "Create a transform"
14
- },
15
- args: {
16
- ...outputFlags,
17
- ...profileFlag,
18
- ...connectionFlags,
19
- ...bodyInputFlags
20
- },
21
- outputSchema: Transform,
22
- examples: ["cat transform.json | metabase transform create", "metabase transform create --file transform.json"],
23
- async run({ args, ctx, getClient }) {
24
- const body = await readBody({
25
- flag: args.body,
26
- file: args.file
27
- }, TransformCreateInput);
28
- const client = await getClient();
29
- const created = await client.requestParsed(Transform, "/api/transform", {
30
- method: "POST",
31
- body
32
- });
33
- renderItem(created, transformView, ctx);
34
- }
35
- });
36
-
37
- //#endregion
38
- export { create_default as default };
@@ -1,42 +0,0 @@
1
- import "./package-BGfw4ZWJ.mjs";
2
- import "./command-augment-D9pI9Vbh.mjs";
3
- import { connectionFlags, defineMetabaseCommand, outputFlags, profileFlag, renderItem } from "./runtime-C9CEZhcn.mjs";
4
- import "./input-Dojr-RTw.mjs";
5
- import { Card, CardCreateInput, cardView } from "./card-CsXk8T6A.mjs";
6
- import { readBody } from "./body-Dv9hQ0Qk.mjs";
7
- import { bodyInputFlags } from "./body-flags-BUA9XV1u.mjs";
8
-
9
- //#region src/commands/card/create.ts
10
- var create_default = defineMetabaseCommand({
11
- meta: {
12
- name: "create",
13
- description: "Create a card from a JSON spec"
14
- },
15
- args: {
16
- ...outputFlags,
17
- ...profileFlag,
18
- ...connectionFlags,
19
- ...bodyInputFlags
20
- },
21
- outputSchema: Card,
22
- examples: [
23
- "cat card.json | metabase card create",
24
- "metabase card create --file card.json",
25
- "metabase card create --body '{\"name\":\"x\",\"display\":\"table\",\"dataset_query\":{...},\"visualization_settings\":{}}'"
26
- ],
27
- async run({ args, ctx, getClient }) {
28
- const body = await readBody({
29
- flag: args.body,
30
- file: args.file
31
- }, CardCreateInput);
32
- const client = await getClient();
33
- const created = await client.requestParsed(Card, "/api/card", {
34
- method: "POST",
35
- body
36
- });
37
- renderItem(created, cardView, ctx);
38
- }
39
- });
40
-
41
- //#endregion
42
- export { create_default as default };
@@ -1,33 +0,0 @@
1
- import { z } from "zod";
2
-
3
- //#region src/domain/database.ts
4
- const Database = z.object({
5
- id: z.number().int(),
6
- name: z.string(),
7
- engine: z.string()
8
- }).loose();
9
- const DatabaseCompact = Database.pick({
10
- id: true,
11
- name: true,
12
- engine: true
13
- }).strip();
14
- const databaseView = {
15
- compactPick: DatabaseCompact,
16
- tableColumns: [
17
- {
18
- key: "id",
19
- label: "ID"
20
- },
21
- {
22
- key: "name",
23
- label: "Name"
24
- },
25
- {
26
- key: "engine",
27
- label: "Engine"
28
- }
29
- ]
30
- };
31
-
32
- //#endregion
33
- export { Database, DatabaseCompact, databaseView };
@@ -1,17 +0,0 @@
1
- import { defineCommand } from "citty";
2
-
3
- //#region src/commands/db/index.ts
4
- var db_default = defineCommand({
5
- meta: {
6
- name: "db",
7
- description: "Inspect Metabase databases",
8
- alias: "database"
9
- },
10
- subCommands: {
11
- list: () => import("./list-CBSBHtK-.mjs").then((m) => m.default),
12
- get: () => import("./get-Dh_acl8q.mjs").then((m) => m.default)
13
- }
14
- });
15
-
16
- //#endregion
17
- export { db_default as default };