diff --git a/knip.json b/knip.json index 7097761d3..074bec74a 100644 --- a/knip.json +++ b/knip.json @@ -19,6 +19,7 @@ "@databricks/sdk-jobs", "@databricks/sdk-postgres", "@databricks/sdk-modelserving", + "@databricks/sdk-uc-connections", "@databricks/sdk-uc-tables", "@databricks/sdk-uc-volumes", "@databricks/sdk-vectorsearch", diff --git a/packages/appkit/package.json b/packages/appkit/package.json index 902993f70..97fc8db96 100644 --- a/packages/appkit/package.json +++ b/packages/appkit/package.json @@ -79,6 +79,7 @@ "@databricks/sdk-uc-functions": "0.51.0", "@databricks/sdk-jobs": "0.57.0", "@databricks/sdk-modelserving": "0.53.0", + "@databricks/sdk-uc-connections": "0.52.0", "@databricks/sdk-uc-tables": "0.52.0", "@databricks/sdk-uc-volumes": "0.51.0", "@databricks/sdk-vectorsearch": "0.51.0", diff --git a/packages/appkit/src/testing/mock-workspace-client.ts b/packages/appkit/src/testing/mock-workspace-client.ts index 182907e15..a8fba79d5 100644 --- a/packages/appkit/src/testing/mock-workspace-client.ts +++ b/packages/appkit/src/testing/mock-workspace-client.ts @@ -74,6 +74,7 @@ const FACADE_SERVICES = [ "postgres", "volumes", "functions", + "connections", "statementExecution", "modelServing", "servingEndpoints", diff --git a/packages/shared/package.json b/packages/shared/package.json index da07ee9c9..3052c0ecd 100644 --- a/packages/shared/package.json +++ b/packages/shared/package.json @@ -56,6 +56,7 @@ "@databricks/sdk-uc-functions": "0.51.0", "@databricks/sdk-jobs": "0.57.0", "@databricks/sdk-modelserving": "0.53.0", + "@databricks/sdk-uc-connections": "0.52.0", "@databricks/sdk-uc-tables": "0.52.0", "@databricks/sdk-uc-volumes": "0.51.0", "@databricks/sdk-vectorsearch": "0.51.0", diff --git a/packages/shared/src/workspace-client/client.ts b/packages/shared/src/workspace-client/client.ts index d2ace29c2..a8ca04963 100644 --- a/packages/shared/src/workspace-client/client.ts +++ b/packages/shared/src/workspace-client/client.ts @@ -28,6 +28,8 @@ import { type ModelServingClient, buildFilesClient, type FilesClient, + buildConnectionsClient, + type ConnectionsClient, buildTablesClient, type TablesClient, buildPostgresClient, @@ -59,6 +61,7 @@ export class AppKitWorkspaceClient implements WorkspaceClient { #postgres?: PostgresClient; #volumes?: VolumesClient; #functions?: FunctionsClient; + #connections?: ConnectionsClient; constructor(opts: WorkspaceClientOptions) { this.#opts = opts; @@ -120,6 +123,14 @@ export class AppKitWorkspaceClient implements WorkspaceClient { return this.#postgres; } + // Migrated to the modular SDK — built lazily, independent of the legacy client. + get connections(): ConnectionsClient { + if (!this.#connections) { + this.#connections = buildConnectionsClient(this.#opts); + } + return this.#connections; + } + // Migrated to the modular SDK — built lazily, independent of the legacy client. get functions(): FunctionsClient { if (!this.#functions) { diff --git a/packages/shared/src/workspace-client/modular.ts b/packages/shared/src/workspace-client/modular.ts index e01318fcc..1d7e78e12 100644 --- a/packages/shared/src/workspace-client/modular.ts +++ b/packages/shared/src/workspace-client/modular.ts @@ -60,6 +60,7 @@ import type { ClientOptions } from "@databricks/sdk-options/client"; import type { PostgresClient } from "@databricks/sdk-postgres/v1"; import { ScimClient } from "@databricks/sdk-scim/v1"; import { StatementExecutionClient } from "@databricks/sdk-statementexecution/v1"; +import type { ConnectionsClient } from "@databricks/sdk-uc-connections/v1"; import type { FunctionsClient } from "@databricks/sdk-uc-functions/v1"; import type { TablesClient } from "@databricks/sdk-uc-tables/v1"; import type { VolumesClient } from "@databricks/sdk-uc-volumes/v1"; @@ -661,6 +662,19 @@ export function buildFunctionsClient( ); } +/** Build a modular Unity Catalog Connections client from wrapper options. */ +export function buildConnectionsClient( + opts: WorkspaceClientOptions, +): ConnectionsClient { + return lazyClient( + () => + import("@databricks/sdk-uc-connections/v1").then( + (m) => m.ConnectionsClient, + ), + mapToClientOptions(opts), + ); +} + /** * Build a modular Lakebase Postgres (autoscaling: projects, branches, * endpoints) client from wrapper options. Distinct from the provisioned @@ -688,6 +702,7 @@ export type { PostgresClient } from "@databricks/sdk-postgres/v1"; export type { ScimClient } from "@databricks/sdk-scim/v1"; export type { StatementExecutionClient } from "@databricks/sdk-statementexecution/v1"; export type { FunctionsClient } from "@databricks/sdk-uc-functions/v1"; +export type { ConnectionsClient } from "@databricks/sdk-uc-connections/v1"; export type { TablesClient } from "@databricks/sdk-uc-tables/v1"; export type { VolumesClient } from "@databricks/sdk-uc-volumes/v1"; export type { VectorSearchClient } from "@databricks/sdk-vectorsearch/v1"; @@ -698,6 +713,12 @@ export type { WarehousesClient } from "@databricks/sdk-warehouses/v1"; // than the SDK, so the import boundary holds. Type-only: the connector compares // state against string literals, which satisfy the SDK's `Enum | (string & {})` // field unions — no runtime enum values needed. +export type { + ConnectionInfo, + GetConnectionRequest, + ListConnectionsRequest, + ListConnectionsResponse, +} from "@databricks/sdk-uc-connections/v1"; export type { ColumnInfo, Disposition, diff --git a/packages/shared/src/workspace-client/tests/modular.test.ts b/packages/shared/src/workspace-client/tests/modular.test.ts index b83bf24e1..5df56b151 100644 --- a/packages/shared/src/workspace-client/tests/modular.test.ts +++ b/packages/shared/src/workspace-client/tests/modular.test.ts @@ -73,6 +73,12 @@ vi.mock("@databricks/sdk-uc-functions/v1", () => ({ return { opts, getFunction: async () => ({}) }; }), })); +vi.mock("@databricks/sdk-uc-connections/v1", () => ({ + ConnectionsClient: vi.fn().mockImplementation((opts) => { + ctorOpts.push(opts); + return { opts, getConnection: async () => ({}) }; + }), +})); vi.mock("@databricks/sdk-postgres/v1", () => ({ PostgresClient: vi.fn().mockImplementation((opts) => { ctorOpts.push(opts); @@ -143,6 +149,7 @@ vi.mock("node:child_process", () => ({ import { ApiError } from "../errors"; import { buildFunctionsClient, + buildConnectionsClient, buildGenieClient, buildModelServingClient, buildVolumesClient, @@ -457,6 +464,31 @@ describe("modular mapToClientOptions (via buildWarehousesClient)", () => { expect(m2mOpts).toEqual([]); }); + test("connections normalizes a scheme-less host and uses SP M2M creds", async () => { + process.env.DATABRICKS_CLIENT_ID = "sp-client-id"; + process.env.DATABRICKS_CLIENT_SECRET = "sp-secret"; + await buildConnectionsClient({ + host: "my-ws.cloud.databricks.com", + }).getConnection({} as never); + expect(ctorOpts[0].host).toBe("https://my-ws.cloud.databricks.com"); + expect(m2mOpts).toHaveLength(1); + expect(patTokens).toEqual([]); + }); + + test("connections (asUser) uses the OBO token as PAT", async () => { + process.env.DATABRICKS_CLIENT_ID = "sp-client-id"; + process.env.DATABRICKS_CLIENT_SECRET = "sp-secret"; + await buildConnectionsClient({ + token: "user-token", + host: "https://x", + }).getConnection({} as never); + expect(ctorOpts[0].credentials).toMatchObject({ + kind: "pat", + token: "user-token", + }); + expect(m2mOpts).toEqual([]); + }); + test("postgres normalizes the host and passes SP M2M credentials", async () => { process.env.DATABRICKS_HOST = "envhost.cloud.databricks.com"; process.env.DATABRICKS_CLIENT_ID = "sp-client-id"; diff --git a/packages/shared/src/workspace-client/types.ts b/packages/shared/src/workspace-client/types.ts index 8904cee2b..89bbf8992 100644 --- a/packages/shared/src/workspace-client/types.ts +++ b/packages/shared/src/workspace-client/types.ts @@ -26,6 +26,7 @@ import type { TablesClient, VolumesClient, FunctionsClient, + ConnectionsClient, VectorSearchClient, PostgresClient, } from "./modular"; @@ -77,6 +78,9 @@ export interface WorkspaceClient extends WorkspaceAuth { /** Unity Catalog Functions (modular SDK). */ readonly functions: FunctionsClient; + /** Unity Catalog Connections (modular SDK). */ + readonly connections: ConnectionsClient; + /** Statement Execution (modular SDK). */ readonly statementExecution: StatementExecutionClient; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 5719dcd05..7ff157b20 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -314,6 +314,9 @@ importers: '@databricks/sdk-statementexecution': specifier: 0.52.0 version: 0.52.0(patch_hash=9377a46b883b548d47116662bf73b159a4da51ec28b9ff1896a7e4a7841c240c) + '@databricks/sdk-uc-connections': + specifier: 0.52.0 + version: 0.52.0 '@databricks/sdk-uc-functions': specifier: 0.51.0 version: 0.51.0 @@ -677,6 +680,9 @@ importers: '@databricks/sdk-statementexecution': specifier: 0.52.0 version: 0.52.0(patch_hash=9377a46b883b548d47116662bf73b159a4da51ec28b9ff1896a7e4a7841c240c) + '@databricks/sdk-uc-connections': + specifier: 0.52.0 + version: 0.52.0 '@databricks/sdk-uc-functions': specifier: 0.51.0 version: 0.51.0 @@ -2105,6 +2111,10 @@ packages: resolution: {integrity: sha512-ymDGDW67PJ/0VujM89mUrE6mbbrabsKJP5LvPv8ZbgzPR0bm0DwXMcQzvS0XUt0UGITjV2gqbx5jQwP3ijtOmg==} engines: {node: '>=22.0.0'} + '@databricks/sdk-uc-connections@0.52.0': + resolution: {integrity: sha512-1kdWnXUSsjGWiQBVVrmiONDB+DohE+uMxgBwIg8p6A8d+p/kkcoR4KHDpj9QhJJ6/ae3Iy0vNFE4pIbA+pxlGw==} + engines: {node: '>=22.0.0'} + '@databricks/sdk-uc-functions@0.51.0': resolution: {integrity: sha512-L5Qq3lB8OIiEOW4h8s9EJQ82VeBFiPnA0F5S2Fhqpd8L8bpx3rjG/e88ZYDtDg3bg4xunOdMQS1VWRxSF9IMxA==} engines: {node: '>=22.0.0'} @@ -14489,6 +14499,15 @@ snapshots: json-bigint: 1.0.0 zod: 4.3.6 + '@databricks/sdk-uc-connections@0.52.0': + dependencies: + '@databricks/sdk-auth': 0.51.0 + '@databricks/sdk-core': 0.51.0 + '@databricks/sdk-options': 0.51.0 + '@js-temporal/polyfill': 0.5.1 + json-bigint: 1.0.0 + zod: 4.3.6 + '@databricks/sdk-uc-functions@0.51.0': dependencies: '@databricks/sdk-auth': 0.51.0