From 6e34c1be85f2a2695a18556d09d0bf2644445c4a Mon Sep 17 00:00:00 2001 From: MarioCadenas Date: Fri, 9 Oct 2026 17:44:31 +0200 Subject: [PATCH 1/2] feat(shared): add a modular Apps client to the workspace client Add buildAppsClient (@databricks/sdk-apps 0.54.0, via mapToClientOptions) and a lazy `apps` accessor on the facade, plus App/ListApps* type re-exports, so the CLI can list apps through AppsClient.listApps / listAppsIter instead of raw request(). Co-authored-by: Isaac Signed-off-by: MarioCadenas --- knip.json | 1 + packages/appkit/package.json | 1 + .../src/testing/mock-workspace-client.ts | 1 + packages/shared/package.json | 1 + .../shared/src/workspace-client/client.ts | 11 ++++++++ .../shared/src/workspace-client/modular.ts | 15 +++++++++++ .../workspace-client/tests/modular.test.ts | 27 +++++++++++++++++++ packages/shared/src/workspace-client/types.ts | 4 +++ pnpm-lock.yaml | 19 +++++++++++++ 9 files changed, 80 insertions(+) diff --git a/knip.json b/knip.json index 6963fc6a9..12cc73f4f 100644 --- a/knip.json +++ b/knip.json @@ -10,6 +10,7 @@ "packages/appkit": { "ignoreDependencies": [ "vitest", + "@databricks/sdk-apps", "@databricks/sdk-auth", "@databricks/sdk-core", "@databricks/sdk-experimental", diff --git a/packages/appkit/package.json b/packages/appkit/package.json index 041761741..2facc55aa 100644 --- a/packages/appkit/package.json +++ b/packages/appkit/package.json @@ -71,6 +71,7 @@ "dependencies": { "@ast-grep/napi": "0.37.0", "@databricks/lakebase": "workspace:*", + "@databricks/sdk-apps": "0.54.0", "@databricks/sdk-auth": "0.51.0", "@databricks/sdk-core": "0.51.0", "@databricks/sdk-experimental": "0.17.0", diff --git a/packages/appkit/src/testing/mock-workspace-client.ts b/packages/appkit/src/testing/mock-workspace-client.ts index 27a47048a..dda9da370 100644 --- a/packages/appkit/src/testing/mock-workspace-client.ts +++ b/packages/appkit/src/testing/mock-workspace-client.ts @@ -69,6 +69,7 @@ const FACADE_SERVICES = [ "warehouses", "genie", "database", + "apps", "jobs", "experiments", "vectorSearch", diff --git a/packages/shared/package.json b/packages/shared/package.json index 844833fd2..9c2121e65 100644 --- a/packages/shared/package.json +++ b/packages/shared/package.json @@ -48,6 +48,7 @@ "dependencies": { "@ast-grep/napi": "0.37.0", "@clack/prompts": "1.0.1", + "@databricks/sdk-apps": "0.54.0", "@databricks/sdk-auth": "0.51.0", "@databricks/sdk-core": "0.51.0", "@databricks/sdk-experimental": "0.17.0", diff --git a/packages/shared/src/workspace-client/client.ts b/packages/shared/src/workspace-client/client.ts index 335a4aeab..19f19308a 100644 --- a/packages/shared/src/workspace-client/client.ts +++ b/packages/shared/src/workspace-client/client.ts @@ -24,6 +24,8 @@ import { buildGenieClient, type FunctionsClient, type GenieClient, + buildAppsClient, + type AppsClient, buildJobsClient, buildExperimentsClient, type ExperimentsClient, @@ -58,6 +60,7 @@ export class AppKitWorkspaceClient implements WorkspaceClient { #currentUser?: ScimClient; #genie?: GenieClient; #database?: DatabaseClient; + #apps?: AppsClient; #jobs?: JobsClient; #modelServing?: ModelServingClient; #experiments?: ExperimentsClient; @@ -97,6 +100,14 @@ export class AppKitWorkspaceClient implements WorkspaceClient { return this.#genie; } + // Migrated to the modular SDK — built lazily, independent of the legacy client. + get apps(): AppsClient { + if (!this.#apps) { + this.#apps = buildAppsClient(this.#opts); + } + return this.#apps; + } + // Migrated to the modular SDK — built lazily, independent of the legacy client. get database(): DatabaseClient { if (!this.#database) { diff --git a/packages/shared/src/workspace-client/modular.ts b/packages/shared/src/workspace-client/modular.ts index a8b322f12..f20e32b0e 100644 --- a/packages/shared/src/workspace-client/modular.ts +++ b/packages/shared/src/workspace-client/modular.ts @@ -33,6 +33,7 @@ import { execFile } from "node:child_process"; import { STATUS_CODES } from "node:http"; import { promisify } from "node:util"; +import type { AppsClient } from "@databricks/sdk-apps/v1"; import { type Credentials, newTokenCredentials, @@ -547,6 +548,14 @@ export function buildScimClient(opts: WorkspaceClientOptions): ScimClient { return new ScimClient(mapToClientOptions(opts)); } +/** Build a modular Apps client from wrapper options. */ +export function buildAppsClient(opts: WorkspaceClientOptions): AppsClient { + return lazyClient( + () => import("@databricks/sdk-apps/v1").then((m) => m.AppsClient), + mapToClientOptions(opts), + ); +} + /** * Defer loading an SDK client's module until its first method call, so app * boot doesn't pay for clients it never uses. Generated methods return either @@ -715,6 +724,7 @@ export function buildPostgresClient( // ── Client type re-exports (for the facade accessor types) ─────────────── export type { DatabaseClient } from "@databricks/sdk-database/v1"; export type { ExperimentsClient } from "@databricks/sdk-experiments/v1"; +export type { AppsClient } from "@databricks/sdk-apps/v1"; export type { FilesClient } from "@databricks/sdk-files/v2"; export type { DirectoryEntry as FilesDirectoryEntry, @@ -766,6 +776,11 @@ export type { ListDatabaseInstancesRequest, ListDatabaseInstancesResponse, } from "@databricks/sdk-database/v1"; +export type { + App, + ListAppsRequest, + ListAppsResponse, +} from "@databricks/sdk-apps/v1"; export type { GenieGetMessageQueryResultResponse, GenieMessage, diff --git a/packages/shared/src/workspace-client/tests/modular.test.ts b/packages/shared/src/workspace-client/tests/modular.test.ts index e8a938375..595b774e5 100644 --- a/packages/shared/src/workspace-client/tests/modular.test.ts +++ b/packages/shared/src/workspace-client/tests/modular.test.ts @@ -42,6 +42,12 @@ vi.mock("@databricks/sdk-warehouses/v1", () => ({ vi.mock("@databricks/sdk-statementexecution/v1", () => ({ StatementExecutionClient: vi.fn().mockImplementation((opts) => ({ opts })), })); +vi.mock("@databricks/sdk-apps/v1", () => ({ + AppsClient: vi.fn().mockImplementation((opts) => { + ctorOpts.push(opts); + return { opts, getApp: async () => ({}) }; + }), +})); vi.mock("@databricks/sdk-experiments/v1", () => ({ ExperimentsClient: vi.fn().mockImplementation((opts) => { ctorOpts.push(opts); @@ -164,6 +170,7 @@ import { buildConnectionsClient, buildDatabaseClient, buildExperimentsClient, + buildAppsClient, buildGenieClient, buildModelServingClient, buildVolumesClient, @@ -394,6 +401,26 @@ describe("modular mapToClientOptions (via buildWarehousesClient)", () => { expect(Reflect.get(client, "then")).toBeUndefined(); }); + test("apps passes the mapped options (normalized host, credentials) to the client", async () => { + await buildAppsClient({ + host: "x.cloud.databricks.com", + token: "user-token", + clientOptions: { + product: "@databricks/appkit", + productVersion: "0.64.0", + }, + } as never).getApp({} as never); + expect(ctorOpts[0].host).toBe("https://x.cloud.databricks.com"); + expect(ctorOpts[0].credentials).toMatchObject({ + kind: "pat", + token: "user-token", + }); + expect(m2mOpts).toEqual([]); + expect(await sentUserAgent(ctorOpts[0].httpClient)).toBe( + "@databricks/appkit/0.64.0", + ); + }); + test("database maps host normalization + SP M2M credentials through mapToClientOptions", async () => { process.env.DATABRICKS_CLIENT_ID = "sp-client-id"; process.env.DATABRICKS_CLIENT_SECRET = "sp-secret"; diff --git a/packages/shared/src/workspace-client/types.ts b/packages/shared/src/workspace-client/types.ts index 95fa14523..b337d1128 100644 --- a/packages/shared/src/workspace-client/types.ts +++ b/packages/shared/src/workspace-client/types.ts @@ -19,6 +19,7 @@ import type { WarehousesClient, WorkspaceAuth, ScimClient, + AppsClient, GenieClient, DatabaseClient, JobsClient, @@ -66,6 +67,9 @@ export interface WorkspaceClient extends WorkspaceAuth { /** Lakebase provisioned database instances + credentials (modular SDK). */ readonly database: DatabaseClient; + /** Databricks Apps (modular SDK). */ + readonly apps: AppsClient; + /** Jobs (modular SDK, Jobs API 2.2). */ readonly jobs: JobsClient; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 64e02c17e..bff41d96a 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -281,6 +281,9 @@ importers: '@databricks/lakebase': specifier: workspace:* version: link:../lakebase + '@databricks/sdk-apps': + specifier: 0.54.0 + version: 0.54.0 '@databricks/sdk-auth': specifier: 0.51.0 version: 0.51.0 @@ -653,6 +656,9 @@ importers: '@clack/prompts': specifier: 1.0.1 version: 1.0.1 + '@databricks/sdk-apps': + specifier: 0.54.0 + version: 0.54.0 '@databricks/sdk-auth': specifier: 0.51.0 version: 0.51.0 @@ -2075,6 +2081,10 @@ packages: engines: {node: ^20 || ^22 || ^24 || ^25, pnpm: '>=10'} hasBin: true + '@databricks/sdk-apps@0.54.0': + resolution: {integrity: sha512-7cz5Smp/OXfwLn7jGKs0yQjOy1dMbOuPz6l6WoiTnVakw5RClagnLp56hePo2D6HlXMcFRMzTNe5BbW89dgveg==} + engines: {node: '>=22.0.0'} + '@databricks/sdk-auth@0.51.0': resolution: {integrity: sha512-CswN+io9XB7rrcHo9BG/2qIdRCUMb8gFjiZmqVDG2qRmyhzY7Wv1tvwzA+U8uBplmdzAcdhuxMvHQ7vKGFWYqQ==} engines: {node: '>=22.0.0'} @@ -14423,6 +14433,15 @@ snapshots: transitivePeerDependencies: - supports-color + '@databricks/sdk-apps@0.54.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-auth@0.51.0': dependencies: '@databricks/sdk-core': 0.51.0 From d057a0d7615cf1ce1426afb07781ac1e46aaac5f Mon Sep 17 00:00:00 2001 From: MarioCadenas Date: Tue, 13 Oct 2026 15:40:38 +0200 Subject: [PATCH 2/2] docs(shared): bring the workspace-client facade docstrings up to date List every service now on the modular SDK, name the accessors still on the legacy client, and point at the current statementExecution patch file. Co-authored-by: Isaac Signed-off-by: MarioCadenas --- packages/shared/src/workspace-client/client.ts | 9 +++++---- packages/shared/src/workspace-client/modular.ts | 11 +++++++---- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/packages/shared/src/workspace-client/client.ts b/packages/shared/src/workspace-client/client.ts index 19f19308a..0681d901d 100644 --- a/packages/shared/src/workspace-client/client.ts +++ b/packages/shared/src/workspace-client/client.ts @@ -2,10 +2,11 @@ * `AppKitWorkspaceClient` — the facade implementation. Construct via * `createWorkspaceClient(...)`; this class is internal. * - * Every service accessor delegates to a single lazily-constructed legacy SDK - * client. This is the seam: to migrate a service to the modular SDK, replace - * its getter here with a modular client instance (and update its connector + - * the accessor type in `types.ts`). No other AppKit module touches the SDK. + * Migrated service accessors build their modular client lazily (see + * `modular.ts`); the rest (`servingEndpoints`, `config`, `apiClient`) delegate + * to a single lazily-constructed legacy SDK client. To migrate one, replace its + * getter here with a modular client instance (and update its connector + the + * accessor type in `types.ts`). No other AppKit module touches the SDK. */ import { buildLegacyWorkspaceClient, diff --git a/packages/shared/src/workspace-client/modular.ts b/packages/shared/src/workspace-client/modular.ts index f20e32b0e..af20ba684 100644 --- a/packages/shared/src/workspace-client/modular.ts +++ b/packages/shared/src/workspace-client/modular.ts @@ -8,12 +8,15 @@ * * Migrated services are built here as per-service clients; the facade delegates * their accessors to these instead of the legacy monolithic client. Currently - * `warehouses`, `statementExecution`, `currentUser` (SCIM), `genie`, `jobs`, `vectorSearch` - * and `tables` (UC) are migrated, plus the auth + raw-request seam ({@link buildWorkspaceAuth}); - * every other service still routes through `legacy.ts`. + * `warehouses`, `statementExecution`, `currentUser` (SCIM), `genie`, `jobs`, + * `files`, `vectorSearch`, `tables`, `modelServing`, `volumes`, `functions`, + * `connections`, `database`, `postgres`, `experiments` and `apps` are + * migrated, plus the auth + raw-request seam ({@link buildWorkspaceAuth}). + * Only `servingEndpoints`, `config` and `apiClient` still route through + * `legacy.ts`. * * NOTE: statementExecution relies on a pinned pnpm patch - * (`patches/@databricks__sdk-statementexecution@0.46.0.patch`) that restores the + * (`patches/@databricks__sdk-statementexecution@0.52.0.patch`) that restores the * undocumented Reyden `attachment` response field, which the SDK's generated * unmarshal transform would otherwise strip. *