Skip to content

Commit 7ac43a5

Browse files
committed
refactor: generate plugin types from JSON Schema
Eliminate three hand-maintained copies of ResourceFieldEntry, ResourceRequirement, and PluginManifest by generating TypeScript interfaces from plugin-manifest.schema.json using json-schema-to-typescript. - Add tools/generate-schema-types.ts for schema→TS generation - shared/plugin.ts imports and extends generated types - manifest-types.ts re-exports from generated types - appkit/registry/types.ts narrows type→ResourceType enum, permission→ResourcePermission union - Add generate:types root script and CI drift check - Keep custom script for ResourceType enum, permission hierarchies Signed-off-by: Pawel Kosiec <pawel.kosiec@databricks.com>
1 parent 23cfc51 commit 7ac43a5

15 files changed

Lines changed: 536 additions & 182 deletions

File tree

.github/workflows/ci.yml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,18 @@ jobs:
5050
cache: 'pnpm'
5151
- name: Install dependencies
5252
run: pnpm install --frozen-lockfile
53+
- name: Check generated types are up to date
54+
run: |
55+
pnpm run generate:types
56+
if ! git diff --exit-code packages/shared/src/schemas/plugin-manifest.generated.ts packages/appkit/src/registry/types.generated.ts; then
57+
echo "❌ Error: Generated types are out of sync with plugin-manifest.schema.json."
58+
echo ""
59+
echo "To fix this:"
60+
echo " 1. Run: pnpm run generate:types"
61+
echo " 2. Review and commit the changes"
62+
echo ""
63+
exit 1
64+
fi
5365
- name: Run Biome Check
5466
run: pnpm run check
5567
- name: Run Types Check

docs/docs/api/appkit/Interface.PluginManifest.md

Lines changed: 88 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
# Interface: PluginManifest\<TName\>
22

33
Plugin manifest that declares metadata and resource requirements.
4-
Attached to plugin classes as a static property.
4+
Extends the shared PluginManifest with strict resource types.
5+
6+
## Extends
7+
8+
- `Omit`\<`SharedPluginManifest`, `"resources"` \| `"config"`\>
59

610
## Type Parameters
711

@@ -17,7 +21,13 @@ Attached to plugin classes as a static property.
1721
optional author: string;
1822
```
1923

20-
Optional metadata for community plugins
24+
Author name or organization
25+
26+
#### Inherited from
27+
28+
```ts
29+
Omit.author
30+
```
2131

2232
***
2333

@@ -30,7 +40,7 @@ optional config: {
3040
```
3141

3242
Configuration schema for the plugin.
33-
Defines the shape and validation rules for plugin config.
43+
Uses JSONSchema7 instead of the generated ConfigSchema (which is too restrictive).
3444

3545
#### schema
3646

@@ -48,6 +58,12 @@ description: string;
4858

4959
Brief description of what the plugin does
5060

61+
#### Inherited from
62+
63+
```ts
64+
Omit.description
65+
```
66+
5167
***
5268

5369
### displayName
@@ -56,7 +72,13 @@ Brief description of what the plugin does
5672
displayName: string;
5773
```
5874

59-
Human-readable display name for UI/CLI
75+
Human-readable display name for UI and CLI
76+
77+
#### Inherited from
78+
79+
```ts
80+
Omit.displayName
81+
```
6082

6183
***
6284

@@ -66,7 +88,13 @@ Human-readable display name for UI/CLI
6688
optional hidden: boolean;
6789
```
6890

69-
When true, excluded from the template plugins manifest during sync.
91+
When true, this plugin is excluded from the template plugins manifest (appkit.plugins.json) during sync.
92+
93+
#### Inherited from
94+
95+
```ts
96+
Omit.hidden
97+
```
7098

7199
***
72100

@@ -76,6 +104,14 @@ When true, excluded from the template plugins manifest during sync.
76104
optional keywords: string[];
77105
```
78106

107+
Keywords for plugin discovery
108+
109+
#### Inherited from
110+
111+
```ts
112+
Omit.keywords
113+
```
114+
79115
***
80116

81117
### license?
@@ -84,6 +120,14 @@ optional keywords: string[];
84120
optional license: string;
85121
```
86122

123+
SPDX license identifier
124+
125+
#### Inherited from
126+
127+
```ts
128+
Omit.license
129+
```
130+
87131
***
88132

89133
### name
@@ -94,6 +138,28 @@ name: TName;
94138

95139
Plugin identifier — the single source of truth for the plugin's name
96140

141+
#### Overrides
142+
143+
```ts
144+
Omit.name
145+
```
146+
147+
***
148+
149+
### onSetupMessage?
150+
151+
```ts
152+
optional onSetupMessage: string;
153+
```
154+
155+
Message displayed to the user after project initialization. Use this to inform about manual setup steps (e.g. environment variables, resource provisioning).
156+
157+
#### Inherited from
158+
159+
```ts
160+
Omit.onSetupMessage
161+
```
162+
97163
***
98164

99165
### repository?
@@ -102,6 +168,14 @@ Plugin identifier — the single source of truth for the plugin's name
102168
optional repository: string;
103169
```
104170

171+
URL to the plugin's source repository
172+
173+
#### Inherited from
174+
175+
```ts
176+
Omit.repository
177+
```
178+
105179
***
106180

107181
### resources
@@ -113,7 +187,7 @@ resources: {
113187
};
114188
```
115189

116-
Resource requirements declaration
190+
Resource requirements declaration (with strict ResourceRequirement types)
117191

118192
#### optional
119193

@@ -138,3 +212,11 @@ Resources that must be available for the plugin to function
138212
```ts
139213
optional version: string;
140214
```
215+
216+
Plugin version (semver format)
217+
218+
#### Inherited from
219+
220+
```ts
221+
Omit.version
222+
```

docs/docs/api/appkit/Interface.ResourceEntry.md

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ Extends ResourceRequirement with resolution state and plugin ownership.
1515
alias: string;
1616
```
1717

18-
Unique alias for this resource within the plugin (e.g., 'warehouse', 'secrets'). Used for UI/display.
18+
Human-readable label for UI/display only. Deduplication uses resourceKey, not alias.
1919

2020
#### Inherited from
2121

@@ -43,8 +43,7 @@ Human-readable description of why this resource is needed
4343
fields: Record<string, ResourceFieldEntry>;
4444
```
4545

46-
Map of field name to env and optional description.
47-
Single-value types use one key (e.g. id); multi-value (database, secret) use multiple keys.
46+
Map of field name to env and optional description. Single-value types use one key (e.g. id); multi-value (database, secret) use multiple (e.g. instance_name, database_name or scope, key).
4847

4948
#### Inherited from
5049

@@ -58,7 +57,7 @@ Single-value types use one key (e.g. id); multi-value (database, secret) use mul
5857
permission: ResourcePermission;
5958
```
6059

61-
Required permission level for the resource
60+
Required permission level for the resource (narrowed to union)
6261

6362
#### Inherited from
6463

@@ -94,8 +93,6 @@ Plugin(s) that require this resource (comma-separated if multiple)
9493
required: boolean;
9594
```
9695

97-
Whether this resource is required (true) or optional (false)
98-
9996
#### Inherited from
10097

10198
[`ResourceRequirement`](Interface.ResourceRequirement.md).[`required`](Interface.ResourceRequirement.md#required)
@@ -118,7 +115,7 @@ Whether the resource has been resolved (all field env vars set)
118115
resourceKey: string;
119116
```
120117

121-
Stable key for machine use (env naming, composite keys, app.yaml). Required.
118+
Stable key for machine use: deduplication, env naming, composite keys, app.yaml. Required for registry lookup.
122119

123120
#### Inherited from
124121

@@ -132,7 +129,7 @@ Stable key for machine use (env naming, composite keys, app.yaml). Required.
132129
type: ResourceType;
133130
```
134131

135-
Type of Databricks resource required
132+
Type of Databricks resource required (narrowed to enum)
136133

137134
#### Inherited from
138135

docs/docs/api/appkit/Interface.ResourceFieldEntry.md

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,5 @@
11
# Interface: ResourceFieldEntry
22

3-
Defines a single field for a resource. Each field has its own environment variable and optional description.
4-
Single-value types use one key (e.g. id); multi-value types (database, secret) use multiple (e.g. instance_name, database_name or scope, key).
5-
63
## Properties
74

85
### bundleIgnore?

docs/docs/api/appkit/Interface.ResourceRequirement.md

Lines changed: 51 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
# Interface: ResourceRequirement
22

33
Declares a resource requirement for a plugin.
4-
Can be defined statically in a manifest or dynamically via getResourceRequirements().
4+
Narrows the generated base: type → ResourceType enum, permission → ResourcePermission union.
5+
6+
## Extends
7+
8+
- `ResourceRequirement`
59

610
## Extended by
711

@@ -15,7 +19,13 @@ Can be defined statically in a manifest or dynamically via getResourceRequiremen
1519
alias: string;
1620
```
1721

18-
Unique alias for this resource within the plugin (e.g., 'warehouse', 'secrets'). Used for UI/display.
22+
Human-readable label for UI/display only. Deduplication uses resourceKey, not alias.
23+
24+
#### Inherited from
25+
26+
```ts
27+
SharedResourceRequirement.alias
28+
```
1929

2030
***
2131

@@ -27,6 +37,12 @@ description: string;
2737

2838
Human-readable description of why this resource is needed
2939

40+
#### Inherited from
41+
42+
```ts
43+
SharedResourceRequirement.description
44+
```
45+
3046
***
3147

3248
### fields
@@ -35,8 +51,13 @@ Human-readable description of why this resource is needed
3551
fields: Record<string, ResourceFieldEntry>;
3652
```
3753

38-
Map of field name to env and optional description.
39-
Single-value types use one key (e.g. id); multi-value (database, secret) use multiple keys.
54+
Map of field name to env and optional description. Single-value types use one key (e.g. id); multi-value (database, secret) use multiple (e.g. instance_name, database_name or scope, key).
55+
56+
#### Inherited from
57+
58+
```ts
59+
SharedResourceRequirement.fields
60+
```
4061

4162
***
4263

@@ -46,7 +67,13 @@ Single-value types use one key (e.g. id); multi-value (database, secret) use mul
4667
permission: ResourcePermission;
4768
```
4869

49-
Required permission level for the resource
70+
Required permission level for the resource (narrowed to union)
71+
72+
#### Overrides
73+
74+
```ts
75+
SharedResourceRequirement.permission
76+
```
5077

5178
***
5279

@@ -56,7 +83,11 @@ Required permission level for the resource
5683
required: boolean;
5784
```
5885

59-
Whether this resource is required (true) or optional (false)
86+
#### Inherited from
87+
88+
```ts
89+
SharedResourceRequirement.required
90+
```
6091

6192
***
6293

@@ -66,7 +97,13 @@ Whether this resource is required (true) or optional (false)
6697
resourceKey: string;
6798
```
6899

69-
Stable key for machine use (env naming, composite keys, app.yaml). Required.
100+
Stable key for machine use: deduplication, env naming, composite keys, app.yaml. Required for registry lookup.
101+
102+
#### Inherited from
103+
104+
```ts
105+
SharedResourceRequirement.resourceKey
106+
```
70107

71108
***
72109

@@ -76,4 +113,10 @@ Stable key for machine use (env naming, composite keys, app.yaml). Required.
76113
type: ResourceType;
77114
```
78115

79-
Type of Databricks resource required
116+
Type of Databricks resource required (narrowed to enum)
117+
118+
#### Overrides
119+
120+
```ts
121+
SharedResourceRequirement.type
122+
```

docs/docs/api/appkit/index.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,12 +36,12 @@ plugin architecture, and React integration.
3636
| [GenerateDatabaseCredentialRequest](Interface.GenerateDatabaseCredentialRequest.md) | Request parameters for generating database OAuth credentials |
3737
| [ITelemetry](Interface.ITelemetry.md) | Plugin-facing interface for OpenTelemetry instrumentation. Provides a thin abstraction over OpenTelemetry APIs for plugins. |
3838
| [LakebasePoolConfig](Interface.LakebasePoolConfig.md) | Configuration for creating a Lakebase connection pool |
39-
| [PluginManifest](Interface.PluginManifest.md) | Plugin manifest that declares metadata and resource requirements. Attached to plugin classes as a static property. |
39+
| [PluginManifest](Interface.PluginManifest.md) | Plugin manifest that declares metadata and resource requirements. Extends the shared PluginManifest with strict resource types. |
4040
| [RequestedClaims](Interface.RequestedClaims.md) | Optional claims for fine-grained Unity Catalog table permissions When specified, the returned token will be scoped to only the requested tables |
4141
| [RequestedResource](Interface.RequestedResource.md) | Resource to request permissions for in Unity Catalog |
4242
| [ResourceEntry](Interface.ResourceEntry.md) | Internal representation of a resource in the registry. Extends ResourceRequirement with resolution state and plugin ownership. |
43-
| [ResourceFieldEntry](Interface.ResourceFieldEntry.md) | Defines a single field for a resource. Each field has its own environment variable and optional description. Single-value types use one key (e.g. id); multi-value types (database, secret) use multiple (e.g. instance_name, database_name or scope, key). |
44-
| [ResourceRequirement](Interface.ResourceRequirement.md) | Declares a resource requirement for a plugin. Can be defined statically in a manifest or dynamically via getResourceRequirements(). |
43+
| [ResourceFieldEntry](Interface.ResourceFieldEntry.md) | - |
44+
| [ResourceRequirement](Interface.ResourceRequirement.md) | Declares a resource requirement for a plugin. Narrows the generated base: type → ResourceType enum, permission → ResourcePermission union. |
4545
| [StreamExecutionSettings](Interface.StreamExecutionSettings.md) | Configuration for streaming execution with default and user-scoped settings |
4646
| [TelemetryConfig](Interface.TelemetryConfig.md) | OpenTelemetry configuration for AppKit applications |
4747
| [ValidationResult](Interface.ValidationResult.md) | Result of validating all registered resources against the environment. |

0 commit comments

Comments
 (0)