@dbx-tools/appkit 0.1.9

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 ADDED
@@ -0,0 +1,201 @@
1
+ # @dbx-tools/node-appkit
2
+
3
+ Node-side helpers for Databricks AppKit apps.
4
+
5
+ Import this package when backend code needs AppKit execution context, typed
6
+ plugin lookup, Databricks SDK cancellation, layered config resolution, or
7
+ Lakebase auto-configuration without taking on a heavier feature package.
8
+
9
+ Key features:
10
+
11
+ - Auto-configuration before AppKit setup, especially for Lakebase/Postgres env
12
+ values that AppKit plugins read during initialization.
13
+ - Runtime-safe context access for code that may run inside an AppKit request,
14
+ from a CLI, or from a background script.
15
+ - Typed plugin lookup helpers for AppKit plugins that depend on exports from
16
+ sibling plugins.
17
+ - Config resolution across explicit options, CLI flags, env vars, Databricks
18
+ Asset Bundle outputs, and `app.yaml`.
19
+ - SDK cancellation bridging from web `AbortSignal` values into Databricks SDK
20
+ `Context` values.
21
+ - Lakebase cache-schema provisioning for deployments where the app identity must
22
+ be granted access before persistent cache initialization.
23
+
24
+ ## Why Not Just AppKit?
25
+
26
+ Use native AppKit directly when your app can read its required env vars before
27
+ `createApp()` and does not need extra setup around plugin exports or config
28
+ sources.
29
+
30
+ Use this package when the friction is around bootstrapping and reuse:
31
+
32
+ - AppKit plugins read Lakebase/Postgres env during initialization; this package
33
+ resolves and applies those values before setup.
34
+ - AppKit exposes request context inside AppKit handlers; these helpers make code
35
+ safe to call from scripts, tests, and background jobs too.
36
+ - AppKit plugin instances are generic; the lookup helpers keep sibling-plugin
37
+ access typed and errors actionable.
38
+ - AppKit does not own your local CLI flags, bundle validation output, or
39
+ `app.yaml`; `config.resolveConfigValue()` gives setup scripts one resolution
40
+ path across those sources.
41
+
42
+ ## Create An Auto-Configured App
43
+
44
+ `createApp.createApp` is a drop-in wrapper around AppKit `createApp`. It runs
45
+ `createApp.autoConfigure()` first so enabled capabilities can populate
46
+ environment variables before plugin setup runs.
47
+
48
+ ```ts
49
+ import { lakebase, server } from "@databricks/appkit";
50
+ import { createApp } from "@dbx-tools/node-appkit";
51
+
52
+ await createApp.createApp({
53
+ plugins: [server(), lakebase()],
54
+ });
55
+ ```
56
+
57
+ When `lakebase()` is present, auto-config resolves Lakebase Postgres connection
58
+ settings and fills missing `PG*` / `LAKEBASE_*` variables. That avoids a startup
59
+ race where the Lakebase plugin reads env before another async setup step can
60
+ discover it.
61
+
62
+ Auto-configuration is conservative: existing env vars win unless a caller passes
63
+ explicit options, and local-only discovery is skipped inside a Databricks App
64
+ environment. This makes the same entrypoint usable in local development,
65
+ Databricks Asset Bundle validation, and deployed Apps.
66
+
67
+ Use the lower-level functions when you need to inspect or customize the result:
68
+
69
+ ```ts
70
+ import { lakebaseResolver } from "@dbx-tools/node-appkit";
71
+
72
+ const resolved = await lakebaseResolver.resolveLakebaseConnection({
73
+ endpoint: process.env.LAKEBASE_ENDPOINT,
74
+ autoCreate: false,
75
+ });
76
+
77
+ lakebaseResolver.applyLakebaseToEnv(resolved);
78
+ ```
79
+
80
+ ## Resolve Local And Bundle Config
81
+
82
+ `config.resolveConfigValue()` checks explicit options, CLI overrides, env vars,
83
+ Databricks Asset Bundle validation output, and `app.yaml` env entries.
84
+
85
+ ```ts
86
+ import { config } from "@dbx-tools/node-appkit";
87
+
88
+ const warehouseId = await config.resolveConfigValue("SQL_WAREHOUSE_ID", {
89
+ cli: { SQL_WAREHOUSE_ID: flags.warehouse },
90
+ sources: config.withCliSources(),
91
+ });
92
+ ```
93
+
94
+ Use this in CLIs and setup scripts that should behave the same locally and in a
95
+ Databricks App deployment. `config.bundle()` and `config.appYaml()` expose the
96
+ parsed files when you need to diagnose which source won.
97
+
98
+ ## Parse Lakebase Addresses
99
+
100
+ `pgaddress.parseAddress()` accepts resource paths, Postgres URLs, bare
101
+ Lakebase hosts, and partial inputs. It gives the resolver a common shape without
102
+ requiring users to remember one canonical format.
103
+
104
+ ```ts
105
+ import { pgaddress } from "@dbx-tools/node-appkit";
106
+
107
+ pgaddress.parseAddress(
108
+ "postgresql://user@ep-foo.database.azuredatabricks.net/databricks_postgres?sslmode=require",
109
+ );
110
+ ```
111
+
112
+ `pgaddress.parseResourcePath()` is useful when you specifically expect a
113
+ `projects/<id>/branches/<id>/endpoints/<id>` value.
114
+
115
+ ## Use AppKit Execution Context Safely
116
+
117
+ `appkit.tryGetExecutionContext()` returns the active AppKit request context when
118
+ code is running under AppKit, and `undefined` elsewhere. That lets libraries
119
+ preserve OBO auth in apps while still working from scripts.
120
+
121
+ ```ts
122
+ import { appkit } from "@dbx-tools/node-appkit";
123
+ import { WorkspaceClient } from "@databricks/sdk-experimental";
124
+
125
+ const client = appkit.tryGetExecutionContext()?.client ?? new WorkspaceClient({});
126
+ ```
127
+
128
+ `appkit.ensureInitialized()` lazily initializes AppKit runtime state before
129
+ context lookup in code paths that may run early.
130
+
131
+ ## Adapt Databricks SDK Cancellation
132
+
133
+ Databricks SDK calls accept a `Context`. Many app and web APIs use
134
+ `AbortSignal`. `databricks.toContext()` bridges the two.
135
+
136
+ ```ts
137
+ import { databricks } from "@dbx-tools/node-appkit";
138
+
139
+ const context = databricks.toContext(request.signal);
140
+ await client.apiClient.request({
141
+ path: "/api/2.0/serving-endpoints",
142
+ method: "GET",
143
+ headers: new Headers(),
144
+ raw: false,
145
+ context,
146
+ });
147
+ ```
148
+
149
+ `databricks.isAppEnv()` checks the Databricks App environment shape for setup
150
+ code that should skip local-only filesystem or bundle discovery.
151
+
152
+ ## Look Up Sibling Plugins
153
+
154
+ AppKit's plugin map is intentionally generic. `plugin.data()`,
155
+ `plugin.instance()`, and `plugin.require()` keep lookups typed and produce better
156
+ errors when a required plugin is missing.
157
+
158
+ ```ts
159
+ import { lakebase } from "@databricks/appkit";
160
+ import { plugin } from "@dbx-tools/node-appkit";
161
+
162
+ const lake = plugin.instance(this.context, lakebase);
163
+ const pool = lake?.exports().pool;
164
+
165
+ const required = plugin.require(this.context, lakebase, "my-plugin").exports();
166
+ ```
167
+
168
+ Use this in AppKit plugins that depend on sibling plugin exports but should not
169
+ hard-code registered names or casts at every call site.
170
+
171
+ ## Provision Lakebase Cache Schema
172
+
173
+ `provision.provisionCacheSchema()` grants the AppKit cache schema in Lakebase to
174
+ the Postgres role that will run the app. Use it after Lakebase connection env has
175
+ been resolved and before AppKit initializes its persistent cache.
176
+
177
+ ```ts
178
+ import { provision } from "@dbx-tools/node-appkit";
179
+ import { log } from "@dbx-tools/shared-core";
180
+
181
+ await provision.provisionCacheSchema(
182
+ log.logger("appkit-cache"),
183
+ "app-service-principal@databricks.com",
184
+ );
185
+ ```
186
+
187
+ ## Modules
188
+
189
+ - `createApp` - `createApp()` wrapper and `autoConfigure()`.
190
+ - `lakebaseResolver` - Lakebase connection discovery, default picking, optional
191
+ auto-create, and env application.
192
+ - `pgaddress` - permissive Lakebase/Postgres address parser.
193
+ - `config` - local/env/bundle/app-yaml config lookup.
194
+ - `appkit` - execution context lookup and initialization.
195
+ - `databricks` - App env detection and SDK context cancellation adapters.
196
+ - `plugin` - typed AppKit plugin data, instance, and required-instance lookup.
197
+ - `provision` - cache schema provisioning helpers.
198
+
199
+ The shell-facing wrapper for auto-config is
200
+ [`@dbx-tools/appkit-env`](../../cli/appkit-env). Higher-level agent composition
201
+ is in [`@dbx-tools/node-appkit-mastra`](../appkit-mastra).
package/index.ts ADDED
@@ -0,0 +1,18 @@
1
+ // GENERATED by projen watch - DO NOT EDIT.
2
+ // Regenerated from the exporting modules in ./src.
3
+ // Hand edits are overwritten on the next watch; this file is read-only.
4
+
5
+ export * as appkit from "./src/appkit";
6
+ export * as config from "./src/config";
7
+ export * as createApp from "./src/create-app";
8
+ export * as databricks from "./src/databricks";
9
+ export * as lakebaseResolver from "./src/lakebase-resolver";
10
+ export * as pgaddress from "./src/pgaddress";
11
+ export * as plugin from "./src/plugin";
12
+ export * as provision from "./src/provision";
13
+ export type { ExecutionContextLike, WorkspaceClientLike } from "./src/appkit";
14
+ export type { BundleValidateJson, ConfigFile, ConfigSource, ConfigMapValue, ResolveConfigValueOptions } from "./src/config";
15
+ export type { ContextLike } from "./src/databricks";
16
+ export type { LakebaseResolverInputs, LakebaseConnection } from "./src/lakebase-resolver";
17
+ export type { SslMode, LakebaseConnectionInputs, ParsedAddress } from "./src/pgaddress";
18
+ export type { PluginContextLike } from "./src/plugin";
package/package.json ADDED
@@ -0,0 +1,55 @@
1
+ {
2
+ "name": "@dbx-tools/appkit",
3
+ "repository": {
4
+ "type": "git",
5
+ "url": "git+https://github.com/reggie-db/dbx-tools.git",
6
+ "directory": "workspaces/node/appkit"
7
+ },
8
+ "devDependencies": {
9
+ "@databricks/appkit": "^0.43.0",
10
+ "@types/node": "^24.6.0",
11
+ "tsx": "^4.23.0",
12
+ "typescript": "^5.9.3"
13
+ },
14
+ "peerDependencies": {
15
+ "@databricks/appkit": "^0.43.0"
16
+ },
17
+ "dependencies": {
18
+ "@databricks/sdk-experimental": "^0.17.0",
19
+ "yaml": "^2.9.0",
20
+ "zod": "^4.3.6",
21
+ "@dbx-tools/core": "0.1.9",
22
+ "@dbx-tools/shared-core": "0.1.9"
23
+ },
24
+ "main": "index.ts",
25
+ "license": "UNLICENSED",
26
+ "version": "0.1.9",
27
+ "types": "index.ts",
28
+ "type": "module",
29
+ "exports": {
30
+ ".": "./index.ts",
31
+ "./package.json": "./package.json"
32
+ },
33
+ "peerDependenciesMeta": {
34
+ "@databricks/appkit": {
35
+ "optional": true
36
+ }
37
+ },
38
+ "dbxToolsConfig": {
39
+ "tags": [
40
+ "node"
41
+ ]
42
+ },
43
+ "//": "~~ Generated by projen. To modify, edit .projenrc.js and run \"pnpm exec projen\".",
44
+ "scripts": {
45
+ "build": "projen build",
46
+ "compile": "projen compile",
47
+ "default": "projen default",
48
+ "package": "projen package",
49
+ "post-compile": "projen post-compile",
50
+ "pre-compile": "projen pre-compile",
51
+ "test": "projen test",
52
+ "watch": "projen watch",
53
+ "projen": "projen"
54
+ }
55
+ }
package/src/appkit.ts ADDED
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Generic AppKit runtime glue: the per-request execution context and the types
3
+ * derived from it. Not plugin-specific - that lives in `./plugin`.
4
+ *
5
+ * `getExecutionContext()` is AppKit's own accessor for the OBO-scoped workspace
6
+ * client + request metadata; the wrappers here make it safe to call outside a
7
+ * request scope ({@link tryGetExecutionContext}) and to lazily boot a bare app
8
+ * ({@link ensureInitialized}), and re-export the derived types so add-on
9
+ * packages can type a context / client without re-deriving them inline.
10
+ */
11
+
12
+ import { createApp, getExecutionContext, InitializationError } from "@databricks/appkit";
13
+
14
+ /**
15
+ * The AppKit per-request execution context returned by `getExecutionContext()`
16
+ * - the OBO-scoped workspace client plus the surrounding request metadata.
17
+ * Derived from AppKit's own return type so it tracks the installed version, and
18
+ * re-exported here so add-on packages can type a context parameter without each
19
+ * re-deriving the same `ReturnType<typeof getExecutionContext>` inline.
20
+ */
21
+ export type ExecutionContextLike = ReturnType<typeof getExecutionContext>;
22
+
23
+ /**
24
+ * The auth-scoped Databricks workspace client carried on an
25
+ * `ExecutionContextLike` (`getExecutionContext().client`). Typed structurally
26
+ * off AppKit so consumers don't take a direct `@databricks/sdk-experimental`
27
+ * dependency - the dep flows in transitively through `@databricks/appkit`.
28
+ */
29
+ export type WorkspaceClientLike = ExecutionContextLike["client"];
30
+
31
+ /**
32
+ * The current AppKit execution context, or `undefined` when AppKit isn't
33
+ * initialized (outside a request scope). Swallows AppKit's
34
+ * `InitializationError`; any other error propagates.
35
+ */
36
+ export function tryGetExecutionContext(): ExecutionContextLike | undefined {
37
+ try {
38
+ const ctx = getExecutionContext();
39
+ if (ctx?.client) {
40
+ return ctx;
41
+ }
42
+ } catch (error) {
43
+ if (!(error instanceof InitializationError)) {
44
+ throw error;
45
+ }
46
+ }
47
+ return undefined;
48
+ }
49
+
50
+ /** Initialize a bare AppKit app (no plugins) when none is running yet. */
51
+ export async function ensureInitialized(): Promise<void> {
52
+ if (!tryGetExecutionContext()) {
53
+ await createApp({ plugins: [] });
54
+ }
55
+ }