Skip to content

refactor(appkit): add defineManifest to remove manifest casts - #485

Open
MarioCadenas wants to merge 1 commit into
mainfrom
refactor/define-manifest
Open

refactor(appkit): add defineManifest to remove manifest casts#485
MarioCadenas wants to merge 1 commit into
mainfrom
refactor/define-manifest

Conversation

@MarioCadenas

@MarioCadenas MarioCadenas commented Jul 20, 2026

Copy link
Copy Markdown
Collaborator

What

Introduces defineManifest() in the registry so plugins stop hand-casting their JSON manifests. All 10 plugins now declare:

static manifest = defineManifest<"my-plugin">(manifest);

instead of static manifest = manifest as PluginManifest<...> (agents needed the uglier as unknown as PluginManifest).

It's also exported from @databricks/appkit and emitted by appkit plugin create, so external plugins get the same validated, cast-free path.

Why

The cast was unavoidable with a raw .json import:

  • TS widens every JSON field to string, but PluginManifest.resources[].type is the nominal ResourceType enum — a structural string never assigns to it.
  • Multi-resource plugins (only agents today) infer a heterogeneous union for resources, which a plain as also rejects (hence agents' as unknown as).

So the escape hatch wasn't a plugin bug — it was the JSON→type boundary being crossed by assertion in every plugin, with no runtime validation.

How

defineManifest() parses the manifest through the canonical pluginManifestSchema (Zod) and returns the strict type via one audited internal assertion, after parse has confirmed the values are real ResourceType/permission strings. This:

  • removes every per-plugin cast (one bridge assertion, centralized),
  • adds real runtime validation at module load that the old cast never provided — including the camelCase PLUGIN_NAME_PATTERN,
  • preserves the literal plugin name via <TName> (needed — toPlugin derives the typed plugin key from manifest.name; widening to string would collapse the typed registry).

pluginManifestSchema is now exported from shared for the parse.

Public surface

  • defineManifest is exported from the @databricks/appkit root so external plugin authors can use it (previously it lived only in the internal registry barrel).
  • The appkit plugin create scaffold now emits defineManifest<"name">(manifest) instead of manifest as PluginManifest<...>, so newly scaffolded plugins get runtime validation by default.
  • TypeDoc API reference regenerated (new Function.defineManifest page; Variable.agents now shows the restored literal key ToPlugin<..., "agents"> instead of ..., string>).

Verification

  • shared + appkit typecheck — clean
  • Registry + plugins + plugin-CLI suites — 1311 pass, 1 skipped (every real manifest parses at module load)
  • New unit tests: valid pass-through + rejection of unknown resource type, invalid permission, and missing required field
  • Scaffold test updated to assert the defineManifest output
  • oxlint + oxfmt — clean on changed files (no new warnings vs. main)

Split out of the MLflow-tracing PR (pr/agent-evals-1-tracing), which is where this cast friction first surfaced.

@MarioCadenas
MarioCadenas requested a review from a team as a code owner July 20, 2026 16:58
@github-actions

Copy link
Copy Markdown
Contributor

🔬  Run evals on this PR  ·  Go to Evals Monitor →

@github-actions

github-actions Bot commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

📦 Bundle size report

Compared against bundle-size-baseline.json (main).

@databricks/appkit

npm tarball (packed): 862 KB (+22 KB) — gzipped download (dist + bin; excludes release-only docs/NOTICE).

dist raw gzip
JS (runtime) 899 KB (+30 KB) 311 KB (+8.5 KB)
Type declarations 316 KB (+1.2 KB) 109 KB (+497 B)
Source maps 1.7 MB (+58 KB) 580 KB (+14 KB)
Other 11 KB 3.7 KB
Total 2.9 MB (+89 KB) 1005 KB (+23 KB)
Per-entry composition (own code — deps external (as shipped))
Entry Initial (gz) Lazy (gz) Total (gz) node_modules (min) Own code (min)
. 93 KB (+4.9 KB) 2.5 KB 96 KB (+4.9 KB) external 306 KB (+17 KB)
./beta 54 KB (+5.1 KB) 457 B 54 KB (+5.1 KB) external 161 KB (+18 KB)
./type-generator 21 KB 0 B 21 KB external 61 KB

Chunks:

Entry Chunk Load Size (gz)
. index.js initial 89 KB
. utils.js initial 4.0 KB
. remote-tunnel-manager.js lazy 2.5 KB
./beta beta.js initial 38 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
./type-generator index.js initial 21 KB

@databricks/appkit-ui

npm tarball (packed): 342 KB (-281 B) — gzipped download (dist + bin; excludes release-only docs/NOTICE).

dist raw gzip
JS (runtime) 390 KB 130 KB (+1 B)
Type declarations 228 KB (+32 B) 83 KB (+9 B)
Source maps 752 KB (-334 B) 247 KB (-197 B)
CSS 16 KB (-462 B) 3.2 KB (-90 B)
Total 1.4 MB (-764 B) 464 KB (-277 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 (+127 B) 49 KB 480 KB (+127 B) 1.3 MB 175 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

@MarioCadenas
MarioCadenas marked this pull request as draft July 21, 2026 08:17
@github-actions

Copy link
Copy Markdown
Contributor

This pull request has had no activity for 23 days and has been marked as stale. It will be closed in 7 days if there is no further activity. Add a comment, push a commit, or apply the no-stale label to keep it open.

@github-actions github-actions Bot added the stale label Aug 13, 2026
@github-actions

github-actions Bot commented Aug 18, 2026

Copy link
Copy Markdown
Contributor

🤖 AppKit PR bot

🔬 Run evals

Start an eval for this PR from the evals-monitor app: Go to Evals Monitor →

📦 Try this PR's app template

Scaffolds a new app from this PR's SDK build. Run it in any folder (requires the GitHub CLI — gh auth login — and the Databricks CLI):

gh run download 32349898864 -R databricks/appkit -n appkit-template-0.61.1-pr.495ea7a-refactor-define-manifest-485 -D appkit-pr-485 \
  && unzip -o "appkit-pr-485/appkit-template-0.61.1-pr.495ea7a-refactor-define-manifest-485.zip" -d "appkit-pr-485" \
  && databricks apps init --template "appkit-pr-485"

The template pins @databricks/appkit and @databricks/appkit-ui to tarballs built from this branch, so the scaffolded app runs against this PR's code.

@github-actions github-actions Bot removed the stale label Aug 19, 2026
@MarioCadenas
MarioCadenas force-pushed the refactor/define-manifest branch 2 times, most recently from 219b61c to da0c99f Compare August 19, 2026 16:36
@MarioCadenas
MarioCadenas marked this pull request as ready for review August 19, 2026 16:36
Every plugin declared `static manifest = manifest as PluginManifest`
(agents needed `as unknown as`). The cast is unavoidable with a raw JSON
import: TS widens JSON fields to `string`, but PluginManifest.resources[].type
is the nominal ResourceType enum, so the structural shape never assigns —
and multi-resource plugins infer a heterogeneous union that a plain `as`
also rejects.

Add defineManifest() in the registry: it parses the JSON through the
canonical pluginManifestSchema (real runtime validation, which the loader
did not do before) and returns the strict type via one audited internal
assertion. All 9 plugins now use `static manifest = defineManifest<"name">(manifest)`
with no local casts. Export pluginManifestSchema from shared for the parse.

Adds tests covering valid pass-through and rejection of unknown resource
type, invalid permission, and missing required fields.

Signed-off-by: MarioCadenas <MarioCadenas@users.noreply.github.com>
@MarioCadenas
MarioCadenas force-pushed the refactor/define-manifest branch from da0c99f to c153608 Compare August 20, 2026 08:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant