@dbx-tools/lakebox 0.0.0-stage → 0.9.132

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,81 @@
1
+ import { z } from "zod";
2
+ export declare const LakeboxEntrySchema: z.ZodObject<{
3
+ sandboxId: z.ZodString;
4
+ status: z.ZodString;
5
+ gatewayHost: z.ZodOptional<z.ZodString>;
6
+ name: z.ZodOptional<z.ZodString>;
7
+ createTime: z.ZodOptional<z.ZodString>;
8
+ lastStartTime: z.ZodOptional<z.ZodString>;
9
+ idleTimeout: z.ZodOptional<z.ZodString>;
10
+ noAutostop: z.ZodOptional<z.ZodBoolean>;
11
+ }, z.core.$loose>;
12
+ /** Lakebox record returned by the Databricks Lakebox REST API. */
13
+ export type LakeboxEntry = z.infer<typeof LakeboxEntrySchema>;
14
+ export declare const LakeboxSshKeySchema: z.ZodObject<{
15
+ keyHash: z.ZodString;
16
+ name: z.ZodOptional<z.ZodString>;
17
+ gatewayHost: z.ZodOptional<z.ZodString>;
18
+ }, z.core.$loose>;
19
+ /** Registered SSH key returned by the Databricks Lakebox REST API. */
20
+ export type LakeboxSshKey = z.infer<typeof LakeboxSshKeySchema>;
21
+ /**
22
+ * Workspace credentials for Lakebox REST calls.
23
+ *
24
+ * The Databricks SDK and AppKit `WorkspaceClient.config` satisfy this shape, as
25
+ * does a small adapter over `@dbx-tools/auth`. Lakebox lifecycle calls must use
26
+ * the app service principal, never request-scoped OBO credentials.
27
+ */
28
+ export interface LakeboxAuth {
29
+ /** Workspace URL. */
30
+ readonly host?: string;
31
+ /** Numeric workspace identifier, when known. */
32
+ readonly workspaceId?: string;
33
+ /** Resolves lazy configuration before `host` is read. */
34
+ ensureResolved?(): Promise<void>;
35
+ /** Adds authentication headers to one request. */
36
+ authenticate(headers: Headers): Promise<void>;
37
+ }
38
+ /** Error raised for a non-success Lakebox REST response. */
39
+ export declare class LakeboxApiError extends Error {
40
+ readonly status: number;
41
+ readonly errorCode?: string | undefined;
42
+ readonly requestId?: string | undefined;
43
+ constructor(message: string, status: number, errorCode?: string | undefined, requestId?: string | undefined);
44
+ }
45
+ /**
46
+ * REST client for Databricks Lakeboxes and registered SSH keys.
47
+ *
48
+ * Responses are validated before they reach callers. Diagnostics never include
49
+ * tokens or request headers.
50
+ */
51
+ export declare class LakeboxClient {
52
+ private readonly auth;
53
+ /** Creates a client for one workspace credential. */
54
+ constructor(auth: LakeboxAuth);
55
+ /** Returns the workspace identifier, or the workspace origin when the identifier is unknown. */
56
+ workspaceScope(): Promise<string>;
57
+ /** Lists every Lakebox visible to the caller, following pagination. */
58
+ list(signal?: AbortSignal): Promise<LakeboxEntry[]>;
59
+ /** Returns one Lakebox by ID. */
60
+ get(id: string, signal?: AbortSignal): Promise<LakeboxEntry>;
61
+ /** Creates a Lakebox with a Databricks-assigned display name. */
62
+ create(signal?: AbortSignal): Promise<LakeboxEntry>;
63
+ /** Sets the platform idle timeout that stops the Lakebox after inactivity. */
64
+ setIdleTimeout(id: string, seconds: number, signal?: AbortSignal): Promise<LakeboxEntry>;
65
+ /** Permanently deletes one Lakebox and its persistent home. */
66
+ delete(id: string, signal?: AbortSignal): Promise<void>;
67
+ /** Requests a start and returns the updated record. */
68
+ start(id: string, signal?: AbortSignal): Promise<LakeboxEntry>;
69
+ /** Requests a stop and returns the updated record. */
70
+ stop(id: string, signal?: AbortSignal): Promise<LakeboxEntry>;
71
+ /** Lists SSH public keys registered by the caller. */
72
+ listKeys(signal?: AbortSignal): Promise<LakeboxSshKey[]>;
73
+ /** Registers an SSH public key and returns the Databricks key record. */
74
+ registerKey(publicKey: string, name: string, signal?: AbortSignal): Promise<LakeboxSshKey>;
75
+ private request;
76
+ }
77
+ /**
78
+ * Returns whether an API error indicates that Lakeboxes are unavailable in the
79
+ * workspace or region.
80
+ */
81
+ export declare function isLakeboxUnavailable(error: unknown): boolean;
@@ -0,0 +1,199 @@
1
+ import { errorUtils, log, net } from "@dbx-tools/shared-core";
2
+ import { z } from "zod";
3
+ const LAKEBOX_ROOT = "/api/2.0/lakebox";
4
+ const LAKEBOXES_PATH = `${LAKEBOX_ROOT}/sandboxes`;
5
+ const SSH_KEYS_PATH = `${LAKEBOX_ROOT}/ssh-keys`;
6
+ const ORG_ID_HEADER = "X-Databricks-Org-Id";
7
+ const logger = log.logger("lakebox:rest");
8
+ export const LakeboxEntrySchema = z
9
+ .object({
10
+ sandboxId: z.string().describe("Lakebox identifier; also the SSH gateway username."),
11
+ status: z.string().describe("Upstream lifecycle status, such as Running or Stopped."),
12
+ gatewayHost: z.string().optional().describe("SSH gateway hostname."),
13
+ name: z.string().optional().describe("Display label."),
14
+ createTime: z.string().optional().describe("Creation time."),
15
+ lastStartTime: z.string().optional().describe("Last start time."),
16
+ idleTimeout: z.string().optional().describe("Platform idle timeout, such as 600s."),
17
+ noAutostop: z.boolean().optional().describe("Whether idle auto-stop is disabled."),
18
+ })
19
+ .passthrough()
20
+ .describe("Lakebox record returned by the Databricks Lakebox REST API.");
21
+ const LakeboxListSchema = z
22
+ .object({
23
+ sandboxes: z.array(LakeboxEntrySchema).default([]),
24
+ nextPageToken: z.string().optional(),
25
+ })
26
+ .passthrough();
27
+ export const LakeboxSshKeySchema = z
28
+ .object({
29
+ keyHash: z.string().describe("Registered public key hash."),
30
+ name: z.string().optional().describe("Key label."),
31
+ gatewayHost: z.string().optional().describe("Gateway hostname for this key."),
32
+ })
33
+ .passthrough()
34
+ .describe("Registered SSH key returned by the Databricks Lakebox REST API.");
35
+ const LakeboxSshKeyListSchema = z
36
+ .object({ sshKeys: z.array(LakeboxSshKeySchema).default([]) })
37
+ .passthrough();
38
+ /** Error raised for a non-success Lakebox REST response. */
39
+ export class LakeboxApiError extends Error {
40
+ status;
41
+ errorCode;
42
+ requestId;
43
+ constructor(message, status, errorCode, requestId) {
44
+ super(message);
45
+ this.status = status;
46
+ this.errorCode = errorCode;
47
+ this.requestId = requestId;
48
+ this.name = "LakeboxApiError";
49
+ }
50
+ }
51
+ /**
52
+ * REST client for Databricks Lakeboxes and registered SSH keys.
53
+ *
54
+ * Responses are validated before they reach callers. Diagnostics never include
55
+ * tokens or request headers.
56
+ */
57
+ export class LakeboxClient {
58
+ auth;
59
+ /** Creates a client for one workspace credential. */
60
+ constructor(auth) {
61
+ this.auth = auth;
62
+ }
63
+ /** Returns the workspace identifier, or the workspace origin when the identifier is unknown. */
64
+ async workspaceScope() {
65
+ await this.auth.ensureResolved?.();
66
+ return (process.env.DATABRICKS_WORKSPACE_ID?.trim() ||
67
+ this.auth.workspaceId?.trim() ||
68
+ net.urlBuilder(this.auth.host ?? "")?.origin ||
69
+ "workspace");
70
+ }
71
+ /** Lists every Lakebox visible to the caller, following pagination. */
72
+ async list(signal) {
73
+ const entries = [];
74
+ let pageToken;
75
+ do {
76
+ const query = new URLSearchParams({ page_size: "100" });
77
+ if (pageToken)
78
+ query.set("page_token", pageToken);
79
+ const response = LakeboxListSchema.parse(await this.request("GET", `${LAKEBOXES_PATH}?${query}`, undefined, signal));
80
+ entries.push(...response.sandboxes);
81
+ pageToken = response.nextPageToken || undefined;
82
+ } while (pageToken);
83
+ return entries;
84
+ }
85
+ /** Returns one Lakebox by ID. */
86
+ async get(id, signal) {
87
+ return LakeboxEntrySchema.parse(await this.request("GET", lakeboxPath(id), undefined, signal));
88
+ }
89
+ /** Creates a Lakebox with a Databricks-assigned display name. */
90
+ async create(signal) {
91
+ return LakeboxEntrySchema.parse(await this.request("POST", LAKEBOXES_PATH, { sandbox: {} }, signal));
92
+ }
93
+ /** Sets the platform idle timeout that stops the Lakebox after inactivity. */
94
+ async setIdleTimeout(id, seconds, signal) {
95
+ return LakeboxEntrySchema.parse(await this.request("PATCH", lakeboxPath(id), { sandbox_id: id, idle_timeout: `${seconds}s` }, signal));
96
+ }
97
+ /** Permanently deletes one Lakebox and its persistent home. */
98
+ async delete(id, signal) {
99
+ await this.request("DELETE", lakeboxPath(id), undefined, signal);
100
+ }
101
+ /** Requests a start and returns the updated record. */
102
+ async start(id, signal) {
103
+ return LakeboxEntrySchema.parse(await this.request("POST", `${lakeboxPath(id)}/start`, { sandbox_id: id }, signal));
104
+ }
105
+ /** Requests a stop and returns the updated record. */
106
+ async stop(id, signal) {
107
+ return LakeboxEntrySchema.parse(await this.request("POST", `${lakeboxPath(id)}/stop`, { sandbox_id: id }, signal));
108
+ }
109
+ /** Lists SSH public keys registered by the caller. */
110
+ async listKeys(signal) {
111
+ return LakeboxSshKeyListSchema.parse(await this.request("GET", SSH_KEYS_PATH, undefined, signal)).sshKeys;
112
+ }
113
+ /** Registers an SSH public key and returns the Databricks key record. */
114
+ async registerKey(publicKey, name, signal) {
115
+ return LakeboxSshKeySchema.parse(await this.request("POST", SSH_KEYS_PATH, { public_key: publicKey, name }, signal));
116
+ }
117
+ async request(method, path, payload, signal) {
118
+ await this.auth.ensureResolved?.();
119
+ const host = this.auth.host?.replace(/\/+$/, "");
120
+ if (!host)
121
+ throw new Error("Lakebox REST requests require a Databricks workspace host");
122
+ const headers = new Headers({ Accept: "application/json" });
123
+ const workspaceId = this.auth.workspaceId;
124
+ if (workspaceId && workspaceId !== "none")
125
+ headers.set(ORG_ID_HEADER, workspaceId);
126
+ if (payload !== undefined)
127
+ headers.set("Content-Type", "application/json");
128
+ await this.auth.authenticate(headers);
129
+ const startedAt = Date.now();
130
+ const metadata = { method, path: path.split("?")[0], hasPayload: payload !== undefined };
131
+ logger.debug("lakebox REST request", metadata);
132
+ let response;
133
+ try {
134
+ response = await fetch(`${host}${path}`, {
135
+ method,
136
+ headers,
137
+ ...(payload === undefined ? {} : { body: JSON.stringify(payload) }),
138
+ ...(signal ? { signal } : {}),
139
+ });
140
+ }
141
+ catch (error) {
142
+ logger.warn("lakebox REST request failed", {
143
+ ...metadata,
144
+ durationMs: Date.now() - startedAt,
145
+ error: errorUtils.toError(error),
146
+ });
147
+ throw error;
148
+ }
149
+ const text = await response.text();
150
+ const body = parseBody(text);
151
+ if (!response.ok) {
152
+ const record = z
153
+ .object({
154
+ message: z.string().optional(),
155
+ error_code: z.string().optional(),
156
+ request_id: z.string().optional(),
157
+ })
158
+ .passthrough()
159
+ .safeParse(body);
160
+ const details = record.success ? record.data : {};
161
+ const error = new LakeboxApiError(details.message || `Lakebox request failed (${response.status})`, response.status, details.error_code, details.request_id ?? response.headers.get("x-request-id") ?? undefined);
162
+ logger.warn("lakebox REST request failed", {
163
+ ...metadata,
164
+ durationMs: Date.now() - startedAt,
165
+ status: error.status,
166
+ errorCode: error.errorCode,
167
+ requestId: error.requestId,
168
+ });
169
+ throw error;
170
+ }
171
+ logger.debug("lakebox REST response", { ...metadata, durationMs: Date.now() - startedAt });
172
+ return body ?? {};
173
+ }
174
+ }
175
+ /**
176
+ * Returns whether an API error indicates that Lakeboxes are unavailable in the
177
+ * workspace or region.
178
+ */
179
+ export function isLakeboxUnavailable(error) {
180
+ if (!(error instanceof LakeboxApiError))
181
+ return false;
182
+ return (error.status === 404 ||
183
+ error.status === 503 ||
184
+ /not available in your region/i.test(error.message));
185
+ }
186
+ function lakeboxPath(id) {
187
+ return `${LAKEBOXES_PATH}/${encodeURIComponent(id)}`;
188
+ }
189
+ function parseBody(text) {
190
+ if (!text.trim())
191
+ return undefined;
192
+ try {
193
+ return JSON.parse(text);
194
+ }
195
+ catch {
196
+ return { message: text.slice(0, 4_000) };
197
+ }
198
+ }
199
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmVzdC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9yZXN0LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxVQUFVLEVBQUUsR0FBRyxFQUFFLEdBQUcsRUFBRSxNQUFNLHdCQUF3QixDQUFDO0FBQzlELE9BQU8sRUFBRSxDQUFDLEVBQUUsTUFBTSxLQUFLLENBQUM7QUFFeEIsTUFBTSxZQUFZLEdBQUcsa0JBQWtCLENBQUM7QUFDeEMsTUFBTSxjQUFjLEdBQUcsR0FBRyxZQUFZLFlBQVksQ0FBQztBQUNuRCxNQUFNLGFBQWEsR0FBRyxHQUFHLFlBQVksV0FBVyxDQUFDO0FBQ2pELE1BQU0sYUFBYSxHQUFHLHFCQUFxQixDQUFDO0FBQzVDLE1BQU0sTUFBTSxHQUFHLEdBQUcsQ0FBQyxNQUFNLENBQUMsY0FBYyxDQUFDLENBQUM7QUFFMUMsTUFBTSxDQUFDLE1BQU0sa0JBQWtCLEdBQUcsQ0FBQztLQUNoQyxNQUFNLENBQUM7SUFDTixTQUFTLEVBQUUsQ0FBQyxDQUFDLE1BQU0sRUFBRSxDQUFDLFFBQVEsQ0FBQyxvREFBb0QsQ0FBQztJQUNwRixNQUFNLEVBQUUsQ0FBQyxDQUFDLE1BQU0sRUFBRSxDQUFDLFFBQVEsQ0FBQyx3REFBd0QsQ0FBQztJQUNyRixXQUFXLEVBQUUsQ0FBQyxDQUFDLE1BQU0sRUFBRSxDQUFDLFFBQVEsRUFBRSxDQUFDLFFBQVEsQ0FBQyx1QkFBdUIsQ0FBQztJQUNwRSxJQUFJLEVBQUUsQ0FBQyxDQUFDLE1BQU0sRUFBRSxDQUFDLFFBQVEsRUFBRSxDQUFDLFFBQVEsQ0FBQyxnQkFBZ0IsQ0FBQztJQUN0RCxVQUFVLEVBQUUsQ0FBQyxDQUFDLE1BQU0sRUFBRSxDQUFDLFFBQVEsRUFBRSxDQUFDLFFBQVEsQ0FBQyxnQkFBZ0IsQ0FBQztJQUM1RCxhQUFhLEVBQUUsQ0FBQyxDQUFDLE1BQU0sRUFBRSxDQUFDLFFBQVEsRUFBRSxDQUFDLFFBQVEsQ0FBQyxrQkFBa0IsQ0FBQztJ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QUUsT0FBTyxLQUFLLENBQUM7SUFDdEQsT0FBTyxDQUNMLEtBQUssQ0FBQyxNQUFNLEtBQUssR0FBRztRQUNwQixLQUFLLENBQUMsTUFBTSxLQUFLLEdBQUc7UUFDcEIsK0JBQStCLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUMsQ0FDcEQsQ0FBQztBQUNKLENBQUM7QUFFRCxTQUFTLFdBQVcsQ0FBQyxFQUFVO0lBQzdCLE9BQU8sR0FBRyxjQUFjLElBQUksa0JBQWtCLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQztBQUN2RCxDQUFDO0FBRUQsU0FBUyxTQUFTLENBQUMsSUFBWTtJQUM3QixJQUFJLENBQUMsSUFBSSxDQUFDLElBQUksRUFBRTtRQUFFLE9BQU8sU0FBUyxDQUFDO0lBQ25DLElBQUksQ0FBQztRQUNILE9BQU8sSUFBSSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQVksQ0FBQztJQUNyQyxDQUFDO0lBQUMsTUFBTSxDQUFDO1FBQ1AsT0FBTyxFQUFFLE9BQU8sRUFBRSxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUMsRUFBRSxLQUFLLENBQUMsRUFBRSxDQUFDO0lBQzNDLENBQUM7QUFDSCxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgZXJyb3JVdGlscywgbG9nLCBuZXQgfSBmcm9tIFwiQGRieC10b29scy9zaGFyZWQtY29yZVwiO1xuaW1wb3J0IHsgeiB9IGZyb20gXCJ6b2RcIjtcblxuY29uc3QgTEFLRUJPWF9ST09UID0gXCIvYXBpLzIuMC9sYWtlYm94XCI7XG5jb25zdCBMQUtFQk9YRVNfUEFUSCA9IGAke0xBS0VCT1hfUk9PVH0vc2FuZGJveGVzYDtcbmNvbnN0IFNTSF9LRVlTX1BBVEggPSBgJHtMQUtFQk9YX1JPT1R9L3NzaC1rZXlzYDtcbmNvbnN0IE9SR19JRF9IRUFERVIgPSBcIlgtRGF0YWJyaWNrcy1PcmctSWRcIjtcbmNvbnN0IGxvZ2dlciA9IGxvZy5sb2dnZXIoXCJsYWtlYm94OnJlc3RcIik7XG5cbmV4cG9ydCBjb25zdCBMYWtlYm94RW50cnlTY2hlbWEgPSB6XG4gIC5vYmplY3Qoe1xuICAgIHNhbmRib3hJZDogei5zdHJpbmcoKS5kZXNjcmliZShcIkxha2Vib3ggaWRlbnRpZmllcjsgYWxzbyB0aGUgU1NIIGdhdGV3YXkgdXNlcm5hbWUuXCIpLFxuICAgIHN0YXR1czogei5zdHJpbmcoKS5kZXNjcmliZShcIlVwc3RyZWFtIGxpZmVjeWNsZSBzdGF0dXMsIHN1Y2ggYXMgUnVubmluZyBvciBTdG9wcGVkLlwiKSxcbiAgICBnYXRld2F5SG9zdDogei5zdHJpbmcoKS5vcHRpb25hbCgpLmRlc2NyaWJlKFwiU1NIIGdhdGV3YXkgaG9zdG5hbWUuXCIpLFxuICAgIG5hbWU6IHouc3RyaW5nKCkub3B0aW9uYWwoKS5kZXNjcmliZShcIkRpc3BsYXkgbGFiZWwuXCIpLFxuICAgIGNyZWF0ZVRpbWU6IHouc3RyaW5nKCkub3B0aW9uYWwoKS5kZXNjcmliZShcIkNyZWF0aW9uIHRpbWUuXCIpLFxuICAgIGxhc3RTdGFydFRpbWU6IHouc3RyaW5nKCkub3B0aW9uYWwoKS5kZXNjcmliZShcIkxhc3Qgc3RhcnQgdGltZS5cIiksXG4gICAgaWRsZVRpbWVvdXQ6IHouc3RyaW5nKCkub3B0aW9uYWwoKS5kZXNjcmliZShcIlBsYXRmb3JtIGlkbGUgdGltZW91dCwgc3VjaCBhcyA2MDBzLlwiKSxcbiAgICBub0F1dG9zdG9wOiB6LmJvb2xlYW4oKS5vcHRpb25hbCgpLmRlc2NyaWJlKFwiV2hldGhlciBpZGxlIGF1dG8tc3RvcCBpcyBkaXNhYmxlZC5cIiksXG4gIH0pXG4gIC5wYXNzdGhyb3VnaCgpXG4gIC5kZXNjcmliZShcIkxha2Vib3ggcmVjb3JkIHJldHVybmVkIGJ5IHRoZSBEYXRhYnJpY2tzIExha2Vib3ggUkVTVCBBUEkuXCIpO1xuLyoqIExha2Vib3ggcmVjb3JkIHJldHVybmVkIGJ5IHRoZSBEYXRhYnJpY2tzIExha2Vib3ggUkVTVCBBUEkuICovXG5leHBvcnQgdHlwZSBMYWtlYm94RW50cnkgPSB6LmluZmVyPHR5cGVvZiBMYWtlYm94RW50cnlTY2hlbWE+O1xuXG5jb25zdCBMYWtlYm94TGlzdFNjaGVtYSA9IHpcbiAgLm9iamVjdCh7XG4gICAgc2FuZGJveGVzOiB6LmFycmF5KExha2Vib3hFbnRyeVNjaGVtYSkuZGVmYXVsdChbXSksXG4gICAgbmV4dFBhZ2VUb2tlbjogei5zdHJpbmcoKS5vcHRpb25hbCgpLFxuICB9KVxuICAucGFzc3Rocm91Z2goKTtcblxuZXhwb3J0IGNvbnN0IExha2Vib3hTc2hLZXlTY2hlbWEgPSB6XG4gIC5vYmplY3Qoe1xuICAgIGtleUhhc2g6IHouc3RyaW5nKCkuZGVzY3JpYmUoXCJSZWdpc3RlcmVkIHB1YmxpYyBrZXkgaGFzaC5cIiksXG4gICAgbmFtZTogei5zdHJpbmcoKS5vcHRpb25hbCgpLmRlc2NyaWJlKFwiS2V5IGxhYmVsLlwiKSxcbiAgICBnYXRld2F5SG9zdDogei5zdHJpbmcoKS5vcHRpb25hbCgpLmRlc2NyaWJlKFwiR2F0ZXdheSBob3N0bmFtZSBmb3IgdGhpcyBrZXkuXCIpLFxuICB9KVxuICAucGFzc3Rocm91Z2goKVxuICAuZGVzY3JpYmUoXCJSZWdpc3RlcmVkIFNTSCBrZXkgcmV0dXJuZWQgYnkgdGhlIERhdGFicmlja3MgTGFrZWJveCBSRVNUIEFQSS5cIik7XG4vKiogUmVnaXN0ZXJlZCBTU0gga2V5IHJldHVybmVkIGJ5IHRoZSBEYXRhYnJpY2tzIExha2Vib3ggUkVTVCBBUEkuICovXG5leHBvcnQgdHlwZSBMYWtlYm94U3NoS2V5ID0gei5pbmZlcjx0eXBlb2YgTGFrZWJveFNzaEtleVNjaGVtYT47XG5cbmNvbnN0IExha2Vib3hTc2hLZXlMaXN0U2NoZW1hID0gelxuICAub2JqZWN0KHsgc3NoS2V5czogei5hcnJheShMYWtlYm94U3NoS2V5U2NoZW1hKS5kZWZhdWx0KFtdKSB9KVxuICAucGFzc3Rocm91Z2goKTtcblxuLyoqXG4gKiBXb3Jrc3BhY2UgY3JlZGVudGlhbHMgZm9yIExha2Vib3ggUkVTVCBjYWxscy5cbiAqXG4gKiBUaGUgRGF0YWJyaWNrcyBTREsgYW5kIEFwcEtpdCBgV29ya3NwYWNlQ2xpZW50LmNvbmZpZ2Agc2F0aXNmeSB0aGlzIHNoYXBlLCBhc1xuICogZG9lcyBhIHNtYWxsIGFkYXB0ZXIgb3ZlciBgQGRieC10b29scy9hdXRoYC4gTGFrZWJveCBsaWZlY3ljbGUgY2FsbHMgbXVzdCB1c2VcbiAqIHRoZSBhcHAgc2VydmljZSBwcmluY2lwYWwsIG5ldmVyIHJlcXVlc3Qtc2NvcGVkIE9CTyBjcmVkZW50aWFscy5cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBMYWtlYm94QXV0aCB7XG4gIC8qKiBXb3Jrc3BhY2UgVVJMLiAqL1xuICByZWFkb25seSBob3N0Pzogc3RyaW5nO1xuICAvKiogTnVtZXJpYyB3b3Jrc3BhY2UgaWRlbnRpZmllciwgd2hlbiBrbm93bi4gKi9cbiAgcmVhZG9ubHkgd29ya3NwYWNlSWQ/OiBzdHJpbmc7XG4gIC8qKiBSZXNvbHZlcyBsYXp5IGNvbmZpZ3VyYXRpb24gYmVmb3JlIGBob3N0YCBpcyByZWFkLiAqL1xuICBlbnN1cmVSZXNvbHZlZD8oKTogUHJvbWlzZTx2b2lkPjtcbiAgLyoqIEFkZHMgYXV0aGVudGljYXRpb24gaGVhZGVycyB0byBvbmUgcmVxdWVzdC4gKi9cbiAgYXV0aGVudGljYXRlKGhlYWRlcnM6IEhlYWRlcnMpOiBQcm9taXNlPHZvaWQ+O1xufVxuXG4vKiogRXJyb3IgcmFpc2VkIGZvciBhIG5vbi1zdWNjZXNzIExha2Vib3ggUkVTVCByZXNwb25zZS4gKi9cbmV4cG9ydCBjbGFzcyBMYWtlYm94QXBpRXJyb3IgZXh0ZW5kcyBFcnJvciB7XG4gIGNvbnN0cnVjdG9yKFxuICAgIG1lc3NhZ2U6IHN0cmluZyxcbiAgICByZWFkb25seSBzdGF0dXM6IG51bWJlcixcbiAgICByZWFkb25seSBlcnJvckNvZGU/OiBzdHJpbmcsXG4gICAgcmVhZG9ubHkgcmVxdWVzdElkPzogc3RyaW5nLFxuICApIHtcbiAgICBzdXBlcihtZXNzYWdlKTtcbiAgICB0aGlzLm5hbWUgPSBcIkxha2Vib3hBcGlFcnJvclwiO1xuICB9XG59XG5cbnR5cGUgUmVxdWVzdE1ldGhvZCA9IFwiR0VUXCIgfCBcIlBPU1RcIiB8IFwiUEFUQ0hcIiB8IFwiREVMRVRFXCI7XG5cbi8qKlxuICogUkVTVCBjbGllbnQgZm9yIERhdGFicmlja3MgTGFrZWJveGVzIGFuZCByZWdpc3RlcmVkIFNTSCBrZXlzLlxuICpcbiAqIFJlc3BvbnNlcyBhcmUgdmFsaWRhdGVkIGJlZm9yZSB0aGV5IHJlYWNoIGNhbGxlcnMuIERpYWdub3N0aWNzIG5ldmVyIGluY2x1ZGVcbiAqIHRva2VucyBvciByZXF1ZXN0IGhlYWRlcnMuXG4gKi9cbmV4cG9ydCBjbGFzcyBMYWtlYm94Q2xpZW50IHtcbiAgLyoqIENyZWF0ZXMgYSBjbGllbnQgZm9yIG9uZSB3b3Jrc3BhY2UgY3JlZGVudGlhbC4gKi9cbiAgY29uc3RydWN0b3IocHJpdmF0ZSByZWFkb25seSBhdXRoOiBMYWtlYm94QXV0aCkge31cblxuICAvKiogUmV0dXJucyB0aGUgd29ya3NwYWNlIGlkZW50aWZpZXIsIG9yIHRoZSB3b3Jrc3BhY2Ugb3JpZ2luIHdoZW4gdGhlIGlkZW50aWZpZXIgaXMgdW5rbm93bi4gKi9cbiAgYXN5bmMgd29ya3NwYWNlU2NvcGUoKTogUHJvbWlzZTxzdHJpbmc+IHtcbiAgICBhd2FpdCB0aGlzLmF1dGguZW5zdXJlUmVzb2x2ZWQ/LigpO1xuICAgIHJldHVybiAoXG4gICAgICBwcm9jZXNzLmVudi5EQVRBQlJJQ0tTX1dPUktTUEFDRV9JRD8udHJpbSgpIHx8XG4gICAgICB0aGlzLmF1dGgud29ya3NwYWNlSWQ/LnRyaW0oKSB8fFxuICAgICAgbmV0LnVybEJ1aWxkZXIodGhpcy5hdXRoLmhvc3QgPz8gXCJcIik/Lm9yaWdpbiB8fFxuICAgICAgXCJ3b3Jrc3BhY2VcIlxuICAgICk7XG4gIH1cblxuICAvKiogTGlzdHMgZXZlcnkgTGFrZWJveCB2aXNpYmxlIHRvIHRoZSBjYWxsZXIsIGZvbGxvd2luZyBwYWdpbmF0aW9uLiAqL1xuICBhc3luYyBsaXN0KHNpZ25hbD86IEFib3J0U2lnbmFsKTogUHJvbWlzZTxMYWtlYm94RW50cnlbXT4ge1xuICAgIGNvbnN0IGVudHJpZXM6IExha2Vib3hFbnRyeVtdID0gW107XG4gICAgbGV0IHBhZ2VUb2tlbjogc3RyaW5nIHwgdW5kZWZpbmVkO1xuICAgIGRvIHtcbiAgICAgIGNvbnN0IHF1ZXJ5ID0gbmV3IFVSTFNlYXJjaFBhcmFtcyh7IHBhZ2Vfc2l6ZTogXCIxMDBcIiB9KTtcbiAgICAgIGlmIChwYWdlVG9rZW4pIHF1ZXJ5LnNldChcInBhZ2VfdG9rZW5cIiwgcGFnZVRva2VuKTtcbiAgICAgIGNvbnN0IHJlc3BvbnNlID0gTGFrZWJveExpc3RTY2hlbWEucGFyc2UoXG4gICAgICAgIGF3YWl0IHRoaXMucmVxdWVzdChcIkdFVFwiLCBgJHtMQUtFQk9YRVNfUEFUSH0/JHtxdWVyeX1gLCB1bmRlZmluZWQsIHNpZ25hbCksXG4gICAgICApO1xuICAgICAgZW50cmllcy5wdXNoKC4uLnJlc3BvbnNlLnNhbmRib3hlcyk7XG4gICAgICBwYWdlVG9rZW4gPSByZXNwb25zZS5uZXh0UGFnZVRva2VuIHx8IHVuZGVmaW5lZDtcbiAgICB9IHdoaWxlIChwYWdlVG9rZW4pO1xuICAgIHJldHVybiBlbnRyaWVzO1xuICB9XG5cbiAgLyoqIFJldHVybnMgb25lIExha2Vib3ggYnkgSUQuICovXG4gIGFzeW5jIGdldChpZDogc3RyaW5nLCBzaWduYWw/OiBBYm9ydFNpZ25hbCk6IFByb21pc2U8TGFrZWJveEVudHJ5PiB7XG4gICAgcmV0dXJuIExha2Vib3hFbnRyeVNjaGVtYS5wYXJzZShhd2FpdCB0aGlzLnJlcXVlc3QoXCJHRVRcIiwgbGFrZWJveFBhdGgoaWQpLCB1bmRlZmluZWQsIHNpZ25hbCkpO1xuICB9XG5cbiAgLyoqIENyZWF0ZXMgYSBMYWtlYm94IHdpdGggYSBEYXRhYnJpY2tzLWFzc2lnbmVkIGRpc3BsYXkgbmFtZS4gKi9cbiAgYXN5bmMgY3JlYXRlKHNpZ25hbD86IEFib3J0U2lnbmFsKTogUHJvbWlzZTxMYWtlYm94RW50cnk+IHtcbiAgICByZXR1cm4gTGFrZWJveEVudHJ5U2NoZW1hLnBhcnNlKFxuICAgICAgYXdhaXQgdGhpcy5yZXF1ZXN0KFwiUE9TVFwiLCBMQUtFQk9YRVNfUEFUSCwgeyBzYW5kYm94OiB7fSB9LCBzaWduYWwpLFxuICAgICk7XG4gIH1cblxuICAvKiogU2V0cyB0aGUgcGxhdGZvcm0gaWRsZSB0aW1lb3V0IHRoYXQgc3RvcHMgdGhlIExha2Vib3ggYWZ0ZXIgaW5hY3Rpdml0eS4gKi9cbiAgYXN5bmMgc2V0SWRsZVRpbWVvdXQoaWQ6IHN0cmluZywgc2Vjb25kczogbnVtYmVyLCBzaWduYWw/OiBBYm9ydFNpZ25hbCk6IFByb21pc2U8TGFrZWJveEVudHJ5PiB7XG4gICAgcmV0dXJuIExha2Vib3hFbnRyeVNjaGVtYS5wYXJzZShcbiAgICAgIGF3YWl0IHRoaXMucmVxdWVzdChcbiAgICAgICAgXCJQQVRDSFwiLFxuICAgICAgICBsYWtlYm94UGF0aChpZCksXG4gICAgICAgIHsgc2FuZGJveF9pZDogaWQsIGlkbGVfdGltZW91dDogYCR7c2Vjb25kc31zYCB9LFxuICAgICAgICBzaWduYWwsXG4gICAgICApLFxuICAgICk7XG4gIH1cblxuICAvKiogUGVybWFuZW50bHkgZGVsZXRlcyBvbmUgTGFrZWJveCBhbmQgaXRzIHBlcnNpc3RlbnQgaG9tZS4gKi9cbiAgYXN5bmMgZGVsZXRlKGlkOiBzdHJpbmcsIHNpZ25hbD86IEFib3J0U2lnbmFsKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgYXdhaXQgdGhpcy5yZXF1ZXN0KFwiREVMRVRFXCIsIGxha2Vib3hQYXRoKGlkKSwgdW5kZWZpbmVkLCBzaWduYWwpO1xuICB9XG5cbiAgLyoqIFJlcXVlc3RzIGEgc3RhcnQgYW5kIHJldHVybnMgdGhlIHVwZGF0ZWQgcmVjb3JkLiAqL1xuICBhc3luYyBzdGFydChpZDogc3RyaW5nLCBzaWduYWw/OiBBYm9ydFNpZ25hbCk6IFByb21pc2U8TGFrZWJveEVudHJ5PiB7XG4gICAgcmV0dXJuIExha2Vib3hFbnRyeVNjaGVtYS5wYXJzZShcbiAgICAgIGF3YWl0IHRoaXMucmVxdWVzdChcIlBPU1RcIiwgYCR7bGFrZWJveFBhdGgoaWQpfS9zdGFydGAsIHsgc2FuZGJveF9pZDogaWQgfSwgc2lnbmFsKSxcbiAgICApO1xuICB9XG5cbiAgLyoqIFJlcXVlc3RzIGEgc3RvcCBhbmQgcmV0dXJucyB0aGUgdXBkYXRlZCByZWNvcmQuICovXG4gIGFzeW5jIHN0b3AoaWQ6IHN0cmluZywgc2lnbmFsPzogQWJvcnRTaWduYWwpOiBQcm9taXNlPExha2Vib3hFbnRyeT4ge1xuICAgIHJldHVybiBMYWtlYm94RW50cnlTY2hlbWEucGFyc2UoXG4gICAgICBhd2FpdCB0aGlzLnJlcXVlc3QoXCJQT1NUXCIsIGAke2xha2Vib3hQYXRoKGlkKX0vc3RvcGAsIHsgc2FuZGJveF9pZDogaWQgfSwgc2lnbmFsKSxcbiAgICApO1xuICB9XG5cbiAgLyoqIExpc3RzIFNTSCBwdWJsaWMga2V5cyByZWdpc3RlcmVkIGJ5IHRoZSBjYWxsZXIuICovXG4gIGFzeW5jIGxpc3RLZXlzKHNpZ25hbD86IEFib3J0U2lnbmFsKTogUHJvbWlzZTxMYWtlYm94U3NoS2V5W10+IHtcbiAgICByZXR1cm4gTGFrZWJveFNzaEtleUxpc3RTY2hlbWEucGFyc2UoXG4gICAgICBhd2FpdCB0aGlzLnJlcXVlc3QoXCJHRVRcIiwgU1NIX0tFWVNfUEFUSCwgdW5kZWZpbmVkLCBzaWduYWwpLFxuICAgICkuc3NoS2V5cztcbiAgfVxuXG4gIC8qKiBSZWdpc3RlcnMgYW4gU1NIIHB1YmxpYyBrZXkgYW5kIHJldHVybnMgdGhlIERhdGFicmlja3Mga2V5IHJlY29yZC4gKi9cbiAgYXN5bmMgcmVnaXN0ZXJLZXkocHVibGljS2V5OiBzdHJpbmcsIG5hbWU6IHN0cmluZywgc2lnbmFsPzogQWJvcnRTaWduYWwpOiBQcm9taXNlPExha2Vib3hTc2hLZXk+IHtcbiAgICByZXR1cm4gTGFrZWJveFNzaEtleVNjaGVtYS5wYXJzZShcbiAgICAgIGF3YWl0IHRoaXMucmVxdWVzdChcIlBPU1RcIiwgU1NIX0tFWVNfUEFUSCwgeyBwdWJsaWNfa2V5OiBwdWJsaWNLZXksIG5hbWUgfSwgc2lnbmFsKSxcbiAgICApO1xuICB9XG5cbiAgcHJpdmF0ZSBhc3luYyByZXF1ZXN0KFxuICAgIG1ldGhvZDogUmVxdWVzdE1ldGhvZCxcbiAgICBwYXRoOiBzdHJpbmcsXG4gICAgcGF5bG9hZDogdW5rbm93bixcbiAgICBzaWduYWw/OiBBYm9ydFNpZ25hbCxcbiAgKTogUHJvbWlzZTx1bmtub3duPiB7XG4gICAgYXdhaXQgdGhpcy5hdXRoLmVuc3VyZVJlc29sdmVkPy4oKTtcbiAgICBjb25zdCBob3N0ID0gdGhpcy5hdXRoLmhvc3Q/LnJlcGxhY2UoL1xcLyskLywgXCJcIik7XG4gICAgaWYgKCFob3N0KSB0aHJvdyBuZXcgRXJyb3IoXCJMYWtlYm94IFJFU1QgcmVxdWVzdHMgcmVxdWlyZSBhIERhdGFicmlja3Mgd29ya3NwYWNlIGhvc3RcIik7XG4gICAgY29uc3QgaGVhZGVycyA9IG5ldyBIZWFkZXJzKHsgQWNjZXB0OiBcImFwcGxpY2F0aW9uL2pzb25cIiB9KTtcbiAgICBjb25zdCB3b3Jrc3BhY2VJZCA9IHRoaXMuYXV0aC53b3Jrc3BhY2VJZDtcbiAgICBpZiAod29ya3NwYWNlSWQgJiYgd29ya3NwYWNlSWQgIT09IFwibm9uZVwiKSBoZWFkZXJzLnNldChPUkdfSURfSEVBREVSLCB3b3Jrc3BhY2VJZCk7XG4gICAgaWYgKHBheWxvYWQgIT09IHVuZGVmaW5lZCkgaGVhZGVycy5zZXQoXCJDb250ZW50LVR5cGVcIiwgXCJhcHBsaWNhdGlvbi9qc29uXCIpO1xuICAgIGF3YWl0IHRoaXMuYXV0aC5hdXRoZW50aWNhdGUoaGVhZGVycyk7XG4gICAgY29uc3Qgc3RhcnRlZEF0ID0gRGF0ZS5ub3coKTtcbiAgICBjb25zdCBtZXRhZGF0YSA9IHsgbWV0aG9kLCBwYXRoOiBwYXRoLnNwbGl0KFwiP1wiKVswXSwgaGFzUGF5bG9hZDogcGF5bG9hZCAhPT0gdW5kZWZpbmVkIH07XG4gICAgbG9nZ2VyLmRlYnVnKFwibGFrZWJveCBSRVNUIHJlcXVlc3RcIiwgbWV0YWRhdGEpO1xuICAgIGxldCByZXNwb25zZTogUmVzcG9uc2U7XG4gICAgdHJ5IHtcbiAgICAgIHJlc3BvbnNlID0gYXdhaXQgZmV0Y2goYCR7aG9zdH0ke3BhdGh9YCwge1xuICAgICAgICBtZXRob2QsXG4gICAgICAgIGhlYWRlcnMsXG4gICAgICAgIC4uLihwYXlsb2FkID09PSB1bmRlZmluZWQgPyB7fSA6IHsgYm9keTogSlNPTi5zdHJpbmdpZnkocGF5bG9hZCkgfSksXG4gICAgICAgIC4uLihzaWduYWwgPyB7IHNpZ25hbCB9IDoge30pLFxuICAgICAgfSk7XG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIGxvZ2dlci53YXJuKFwibGFrZWJveCBSRVNUIHJlcXVlc3QgZmFpbGVkXCIsIHtcbiAgICAgICAgLi4ubWV0YWRhdGEsXG4gICAgICAgIGR1cmF0aW9uTXM6IERhdGUubm93KCkgLSBzdGFydGVkQXQsXG4gICAgICAgIGVycm9yOiBlcnJvclV0aWxzLnRvRXJyb3IoZXJyb3IpLFxuICAgICAgfSk7XG4gICAgICB0aHJvdyBlcnJvcjtcbiAgICB9XG4gICAgY29uc3QgdGV4dCA9IGF3YWl0IHJlc3BvbnNlLnRleHQoKTtcbiAgICBjb25zdCBib2R5ID0gcGFyc2VCb2R5KHRleHQpO1xuICAgIGlmICghcmVzcG9uc2Uub2spIHtcbiAgICAgIGNvbnN0IHJlY29yZCA9IHpcbiAgICAgICAgLm9iamVjdCh7XG4gICAgICAgICAgbWVzc2FnZTogei5zdHJpbmcoKS5vcHRpb25hbCgpLFxuICAgICAgICAgIGVycm9yX2NvZGU6IHouc3RyaW5nKCkub3B0aW9uYWwoKSxcbiAgICAgICAgICByZXF1ZXN0X2lkOiB6LnN0cmluZygpLm9wdGlvbmFsKCksXG4gICAgICAgIH0pXG4gICAgICAgIC5wYXNzdGhyb3VnaCgpXG4gICAgICAgIC5zYWZlUGFyc2UoYm9keSk7XG4gICAgICBjb25zdCBkZXRhaWxzID0gcmVjb3JkLnN1Y2Nlc3MgPyByZWNvcmQuZGF0YSA6IHt9O1xuICAgICAgY29uc3QgZXJyb3IgPSBuZXcgTGFrZWJveEFwaUVycm9yKFxuICAgICAgICBkZXRhaWxzLm1lc3NhZ2UgfHwgYExha2Vib3ggcmVxdWVzdCBmYWlsZWQgKCR7cmVzcG9uc2Uuc3RhdHVzfSlgLFxuICAgICAgICByZXNwb25zZS5zdGF0dXMsXG4gICAgICAgIGRldGFpbHMuZXJyb3JfY29kZSxcbiAgICAgICAgZGV0YWlscy5yZXF1ZXN0X2lkID8/IHJlc3BvbnNlLmhlYWRlcnMuZ2V0KFwieC1yZXF1ZXN0LWlkXCIpID8/IHVuZGVmaW5lZCxcbiAgICAgICk7XG4gICAgICBsb2dnZXIud2FybihcImxha2Vib3ggUkVTVCByZXF1ZXN0IGZhaWxlZFwiLCB7XG4gICAgICAgIC4uLm1ldGFkYXRhLFxuICAgICAgICBkdXJhdGlvbk1zOiBEYXRlLm5vdygpIC0gc3RhcnRlZEF0LFxuICAgICAgICBzdGF0dXM6IGVycm9yLnN0YXR1cyxcbiAgICAgICAgZXJyb3JDb2RlOiBlcnJvci5lcnJvckNvZGUsXG4gICAgICAgIHJlcXVlc3RJZDogZXJyb3IucmVxdWVzdElkLFxuICAgICAgfSk7XG4gICAgICB0aHJvdyBlcnJvcjtcbiAgICB9XG4gICAgbG9nZ2VyLmRlYnVnKFwibGFrZWJveCBSRVNUIHJlc3BvbnNlXCIsIHsgLi4ubWV0YWRhdGEsIGR1cmF0aW9uTXM6IERhdGUubm93KCkgLSBzdGFydGVkQXQgfSk7XG4gICAgcmV0dXJuIGJvZHkgPz8ge307XG4gIH1cbn1cblxuLyoqXG4gKiBSZXR1cm5zIHdoZXRoZXIgYW4gQVBJIGVycm9yIGluZGljYXRlcyB0aGF0IExha2Vib3hlcyBhcmUgdW5hdmFpbGFibGUgaW4gdGhlXG4gKiB3b3Jrc3BhY2Ugb3IgcmVnaW9uLlxuICovXG5leHBvcnQgZnVuY3Rpb24gaXNMYWtlYm94VW5hdmFpbGFibGUoZXJyb3I6IHVua25vd24pOiBib29sZWFuIHtcbiAgaWYgKCEoZXJyb3IgaW5zdGFuY2VvZiBMYWtlYm94QXBpRXJyb3IpKSByZXR1cm4gZmFsc2U7XG4gIHJldHVybiAoXG4gICAgZXJyb3Iuc3RhdHVzID09PSA0MDQgfHxcbiAgICBlcnJvci5zdGF0dXMgPT09IDUwMyB8fFxuICAgIC9ub3QgYXZhaWxhYmxlIGluIHlvdXIgcmVnaW9uL2kudGVzdChlcnJvci5tZXNzYWdlKVxuICApO1xufVxuXG5mdW5jdGlvbiBsYWtlYm94UGF0aChpZDogc3RyaW5nKTogc3RyaW5nIHtcbiAgcmV0dXJuIGAke0xBS0VCT1hFU19QQVRIfS8ke2VuY29kZVVSSUNvbXBvbmVudChpZCl9YDtcbn1cblxuZnVuY3Rpb24gcGFyc2VCb2R5KHRleHQ6IHN0cmluZyk6IHVua25vd24ge1xuICBpZiAoIXRleHQudHJpbSgpKSByZXR1cm4gdW5kZWZpbmVkO1xuICB0cnkge1xuICAgIHJldHVybiBKU09OLnBhcnNlKHRleHQpIGFzIHVua25vd247XG4gIH0gY2F0Y2gge1xuICAgIHJldHVybiB7IG1lc3NhZ2U6IHRleHQuc2xpY2UoMCwgNF8wMDApIH07XG4gIH1cbn1cbiJdfQ==
@@ -0,0 +1,89 @@
1
+ import type { Duplex } from "node:stream";
2
+ import { SshCommand } from "./_ssh.ts";
3
+ import type { Ssh2PatchMode, SshTransportMode } from "./transport.ts";
4
+ export { SshCommand, sshCommandScript, type SshCommandIdentity } from "./_ssh.ts";
5
+ /** Connection, key, host-verification, and command settings for one SSH machine. */
6
+ export interface SshSessionOptions {
7
+ /** Databricks Lakebox gateway hostname. */
8
+ host: string;
9
+ /** SSH gateway port. */
10
+ port: number;
11
+ /** SSH username accepted by the gateway: the Lakebox ID. */
12
+ username: string;
13
+ /** In-memory private key used for the verified SSH handshake and ssh2 fallback. */
14
+ privateKey: string;
15
+ /** Private key file used by native OpenSSH. */
16
+ privateKeyPath: string;
17
+ /** Dedicated OpenSSH known-host file for this workspace, user, and gateway. */
18
+ knownHostsPath: string;
19
+ /** Connection timeout in milliseconds. */
20
+ connectTimeoutMs: number;
21
+ /** SSH transport selected for this session. */
22
+ sshTransport: SshTransportMode;
23
+ /** ssh2 missing-exec-reply patch policy. */
24
+ ssh2Patch: Ssh2PatchMode;
25
+ /** Previously trusted SHA-256 host-key fingerprint. */
26
+ knownHost?: string;
27
+ /** Persists the accepted host key for both ssh2 and native OpenSSH. */
28
+ rememberHost?: (fingerprint: string, key: Buffer) => Promise<void>;
29
+ /** Native OpenSSH executable. Defaults to `ssh` on `PATH`. */
30
+ sshCommand?: string;
31
+ /** Resolves public fallback addresses for a service-direct gateway. */
32
+ resolvePublicAddresses?: (host: string) => Promise<string[]>;
33
+ }
34
+ /**
35
+ * Verified SSH session that delegates commands and remote TCP connections to
36
+ * the transport selected by `src/_ssh.ts`.
37
+ *
38
+ * The initial ssh2 handshake verifies and persists the Databricks gateway host
39
+ * key. The selected transport then starts its pooled command and forwarding
40
+ * resources. Resolved transport and patch policy determine whether the verified
41
+ * client seeds the ssh2 pool or is replaced by native OpenSSH ControlMasters.
42
+ */
43
+ export declare class SshSession {
44
+ private readonly options;
45
+ private readonly activeCommands;
46
+ private readonly pendingClients;
47
+ private transport?;
48
+ private connecting?;
49
+ private closing?;
50
+ private knownHost?;
51
+ private closed;
52
+ /** Creates a disconnected session. Call {@link connect} or another operation to connect. */
53
+ constructor(options: SshSessionOptions);
54
+ /**
55
+ * Verifies the gateway, resolves its public fallback when necessary, and
56
+ * selects the command and forwarding transport.
57
+ */
58
+ connect(): Promise<void>;
59
+ private connectWithFallback;
60
+ private connectHost;
61
+ private createVerifiedClient;
62
+ /**
63
+ * Starts one command as a Lakebox user and returns its live output and
64
+ * completion state immediately.
65
+ */
66
+ execute(command: string, args: string[], options: {
67
+ user: {
68
+ name: string;
69
+ home: string;
70
+ };
71
+ cwd?: string;
72
+ env?: Record<string, string>;
73
+ timeoutMs: number;
74
+ signal?: AbortSignal;
75
+ }): SshCommand;
76
+ private startCommand;
77
+ /** Opens a remote TCP connection through native SOCKS5 or ssh2 direct forwarding. */
78
+ forwardOut(remoteHost: string, remotePort: number): Promise<Duplex>;
79
+ /** Cancels active commands, closes the selected transport, and clears connection state. */
80
+ close(): Promise<void>;
81
+ private closeResources;
82
+ }
83
+ /**
84
+ * Resolves public IPv4 addresses for a Databricks service-direct gateway.
85
+ *
86
+ * Returns an empty list for other hostnames. DNS-over-HTTPS requests time out
87
+ * after five seconds and reject invalid responses.
88
+ */
89
+ export declare function resolvePublicGatewayAddresses(host: string, fetcher?: typeof fetch): Promise<string[]>;