databricks-axi 0.1.0 → 0.3.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.
@@ -0,0 +1,28 @@
1
+ import { AxiError } from "axi-sdk-js";
2
+ import type { RunDatabricksOptions } from "../databricks.js";
3
+ export type AxiStructuredOutput = Record<string, unknown>;
4
+ export type AxiRenderable = string | AxiStructuredOutput;
5
+ export type FlagSpec = Record<string, "value" | "boolean">;
6
+ export type Flags = Map<string, string | boolean>;
7
+ export declare function spawnOpts(flags: Flags): RunDatabricksOptions;
8
+ /** Suffix for suggested follow-up commands so they hit the same workspace. */
9
+ export declare function profileSuffix(profile: unknown): string;
10
+ /** Guard for endpoints whose result gets dereferenced — empty stdout (null)
11
+ * becomes a structured UPSTREAM_ERROR instead of a raw TypeError. */
12
+ export declare function assertObject<T>(parsed: unknown, label: string): T;
13
+ /**
14
+ * The Go CLI prints either a bare item array (>= 0.298) or the response
15
+ * object ({items, ...}) depending on version — tolerate both.
16
+ */
17
+ export declare function asList(parsed: unknown, key: string): AxiStructuredOutput[];
18
+ /** Helpers whose usage errors point at `databricks-axi <domain> --help`. */
19
+ export declare function domainHelpers(domain: string): {
20
+ usage: (message: string, extraHelp?: string[]) => AxiError;
21
+ parseArgs: (args: string[], spec: FlagSpec) => {
22
+ positional: string[];
23
+ flags: Flags;
24
+ };
25
+ parseIntFlag: (flags: Flags, name: string, fallback: number, min?: number) => number;
26
+ requireId: (positional: string[], usageText: string, pattern?: RegExp) => string;
27
+ renderRows: (items: AxiStructuredOutput[], flags: Flags, defaults: string[]) => AxiStructuredOutput[];
28
+ };
@@ -0,0 +1,105 @@
1
+ import { parseArgs as nodeParseArgs } from "node:util";
2
+ import { AxiError } from "axi-sdk-js";
3
+ export function spawnOpts(flags) {
4
+ const profile = flags.get("profile");
5
+ return typeof profile === "string" ? { profile } : {};
6
+ }
7
+ /** Suffix for suggested follow-up commands so they hit the same workspace. */
8
+ export function profileSuffix(profile) {
9
+ return typeof profile === "string" ? ` --profile ${profile}` : "";
10
+ }
11
+ /** Guard for endpoints whose result gets dereferenced — empty stdout (null)
12
+ * becomes a structured UPSTREAM_ERROR instead of a raw TypeError. */
13
+ export function assertObject(parsed, label) {
14
+ if (parsed === null || typeof parsed !== "object") {
15
+ throw new AxiError(`${label} returned an empty response`, "UPSTREAM_ERROR", ["Retry, or check workspace availability"]);
16
+ }
17
+ return parsed;
18
+ }
19
+ /**
20
+ * The Go CLI prints either a bare item array (>= 0.298) or the response
21
+ * object ({items, ...}) depending on version — tolerate both.
22
+ */
23
+ export function asList(parsed, key) {
24
+ if (Array.isArray(parsed)) {
25
+ return parsed;
26
+ }
27
+ const obj = (parsed ?? {});
28
+ return obj[key] ?? [];
29
+ }
30
+ /** Helpers whose usage errors point at `databricks-axi <domain> --help`. */
31
+ export function domainHelpers(domain) {
32
+ const usage = (message, extraHelp = []) => new AxiError(message, "VALIDATION_ERROR", [
33
+ ...extraHelp,
34
+ `Run \`databricks-axi ${domain} --help\``,
35
+ ]);
36
+ const parseArgs = (args, spec) => {
37
+ const options = Object.fromEntries(Object.entries(spec).map(([name, kind]) => [
38
+ name,
39
+ { type: kind === "value" ? "string" : "boolean" },
40
+ ]));
41
+ try {
42
+ const { values, positionals } = nodeParseArgs({
43
+ args,
44
+ options,
45
+ strict: true,
46
+ allowPositionals: true,
47
+ });
48
+ return {
49
+ positional: positionals,
50
+ flags: new Map(Object.entries(values)),
51
+ };
52
+ }
53
+ catch (error) {
54
+ const valid = Object.keys(spec)
55
+ .map((f) => `--${f}`)
56
+ .join(", ");
57
+ // First sentence only — node appends a long "--" placement hint,
58
+ // sometimes as extra lines (e.g. the ambiguous-option error).
59
+ const message = error.message.split("\n")[0].split(". ")[0];
60
+ throw usage(message, [`Valid flags: ${valid}`]);
61
+ }
62
+ };
63
+ const parseIntFlag = (flags, name, fallback, min = 1) => {
64
+ const raw = flags.get(name);
65
+ if (raw === undefined) {
66
+ return fallback;
67
+ }
68
+ const value = Number(raw);
69
+ if (!Number.isInteger(value) || value < min) {
70
+ const kind = min === 0 ? "non-negative" : "positive";
71
+ throw usage(`--${name} must be a ${kind} integer, got: ${String(raw)}`);
72
+ }
73
+ return value;
74
+ };
75
+ const requireId = (positional, usageText, pattern) => {
76
+ const id = positional[0];
77
+ if (!id || positional.length > 1 || (pattern && !pattern.test(id))) {
78
+ throw usage(`Usage: databricks-axi ${usageText}`);
79
+ }
80
+ return id;
81
+ };
82
+ /** Apply --fields (raw top-level keys) or the default field list. */
83
+ const renderRows = (items, flags, defaults) => {
84
+ const spec = flags.get("fields");
85
+ const fields = typeof spec === "string"
86
+ ? spec
87
+ .split(",")
88
+ .map((f) => f.trim())
89
+ .filter(Boolean)
90
+ : defaults;
91
+ if (typeof spec === "string" && items.length > 0) {
92
+ const known = new Set(items.flatMap((item) => Object.keys(item)));
93
+ for (const field of fields) {
94
+ if (!known.has(field)) {
95
+ throw usage(`Unknown field: ${field}`, [
96
+ `Available fields: ${[...known].sort().join(", ")}`,
97
+ ]);
98
+ }
99
+ }
100
+ }
101
+ return items.map((item) => Object.fromEntries(fields.map((field) => [field, item[field] ?? ""])));
102
+ };
103
+ return { usage, parseArgs, parseIntFlag, requireId, renderRows };
104
+ }
105
+ //# sourceMappingURL=shared.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shared.js","sourceRoot":"","sources":["../../../src/commands/shared.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ import { type AxiRenderable } from "./shared.js";
2
+ export declare const SQL_HELP = "usage: databricks-axi sql <subcommand> [args] [flags]\nsubcommands[6]:\n warehouses [--fields a,b]\n warehouses view <id>\n warehouses start <id> [--wait]\n warehouses stop <id> [--wait]\n exec \"<query>\" [--warehouse <id>] [--limit N] [--timeout S] [--full]\n statement view <statement_id>\nflags:\n --profile <name> databricks auth profile passthrough\nexamples:\n databricks-axi sql warehouses\n databricks-axi sql exec \"SELECT count(*) FROM workspace.default.my_table\"\n databricks-axi sql statement view <statement_id>\nnotes:\n exec picks the warehouse automatically when the workspace has exactly one\n exec waits up to --timeout seconds (default 120), then exits 0 with the\n statement id \u2014 resume with sql statement view\n warehouse start/stop are async by default; --wait blocks up to ~20 min\n never put secret values in the query text: it lands on child argv\n (visible in ps) via the api substrate\n";
3
+ export declare const sqlPoll: {
4
+ sleep: (ms: number) => Promise<void>;
5
+ };
6
+ export declare function sqlCommand(args: string[]): Promise<AxiRenderable>;
@@ -0,0 +1,268 @@
1
+ import { AxiError } from "axi-sdk-js";
2
+ import { runDatabricks, runDatabricksApi, } from "../databricks.js";
3
+ import { redactSecrets } from "../errors.js";
4
+ import { asList, assertObject, domainHelpers, profileSuffix, spawnOpts, } from "./shared.js";
5
+ const { usage, parseArgs, parseIntFlag, requireId, renderRows } = domainHelpers("sql");
6
+ export const SQL_HELP = `usage: databricks-axi sql <subcommand> [args] [flags]
7
+ subcommands[6]:
8
+ warehouses [--fields a,b]
9
+ warehouses view <id>
10
+ warehouses start <id> [--wait]
11
+ warehouses stop <id> [--wait]
12
+ exec "<query>" [--warehouse <id>] [--limit N] [--timeout S] [--full]
13
+ statement view <statement_id>
14
+ flags:
15
+ --profile <name> databricks auth profile passthrough
16
+ examples:
17
+ databricks-axi sql warehouses
18
+ databricks-axi sql exec "SELECT count(*) FROM workspace.default.my_table"
19
+ databricks-axi sql statement view <statement_id>
20
+ notes:
21
+ exec picks the warehouse automatically when the workspace has exactly one
22
+ exec waits up to --timeout seconds (default 120), then exits 0 with the
23
+ statement id — resume with sql statement view
24
+ warehouse start/stop are async by default; --wait blocks up to ~20 min
25
+ never put secret values in the query text: it lands on child argv
26
+ (visible in ps) via the api substrate
27
+ `;
28
+ // Injectable so poll tests run at full speed.
29
+ export const sqlPoll = {
30
+ sleep: (ms) => new Promise((r) => setTimeout(r, ms)),
31
+ };
32
+ const STATEMENTS_PATH = "/api/2.0/sql/statements";
33
+ const SUBMIT_TIMEOUT_MS = 60_000; // must exceed the API-side 50s wait_timeout
34
+ const WAIT_TIMEOUT_MS = 25 * 60_000; // upstream blocks up to 20 min on --wait
35
+ const POLL_INTERVAL_MS = 2_000;
36
+ const DEFAULT_ROW_LIMIT = 100;
37
+ const DEFAULT_BUDGET_S = 120;
38
+ export async function sqlCommand(args) {
39
+ const [sub, ...rest] = args;
40
+ switch (sub) {
41
+ case "warehouses":
42
+ switch (rest[0]) {
43
+ case "view":
44
+ return warehousesView(rest.slice(1));
45
+ case "start":
46
+ case "stop":
47
+ return warehousesStartStop(rest[0], rest.slice(1));
48
+ default:
49
+ return warehousesList(rest);
50
+ }
51
+ case "exec":
52
+ return sqlExec(rest);
53
+ case "statement":
54
+ if (rest[0] !== "view") {
55
+ throw usage("Usage: databricks-axi sql statement view <statement_id>");
56
+ }
57
+ return statementView(rest.slice(1));
58
+ default:
59
+ throw usage(sub ? `Unknown sql subcommand: ${sub}` : "sql requires a subcommand");
60
+ }
61
+ }
62
+ // --- warehouses ---
63
+ function warehouseSize(w) {
64
+ const size = w.cluster_size ?? "";
65
+ return w.enable_serverless_compute ? `${size} (serverless)`.trim() : size;
66
+ }
67
+ async function listWarehouses(opts) {
68
+ const parsed = await runDatabricks(["warehouses", "list"], opts);
69
+ return asList(parsed, "warehouses");
70
+ }
71
+ async function warehousesList(args) {
72
+ const { positional, flags } = parseArgs(args, {
73
+ profile: "value",
74
+ fields: "value",
75
+ });
76
+ if (positional.length > 0) {
77
+ throw usage(`sql warehouses takes no arguments, got: ${positional[0]}`);
78
+ }
79
+ const items = await listWarehouses(spawnOpts(flags));
80
+ const p = profileSuffix(flags.get("profile"));
81
+ if (items.length === 0) {
82
+ return {
83
+ warehouses: [],
84
+ status: "no SQL warehouses in this workspace",
85
+ help: ["Create one in the workspace UI: SQL Warehouses > Create"],
86
+ };
87
+ }
88
+ const flattened = items.map((w) => ({ ...w, size: warehouseSize(w) }));
89
+ const rows = renderRows(flattened, flags, ["id", "name", "state", "size"]);
90
+ const help = [`databricks-axi sql exec "<query>" --warehouse <id>${p}`];
91
+ const stopped = items.find((w) => w.state === "STOPPED");
92
+ if (stopped) {
93
+ help.push(`databricks-axi sql warehouses start ${stopped.id}${p}`);
94
+ }
95
+ return { warehouses: rows, count: rows.length, help };
96
+ }
97
+ async function warehousesView(args) {
98
+ const { positional, flags } = parseArgs(args, { profile: "value" });
99
+ const id = requireId(positional, "sql warehouses view <id>");
100
+ const w = assertObject(await runDatabricks(["warehouses", "get", id], spawnOpts(flags)), "warehouses get");
101
+ const p = profileSuffix(flags.get("profile"));
102
+ return {
103
+ id: w.id,
104
+ name: w.name,
105
+ state: w.state,
106
+ size: warehouseSize(w),
107
+ auto_stop_mins: w.auto_stop_mins,
108
+ creator_name: w.creator_name,
109
+ help: [
110
+ w.state === "RUNNING"
111
+ ? `databricks-axi sql warehouses stop ${id}${p}`
112
+ : `databricks-axi sql warehouses start ${id}${p}`,
113
+ `databricks-axi sql exec "<query>" --warehouse ${id}${p}`,
114
+ ],
115
+ };
116
+ }
117
+ async function warehousesStartStop(verb, args) {
118
+ const { positional, flags } = parseArgs(args, {
119
+ profile: "value",
120
+ wait: "boolean",
121
+ });
122
+ const id = requireId(positional, `sql warehouses ${verb} <id> [--wait]`);
123
+ const wait = flags.get("wait") === true;
124
+ const p = profileSuffix(flags.get("profile"));
125
+ const argv = ["warehouses", verb, id];
126
+ if (!wait) {
127
+ argv.push("--no-wait");
128
+ }
129
+ // Upstream is already idempotent here: start-on-RUNNING / stop-on-STOPPED
130
+ // exit 0 with no output (pinned live 2026-07-07), so no no-op mapping.
131
+ await runDatabricks(argv, {
132
+ ...spawnOpts(flags),
133
+ ...(wait ? { timeoutMs: WAIT_TIMEOUT_MS } : {}),
134
+ timeoutHelp: [
135
+ `The ${verb} may have applied despite the timeout — check state:`,
136
+ `databricks-axi sql warehouses view ${id}${p}`,
137
+ ],
138
+ });
139
+ return {
140
+ id,
141
+ status: `${verb} requested`,
142
+ help: [`databricks-axi sql warehouses view ${id}${p}`],
143
+ };
144
+ }
145
+ // --- exec / statement view ---
146
+ async function sqlExec(args) {
147
+ const { positional, flags } = parseArgs(args, {
148
+ profile: "value",
149
+ warehouse: "value",
150
+ limit: "value",
151
+ timeout: "value",
152
+ full: "boolean",
153
+ });
154
+ const query = positional[0];
155
+ if (!query || positional.length > 1) {
156
+ throw usage('Usage: databricks-axi sql exec "<query>" [--warehouse <id>]');
157
+ }
158
+ const limit = parseIntFlag(flags, "limit", DEFAULT_ROW_LIMIT);
159
+ const budgetS = parseIntFlag(flags, "timeout", DEFAULT_BUDGET_S, 0);
160
+ const full = flags.get("full") === true;
161
+ const opts = spawnOpts(flags);
162
+ const p = profileSuffix(flags.get("profile"));
163
+ const warehouseId = await resolveWarehouse(flags.get("warehouse"), opts);
164
+ const deadline = Date.now() + budgetS * 1000;
165
+ const waitTimeoutS = Math.max(5, Math.min(budgetS, 50));
166
+ let stmt = assertObject(await runDatabricksApi("post", STATEMENTS_PATH, JSON.stringify({
167
+ statement: query,
168
+ warehouse_id: warehouseId,
169
+ wait_timeout: `${waitTimeoutS}s`,
170
+ on_wait_timeout: "CONTINUE",
171
+ disposition: "INLINE",
172
+ format: "JSON_ARRAY",
173
+ row_limit: limit,
174
+ }), { ...opts, timeoutMs: SUBMIT_TIMEOUT_MS }), "sql statement submit");
175
+ while (isPendingState(stmt)) {
176
+ if (Date.now() >= deadline) {
177
+ return {
178
+ statement_id: stmt.statement_id,
179
+ state: stmt.status?.state,
180
+ status: `still running — stopped waiting after ${budgetS}s (statement continues server-side)`,
181
+ help: [`databricks-axi sql statement view ${stmt.statement_id}${p}`],
182
+ };
183
+ }
184
+ await sqlPoll.sleep(POLL_INTERVAL_MS);
185
+ stmt = assertObject(await runDatabricksApi("get", `${STATEMENTS_PATH}/${stmt.statement_id}`, undefined, opts), "sql statement poll");
186
+ }
187
+ return renderTerminalStatement(stmt, { full, limit, opts, p });
188
+ }
189
+ async function statementView(args) {
190
+ const { positional, flags } = parseArgs(args, {
191
+ profile: "value",
192
+ full: "boolean",
193
+ });
194
+ const id = requireId(positional, "sql statement view <statement_id>");
195
+ const opts = spawnOpts(flags);
196
+ const p = profileSuffix(flags.get("profile"));
197
+ const stmt = assertObject(await runDatabricksApi("get", `${STATEMENTS_PATH}/${id}`, undefined, opts), "sql statement get");
198
+ if (isPendingState(stmt)) {
199
+ return {
200
+ statement_id: stmt.statement_id ?? id,
201
+ state: stmt.status?.state,
202
+ help: [`databricks-axi sql statement view ${id}${p}`],
203
+ };
204
+ }
205
+ return renderTerminalStatement(stmt, {
206
+ full: flags.get("full") === true,
207
+ opts,
208
+ p,
209
+ });
210
+ }
211
+ function isPendingState(stmt) {
212
+ const state = stmt.status?.state;
213
+ return state === "PENDING" || state === "RUNNING";
214
+ }
215
+ async function resolveWarehouse(flagValue, opts) {
216
+ if (typeof flagValue === "string") {
217
+ return flagValue;
218
+ }
219
+ const warehouses = await listWarehouses(opts);
220
+ if (warehouses.length === 1 && warehouses[0].id) {
221
+ return warehouses[0].id;
222
+ }
223
+ if (warehouses.length === 0) {
224
+ throw new AxiError("no SQL warehouses in this workspace", "NOT_FOUND", [
225
+ "Create one in the workspace UI: SQL Warehouses > Create",
226
+ ]);
227
+ }
228
+ throw usage("multiple SQL warehouses — pick one with --warehouse <id>", warehouses.map((w) => `${w.id}: ${w.name}`));
229
+ }
230
+ async function renderTerminalStatement(stmt, ctx) {
231
+ const state = stmt.status?.state ?? "UNKNOWN";
232
+ const id = stmt.statement_id;
233
+ if (state !== "SUCCEEDED") {
234
+ const detail = stmt.status?.error?.message ?? `statement ${state}`;
235
+ throw new AxiError(redactSecrets(detail), "SQL_ERROR", id ? [`databricks-axi sql statement view ${id}${ctx.p}`] : []);
236
+ }
237
+ const manifest = stmt.manifest ?? {};
238
+ const columns = (manifest.schema?.columns ?? []).map((c) => `${c.name}:${c.type_text}`);
239
+ let rows = stmt.result?.data_array ?? [];
240
+ const totalChunks = manifest.total_chunk_count ?? 1;
241
+ const totalRows = manifest.total_row_count ?? rows.length;
242
+ if (ctx.full && totalChunks > 1 && id) {
243
+ for (let chunk = 1; chunk < totalChunks; chunk++) {
244
+ const next = assertObject(await runDatabricksApi("get", `${STATEMENTS_PATH}/${id}/result/chunks/${chunk}`, undefined, ctx.opts), "sql statement chunk fetch");
245
+ rows = rows.concat(next.data_array ?? []);
246
+ }
247
+ }
248
+ const out = {
249
+ statement_id: id,
250
+ columns,
251
+ rows,
252
+ total_row_count: totalRows,
253
+ };
254
+ const notes = [];
255
+ if (!ctx.full && totalChunks > 1) {
256
+ notes.push(`showing ${rows.length} of ${totalRows} rows — rerun with --full`);
257
+ }
258
+ if (manifest.truncated) {
259
+ // Server-side row_limit hit: --full can never exceed the submitted cap,
260
+ // so report what was actually delivered, not the true upstream total.
261
+ notes.push(`result capped at ${rows.length} rows — rerun with --limit ${(ctx.limit ?? rows.length) * 2}`);
262
+ }
263
+ if (notes.length > 0) {
264
+ out.truncated = notes.join("; ");
265
+ }
266
+ return out;
267
+ }
268
+ //# sourceMappingURL=sql.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sql.js","sourceRoot":"","sources":["../../../src/commands/sql.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ export type RunDatabricksOptions = {
2
+ profile?: string;
3
+ timeoutMs?: number;
4
+ /** TIMEOUT suggestions — mutations pass a state check, not "retry". */
5
+ timeoutHelp?: string[];
6
+ };
7
+ /**
8
+ * Run the official databricks CLI and return its parsed JSON output.
9
+ * Array argv only (never a shell), stdin ignored, hard timeout, always
10
+ * `-o json`. All failures surface as AxiError.
11
+ */
12
+ export declare function runDatabricks(args: string[], opts?: RunDatabricksOptions): Promise<unknown>;
13
+ /**
14
+ * REST passthrough over the CLI's `api` subcommand. Rule for all callers:
15
+ * `body` lands on child argv (visible in `ps`) — secret-bearing bodies are
16
+ * forbidden (the secrets domain uses upstream's stdin mechanism instead).
17
+ */
18
+ export declare function runDatabricksApi(method: string, path: string, body?: string, opts?: RunDatabricksOptions): Promise<unknown>;
@@ -0,0 +1,105 @@
1
+ import { spawn } from "node:child_process";
2
+ import { AxiError } from "axi-sdk-js";
3
+ import { mapUpstreamError, redactSecrets } from "./errors.js";
4
+ const DEFAULT_TIMEOUT_MS = 30_000;
5
+ const MIN_MINOR_VERSION = 298; // databricks CLI floor: 0.298 (pre-0.298 pagination flags differ)
6
+ const INSTALL_HELP = "Install it: https://docs.databricks.com/dev-tools/cli/install";
7
+ /**
8
+ * Run the official databricks CLI and return its parsed JSON output.
9
+ * Array argv only (never a shell), stdin ignored, hard timeout, always
10
+ * `-o json`. All failures surface as AxiError.
11
+ */
12
+ export async function runDatabricks(args, opts = {}) {
13
+ const argv = [
14
+ ...(opts.profile ? ["-p", opts.profile] : []),
15
+ ...args,
16
+ "-o",
17
+ "json",
18
+ ];
19
+ const timeoutMs = opts.timeoutMs ?? DEFAULT_TIMEOUT_MS;
20
+ const result = await spawnCollect(argv, timeoutMs);
21
+ if (result.enoent) {
22
+ throw new AxiError("databricks CLI not found on PATH", "CLI_MISSING", [
23
+ INSTALL_HELP,
24
+ ]);
25
+ }
26
+ if (result.timedOut) {
27
+ throw new AxiError(`databricks ${args[0] ?? ""} timed out after ${timeoutMs}ms`, "TIMEOUT", opts.timeoutHelp ?? ["Retry, or check workspace availability"]);
28
+ }
29
+ if (result.code !== 0) {
30
+ throw await diagnoseFailure(result.stderr);
31
+ }
32
+ const trimmed = result.stdout.trim();
33
+ if (!trimmed) {
34
+ return null;
35
+ }
36
+ try {
37
+ // int64 ids (job_id/run_id) can exceed 2^53, where JSON.parse silently
38
+ // rounds; quote 16+-digit id values so they stay exact as strings.
39
+ return JSON.parse(trimmed.replace(/"(\w*_id)"\s*:\s*(\d{16,})(?=\s*[,}])/g, '"$1":"$2"'));
40
+ }
41
+ catch {
42
+ throw new AxiError(`databricks returned invalid JSON: ${redactSecrets(trimmed).slice(0, 120)}`, "UPSTREAM_ERROR");
43
+ }
44
+ }
45
+ /**
46
+ * REST passthrough over the CLI's `api` subcommand. Rule for all callers:
47
+ * `body` lands on child argv (visible in `ps`) — secret-bearing bodies are
48
+ * forbidden (the secrets domain uses upstream's stdin mechanism instead).
49
+ */
50
+ export async function runDatabricksApi(method, path, body, opts = {}) {
51
+ return runDatabricks(["api", method, path, ...(body !== undefined ? ["--json", body] : [])], opts);
52
+ }
53
+ function spawnCollect(argv, timeoutMs) {
54
+ return new Promise((resolve) => {
55
+ const child = spawn("databricks", argv, {
56
+ stdio: ["ignore", "pipe", "pipe"],
57
+ });
58
+ let stdout = "";
59
+ let stderr = "";
60
+ let timedOut = false;
61
+ const timer = setTimeout(() => {
62
+ timedOut = true;
63
+ child.kill("SIGKILL");
64
+ }, timeoutMs);
65
+ child.stdout.setEncoding("utf8");
66
+ child.stderr.setEncoding("utf8");
67
+ child.stdout.on("data", (chunk) => (stdout += chunk));
68
+ child.stderr.on("data", (chunk) => (stderr += chunk));
69
+ child.on("error", (error) => {
70
+ clearTimeout(timer);
71
+ resolve({
72
+ code: null,
73
+ stdout,
74
+ stderr: stderr || error.message,
75
+ enoent: error.code === "ENOENT",
76
+ timedOut,
77
+ });
78
+ });
79
+ child.on("close", (code) => {
80
+ clearTimeout(timer);
81
+ resolve({ code, stdout, stderr, enoent: false, timedOut });
82
+ });
83
+ });
84
+ }
85
+ // ponytail: version guard runs only on the failure path — a pre-flight
86
+ // `databricks -v` would tax every happy-path invocation for nothing.
87
+ async function diagnoseFailure(stderr) {
88
+ if (/unknown (command|flag|shorthand)|no such (option|command)/i.test(stderr)) {
89
+ const version = await detectVersion();
90
+ if (version && version.major === 0 && version.minor < MIN_MINOR_VERSION) {
91
+ return new AxiError(`databricks CLI ${version.raw} is too old (need >= 0.298)`, "CLI_TOO_OLD", [`Upgrade: https://docs.databricks.com/dev-tools/cli/install`]);
92
+ }
93
+ }
94
+ return mapUpstreamError(stderr);
95
+ }
96
+ async function detectVersion() {
97
+ const result = await spawnCollect(["-v"], 5_000);
98
+ // Legacy CLIs print the version to stderr.
99
+ const match = /v?(\d+)\.(\d+)\.(\d+)/.exec(result.stdout + result.stderr);
100
+ if (!match) {
101
+ return null;
102
+ }
103
+ return { major: Number(match[1]), minor: Number(match[2]), raw: match[0] };
104
+ }
105
+ //# sourceMappingURL=databricks.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"databricks.js","sourceRoot":"","sources":["../../src/databricks.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ import { AxiError } from "axi-sdk-js";
2
+ /**
3
+ * Strip token-shaped strings from upstream text before it can reach stdout.
4
+ * Order matters: dapi tokens first (they are also long hex).
5
+ */
6
+ export declare function redactSecrets(text: string): string;
7
+ /**
8
+ * Pattern-match the Go CLI's plain-text stderr into the AXI taxonomy.
9
+ * Returns (never throws) so callers decide whether to throw or inspect.
10
+ */
11
+ export declare function mapUpstreamError(stderr: string): AxiError;
@@ -0,0 +1,37 @@
1
+ import { AxiError } from "axi-sdk-js";
2
+ const AUTH_HELP = [
3
+ "Ask the user to run: databricks auth login --host <workspace-url>",
4
+ ];
5
+ /**
6
+ * Strip token-shaped strings from upstream text before it can reach stdout.
7
+ * Order matters: dapi tokens first (they are also long hex).
8
+ */
9
+ export function redactSecrets(text) {
10
+ return text
11
+ .replace(/dapi[0-9a-f]{16,}/gi, "[redacted]")
12
+ .replace(/\b[0-9a-f]{32,}\b/gi, "[redacted]")
13
+ .replace(/\b[A-Za-z0-9+=_-]{40,}\b/g, "[redacted]"); // no "/" so workspace paths stay readable
14
+ }
15
+ /**
16
+ * Pattern-match the Go CLI's plain-text stderr into the AXI taxonomy.
17
+ * Returns (never throws) so callers decide whether to throw or inspect.
18
+ */
19
+ export function mapUpstreamError(stderr) {
20
+ const text = redactSecrets(stderr.trim()) ||
21
+ "databricks CLI failed with no error output";
22
+ const firstLine = text.split("\n", 1)[0] ?? text;
23
+ if (/\b401\b|unauthorized|token.{0,20}expired|cannot configure default credentials|oauth/i.test(text)) {
24
+ return new AxiError(firstLine, "AUTH_ERROR", AUTH_HELP);
25
+ }
26
+ if (/\b403\b|PERMISSION_DENIED/i.test(text)) {
27
+ return new AxiError(firstLine, "PERMISSION_DENIED");
28
+ }
29
+ if (/RESOURCE_DOES_NOT_EXIST|\b404\b|does not exist/i.test(text)) {
30
+ return new AxiError(firstLine, "NOT_FOUND");
31
+ }
32
+ if (/INVALID_STATE/.test(text)) {
33
+ return new AxiError(firstLine, "INVALID_STATE");
34
+ }
35
+ return new AxiError(firstLine, "UPSTREAM_ERROR");
36
+ }
37
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/errors.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAEtC,MAAM,SAAS,GAAG;IAChB,mEAAmE;CACpE,CAAC;AAEF;;;GAGG;AACH,MAAM,UAAU,aAAa,CAAC,IAAY;IACxC,OAAO,IAAI;SACR,OAAO,CAAC,qBAAqB,EAAE,YAAY,CAAC;SAC5C,OAAO,CAAC,qBAAqB,EAAE,YAAY,CAAC;SAC5C,OAAO,CAAC,2BAA2B,EAAE,YAAY,CAAC,CAAC,CAAC,0CAA0C;AACnG,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,gBAAgB,CAAC,MAAc;IAC7C,MAAM,IAAI,GACR,aAAa,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;QAC5B,4CAA4C,CAAC;IAC/C,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC;IACjD,IACE,sFAAsF,CAAC,IAAI,CACzF,IAAI,CACL,EACD,CAAC;QACD,OAAO,IAAI,QAAQ,CAAC,SAAS,EAAE,YAAY,EAAE,SAAS,CAAC,CAAC;IAC1D,CAAC;IACD,IAAI,4BAA4B,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;QAC5C,OAAO,IAAI,QAAQ,CAAC,SAAS,EAAE,mBAAmB,CAAC,CAAC;IACtD,CAAC;IACD,IAAI,iDAAiD,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;QACjE,OAAO,IAAI,QAAQ,CAAC,SAAS,EAAE,WAAW,CAAC,CAAC;IAC9C,CAAC;IACD,IAAI,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;QAC/B,OAAO,IAAI,QAAQ,CAAC,SAAS,EAAE,eAAe,CAAC,CAAC;IAClD,CAAC;IACD,OAAO,IAAI,QAAQ,CAAC,SAAS,EAAE,gBAAgB,CAAC,CAAC;AACnD,CAAC"}