feat(appkit): add the service-principal typed DatabasePlugin API - #526
feat(appkit): add the service-principal typed DatabasePlugin API#526ditadi wants to merge 3 commits into
Conversation
Expose the hardened runtime as one service-principal plugin with typed entity clients, transactions, tagged SQL, and schema-derived declarations in the existing typegen flow. Driver, setup, and unclassified failures are logged with their original cause before the safe error replaces them, so operators can diagnose what the client never sees. Signed-off-by: ditadi <victordperd@gmail.com>
441393c to
84e6494
Compare
📦 Bundle size reportCompared against
|
| dist | raw | gzip |
|---|---|---|
| JS (runtime) | 1010 KB (+105 KB) | 351 KB (+34 KB) |
| Type declarations | 379 KB (+35 KB) | 133 KB (+13 KB) |
| Source maps | 2.0 MB (+215 KB) | 661 KB (+66 KB) |
| Other | 11 KB | 3.7 KB |
| Total | 3.3 MB (+354 KB) | 1.1 MB (+113 KB) |
Per-entry composition (own code — deps external (as shipped))
| Entry | Initial (gz) | Lazy (gz) | Total (gz) | node_modules (min) | Own code (min) |
|---|---|---|---|---|---|
. |
95 KB (+6.5 KB) | 2.5 KB | 97 KB (+6.5 KB) | external | 311 KB (+22 KB) |
./beta |
65 KB (+14 KB) | 457 B | 65 KB (+14 KB) | external | 196 KB (+48 KB) |
./testing |
17 KB | 0 B | 17 KB | external | 50 KB |
./tsdown |
520 B | 0 B | 520 B | external | 813 B |
./type-generator |
22 KB (+1.5 KB) | 0 B | 22 KB (+1.5 KB) | external | 65 KB (+4.3 KB) |
Chunks:
| Entry | Chunk | Load | Size (gz) |
|---|---|---|---|
. |
index.js |
initial | 91 KB |
. |
utils.js |
initial | 4.0 KB |
. |
remote-tunnel-manager.js |
lazy | 2.5 KB |
./beta |
beta.js |
initial | 49 KB |
./beta |
stream-manager.js |
initial | 5.8 KB |
./beta |
wide-event-emitter.js |
initial | 3.2 KB |
./beta |
databricks.js |
initial | 3.0 KB |
./beta |
configuration.js |
initial | 2.1 KB |
./beta |
service-context.js |
initial | 1.3 KB |
./beta |
client.js |
initial | 434 B |
./beta |
client-options.js |
initial | 220 B |
./beta |
supervisor-api.js |
lazy | 192 B |
./beta |
databricks.js |
lazy | 142 B |
./beta |
index.js |
lazy | 123 B |
./testing |
index.js |
initial | 17 KB |
./tsdown |
index.js |
initial | 520 B |
./type-generator |
index.js |
initial | 22 KB |
@databricks/appkit-ui
npm tarball (packed): 348 KB (+5 B) — gzipped download (dist + bin; excludes release-only docs/NOTICE).
| dist | raw | gzip |
|---|---|---|
| JS (runtime) | 394 KB | 132 KB |
| Type declarations | 228 KB (+32 B) | 83 KB (+8 B) |
| Source maps | 764 KB | 252 KB |
| CSS | 16 KB | 3.2 KB |
| Total | 1.4 MB (+32 B) | 471 KB (+8 B) |
Per-entry composition (consumer bundle — deps bundled, peerDeps external)
| Entry | Initial (gz) | Lazy (gz) | Total (gz) | node_modules (min) | Own code (min) |
|---|---|---|---|---|---|
./js |
5.3 KB | 49 KB | 55 KB | 208 KB | 14 KB |
./js/beta |
20 B | 0 B | 20 B | 0 B | 0 B |
./react |
432 KB | 49 KB | 481 KB | 1.3 MB | 177 KB |
./react/beta |
1.0 KB | 0 B | 1.0 KB | 0 B | 1.9 KB |
Chunks:
| Entry | Chunk | Load | Size (gz) |
|---|---|---|---|
./js |
index.js |
initial | 5.2 KB |
./js |
chunk |
initial | 120 B |
./js |
apache-arrow |
lazy | 49 KB |
./js/beta |
beta.js |
initial | 20 B |
./react |
index.js |
initial | 430 KB |
./react |
tslib |
initial | 2.1 KB |
./react |
apache-arrow |
lazy | 49 KB |
./react/beta |
beta.js |
initial | 1.0 KB |
⚠️ Over budget: a package's shipped tarball, or a browser entry's consumer bundle (deps included), grew by more than 5% (and >10 KB). This check will fail — reduce the size, or acknowledge the increase by updatingbundle-size-baseline.json.
🤖 AppKit PR bot🔬 Run evalsStart an eval for this PR from the evals-monitor app: Go to Evals Monitor → 📦 Try this PR's app templateScaffolds a new app from this PR's SDK build. Run it in any folder (requires the GitHub CLI — gh run download 32748831942 -R databricks/appkit -n appkit-template-0.64.0-pr.dbbdeaf-stack-database-mvp-02-typed-api-526 -D appkit-pr-526 \
&& unzip -o "appkit-pr-526/appkit-template-0.64.0-pr.dbbdeaf-stack-database-mvp-02-typed-api-526.zip" -d "appkit-pr-526" \
&& databricks apps init --template "appkit-pr-526"The template pins |
Signed-off-by: ditadi <victordperd@gmail.com>
|
@copilot resolve the merge conflicts in this pull request |
Signed-off-by: GitHub <noreply@github.com>
Resolved by merging |
Stack
Each PR targets the one above it, so the diff shown here is only the delta on top of #525. Review in order.
What
Turns the runtime from #525 into a plugin you can actually use.
database({ schema })publishes one typed client per table, plus transactions and parameterized SQL, and the existing typegen flow learns to derive the declarations that make all of it typed from the schema file alone.This is the first PR in the series with an exported surface. The plugin runs as the app's service principal and registers no HTTP routes — generated CRUD arrives in the next PR, so everything here is reachable only from server code you write.
Changes
The plugin (
plugins/database/)database({ schema })binds one plugin instance to one finalized schema.lifecycle.tsowns setup: it validates the schema, builds the Lakebase pool, and publishes the export surface only once it is ready. Setup is single-flight, and a failure ends the pool rather than leaving a half-open plugin.EntityClientwith a chainable read side —where,order,select,include,limit,offset, terminated bytoArray,first,find, orcount— and the keyed writescreate,update,upsert, anddelete. Every call goes through theDataPathfrom feat(appkit): add the database runtime and harden its schema builder #525, so the bounds, the parameterization, and the private-column projection hold here by construction.transaction(cb)hands the callback a client bound to that transaction; the taggedsqltemplate is available both at the top level and inside a transaction, and interpolates values only.defaults.ts): neither retries, and mutations are never cached.Errors (
database/errors.ts)DatabasePluginErrormaps a small closed set of categories onto stable status codes and client messages. A driver error never reaches the caller: it is classified, and the original is logged with its SQLSTATE before the safe error replaces it. The same is true for schema-validation and setup failures, so an operator can diagnose what the client is deliberately not shown.Schema-derived types (
type-generator/database/)walk-schema.tswalks a finalized schema andgenerate.tsrenders it intoappkit-types/database.d.ts, which augments theDatabaseRegistryinterface. That is what makesappkit.database.notesknow its own columns, filters, and relations. The generator loads the schema file throughjiti(pinned at 2.6.1), so a TypeScript schema needs no build step first.It is wired into both existing entry points — the Vite plugin regenerates on change during development, and
appkit generate-typesemits it in CI — following the same shape the analytics and serving generators already use.Exports
defineSchema, the column builders, anddatabaseare exported from@databricks/appkit/beta;DatabaseRegistryis exported from the root so the generated declaration file can augment it.Verification
pnpm vitest run— 4057 passing, 1 skipped; the new suites cover the plugin lifecycle, the entity client, the generated types, and the schema walkerpnpm -r typecheck— clean across all packagespnpm run generate:types,pnpm run sync:template, andpnpm run docs:buildproduce no driftpnpm install --frozen-lockfile—jitiadds 3 lines to the lockfile and nothing else