@dbx-tools/lakebox 0.9.131 → 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.
package/README.md CHANGED
@@ -2,48 +2,146 @@
2
2
 
3
3
  Connect to, provision, and run commands on Databricks Lakeboxes.
4
4
 
5
- The package provides the Lakebox REST client, lifecycle convergence, and a
6
- verified SSH session with pooled native OpenSSH or ssh2 command and forwarding
7
- transport. It has no AppKit, React, or Lakebase dependency. User accounts,
8
- resource identity, and services belong to `@dbx-tools/appkit-lakebox`.
9
-
10
5
  ## Provision a Lakebox
11
6
 
12
7
  ```ts
8
+ import { client as authClient } from "@dbx-tools/auth";
13
9
  import { LakeboxClient } from "@dbx-tools/lakebox/rest";
14
10
  import { ensureLakeboxRunning } from "@dbx-tools/lakebox/lifecycle";
15
11
 
16
- const api = new LakeboxClient(workspaceClient.config);
12
+ const auth = await authClient.createAuthClient({ profile: "MY-PROFILE" });
13
+ const api = new LakeboxClient({
14
+ host: auth.host,
15
+ ...(auth.workspaceId ? { workspaceId: auth.workspaceId } : {}),
16
+ authenticate: async (headers) => {
17
+ for (const [name, value] of Object.entries(await auth.headers())) {
18
+ headers.set(name, value);
19
+ }
20
+ },
21
+ });
17
22
  const entry = await api.create();
18
23
  await api.setIdleTimeout(entry.sandboxId, 3_600);
19
24
  const running = await ensureLakeboxRunning(api, entry);
20
25
  ```
21
26
 
22
27
  `LakeboxClient` accepts any credential object with `host` and
23
- `authenticate(headers)`, such as an AppKit or Databricks SDK
24
- `WorkspaceClient.config`. Use the app service principal for lifecycle calls.
28
+ `authenticate(headers)`. AppKit and the Databricks SDK
29
+ `WorkspaceClient.config` satisfy this contract directly. The example adapts
30
+ `@dbx-tools/auth` for an explicit local profile. Use the app service principal
31
+ for lifecycle calls in a Databricks App.
32
+
33
+ ## Connect and run a command
25
34
 
26
- ## Run a command
35
+ Create or load an SSH key, register it with the workspace, verify the gateway
36
+ host key, and close the session when work finishes:
27
37
 
28
38
  ```ts
39
+ import { SshKeyStore } from "@dbx-tools/lakebox/key-store";
40
+ import type { LakeboxClient, LakeboxEntry } from "@dbx-tools/lakebox/rest";
29
41
  import { SshSession } from "@dbx-tools/lakebox/session";
30
42
 
31
- const command = session.execute("sh", ["-lc", "uname -a"], {
32
- user: { name: "lakebox-abc1234", home: "/home/lakebox-abc1234" },
33
- timeoutMs: 30_000,
34
- });
35
- for await (const chunk of command.stdout) process.stdout.write(chunk);
36
- const result = await command.result;
43
+ export async function runCommand(
44
+ api: LakeboxClient,
45
+ running: LakeboxEntry,
46
+ user: { name: string; home: string },
47
+ ): Promise<void> {
48
+ const owner = "my-service";
49
+ const keys = new SshKeyStore();
50
+ const key = await keys.ensureRegistered(api, owner);
51
+ const gatewayHost = running.gatewayHost ?? key.gatewayHost;
52
+ if (!gatewayHost) {
53
+ throw new Error("The Lakebox API did not return an SSH gateway host");
54
+ }
55
+
56
+ const gatewayPort = 2_222;
57
+ const scope = await api.workspaceScope();
58
+ const knownHost = await keys.knownHost(scope, owner, gatewayHost, gatewayPort);
59
+ const session = new SshSession({
60
+ host: gatewayHost,
61
+ port: gatewayPort,
62
+ username: running.sandboxId,
63
+ privateKey: key.privateKey,
64
+ privateKeyPath: key.privateKeyPath,
65
+ knownHostsPath: keys.knownHostsPath(scope, owner, gatewayHost, gatewayPort),
66
+ connectTimeoutMs: 30_000,
67
+ sshTransport: "auto",
68
+ ssh2Patch: "auto",
69
+ ...(knownHost ? { knownHost } : {}),
70
+ rememberHost: (fingerprint, hostKey) =>
71
+ keys.rememberHost(scope, owner, gatewayHost, gatewayPort, fingerprint, hostKey),
72
+ });
73
+
74
+ try {
75
+ await session.connect();
76
+ const command = session.execute("sh", ["-lc", "uname -a"], {
77
+ user,
78
+ timeoutMs: 30_000,
79
+ });
80
+ const result = await command.result;
81
+ if (!result.success) {
82
+ throw new Error(result.stderr || `Command exited with ${result.exitCode}`);
83
+ }
84
+ } finally {
85
+ await session.close();
86
+ }
87
+ }
37
88
  ```
38
89
 
39
90
  Every command clears inherited Databricks credentials and SSH agent variables
40
- before running. `forwardOut(host, port)` opens a forwarded TCP stream through a
41
- separate pool, so long-lived WebSockets never consume the warm command
91
+ before it runs. `execute()` returns a live `SshCommand`. Its `stdout` and
92
+ `stderr` fields are async iterables, awaiting the command returns its numeric
93
+ exit code, and `result` returns captured output and timing metadata.
94
+
95
+ The low-level package doesn't create Linux users. Pass an account that already
96
+ exists on the Lakebox. `@dbx-tools/appkit-lakebox` creates and isolates
97
+ application user accounts before it runs their commands.
98
+
99
+ `forwardOut(host, port)` opens a forwarded TCP stream through a separate pool.
100
+ Long-lived HTTP and WebSocket streams don't consume the warm command
42
101
  connection.
43
102
 
103
+ ## Stop or delete a Lakebox
104
+
105
+ Use lifecycle convergence when you need to wait for a terminal state:
106
+
107
+ ```ts
108
+ import { ensureLakeboxStopped } from "@dbx-tools/lakebox/lifecycle";
109
+ import type { LakeboxClient, LakeboxEntry } from "@dbx-tools/lakebox/rest";
110
+
111
+ export async function stopAndDelete(api: LakeboxClient, running: LakeboxEntry): Promise<void> {
112
+ const stopped = await ensureLakeboxStopped(api, running);
113
+ await api.delete(stopped.sandboxId);
114
+ }
115
+ ```
116
+
117
+ `stop()` preserves the persistent Lakebox filesystem. `delete()` permanently
118
+ removes the Lakebox and its data.
119
+
44
120
  ## Configuration
45
121
 
46
- | Field | Values | Default |
47
- | --- | --- | --- |
122
+ | Field | Values | Default |
123
+ | -------------- | ------------------------- | ----------------------------------------- |
48
124
  | `sshTransport` | `auto`, `openssh`, `ssh2` | `auto` prefers native OpenSSH with SOCKS5 |
49
- | `ssh2Patch` | `auto`, `true`, `false` | `auto` patches only in development |
125
+ | `ssh2Patch` | `auto`, `true`, `false` | `auto` patches only in development |
126
+
127
+ `SshSessionOptions` also requires the gateway host and port, Lakebox ID as the
128
+ SSH username, private key material, key and known-host paths, and a connection
129
+ timeout. `SshKeyStore` stores keys and gateway fingerprints under
130
+ `~/.dbx-tools/lakebox` unless you pass another root.
131
+
132
+ ## Understand lifecycle and transport limits
133
+
134
+ - `ensureLakeboxRunning()` and `ensureLakeboxStopped()` poll for up to five
135
+ minutes.
136
+ - The REST client doesn't map users, persist app resource identity, or manage
137
+ services. Use [@dbx-tools/appkit-lakebox](../appkit-lakebox/README.md) for
138
+ those application-level capabilities.
139
+ - The command pool keeps one tested connection warm and grows to 10
140
+ connections. Forwarding uses a separate pool with no minimum.
141
+ - Each borrowed SSH resource handles one operation and is destroyed after that
142
+ command or forwarded stream. A failed forwarding open retries once with a new
143
+ resource. Established streams and commands aren't replayed.
144
+ - `auto` selects native OpenSSH when it is available and selects ssh2
145
+ otherwise. It doesn't switch transports after a runtime failure.
146
+ - `close()` cancels active commands, closes transport pools, and waits for an
147
+ in-progress connection attempt to settle.
package/index.ts CHANGED
@@ -3,7 +3,7 @@
3
3
  // Hand edits are overwritten on the next watch; this file is read-only.
4
4
 
5
5
  export const PACKAGE_IDENTIFIER = "@dbx-tools/lakebox";
6
- export const PACKAGE_VERSION = "0.9.131";
6
+ export const PACKAGE_VERSION = "0.9.132";
7
7
  export * as keyStore from "./src/key-store.ts";
8
8
  export * as lifecycle from "./src/lifecycle.ts";
9
9
  export * as rest from "./src/rest.ts";
package/lib/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  export declare const PACKAGE_IDENTIFIER = "@dbx-tools/lakebox";
2
- export declare const PACKAGE_VERSION = "0.9.131";
2
+ export declare const PACKAGE_VERSION = "0.9.132";
3
3
  export * as keyStore from "./src/key-store.ts";
4
4
  export * as lifecycle from "./src/lifecycle.ts";
5
5
  export * as rest from "./src/rest.ts";
package/lib/index.js CHANGED
@@ -2,7 +2,7 @@
2
2
  // Regenerated from the exporting modules in ./src.
3
3
  // Hand edits are overwritten on the next watch; this file is read-only.
4
4
  export const PACKAGE_IDENTIFIER = "@dbx-tools/lakebox";
5
- export const PACKAGE_VERSION = "0.9.131";
5
+ export const PACKAGE_VERSION = "0.9.132";
6
6
  export * as keyStore from "./src/key-store.js";
7
7
  export * as lifecycle from "./src/lifecycle.js";
8
8
  export * as rest from "./src/rest.js";
@@ -12,4 +12,4 @@ export { SshKeyStore } from "./src/key-store.js";
12
12
  export { LakeboxEntrySchema, LakeboxSshKeySchema, LakeboxApiError, LakeboxClient } from "./src/rest.js";
13
13
  export { SshSession } from "./src/session.js";
14
14
  export { SshTransportModeSchema, Ssh2PatchModeSchema } from "./src/transport.js";
15
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9pbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSwyQ0FBMkM7QUFDM0MsbURBQW1EO0FBQ25ELHdFQUF3RTtBQUV4RSxNQUFNLENBQUMsTUFBTSxrQkFBa0IsR0FBRyxvQkFBb0IsQ0FBQztBQUN2RCxNQUFNLENBQUMsTUFBTSxlQUFlLEdBQUcsU0FBUyxDQUFDO0FBQ3pDLE9BQU8sS0FBSyxRQUFRLE1BQU0sb0JBQW9CLENBQUM7QUFDL0MsT0FBTyxLQUFLLFNBQVMsTUFBTSxvQkFBb0IsQ0FBQztBQUNoRCxPQUFPLEtBQUssSUFBSSxNQUFNLGVBQWUsQ0FBQztBQUN0QyxPQUFPLEtBQUssT0FBTyxNQUFNLGtCQUFrQixDQUFDO0FBQzVDLE9BQU8sS0FBSyxTQUFTLE1BQU0sb0JBQW9CLENBQUM7QUFDaEQsT0FBTyxFQUFFLFdBQVcsRUFBRSxNQUFNLG9CQUFvQixDQUFDO0FBQ2pELE9BQU8sRUFBRSxrQkFBa0IsRUFBRSxtQkFBbUIsRUFBRSxlQUFlLEVBQUUsYUFBYSxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBRXhHLE9BQU8sRUFBRSxVQUFVLEVBQUUsTUFBTSxrQkFBa0IsQ0FBQztBQUU5QyxPQUFPLEVBQUUsc0JBQXNCLEVBQUUsbUJBQW1CLEVBQUUsTUFBTSxvQkFBb0IsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8vIEdFTkVSQVRFRCBieSBwcm9qZW4gd2F0Y2ggLSBETyBOT1QgRURJVC5cbi8vIFJlZ2VuZXJhdGVkIGZyb20gdGhlIGV4cG9ydGluZyBtb2R1bGVzIGluIC4vc3JjLlxuLy8gSGFuZCBlZGl0cyBhcmUgb3ZlcndyaXR0ZW4gb24gdGhlIG5leHQgd2F0Y2g7IHRoaXMgZmlsZSBpcyByZWFkLW9ubHkuXG5cbmV4cG9ydCBjb25zdCBQQUNLQUdFX0lERU5USUZJRVIgPSBcIkBkYngtdG9vbHMvbGFrZWJveFwiO1xuZXhwb3J0IGNvbnN0IFBBQ0tBR0VfVkVSU0lPTiA9IFwiMC45LjEzMVwiO1xuZXhwb3J0ICogYXMga2V5U3RvcmUgZnJvbSBcIi4vc3JjL2tleS1zdG9yZS50c1wiO1xuZXhwb3J0ICogYXMgbGlmZWN5Y2xlIGZyb20gXCIuL3NyYy9saWZlY3ljbGUudHNcIjtcbmV4cG9ydCAqIGFzIHJlc3QgZnJvbSBcIi4vc3JjL3Jlc3QudHNcIjtcbmV4cG9ydCAqIGFzIHNlc3Npb24gZnJvbSBcIi4vc3JjL3Nlc3Npb24udHNcIjtcbmV4cG9ydCAqIGFzIHRyYW5zcG9ydCBmcm9tIFwiLi9zcmMvdHJhbnNwb3J0LnRzXCI7XG5leHBvcnQgeyBTc2hLZXlTdG9yZSB9IGZyb20gXCIuL3NyYy9rZXktc3RvcmUudHNcIjtcbmV4cG9ydCB7IExha2Vib3hFbnRyeVNjaGVtYSwgTGFrZWJveFNzaEtleVNjaGVtYSwgTGFrZWJveEFwaUVycm9yLCBMYWtlYm94Q2xpZW50IH0gZnJvbSBcIi4vc3JjL3Jlc3QudHNcIjtcbmV4cG9ydCB0eXBlIHsgTGFrZWJveEVudHJ5LCBMYWtlYm94U3NoS2V5LCBMYWtlYm94QXV0aCB9IGZyb20gXCIuL3NyYy9yZXN0LnRzXCI7XG5leHBvcnQgeyBTc2hTZXNzaW9uIH0gZnJvbSBcIi4vc3JjL3Nlc3Npb24udHNcIjtcbmV4cG9ydCB0eXBlIHsgU3NoU2Vzc2lvbk9wdGlvbnMgfSBmcm9tIFwiLi9zcmMvc2Vzc2lvbi50c1wiO1xuZXhwb3J0IHsgU3NoVHJhbnNwb3J0TW9kZVNjaGVtYSwgU3NoMlBhdGNoTW9kZVNjaGVtYSB9IGZyb20gXCIuL3NyYy90cmFuc3BvcnQudHNcIjtcbmV4cG9ydCB0eXBlIHsgU3NoVHJhbnNwb3J0TW9kZSwgU3NoMlBhdGNoTW9kZSB9IGZyb20gXCIuL3NyYy90cmFuc3BvcnQudHNcIjtcbiJdfQ==
15
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9pbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSwyQ0FBMkM7QUFDM0MsbURBQW1EO0FBQ25ELHdFQUF3RTtBQUV4RSxNQUFNLENBQUMsTUFBTSxrQkFBa0IsR0FBRyxvQkFBb0IsQ0FBQztBQUN2RCxNQUFNLENBQUMsTUFBTSxlQUFlLEdBQUcsU0FBUyxDQUFDO0FBQ3pDLE9BQU8sS0FBSyxRQUFRLE1BQU0sb0JBQW9CLENBQUM7QUFDL0MsT0FBTyxLQUFLLFNBQVMsTUFBTSxvQkFBb0IsQ0FBQztBQUNoRCxPQUFPLEtBQUssSUFBSSxNQUFNLGVBQWUsQ0FBQztBQUN0QyxPQUFPLEtBQUssT0FBTyxNQUFNLGtCQUFrQixDQUFDO0FBQzVDLE9BQU8sS0FBSyxTQUFTLE1BQU0sb0JBQW9CLENBQUM7QUFDaEQsT0FBTyxFQUFFLFdBQVcsRUFBRSxNQUFNLG9CQUFvQixDQUFDO0FBQ2pELE9BQU8sRUFBRSxrQkFBa0IsRUFBRSxtQkFBbUIsRUFBRSxlQUFlLEVBQUUsYUFBYSxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBRXhHLE9BQU8sRUFBRSxVQUFVLEVBQUUsTUFBTSxrQkFBa0IsQ0FBQztBQUU5QyxPQUFPLEVBQUUsc0JBQXNCLEVBQUUsbUJBQW1CLEVBQUUsTUFBTSxvQkFBb0IsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8vIEdFTkVSQVRFRCBieSBwcm9qZW4gd2F0Y2ggLSBETyBOT1QgRURJVC5cbi8vIFJlZ2VuZXJhdGVkIGZyb20gdGhlIGV4cG9ydGluZyBtb2R1bGVzIGluIC4vc3JjLlxuLy8gSGFuZCBlZGl0cyBhcmUgb3ZlcndyaXR0ZW4gb24gdGhlIG5leHQgd2F0Y2g7IHRoaXMgZmlsZSBpcyByZWFkLW9ubHkuXG5cbmV4cG9ydCBjb25zdCBQQUNLQUdFX0lERU5USUZJRVIgPSBcIkBkYngtdG9vbHMvbGFrZWJveFwiO1xuZXhwb3J0IGNvbnN0IFBBQ0tBR0VfVkVSU0lPTiA9IFwiMC45LjEzMlwiO1xuZXhwb3J0ICogYXMga2V5U3RvcmUgZnJvbSBcIi4vc3JjL2tleS1zdG9yZS50c1wiO1xuZXhwb3J0ICogYXMgbGlmZWN5Y2xlIGZyb20gXCIuL3NyYy9saWZlY3ljbGUudHNcIjtcbmV4cG9ydCAqIGFzIHJlc3QgZnJvbSBcIi4vc3JjL3Jlc3QudHNcIjtcbmV4cG9ydCAqIGFzIHNlc3Npb24gZnJvbSBcIi4vc3JjL3Nlc3Npb24udHNcIjtcbmV4cG9ydCAqIGFzIHRyYW5zcG9ydCBmcm9tIFwiLi9zcmMvdHJhbnNwb3J0LnRzXCI7XG5leHBvcnQgeyBTc2hLZXlTdG9yZSB9IGZyb20gXCIuL3NyYy9rZXktc3RvcmUudHNcIjtcbmV4cG9ydCB7IExha2Vib3hFbnRyeVNjaGVtYSwgTGFrZWJveFNzaEtleVNjaGVtYSwgTGFrZWJveEFwaUVycm9yLCBMYWtlYm94Q2xpZW50IH0gZnJvbSBcIi4vc3JjL3Jlc3QudHNcIjtcbmV4cG9ydCB0eXBlIHsgTGFrZWJveEVudHJ5LCBMYWtlYm94U3NoS2V5LCBMYWtlYm94QXV0aCB9IGZyb20gXCIuL3NyYy9yZXN0LnRzXCI7XG5leHBvcnQgeyBTc2hTZXNzaW9uIH0gZnJvbSBcIi4vc3JjL3Nlc3Npb24udHNcIjtcbmV4cG9ydCB0eXBlIHsgU3NoU2Vzc2lvbk9wdGlvbnMgfSBmcm9tIFwiLi9zcmMvc2Vzc2lvbi50c1wiO1xuZXhwb3J0IHsgU3NoVHJhbnNwb3J0TW9kZVNjaGVtYSwgU3NoMlBhdGNoTW9kZVNjaGVtYSB9IGZyb20gXCIuL3NyYy90cmFuc3BvcnQudHNcIjtcbmV4cG9ydCB0eXBlIHsgU3NoVHJhbnNwb3J0TW9kZSwgU3NoMlBhdGNoTW9kZSB9IGZyb20gXCIuL3NyYy90cmFuc3BvcnQudHNcIjtcbiJdfQ==
package/package.json CHANGED
@@ -25,9 +25,9 @@
25
25
  "vitest": "3.2.4"
26
26
  },
27
27
  "dependencies": {
28
- "@dbx-tools/core": "^0.9.131",
29
- "@dbx-tools/shared-core": "^0.9.131",
30
- "@dbx-tools/shared-lakebox": "^0.9.131",
28
+ "@dbx-tools/core": "^0.9.132",
29
+ "@dbx-tools/shared-core": "^0.9.132",
30
+ "@dbx-tools/shared-lakebox": "^0.9.132",
31
31
  "generic-pool": "^3.9.0",
32
32
  "socks": "^2.8.10",
33
33
  "ssh2": "^1.17.0",
@@ -71,7 +71,7 @@
71
71
  "./package.json": "./package.json"
72
72
  }
73
73
  },
74
- "version": "0.9.131",
74
+ "version": "0.9.132",
75
75
  "types": "./lib/index.d.ts",
76
76
  "dbxToolsConfig": {
77
77
  "tags": [