@dbx-tools/appkit-config
v0.1.112
Published
Downloads
8,095
Readme
@dbx-tools/appkit-config
Auto-configuration helpers for AppKit apps. The headline export is
createApp: a drop-in replacement for @databricks/appkit's createApp
that resolves and applies whatever environment each enabled capability
needs, then delegates to the real createApp with the exact same
arguments (and the same per-plugin export inference).
import { createApp } from "@dbx-tools/appkit-config";
import { lakebase, server } from "@databricks/appkit";
// Because `lakebase()` is present, this resolves the Lakebase env vars
// first, then hands the untouched config to AppKit's createApp.
await createApp({ plugins: [server(), lakebase()] });Auto-config runs BEFORE delegating (so plugins see a populated
process.env during their synchronous setup()) and every step is
self-gating, so apps pay nothing for capabilities they don't use:
| Capability | Trigger | Effect |
| ----------------- | ----------------------------------------------------------------------- | ------------------------------------------ |
| Lakebase Postgres | a lakebase plugin in config.plugins, or autoConfigure: true | resolves + writes PG* / LAKEBASE_* env |
The package is intentionally broader than Postgres: new capability
auto-config slots into createApp behind its own plugin/env signal
without changing the call site.
appkit-config-env
Run Lakebase auto-config and print only the env vars it added or changed:
# POSIX: eval or source into your shell
eval "$(bunx appkit-config-env -q)"
# or
source <(bunx appkit-config-env -q)
bunx appkit-config-env -f windows -q # cmd.exe: set KEY=value
bunx appkit-config-env -f json -qUse -q to quiet auto-config logs. Output goes to stdout for piping.
Standalone autoConfigure()
autoConfigure() fills in every Lakebase Postgres env var the AppKit
lakebase plugin needs from whatever fragments your deployment actually
carries. createApp runs it for you; call it directly when you want the
resolution without the wrapper:
import { autoConfigure } from "@dbx-tools/appkit-config";
import { createApp, lakebase, server } from "@databricks/appkit";
await autoConfigure({ plugins: [lakebase()] });
await createApp({ plugins: [lakebase(), server()] });For resolver-only control (inspect before writing env, custom post-processing), use the lower-level exports:
import {
applyLakebaseToEnv,
resolveLakebaseConnection,
} from "@dbx-tools/appkit-config";
const resolved = await resolveLakebaseConnection({ autoCreate: false });
applyLakebaseToEnv(resolved);Why a top-level helper instead of an AppKit plugin
AppKit's static phase field orders plugin setup() invocation, not
async completion. lakebase.setup() synchronously throws on a missing
PGHOST after its first await, so a sibling plugin that performs REST
discovery during setup() races and loses every time. Resolving the env
before createApp(...) delegates sidesteps the race - by the time any
plugin runs, process.env is fully populated.
What it accepts
resolveLakebaseConnection() (and therefore autoConfigure() /
createApp) looks at, in priority order:
- Explicit
resolveLakebaseConnection({ project, branch, endpoint, database, host, port, sslMode, autoCreate }) - Env vars the
lakebaseplugin reads:LAKEBASE_ENDPOINTPGHOST,PGDATABASE,PGPORT,PGSSLMODE
- Whatever the address parser can recover from
LAKEBASE_ENDPOINT/config.endpoint
The address input is permissive - any of these work:
# Canonical resource path
LAKEBASE_ENDPOINT="projects/dbx-tools/branches/main/endpoints/primary"
# Full Postgres URI (auth, host, db, sslmode all extracted)
LAKEBASE_ENDPOINT="postgresql://me%[email protected]/databricks_postgres?sslmode=require"
# Bare Lakebase hostname (resolver reverse-looks-up the project)
LAKEBASE_ENDPOINT="ep-steep-forest-e199v43w.database.eastus2.azuredatabricks.net"
# Bare project id (resolver picks the default branch + endpoint + db)
LAKEBASE_ENDPOINT="dbx-tools"Three resolution modes
After parsing, the resolver fills gaps in this order:
- Reverse-lookup - given just a host, scan
projects->branches->endpointsfor a matchingstatus.hosts.hostand recover the owning resource path. - Pick default - given a
project(and optionally abranch), prefer the server-marked default child (status.default,ENDPOINT_TYPE_READ_WRITE,databricks_postgres) and fall back to "the only one" when a listing returns a single result. - Auto-create - when no projects exist at all, create one whose id
defaults to a slugified
projectUtils.name()(override withautoCreate: "my-id"or disable withautoCreate: false). The create call is idempotent: anALREADY_EXISTSresponse from a concurrent boot is treated as success. Then poll the default endpoint untilcurrent_stateisREADYorIDLE.
Options
const resolved = await resolveLakebaseConnection({
// Pin individual fields - any of these short-circuit the resolver.
project: "dbx-tools",
branch: "main",
endpoint: "projects/dbx-tools/branches/main/endpoints/primary",
database: "databricks_postgres",
// Auto-create behavior.
autoCreate: false, // throw if no project exists
// autoCreate: "my-custom-id", // create with this id
});
applyLakebaseToEnv(resolved); // writes gaps in process.env onlyresolveLakebaseConnection() returns a LakebaseConnection record
(project, branch, endpoint, database, host, port,
sslMode). applyLakebaseToEnv() writes the same values to
process.env, only filling gaps - existing values are preserved.
Address parser
The address parser is exported as well if you want it without the resolver wrapper:
import { parseAddress } from "@dbx-tools/appkit-config";
parseAddress("postgresql://[email protected]/dbpg");
// { user, host, database, port?, sslMode?, project?, branch?, endpointId? }Required permissions
The Databricks user / SP behind getWorkspaceClient() needs
postgres.projects.{list,create}, postgres.branches.list,
postgres.endpoints.{list,get}, and postgres.databases.list on the
account.
License
Apache-2.0
