@databricks/appkit 0.23.0 → 0.25.0
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/CLAUDE.md +9 -1
- package/dist/appkit/package.js +1 -1
- package/dist/cache/index.js.map +1 -1
- package/dist/cli/commands/docs.js +7 -1
- package/dist/cli/commands/docs.js.map +1 -1
- package/dist/cli/commands/generate-types.js +20 -10
- package/dist/cli/commands/generate-types.js.map +1 -1
- package/dist/cli/commands/lint.js +3 -1
- package/dist/cli/commands/lint.js.map +1 -1
- package/dist/cli/commands/plugin/add-resource/add-resource.js +73 -8
- package/dist/cli/commands/plugin/add-resource/add-resource.js.map +1 -1
- package/dist/cli/commands/plugin/create/create.js +164 -20
- package/dist/cli/commands/plugin/create/create.js.map +1 -1
- package/dist/cli/commands/plugin/create/resource-defaults.js +5 -1
- package/dist/cli/commands/plugin/create/resource-defaults.js.map +1 -1
- package/dist/cli/commands/plugin/index.js +7 -1
- package/dist/cli/commands/plugin/index.js.map +1 -1
- package/dist/cli/commands/plugin/list/list.js +7 -1
- package/dist/cli/commands/plugin/list/list.js.map +1 -1
- package/dist/cli/commands/plugin/sync/sync.js +27 -14
- package/dist/cli/commands/plugin/sync/sync.js.map +1 -1
- package/dist/cli/commands/plugin/validate/validate.js +39 -9
- package/dist/cli/commands/plugin/validate/validate.js.map +1 -1
- package/dist/cli/commands/setup.js +6 -5
- package/dist/cli/commands/setup.js.map +1 -1
- package/dist/connectors/index.js +1 -0
- package/dist/connectors/lakebase/index.js.map +1 -1
- package/dist/connectors/lakebase-v1/client.js.map +1 -1
- package/dist/connectors/vector-search/client.js +9 -0
- package/dist/connectors/vector-search/client.js.map +1 -0
- package/dist/connectors/vector-search/index.js +3 -0
- package/dist/context/execution-context.js +1 -7
- package/dist/context/execution-context.js.map +1 -1
- package/dist/context/index.js +1 -1
- package/dist/context/index.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/plugin/dev-reader.js.map +1 -1
- package/dist/plugins/files/plugin.d.ts +46 -15
- package/dist/plugins/files/plugin.d.ts.map +1 -1
- package/dist/plugins/files/plugin.js +182 -103
- package/dist/plugins/files/plugin.js.map +1 -1
- package/dist/plugins/files/policy.d.ts +45 -0
- package/dist/plugins/files/policy.d.ts.map +1 -0
- package/dist/plugins/files/policy.js +63 -0
- package/dist/plugins/files/policy.js.map +1 -0
- package/dist/plugins/files/types.d.ts +16 -8
- package/dist/plugins/files/types.d.ts.map +1 -1
- package/dist/plugins/server/vite-dev-server.js.map +1 -1
- package/dist/plugins/serving/serving.d.ts.map +1 -1
- package/dist/plugins/serving/serving.js +22 -8
- package/dist/plugins/serving/serving.js.map +1 -1
- package/dist/plugins/serving/types.d.ts +11 -10
- package/dist/plugins/serving/types.d.ts.map +1 -1
- package/dist/type-generator/index.js +13 -1
- package/dist/type-generator/index.js.map +1 -1
- package/dist/type-generator/migration.js +155 -0
- package/dist/type-generator/migration.js.map +1 -0
- package/dist/type-generator/serving/generator.js +22 -1
- package/dist/type-generator/serving/generator.js.map +1 -1
- package/dist/type-generator/serving/vite-plugin.d.ts +1 -1
- package/dist/type-generator/serving/vite-plugin.js +2 -2
- package/dist/type-generator/serving/vite-plugin.js.map +1 -1
- package/dist/type-generator/vite-plugin.d.ts.map +1 -1
- package/dist/type-generator/vite-plugin.js +3 -4
- package/dist/type-generator/vite-plugin.js.map +1 -1
- package/docs/api/appkit/Class.PolicyDeniedError.md +52 -0
- package/docs/api/appkit/Interface.FilePolicyUser.md +23 -0
- package/docs/api/appkit/Interface.FileResource.md +36 -0
- package/docs/api/appkit/TypeAlias.FileAction.md +18 -0
- package/docs/api/appkit/TypeAlias.FilePolicy.md +20 -0
- package/docs/api/appkit/TypeAlias.ServingFactory.md +9 -5
- package/docs/api/appkit/Variable.READ_ACTIONS.md +8 -0
- package/docs/api/appkit/Variable.WRITE_ACTIONS.md +8 -0
- package/docs/api/appkit.md +19 -12
- package/docs/development/type-generation.md +6 -5
- package/docs/faq.md +8 -8
- package/docs/plugins/analytics.md +1 -1
- package/docs/plugins/custom-plugins.md +4 -0
- package/docs/plugins/execution-context.md +0 -1
- package/docs/plugins/files.md +150 -2
- package/docs/plugins/{serving.md → model-serving.md} +1 -1
- package/docs/plugins/plugin-management.md +22 -6
- package/docs/plugins/vector-search.md +247 -0
- package/llms.txt +9 -1
- package/package.json +1 -1
- package/sbom.cdx.json +1 -1
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# Interface: FileResource
|
|
2
|
+
|
|
3
|
+
Describes the file or directory being acted upon.
|
|
4
|
+
|
|
5
|
+
## Properties[](#properties "Direct link to Properties")
|
|
6
|
+
|
|
7
|
+
### path[](#path "Direct link to path")
|
|
8
|
+
|
|
9
|
+
```ts
|
|
10
|
+
path: string;
|
|
11
|
+
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
Relative path within the volume.
|
|
15
|
+
|
|
16
|
+
***
|
|
17
|
+
|
|
18
|
+
### size?[](#size "Direct link to size?")
|
|
19
|
+
|
|
20
|
+
```ts
|
|
21
|
+
optional size: number;
|
|
22
|
+
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Content length in bytes — only present for uploads.
|
|
26
|
+
|
|
27
|
+
***
|
|
28
|
+
|
|
29
|
+
### volume[](#volume "Direct link to volume")
|
|
30
|
+
|
|
31
|
+
```ts
|
|
32
|
+
volume: string;
|
|
33
|
+
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
The volume key (e.g. `"uploads"`).
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# Type Alias: FileAction
|
|
2
|
+
|
|
3
|
+
```ts
|
|
4
|
+
type FileAction =
|
|
5
|
+
| "list"
|
|
6
|
+
| "read"
|
|
7
|
+
| "download"
|
|
8
|
+
| "raw"
|
|
9
|
+
| "exists"
|
|
10
|
+
| "metadata"
|
|
11
|
+
| "preview"
|
|
12
|
+
| "upload"
|
|
13
|
+
| "mkdir"
|
|
14
|
+
| "delete";
|
|
15
|
+
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
Every action the files plugin can perform.
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# Type Alias: FilePolicy()
|
|
2
|
+
|
|
3
|
+
```ts
|
|
4
|
+
type FilePolicy = (action: FileAction, resource: FileResource, user: FilePolicyUser) => boolean | Promise<boolean>;
|
|
5
|
+
|
|
6
|
+
```
|
|
7
|
+
|
|
8
|
+
A policy function that decides whether `user` may perform `action` on `resource`. Return `true` to allow, `false` to deny.
|
|
9
|
+
|
|
10
|
+
## Parameters[](#parameters "Direct link to Parameters")
|
|
11
|
+
|
|
12
|
+
| Parameter | Type |
|
|
13
|
+
| ---------- | ----------------------------------------------------------------------- |
|
|
14
|
+
| `action` | [`FileAction`](./docs/api/appkit/TypeAlias.FileAction.md) |
|
|
15
|
+
| `resource` | [`FileResource`](./docs/api/appkit/Interface.FileResource.md) |
|
|
16
|
+
| `user` | [`FilePolicyUser`](./docs/api/appkit/Interface.FilePolicyUser.md) |
|
|
17
|
+
|
|
18
|
+
## Returns[](#returns "Direct link to Returns")
|
|
19
|
+
|
|
20
|
+
`boolean` | `Promise`<`boolean`>
|
|
@@ -1,15 +1,19 @@
|
|
|
1
1
|
# Type Alias: ServingFactory
|
|
2
2
|
|
|
3
3
|
```ts
|
|
4
|
-
type ServingFactory = keyof ServingEndpointRegistry extends never ? (alias?: string) => ServingEndpointHandle : <K>(alias: K) => ServingEndpointHandle<ServingEndpointRegistry[K]["request"], ServingEndpointRegistry[K]["response"]
|
|
4
|
+
type ServingFactory = keyof ServingEndpointRegistry extends never ? (alias?: string) => ServingEndpointHandle : true extends IsUnion<keyof ServingEndpointRegistry> ? <K>(alias: K) => ServingEndpointHandle<ServingEndpointRegistry[K]["request"], ServingEndpointRegistry[K]["response"]> : {
|
|
5
|
+
<K> (alias: K): ServingEndpointHandle<ServingEndpointRegistry[K]["request"], ServingEndpointRegistry[K]["response"]>;
|
|
6
|
+
(): ServingEndpointHandle<never, never>;
|
|
7
|
+
};
|
|
5
8
|
|
|
6
9
|
```
|
|
7
10
|
|
|
8
11
|
Factory function returned by `AppKit.serving`.
|
|
9
12
|
|
|
10
|
-
|
|
13
|
+
Adapts based on the `ServingEndpointRegistry` state:
|
|
11
14
|
|
|
12
|
-
* **
|
|
13
|
-
* **
|
|
15
|
+
* **Empty (default):** `(alias?: string) => ServingEndpointHandle` — any string, untyped.
|
|
16
|
+
* **Single key:** alias optional — `serving()` returns the typed handle for the only endpoint.
|
|
17
|
+
* **Multiple keys:** alias required — must specify which endpoint.
|
|
14
18
|
|
|
15
|
-
Run `
|
|
19
|
+
Run `npx appkit generate-types` or start the dev server to generate the registry.
|
package/docs/api/appkit.md
CHANGED
|
@@ -20,6 +20,7 @@ Core library for building Databricks applications with type-safe SQL queries, pl
|
|
|
20
20
|
| [ExecutionError](./docs/api/appkit/Class.ExecutionError.md) | Error thrown when an operation execution fails. Use for statement failures, canceled operations, or unexpected states. |
|
|
21
21
|
| [InitializationError](./docs/api/appkit/Class.InitializationError.md) | Error thrown when a service or component is not properly initialized. Use when accessing services before they are ready. |
|
|
22
22
|
| [Plugin](./docs/api/appkit/Class.Plugin.md) | Base abstract class for creating AppKit plugins. |
|
|
23
|
+
| [PolicyDeniedError](./docs/api/appkit/Class.PolicyDeniedError.md) | Thrown when a policy denies an action. |
|
|
23
24
|
| [ResourceRegistry](./docs/api/appkit/Class.ResourceRegistry.md) | Central registry for tracking plugin resource requirements. Deduplication uses type + resourceKey (machine-stable); alias is for display only. |
|
|
24
25
|
| [ServerError](./docs/api/appkit/Class.ServerError.md) | Error thrown when server lifecycle operations fail. Use for server start/stop issues, configuration conflicts, etc. |
|
|
25
26
|
| [TunnelError](./docs/api/appkit/Class.TunnelError.md) | Error thrown when remote tunnel operations fail. Use for tunnel connection issues, message parsing failures, etc. |
|
|
@@ -33,6 +34,8 @@ Core library for building Databricks applications with type-safe SQL queries, pl
|
|
|
33
34
|
| [CacheConfig](./docs/api/appkit/Interface.CacheConfig.md) | Configuration for the CacheInterceptor. Controls TTL, size limits, storage backend, and probabilistic cleanup. |
|
|
34
35
|
| [DatabaseCredential](./docs/api/appkit/Interface.DatabaseCredential.md) | Database credentials with OAuth token for Postgres connection |
|
|
35
36
|
| [EndpointConfig](./docs/api/appkit/Interface.EndpointConfig.md) | - |
|
|
37
|
+
| [FilePolicyUser](./docs/api/appkit/Interface.FilePolicyUser.md) | Minimal user identity passed to the policy function. |
|
|
38
|
+
| [FileResource](./docs/api/appkit/Interface.FileResource.md) | Describes the file or directory being acted upon. |
|
|
36
39
|
| [GenerateDatabaseCredentialRequest](./docs/api/appkit/Interface.GenerateDatabaseCredentialRequest.md) | Request parameters for generating database OAuth credentials |
|
|
37
40
|
| [ITelemetry](./docs/api/appkit/Interface.ITelemetry.md) | Plugin-facing interface for OpenTelemetry instrumentation. Provides a thin abstraction over OpenTelemetry APIs for plugins. |
|
|
38
41
|
| [LakebasePoolConfig](./docs/api/appkit/Interface.LakebasePoolConfig.md) | Configuration for creating a Lakebase connection pool |
|
|
@@ -50,21 +53,25 @@ Core library for building Databricks applications with type-safe SQL queries, pl
|
|
|
50
53
|
|
|
51
54
|
## Type Aliases[](#type-aliases "Direct link to Type Aliases")
|
|
52
55
|
|
|
53
|
-
| Type Alias | Description
|
|
54
|
-
| ----------------------------------------------------------------------------- |
|
|
55
|
-
| [ConfigSchema](./docs/api/appkit/TypeAlias.ConfigSchema.md) | Configuration schema definition for plugin config. Re-exported from the standard JSON Schema Draft 7 types.
|
|
56
|
-
| [ExecutionResult](./docs/api/appkit/TypeAlias.ExecutionResult.md) | Discriminated union for plugin execution results.
|
|
57
|
-
| [
|
|
58
|
-
| [
|
|
59
|
-
| [
|
|
60
|
-
| [
|
|
61
|
-
| [
|
|
56
|
+
| Type Alias | Description |
|
|
57
|
+
| ----------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------- |
|
|
58
|
+
| [ConfigSchema](./docs/api/appkit/TypeAlias.ConfigSchema.md) | Configuration schema definition for plugin config. Re-exported from the standard JSON Schema Draft 7 types. |
|
|
59
|
+
| [ExecutionResult](./docs/api/appkit/TypeAlias.ExecutionResult.md) | Discriminated union for plugin execution results. |
|
|
60
|
+
| [FileAction](./docs/api/appkit/TypeAlias.FileAction.md) | Every action the files plugin can perform. |
|
|
61
|
+
| [FilePolicy](./docs/api/appkit/TypeAlias.FilePolicy.md) | A policy function that decides whether `user` may perform `action` on `resource`. Return `true` to allow, `false` to deny. |
|
|
62
|
+
| [IAppRouter](./docs/api/appkit/TypeAlias.IAppRouter.md) | Express router type for plugin route registration |
|
|
63
|
+
| [PluginData](./docs/api/appkit/TypeAlias.PluginData.md) | Tuple of plugin class, config, and name. Created by `toPlugin()` and passed to `createApp()`. |
|
|
64
|
+
| [ResourcePermission](./docs/api/appkit/TypeAlias.ResourcePermission.md) | Union of all possible permission levels across all resource types. |
|
|
65
|
+
| [ServingFactory](./docs/api/appkit/TypeAlias.ServingFactory.md) | Factory function returned by `AppKit.serving`. |
|
|
66
|
+
| [ToPlugin](./docs/api/appkit/TypeAlias.ToPlugin.md) | Factory function type returned by `toPlugin()`. Accepts optional config and returns a PluginData tuple. |
|
|
62
67
|
|
|
63
68
|
## Variables[](#variables "Direct link to Variables")
|
|
64
69
|
|
|
65
|
-
| Variable
|
|
66
|
-
|
|
|
67
|
-
| [
|
|
70
|
+
| Variable | Description |
|
|
71
|
+
| ------------------------------------------------------------------- | ---------------------------- |
|
|
72
|
+
| [READ\_ACTIONS](./docs/api/appkit/Variable.READ_ACTIONS.md) | Actions that only read data. |
|
|
73
|
+
| [sql](./docs/api/appkit/Variable.sql.md) | SQL helper namespace |
|
|
74
|
+
| [WRITE\_ACTIONS](./docs/api/appkit/Variable.WRITE_ACTIONS.md) | Actions that mutate data. |
|
|
68
75
|
|
|
69
76
|
## Functions[](#functions "Direct link to Functions")
|
|
70
77
|
|
|
@@ -4,7 +4,9 @@ AppKit can automatically generate TypeScript types for your SQL queries, providi
|
|
|
4
4
|
|
|
5
5
|
## Goal[](#goal "Direct link to Goal")
|
|
6
6
|
|
|
7
|
-
Generate
|
|
7
|
+
Generate type-safe TypeScript declarations for query keys, parameters, and result rows.
|
|
8
|
+
|
|
9
|
+
All generated files live in `shared/appkit-types/`, one per plugin (e.g. `analytics.d.ts`). They use [`declare module`](https://www.typescriptlang.org/docs/handbook/declaration-merging.html#module-augmentation) to augment existing interfaces, so the types apply globally — you never need to import them. TypeScript auto-discovers them through `"include": ["shared/appkit-types"]` in your tsconfig.
|
|
8
10
|
|
|
9
11
|
## Vite plugin: `appKitTypesPlugin`[](#vite-plugin-appkittypesplugin "Direct link to vite-plugin-appkittypesplugin")
|
|
10
12
|
|
|
@@ -12,7 +14,7 @@ The recommended approach is to use the Vite plugin, which watches your SQL files
|
|
|
12
14
|
|
|
13
15
|
### Configuration[](#configuration "Direct link to Configuration")
|
|
14
16
|
|
|
15
|
-
* `outFile?: string` - Output file path (default: `
|
|
17
|
+
* `outFile?: string` - Output file path (default: `shared/appkit-types/analytics.d.ts`)
|
|
16
18
|
* `watchFolders?: string[]` - Folders to watch for SQL files (default: `["../config/queries"]`)
|
|
17
19
|
|
|
18
20
|
### Example[](#example "Direct link to Example")
|
|
@@ -27,7 +29,6 @@ export default defineConfig({
|
|
|
27
29
|
plugins: [
|
|
28
30
|
react(),
|
|
29
31
|
appKitTypesPlugin({
|
|
30
|
-
outFile: "src/appKitTypes.d.ts",
|
|
31
32
|
watchFolders: ["../config/queries"],
|
|
32
33
|
}),
|
|
33
34
|
],
|
|
@@ -54,14 +55,14 @@ npx @databricks/appkit generate-types [rootDir] [outFile] [warehouseId]
|
|
|
54
55
|
* Generate types using warehouse ID from environment
|
|
55
56
|
|
|
56
57
|
```bash
|
|
57
|
-
npx @databricks/appkit generate-types .
|
|
58
|
+
npx @databricks/appkit generate-types . shared/appkit-types/analytics.d.ts
|
|
58
59
|
|
|
59
60
|
```
|
|
60
61
|
|
|
61
62
|
* Generate types using warehouse ID explicitly
|
|
62
63
|
|
|
63
64
|
```bash
|
|
64
|
-
npx @databricks/appkit generate-types .
|
|
65
|
+
npx @databricks/appkit generate-types . shared/appkit-types/analytics.d.ts abc123...
|
|
65
66
|
|
|
66
67
|
```
|
|
67
68
|
|
package/docs/faq.md
CHANGED
|
@@ -6,14 +6,14 @@
|
|
|
6
6
|
|
|
7
7
|
AppKit provides built-in integrations with the following Databricks services via its [plugin system](./docs/plugins.md):
|
|
8
8
|
|
|
9
|
-
| Plugin
|
|
10
|
-
|
|
|
11
|
-
| [Analytics](./docs/plugins/analytics.md)
|
|
12
|
-
| [Lakebase](./docs/plugins/lakebase.md)
|
|
13
|
-
| [Genie](./docs/plugins/genie.md)
|
|
14
|
-
| [Files](./docs/plugins/files.md)
|
|
15
|
-
| [Serving](./docs/plugins/serving.md)
|
|
16
|
-
| [Server](./docs/plugins/server.md)
|
|
9
|
+
| Plugin | Databricks Service | What It Does |
|
|
10
|
+
| ------------------------------------------------------ | --------------------------------- | --------------------------------------------------------------------------------------- |
|
|
11
|
+
| [Analytics](./docs/plugins/analytics.md) | SQL Warehouses | Execute parameterized SQL queries with built-in caching, retry, and Arrow support |
|
|
12
|
+
| [Lakebase](./docs/plugins/lakebase.md) | Lakebase Autoscaling (PostgreSQL) | Relational database access via standard pg.Pool with automatic OAuth token refresh |
|
|
13
|
+
| [Genie](./docs/plugins/genie.md) | AI/BI Genie Spaces | Natural language data queries with conversation management and streaming |
|
|
14
|
+
| [Files](./docs/plugins/files.md) | Unity Catalog Volumes | Multi-volume file operations (list, read, upload, download, delete, preview) |
|
|
15
|
+
| [Model Serving](./docs/plugins/model-serving.md) | Model Serving | Authenticated proxy to Model Serving endpoints with invoke and streaming support |
|
|
16
|
+
| [Server](./docs/plugins/server.md) | N/A | Express HTTP server with static file serving, Vite dev mode, and plugin route injection |
|
|
17
17
|
|
|
18
18
|
Stay tuned for new plugins as we constantly expand integrations!
|
|
19
19
|
|
|
@@ -139,7 +139,7 @@ function SpendTable() {
|
|
|
139
139
|
Augment the `QueryRegistry` interface to get full type inference on parameters and results:
|
|
140
140
|
|
|
141
141
|
```ts
|
|
142
|
-
//
|
|
142
|
+
// shared/appkit-types/analytics.d.ts
|
|
143
143
|
declare module "@databricks/appkit-ui/react" {
|
|
144
144
|
interface QueryRegistry {
|
|
145
145
|
spend_summary: {
|
|
@@ -3,8 +3,12 @@
|
|
|
3
3
|
If you need custom API routes or background logic, implement an AppKit plugin. The fastest way is to use the CLI:
|
|
4
4
|
|
|
5
5
|
```bash
|
|
6
|
+
# Interactive
|
|
6
7
|
npx @databricks/appkit plugin create
|
|
7
8
|
|
|
9
|
+
# Non-interactive
|
|
10
|
+
npx @databricks/appkit plugin create --placement in-repo --path plugins/my-plugin --name my-plugin --description "My plugin" --force
|
|
11
|
+
|
|
8
12
|
```
|
|
9
13
|
|
|
10
14
|
For a deeper understanding of the plugin structure, read on.
|
|
@@ -38,7 +38,6 @@ Exported from `@databricks/appkit`:
|
|
|
38
38
|
* `getWorkspaceClient()`: Returns the appropriate WorkspaceClient for current context
|
|
39
39
|
* `getWarehouseId()`: `Promise<string>` (from `DATABRICKS_WAREHOUSE_ID` or auto-selected in dev)
|
|
40
40
|
* `getWorkspaceId()`: `Promise<string>` (from `DATABRICKS_WORKSPACE_ID` or fetched)
|
|
41
|
-
* `isInUserContext()`: Returns `true` if currently executing in user context
|
|
42
41
|
|
|
43
42
|
## Development mode behavior[](#development-mode-behavior "Direct link to Development mode behavior")
|
|
44
43
|
|
package/docs/plugins/files.md
CHANGED
|
@@ -12,6 +12,7 @@ File operations against Databricks Unity Catalog Volumes. Supports listing, read
|
|
|
12
12
|
* Automatic cache invalidation on write operations
|
|
13
13
|
* Custom content type mappings
|
|
14
14
|
* Per-user execution context (OBO)
|
|
15
|
+
* **Access policies**: Per-volume policy functions that gate read and write operations
|
|
15
16
|
|
|
16
17
|
## Basic usage[](#basic-usage "Direct link to Basic usage")
|
|
17
18
|
|
|
@@ -75,6 +76,8 @@ interface IFilesConfig {
|
|
|
75
76
|
}
|
|
76
77
|
|
|
77
78
|
interface VolumeConfig {
|
|
79
|
+
/** Access policy for this volume. */
|
|
80
|
+
policy?: FilePolicy;
|
|
78
81
|
/** Maximum upload size in bytes for this volume. Overrides plugin-level default. */
|
|
79
82
|
maxUploadSize?: number;
|
|
80
83
|
/** Map of file extensions to MIME types for this volume. Overrides plugin-level default. */
|
|
@@ -99,6 +102,121 @@ files({
|
|
|
99
102
|
|
|
100
103
|
```
|
|
101
104
|
|
|
105
|
+
### Permission model[](#permission-model "Direct link to Permission model")
|
|
106
|
+
|
|
107
|
+
There are three layers of access control in the files plugin. Understanding how they interact is critical for securing your app:
|
|
108
|
+
|
|
109
|
+
```text
|
|
110
|
+
┌─────────────────────────────────────────────────┐
|
|
111
|
+
│ Unity Catalog grants │
|
|
112
|
+
│ (WRITE_VOLUME on the SP — set at deploy time) │
|
|
113
|
+
├─────────────────────────────────────────────────┤
|
|
114
|
+
│ Execution identity │
|
|
115
|
+
│ HTTP routes → always service principal │
|
|
116
|
+
│ Programmatic → SP by default, asUser() for OBO │
|
|
117
|
+
├─────────────────────────────────────────────────┤
|
|
118
|
+
│ File policies │
|
|
119
|
+
│ Per-volume (action, resource, user) → boolean │
|
|
120
|
+
│ Only app-level gate for HTTP routes │
|
|
121
|
+
└─────────────────────────────────────────────────┘
|
|
122
|
+
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
* **UC grants** control what the service principal can do at the Databricks level. These are set at deploy time via `app.yaml` resource bindings. The SP needs `WRITE_VOLUME` — the plugin declares this via resource requirements.
|
|
126
|
+
* **Execution identity** determines whose credentials are used for the actual API call. HTTP routes always use the SP. The programmatic API uses SP by default but supports `asUser(req)` for OBO.
|
|
127
|
+
* **File policies** are application-level checks evaluated **before** the API call. They receive the requesting user's identity (from the `x-forwarded-user` header) and decide allow/deny. This is the only gate that distinguishes between users on HTTP routes.
|
|
128
|
+
|
|
129
|
+
warning
|
|
130
|
+
|
|
131
|
+
Since HTTP routes always execute as the service principal, removing a user's UC `WRITE_VOLUME` grant has **no effect** on HTTP access — the SP's grant is what's used. Policies are how you restrict what individual users can do through your app.
|
|
132
|
+
|
|
133
|
+
New in v0.21.0
|
|
134
|
+
|
|
135
|
+
File policies are new. Volumes without an explicit policy now default to `publicRead()`, which **denies all write operations** (`upload`, `mkdir`, `delete`). If your app relies on write access, set an explicit policy — for example `files.policy.allowAll()` — on each volume that needs it.
|
|
136
|
+
|
|
137
|
+
#### Access policies[](#access-policies "Direct link to Access policies")
|
|
138
|
+
|
|
139
|
+
Attach a policy to a volume to control which actions are allowed:
|
|
140
|
+
|
|
141
|
+
```ts
|
|
142
|
+
import { files } from "@databricks/appkit";
|
|
143
|
+
|
|
144
|
+
files({
|
|
145
|
+
volumes: {
|
|
146
|
+
uploads: { policy: files.policy.publicRead() },
|
|
147
|
+
},
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
#### Actions[](#actions "Direct link to Actions")
|
|
153
|
+
|
|
154
|
+
Policies receive an action string. The full list, split by category:
|
|
155
|
+
|
|
156
|
+
| Category | Actions |
|
|
157
|
+
| -------- | ------------------------------------------------------------------ |
|
|
158
|
+
| Read | `list`, `read`, `download`, `raw`, `exists`, `metadata`, `preview` |
|
|
159
|
+
| Write | `upload`, `mkdir`, `delete` |
|
|
160
|
+
|
|
161
|
+
#### Built-in policies[](#built-in-policies "Direct link to Built-in policies")
|
|
162
|
+
|
|
163
|
+
| Helper | Allows | Denies |
|
|
164
|
+
| --------------------------- | ---------------- | ----------------- |
|
|
165
|
+
| `files.policy.publicRead()` | all read actions | all write actions |
|
|
166
|
+
| `files.policy.allowAll()` | everything | nothing |
|
|
167
|
+
| `files.policy.denyAll()` | nothing | everything |
|
|
168
|
+
|
|
169
|
+
#### Composing policies[](#composing-policies "Direct link to Composing policies")
|
|
170
|
+
|
|
171
|
+
Combine built-in and custom policies with three combinators:
|
|
172
|
+
|
|
173
|
+
* **`files.policy.all(a, b)`** — AND: all policies must allow. Short-circuits on first denial.
|
|
174
|
+
* **`files.policy.any(a, b)`** — OR: at least one policy must allow. Short-circuits on first allow.
|
|
175
|
+
* **`files.policy.not(p)`** — Inverts a policy. For example, `not(publicRead())` yields a write-only policy (useful for ingestion/drop-box volumes).
|
|
176
|
+
|
|
177
|
+
```ts
|
|
178
|
+
// Read-only for regular users, full access for the service principal
|
|
179
|
+
files({
|
|
180
|
+
volumes: {
|
|
181
|
+
shared: {
|
|
182
|
+
policy: files.policy.any(
|
|
183
|
+
(_action, _resource, user) => !!user.isServicePrincipal,
|
|
184
|
+
files.policy.publicRead(),
|
|
185
|
+
),
|
|
186
|
+
},
|
|
187
|
+
},
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
#### Custom policies[](#custom-policies "Direct link to Custom policies")
|
|
193
|
+
|
|
194
|
+
`FilePolicy` is a function `(action, resource, user) → boolean | Promise<boolean>`, so you can inline arbitrary logic:
|
|
195
|
+
|
|
196
|
+
```ts
|
|
197
|
+
import { type FilePolicy, WRITE_ACTIONS } from "@databricks/appkit";
|
|
198
|
+
|
|
199
|
+
const ADMIN_IDS = ["admin-sp-id", "lead-user-id"];
|
|
200
|
+
|
|
201
|
+
const adminOnly: FilePolicy = (action, _resource, user) => {
|
|
202
|
+
if (WRITE_ACTIONS.has(action)) {
|
|
203
|
+
return ADMIN_IDS.includes(user.id);
|
|
204
|
+
}
|
|
205
|
+
return true; // reads allowed for everyone
|
|
206
|
+
};
|
|
207
|
+
|
|
208
|
+
files({
|
|
209
|
+
volumes: { reports: { policy: adminOnly } },
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
#### Enforcement[](#enforcement "Direct link to Enforcement")
|
|
215
|
+
|
|
216
|
+
* **HTTP routes**: Policy checked before every operation. Denied → `403` JSON response with `Policy denied "{action}" on volume "{volumeKey}"`.
|
|
217
|
+
* **Programmatic API**: Policy checked on both `appkit.files("vol").list()` (SP identity, `isServicePrincipal: true`) and `appkit.files("vol").asUser(req).list()` (user identity). Denied → throws `PolicyDeniedError`.
|
|
218
|
+
* **No policy configured**: Defaults to `files.policy.publicRead()` — read actions are allowed, write actions are denied. A startup warning is logged encouraging you to set an explicit policy.
|
|
219
|
+
|
|
102
220
|
### Custom content types[](#custom-content-types "Direct link to Custom content types")
|
|
103
221
|
|
|
104
222
|
Override or extend the built-in extension → MIME map:
|
|
@@ -118,7 +236,7 @@ Dangerous MIME types (`text/html`, `text/javascript`, `application/javascript`,
|
|
|
118
236
|
|
|
119
237
|
## HTTP routes[](#http-routes "Direct link to HTTP routes")
|
|
120
238
|
|
|
121
|
-
Routes are mounted at `/api/files/*`. All routes
|
|
239
|
+
Routes are mounted at `/api/files/*`. All routes execute as the service principal. Policy enforcement checks user identity (from the `x-forwarded-user` header) before allowing operations — see [Access policies](#access-policies).
|
|
122
240
|
|
|
123
241
|
| Method | Path | Query / Body | Response |
|
|
124
242
|
| ------ | ---------------------- | ---------------------------- | ------------------------------------------------------------ |
|
|
@@ -242,7 +360,36 @@ interface FilePreview extends FileMetadata {
|
|
|
242
360
|
isImage: boolean;
|
|
243
361
|
}
|
|
244
362
|
|
|
363
|
+
type FileAction =
|
|
364
|
+
| "list" | "read" | "download" | "raw"
|
|
365
|
+
| "exists" | "metadata" | "preview"
|
|
366
|
+
| "upload" | "mkdir" | "delete";
|
|
367
|
+
|
|
368
|
+
interface FileResource {
|
|
369
|
+
/** Relative path within the volume. */
|
|
370
|
+
path: string;
|
|
371
|
+
/** The volume key (e.g. `"uploads"`). */
|
|
372
|
+
volume: string;
|
|
373
|
+
/** Content length in bytes — only present for uploads. */
|
|
374
|
+
size?: number;
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
interface FilePolicyUser {
|
|
378
|
+
/** User ID from the `x-forwarded-user` header. */
|
|
379
|
+
id: string;
|
|
380
|
+
/** `true` when the caller is the service principal (direct SDK call, not `asUser`). */
|
|
381
|
+
isServicePrincipal?: boolean;
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
type FilePolicy = (
|
|
385
|
+
action: FileAction,
|
|
386
|
+
resource: FileResource,
|
|
387
|
+
user: FilePolicyUser,
|
|
388
|
+
) => boolean | Promise<boolean>;
|
|
389
|
+
|
|
245
390
|
interface VolumeConfig {
|
|
391
|
+
/** Access policy for this volume. */
|
|
392
|
+
policy?: FilePolicy;
|
|
246
393
|
/** Maximum upload size in bytes for this volume. */
|
|
247
394
|
maxUploadSize?: number;
|
|
248
395
|
/** Map of file extensions to MIME types for this volume. */
|
|
@@ -280,7 +427,7 @@ Built-in extensions: `.png`, `.jpg`, `.jpeg`, `.gif`, `.webp`, `.svg`, `.bmp`, `
|
|
|
280
427
|
|
|
281
428
|
## User context[](#user-context "Direct link to User context")
|
|
282
429
|
|
|
283
|
-
|
|
430
|
+
HTTP routes always execute as the **service principal** — the SP's Databricks credentials are used for all API calls. User identity is extracted from the `x-forwarded-user` header and passed to the volume's [access policy](#access-policies) for authorization. This means UC grants on the SP (not individual users) determine what operations are possible, while policies control what each user is allowed to do through the app.
|
|
284
431
|
|
|
285
432
|
The programmatic API returns a `VolumeHandle` that exposes all `VolumeAPI` methods directly (service principal) and an `asUser(req)` method for OBO access. Calling any method without `asUser()` logs a warning encouraging OBO usage but does not throw. OBO access is strongly recommended for production use.
|
|
286
433
|
|
|
@@ -305,6 +452,7 @@ All errors return JSON:
|
|
|
305
452
|
| Status | Description |
|
|
306
453
|
| ------ | ------------------------------------------------------------- |
|
|
307
454
|
| 400 | Missing or invalid `path` parameter |
|
|
455
|
+
| 403 | Policy denied "`{action}`" on volume "`{volumeKey}`" |
|
|
308
456
|
| 404 | Unknown volume key |
|
|
309
457
|
| 413 | Upload exceeds `maxUploadSize` |
|
|
310
458
|
| 500 | Operation failed (SDK, network, upstream, or unhandled error) |
|
|
@@ -6,19 +6,30 @@ AppKit includes a CLI for managing plugins. All commands are available under `np
|
|
|
6
6
|
|
|
7
7
|
## Create a plugin[](#create-a-plugin "Direct link to Create a plugin")
|
|
8
8
|
|
|
9
|
-
Scaffold a new plugin interactively:
|
|
9
|
+
Scaffold a new plugin interactively or via flags:
|
|
10
10
|
|
|
11
11
|
```bash
|
|
12
|
+
# Interactive mode (prompts for all options)
|
|
12
13
|
npx @databricks/appkit plugin create
|
|
13
14
|
|
|
15
|
+
# Non-interactive mode (all required flags provided)
|
|
16
|
+
npx @databricks/appkit plugin create \
|
|
17
|
+
--placement in-repo \
|
|
18
|
+
--path plugins/my-plugin \
|
|
19
|
+
--name my-plugin \
|
|
20
|
+
--description "My custom plugin" \
|
|
21
|
+
--resources sql_warehouse \
|
|
22
|
+
--force
|
|
23
|
+
|
|
14
24
|
```
|
|
15
25
|
|
|
16
|
-
|
|
26
|
+
In interactive mode, the wizard walks you through:
|
|
17
27
|
|
|
18
28
|
* **Placement**: In your repository (e.g. `plugins/my-plugin`) or as a standalone package
|
|
19
29
|
* **Metadata**: Name, display name, description
|
|
20
30
|
* **Resources**: Which Databricks resources the plugin needs (SQL Warehouse, Secret, etc.) and whether each is required or optional
|
|
21
|
-
|
|
31
|
+
|
|
32
|
+
In non-interactive mode, `--placement`, `--path`, `--name`, and `--description` are required. Resources can be specified as a comma-separated list (`--resources sql_warehouse,volume`) or as JSON for full control (`--resources-json '[{"type":"sql_warehouse","permission":"CAN_MANAGE"}]'`). For all available options, run `npx @databricks/appkit plugin create --help`.
|
|
22
33
|
|
|
23
34
|
The command generates a complete plugin scaffold with `manifest.json` and a TypeScript plugin class that imports the manifest directly — ready to register in your app.
|
|
24
35
|
|
|
@@ -91,12 +102,17 @@ npx @databricks/appkit plugin list --json
|
|
|
91
102
|
|
|
92
103
|
## Add a resource to a plugin[](#add-a-resource-to-a-plugin "Direct link to Add a resource to a plugin")
|
|
93
104
|
|
|
94
|
-
|
|
105
|
+
Add a new resource requirement to an existing plugin manifest. **Requires `manifest.json`** in the plugin directory (the command edits it in place; it does not modify `manifest.js`):
|
|
95
106
|
|
|
96
107
|
```bash
|
|
108
|
+
# Interactive mode
|
|
97
109
|
npx @databricks/appkit plugin add-resource
|
|
98
|
-
|
|
99
|
-
# Or specify the plugin directory
|
|
100
110
|
npx @databricks/appkit plugin add-resource --path plugins/my-plugin
|
|
101
111
|
|
|
112
|
+
# Non-interactive mode (--type triggers flag-based mode)
|
|
113
|
+
npx @databricks/appkit plugin add-resource --path plugins/my-plugin --type sql_warehouse
|
|
114
|
+
npx @databricks/appkit plugin add-resource --path plugins/my-plugin --type volume --no-required --dry-run
|
|
115
|
+
|
|
102
116
|
```
|
|
117
|
+
|
|
118
|
+
In non-interactive mode, only `--type` is required — all other fields (permission, resource key, field env vars) default to sensible values from the schema. Use `--dry-run` to preview the updated manifest without writing. For all available options, run `npx @databricks/appkit plugin add-resource --help`.
|