Abstract Class: Plugin\<TConfig\>
Abstract Class: Plugin<TConfig>
Base abstract class for creating AppKit plugins.
All plugins must declare a static manifest property with their metadata
and resource requirements. The manifest defines:
requiredresources: Always needed for the plugin to functionoptionalresources: May be needed depending on plugin configuration
Static vs Runtime Resource Requirements
The manifest is static and doesn't know the plugin's runtime configuration.
For resources that become required based on config options, plugins can
implement a static getResourceRequirements(config) method.
At runtime, this method is called with the actual config to determine which "optional" resources should be treated as "required".
Examples
import { Plugin, toPlugin, PluginManifest, ResourceType } from '@databricks/appkit';
const myManifest: PluginManifest = {
name: 'myPlugin',
displayName: 'My Plugin',
description: 'Does something awesome',
resources: {
required: [
{ type: ResourceType.SQL_WAREHOUSE, alias: 'warehouse', ... }
],
optional: []
}
};
class MyPlugin extends Plugin<MyConfig> {
static manifest = myManifest;
}interface MyConfig extends BasePluginConfig {
enableCaching?: boolean;
}
const myManifest: PluginManifest = {
name: 'myPlugin',
resources: {
required: [
{ type: ResourceType.SQL_WAREHOUSE, alias: 'warehouse', ... }
],
optional: [
// Database is optional in the static manifest
{ type: ResourceType.DATABASE, alias: 'cache', description: 'Required if caching enabled', ... }
]
}
};
class MyPlugin extends Plugin<MyConfig> {
static manifest = myManifest<"myPlugin">;
// Runtime method: converts optional resources to required based on config
static getResourceRequirements(config: MyConfig) {
const resources = [];
if (config.enableCaching) {
// When caching is enabled, Database becomes required
resources.push({
type: ResourceType.DATABASE,
alias: 'cache',
resourceKey: 'database',
description: 'Cache storage for query results',
permission: 'CAN_CONNECT_AND_CREATE',
fields: {
instance_name: { env: 'DATABRICKS_CACHE_INSTANCE' },
database_name: { env: 'DATABRICKS_CACHE_DB' },
},
required: true // Mark as required at runtime
});
}
return resources;
}
}Type Parameters
| Type Parameter | Default type |
|---|---|
TConfig extends BasePluginConfig | BasePluginConfig |
Implements
BasePlugin
Constructors
Constructor
new Plugin<TConfig>(config: TConfig): Plugin<TConfig>;Parameters
| Parameter | Type |
|---|---|
config | TConfig |
Returns
Plugin<TConfig>
Properties
app
protected app: AppManager;cache
protected cache: CacheManager;config
protected config: TConfig;context?
protected optional context: PluginContext;devFileReader
protected devFileReader: DevFileReader;isReady
protected isReady: boolean = false;name
name: string;Plugin name identifier.
Implementation of
BasePlugin.namestreamManager
protected streamManager: StreamManager;telemetry
protected telemetry: ITelemetry;phase
static phase: PluginPhase = "normal";Plugin initialization phase.
- 'core': Initialized first (e.g., config plugins)
- 'normal': Initialized second (most plugins)
- 'deferred': Initialized last (e.g., server plugin)
Methods
abortActiveOperations()
abortActiveOperations(): void;Cancel in-flight work (abort signals, SSE streams). Runs in the first
phase of graceful shutdown, BEFORE any plugin's shutdown() hook —
so it must not tear down shared resources (e.g. connection pools)
that other plugins' hooks may still need. Put teardown in shutdown().
Returns
void
Implementation of
BasePlugin.abortActiveOperationsasUser()
asUser(req: Request): this;Execute operations using the user's identity from the request. Returns a proxy of this plugin where all method calls execute with the user's Databricks credentials instead of the service principal.
Parameters
| Parameter | Type | Description |
|---|---|---|
req | Request | The Express request containing the user token in headers |
Returns
this
A proxied plugin instance that executes as the user
Throws
AuthenticationError if user token is not available in request headers (production only).
In development mode (NODE_ENV=development), skips user impersonation instead of throwing.
attachContext()
attachContext(deps: {
context?: unknown;
telemetryConfig?: TelemetryOptions;
}): void;Binds runtime dependencies (telemetry provider, cache, plugin context) to
this plugin. Called by AppKit._createApp after construction and before
setup(). Idempotent: safe to call if the constructor already bound them
eagerly. Kept separate so factories can eagerly construct plugin instances
without running this before TelemetryManager.initialize() /
CacheManager.getInstance() have run.
Parameters
| Parameter | Type |
|---|---|
deps | { context?: unknown; telemetryConfig?: TelemetryOptions; } |
deps.context? | unknown |
deps.telemetryConfig? | TelemetryOptions |
Returns
void
Implementation of
BasePlugin.attachContextclientConfig()
clientConfig(): Record<string, unknown>;Returns startup config to expose to the client. Override this to surface server-side values that are safe to publish to the frontend, such as feature flags, resource IDs, or other app boot settings.
This runs once when the server starts, so it should not depend on request-scoped or user-specific state.
String values that match non-public environment variables are redacted
unless you intentionally expose them via a matching PUBLIC_APPKIT_ env var.
Values must be JSON-serializable plain data (no functions, Dates, classes, Maps, Sets, BigInts, or circular references). By default returns an empty object (plugin contributes nothing to client config).
On the client, read the config with the usePluginClientConfig hook
(React) or the getPluginClientConfig function (vanilla JS), both
from @databricks/appkit-ui.
Returns
Record<string, unknown>
Example
// Server — plugin definition
class MyPlugin extends Plugin<MyConfig> {
clientConfig() {
return {
warehouseId: this.config.warehouseId,
features: { darkMode: true },
};
}
}
// Client — React component
import { usePluginClientConfig } from "@databricks/appkit-ui/react";
interface MyPluginConfig { warehouseId: string; features: { darkMode: boolean } }
const config = usePluginClientConfig<MyPluginConfig>("myPlugin");
config.warehouseId; // "abc-123"
// Client — vanilla JS
import { getPluginClientConfig } from "@databricks/appkit-ui/js";
const config = getPluginClientConfig<MyPluginConfig>("myPlugin");Implementation of
BasePlugin.clientConfigexecute()
protected execute<T>(
fn: (signal?: AbortSignal) => Promise<T>,
options: PluginExecutionSettings,
userKey?: string): Promise<ExecutionResult<T>>;Execute a function with the plugin's interceptor chain.
Returns an ExecutionResult discriminated union:
{ ok: true, data: T }on success{ ok: false, status: number, message: string }on failure
Errors are never thrown — the method is production-safe.
Type Parameters
| Type Parameter |
|---|
T |
Parameters
| Parameter | Type |
|---|---|
fn | (signal?: AbortSignal) => Promise<T> |
options | PluginExecutionSettings |
userKey? | string |
Returns
Promise<ExecutionResult<T>>
executeStream()
protected executeStream<T>(
res: IAppResponse,
fn: StreamExecuteHandler<T>,
options: StreamExecutionSettings,
userKey?: string): Promise<void>;Type Parameters
| Type Parameter |
|---|
T |
Parameters
| Parameter | Type |
|---|---|
res | IAppResponse |
fn | StreamExecuteHandler<T> |
options | StreamExecutionSettings |
userKey? | string |
Returns
Promise<void>
exports()
exports(): unknown;Returns the public exports for this plugin. Override this to define a custom public API. By default, returns an empty object.
The returned object becomes the plugin's public API on the AppKit instance
(e.g. appkit.myPlugin.method()). AppKit automatically binds method context
and adds asUser(req) for user-scoped execution.
Returns
unknown
Example
class MyPlugin extends Plugin {
private getData() { return []; }
exports() {
return { getData: this.getData };
}
}
// After registration:
const appkit = await createApp({ plugins: [myPlugin()] });
appkit.myPlugin.getData();Implementation of
BasePlugin.exportsgetEndpoints()
getEndpoints(): PluginEndpointMap;Returns
PluginEndpointMap
Implementation of
BasePlugin.getEndpointsgetSkipBodyParsingPaths()
getSkipBodyParsingPaths(): ReadonlySet<string>;Returns
ReadonlySet<string>
Implementation of
BasePlugin.getSkipBodyParsingPathsinjectRoutes()
injectRoutes(_: Router): void;Parameters
| Parameter | Type |
|---|---|
_ | Router |
Returns
void
Implementation of
BasePlugin.injectRoutesregisterEndpoint()
protected registerEndpoint(name: string, path: string): void;Parameters
| Parameter | Type |
|---|---|
name | string |
path | string |
Returns
void
resolveUserId()
protected resolveUserId(req: Request): string;Resolve the effective user ID from a request.
Returns the x-forwarded-user header when present. In development mode
(NODE_ENV=development) falls back to the current context user ID so
that callers outside an active runInUserContext scope still get a
consistent value.
Parameters
| Parameter | Type |
|---|---|
req | Request |
Returns
string
Throws
AuthenticationError in production when no user header is present.
route()
protected route<_TResponse>(router: Router, config: RouteConfig): void;Type Parameters
| Type Parameter |
|---|
_TResponse |
Parameters
| Parameter | Type |
|---|---|
router | Router |
config | RouteConfig |
Returns
void
setup()
setup(): Promise<void>;Returns
Promise<void>
Implementation of
BasePlugin.setup