@databricks/appkit 0.5.4 → 0.7.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.
Files changed (228) hide show
  1. package/CLAUDE.md +23 -1
  2. package/NOTICE.md +3 -1
  3. package/bin/appkit.js +0 -0
  4. package/dist/_virtual/_rolldown/runtime.js +1 -33
  5. package/dist/appkit/package.js +1 -1
  6. package/dist/cache/index.d.ts.map +1 -1
  7. package/dist/cache/index.js +7 -7
  8. package/dist/cache/index.js.map +1 -1
  9. package/dist/cache/storage/persistent.js +23 -21
  10. package/dist/cache/storage/persistent.js.map +1 -1
  11. package/dist/cli/commands/plugins-sync.js +369 -0
  12. package/dist/cli/commands/plugins-sync.js.map +1 -0
  13. package/dist/cli/commands/plugins.js +19 -0
  14. package/dist/cli/commands/plugins.js.map +1 -0
  15. package/dist/cli/index.js +2 -0
  16. package/dist/cli/index.js.map +1 -1
  17. package/dist/connectors/index.js +2 -2
  18. package/dist/connectors/lakebase/index.d.ts +16 -0
  19. package/dist/connectors/lakebase/index.d.ts.map +1 -0
  20. package/dist/connectors/lakebase/index.js +21 -2
  21. package/dist/connectors/lakebase/index.js.map +1 -0
  22. package/dist/connectors/lakebase-v1/client.js +13 -0
  23. package/dist/connectors/lakebase-v1/client.js.map +1 -0
  24. package/dist/connectors/lakebase-v1/index.js +3 -0
  25. package/dist/connectors/sql-warehouse/client.js +2 -2
  26. package/dist/context/execution-context.js +1 -7
  27. package/dist/context/execution-context.js.map +1 -1
  28. package/dist/context/index.js +4 -16
  29. package/dist/context/index.js.map +1 -1
  30. package/dist/core/appkit.d.ts.map +1 -1
  31. package/dist/core/appkit.js +6 -2
  32. package/dist/core/appkit.js.map +1 -1
  33. package/dist/index.d.ts +5 -1
  34. package/dist/index.js +8 -3
  35. package/dist/index.js.map +1 -1
  36. package/dist/logging/logger.js +1 -1
  37. package/dist/plugin/plugin.d.ts +95 -3
  38. package/dist/plugin/plugin.d.ts.map +1 -1
  39. package/dist/plugin/plugin.js +98 -10
  40. package/dist/plugin/plugin.js.map +1 -1
  41. package/dist/plugins/analytics/analytics.d.ts +3 -1
  42. package/dist/plugins/analytics/analytics.d.ts.map +1 -1
  43. package/dist/plugins/analytics/analytics.js +5 -3
  44. package/dist/plugins/analytics/analytics.js.map +1 -1
  45. package/dist/plugins/analytics/index.js +1 -0
  46. package/dist/plugins/analytics/manifest.js +21 -0
  47. package/dist/plugins/analytics/manifest.js.map +1 -0
  48. package/dist/plugins/analytics/manifest.json +36 -0
  49. package/dist/plugins/index.js +2 -0
  50. package/dist/plugins/server/index.d.ts +3 -1
  51. package/dist/plugins/server/index.d.ts.map +1 -1
  52. package/dist/plugins/server/index.js +5 -3
  53. package/dist/plugins/server/index.js.map +1 -1
  54. package/dist/plugins/server/manifest.js +21 -0
  55. package/dist/plugins/server/manifest.js.map +1 -0
  56. package/dist/plugins/server/manifest.json +36 -0
  57. package/dist/registry/index.js +5 -0
  58. package/dist/registry/manifest-loader.d.ts +44 -0
  59. package/dist/registry/manifest-loader.d.ts.map +1 -0
  60. package/dist/registry/manifest-loader.js +97 -0
  61. package/dist/registry/manifest-loader.js.map +1 -0
  62. package/dist/registry/resource-registry.d.ts +133 -0
  63. package/dist/registry/resource-registry.d.ts.map +1 -0
  64. package/dist/registry/resource-registry.js +297 -0
  65. package/dist/registry/resource-registry.js.map +1 -0
  66. package/dist/registry/types.d.ts +181 -0
  67. package/dist/registry/types.d.ts.map +1 -0
  68. package/dist/registry/types.js +89 -0
  69. package/dist/registry/types.js.map +1 -0
  70. package/dist/shared/src/plugin.d.ts +66 -1
  71. package/dist/shared/src/plugin.d.ts.map +1 -1
  72. package/docs/docs/api/appkit/Class.AppKitError/index.html +5 -5
  73. package/docs/docs/api/appkit/Class.AuthenticationError/index.html +4 -4
  74. package/docs/docs/api/appkit/Class.ConfigurationError/index.html +4 -4
  75. package/docs/docs/api/appkit/Class.ConnectionError/index.html +4 -4
  76. package/docs/docs/api/appkit/Class.ExecutionError/index.html +4 -4
  77. package/docs/docs/api/appkit/Class.InitializationError/index.html +4 -4
  78. package/docs/docs/api/appkit/Class.Plugin/index.html +28 -16
  79. package/docs/docs/api/appkit/Class.Plugin.md +90 -30
  80. package/docs/docs/api/appkit/Class.ResourceRegistry/index.html +150 -0
  81. package/docs/docs/api/appkit/Class.ResourceRegistry.md +301 -0
  82. package/docs/docs/api/appkit/Class.ServerError/index.html +5 -5
  83. package/docs/docs/api/appkit/Class.TunnelError/index.html +4 -4
  84. package/docs/docs/api/appkit/Class.ValidationError/index.html +4 -4
  85. package/docs/docs/api/appkit/Enumeration.RequestedClaimsPermissionSet/index.html +21 -0
  86. package/docs/docs/api/appkit/Enumeration.RequestedClaimsPermissionSet.md +14 -0
  87. package/docs/docs/api/appkit/Enumeration.ResourceType/index.html +66 -0
  88. package/docs/docs/api/appkit/Enumeration.ResourceType.md +135 -0
  89. package/docs/docs/api/appkit/Function.appKitTypesPlugin/index.html +4 -4
  90. package/docs/docs/api/appkit/Function.createApp/index.html +5 -5
  91. package/docs/docs/api/appkit/Function.createLakebasePool/index.html +24 -0
  92. package/docs/docs/api/appkit/Function.createLakebasePool.md +20 -0
  93. package/docs/docs/api/appkit/Function.generateDatabaseCredential/index.html +30 -0
  94. package/docs/docs/api/appkit/Function.generateDatabaseCredential.md +57 -0
  95. package/docs/docs/api/appkit/Function.getExecutionContext/index.html +5 -5
  96. package/docs/docs/api/appkit/Function.getLakebaseOrmConfig/index.html +39 -0
  97. package/docs/docs/api/appkit/Function.getLakebaseOrmConfig.md +90 -0
  98. package/docs/docs/api/appkit/Function.getLakebasePgConfig/index.html +27 -0
  99. package/docs/docs/api/appkit/Function.getLakebasePgConfig.md +31 -0
  100. package/docs/docs/api/appkit/Function.getPluginManifest/index.html +26 -0
  101. package/docs/docs/api/appkit/Function.getPluginManifest.md +24 -0
  102. package/docs/docs/api/appkit/Function.getResourceRequirements/index.html +28 -0
  103. package/docs/docs/api/appkit/Function.getResourceRequirements.md +42 -0
  104. package/docs/docs/api/appkit/Function.getWorkspaceClient/index.html +22 -0
  105. package/docs/docs/api/appkit/Function.getWorkspaceClient.md +18 -0
  106. package/docs/docs/api/appkit/Function.isSQLTypeMarker/index.html +5 -5
  107. package/docs/docs/api/appkit/Interface.BasePluginConfig/index.html +4 -4
  108. package/docs/docs/api/appkit/Interface.CacheConfig/index.html +5 -5
  109. package/docs/docs/api/appkit/Interface.DatabaseCredential/index.html +28 -0
  110. package/docs/docs/api/appkit/Interface.DatabaseCredential.md +32 -0
  111. package/docs/docs/api/appkit/Interface.GenerateDatabaseCredentialRequest/index.html +38 -0
  112. package/docs/docs/api/appkit/Interface.GenerateDatabaseCredentialRequest.md +54 -0
  113. package/docs/docs/api/appkit/Interface.ITelemetry/index.html +5 -5
  114. package/docs/docs/api/appkit/Interface.LakebasePoolConfig/index.html +79 -0
  115. package/docs/docs/api/appkit/Interface.LakebasePoolConfig.md +126 -0
  116. package/docs/docs/api/appkit/Interface.PluginManifest/index.html +63 -0
  117. package/docs/docs/api/appkit/Interface.PluginManifest.md +135 -0
  118. package/docs/docs/api/appkit/Interface.RequestedClaims/index.html +26 -0
  119. package/docs/docs/api/appkit/Interface.RequestedClaims.md +25 -0
  120. package/docs/docs/api/appkit/Interface.RequestedResource/index.html +27 -0
  121. package/docs/docs/api/appkit/Interface.RequestedResource.md +32 -0
  122. package/docs/docs/api/appkit/Interface.ResourceEntry/index.html +83 -0
  123. package/docs/docs/api/appkit/Interface.ResourceEntry.md +156 -0
  124. package/docs/docs/api/appkit/Interface.ResourceFieldEntry/index.html +26 -0
  125. package/docs/docs/api/appkit/Interface.ResourceFieldEntry.md +25 -0
  126. package/docs/docs/api/appkit/Interface.ResourceRequirement/index.html +51 -0
  127. package/docs/docs/api/appkit/Interface.ResourceRequirement.md +84 -0
  128. package/docs/docs/api/appkit/Interface.StreamExecutionSettings/index.html +5 -5
  129. package/docs/docs/api/appkit/Interface.TelemetryConfig/index.html +5 -5
  130. package/docs/docs/api/appkit/Interface.ValidationResult/index.html +29 -0
  131. package/docs/docs/api/appkit/Interface.ValidationResult.md +36 -0
  132. package/docs/docs/api/appkit/TypeAlias.ConfigSchema/index.html +21 -0
  133. package/docs/docs/api/appkit/TypeAlias.ConfigSchema.md +12 -0
  134. package/docs/docs/api/appkit/TypeAlias.IAppRouter/index.html +5 -5
  135. package/docs/docs/api/appkit/TypeAlias.ResourcePermission/index.html +18 -0
  136. package/docs/docs/api/appkit/TypeAlias.ResourcePermission.md +20 -0
  137. package/docs/docs/api/appkit/Variable.sql/index.html +5 -5
  138. package/docs/docs/api/appkit/index.html +10 -8
  139. package/docs/docs/api/appkit-ui/data/AreaChart/index.html +3 -3
  140. package/docs/docs/api/appkit-ui/data/BarChart/index.html +3 -3
  141. package/docs/docs/api/appkit-ui/data/DataTable/index.html +3 -3
  142. package/docs/docs/api/appkit-ui/data/DonutChart/index.html +3 -3
  143. package/docs/docs/api/appkit-ui/data/HeatmapChart/index.html +3 -3
  144. package/docs/docs/api/appkit-ui/data/LineChart/index.html +3 -3
  145. package/docs/docs/api/appkit-ui/data/PieChart/index.html +3 -3
  146. package/docs/docs/api/appkit-ui/data/RadarChart/index.html +3 -3
  147. package/docs/docs/api/appkit-ui/data/ScatterChart/index.html +3 -3
  148. package/docs/docs/api/appkit-ui/index.html +3 -3
  149. package/docs/docs/api/appkit-ui/styling/index.html +3 -3
  150. package/docs/docs/api/appkit-ui/ui/Accordion/index.html +3 -3
  151. package/docs/docs/api/appkit-ui/ui/Alert/index.html +3 -3
  152. package/docs/docs/api/appkit-ui/ui/AlertDialog/index.html +3 -3
  153. package/docs/docs/api/appkit-ui/ui/AspectRatio/index.html +3 -3
  154. package/docs/docs/api/appkit-ui/ui/Avatar/index.html +3 -3
  155. package/docs/docs/api/appkit-ui/ui/Badge/index.html +3 -3
  156. package/docs/docs/api/appkit-ui/ui/Breadcrumb/index.html +3 -3
  157. package/docs/docs/api/appkit-ui/ui/Button/index.html +3 -3
  158. package/docs/docs/api/appkit-ui/ui/ButtonGroup/index.html +3 -3
  159. package/docs/docs/api/appkit-ui/ui/Calendar/index.html +3 -3
  160. package/docs/docs/api/appkit-ui/ui/Card/index.html +3 -3
  161. package/docs/docs/api/appkit-ui/ui/Carousel/index.html +3 -3
  162. package/docs/docs/api/appkit-ui/ui/ChartContainer/index.html +3 -3
  163. package/docs/docs/api/appkit-ui/ui/Checkbox/index.html +3 -3
  164. package/docs/docs/api/appkit-ui/ui/Collapsible/index.html +3 -3
  165. package/docs/docs/api/appkit-ui/ui/Command/index.html +3 -3
  166. package/docs/docs/api/appkit-ui/ui/ContextMenu/index.html +3 -3
  167. package/docs/docs/api/appkit-ui/ui/Dialog/index.html +3 -3
  168. package/docs/docs/api/appkit-ui/ui/Drawer/index.html +3 -3
  169. package/docs/docs/api/appkit-ui/ui/DropdownMenu/index.html +3 -3
  170. package/docs/docs/api/appkit-ui/ui/Empty/index.html +3 -3
  171. package/docs/docs/api/appkit-ui/ui/Field/index.html +3 -3
  172. package/docs/docs/api/appkit-ui/ui/FormControl/index.html +3 -3
  173. package/docs/docs/api/appkit-ui/ui/HoverCard/index.html +3 -3
  174. package/docs/docs/api/appkit-ui/ui/Input/index.html +3 -3
  175. package/docs/docs/api/appkit-ui/ui/InputGroup/index.html +3 -3
  176. package/docs/docs/api/appkit-ui/ui/InputOTP/index.html +3 -3
  177. package/docs/docs/api/appkit-ui/ui/Item/index.html +3 -3
  178. package/docs/docs/api/appkit-ui/ui/Kbd/index.html +3 -3
  179. package/docs/docs/api/appkit-ui/ui/Label/index.html +3 -3
  180. package/docs/docs/api/appkit-ui/ui/Menubar/index.html +3 -3
  181. package/docs/docs/api/appkit-ui/ui/NavigationMenu/index.html +3 -3
  182. package/docs/docs/api/appkit-ui/ui/Pagination/index.html +3 -3
  183. package/docs/docs/api/appkit-ui/ui/Popover/index.html +3 -3
  184. package/docs/docs/api/appkit-ui/ui/Progress/index.html +3 -3
  185. package/docs/docs/api/appkit-ui/ui/RadioGroup/index.html +3 -3
  186. package/docs/docs/api/appkit-ui/ui/ResizableHandle/index.html +3 -3
  187. package/docs/docs/api/appkit-ui/ui/ScrollArea/index.html +3 -3
  188. package/docs/docs/api/appkit-ui/ui/Select/index.html +3 -3
  189. package/docs/docs/api/appkit-ui/ui/Separator/index.html +3 -3
  190. package/docs/docs/api/appkit-ui/ui/Sheet/index.html +3 -3
  191. package/docs/docs/api/appkit-ui/ui/Sidebar/index.html +3 -3
  192. package/docs/docs/api/appkit-ui/ui/Skeleton/index.html +3 -3
  193. package/docs/docs/api/appkit-ui/ui/Slider/index.html +3 -3
  194. package/docs/docs/api/appkit-ui/ui/Spinner/index.html +3 -3
  195. package/docs/docs/api/appkit-ui/ui/Switch/index.html +3 -3
  196. package/docs/docs/api/appkit-ui/ui/Table/index.html +3 -3
  197. package/docs/docs/api/appkit-ui/ui/Tabs/index.html +3 -3
  198. package/docs/docs/api/appkit-ui/ui/Textarea/index.html +3 -3
  199. package/docs/docs/api/appkit-ui/ui/Toaster/index.html +3 -3
  200. package/docs/docs/api/appkit-ui/ui/Toggle/index.html +3 -3
  201. package/docs/docs/api/appkit-ui/ui/ToggleGroup/index.html +3 -3
  202. package/docs/docs/api/appkit-ui/ui/Tooltip/index.html +3 -3
  203. package/docs/docs/api/appkit.md +55 -28
  204. package/docs/docs/api/index.html +3 -3
  205. package/docs/docs/app-management/index.html +3 -3
  206. package/docs/docs/architecture/index.html +4 -4
  207. package/docs/docs/architecture.md +1 -1
  208. package/docs/docs/category/development/index.html +3 -3
  209. package/docs/docs/configuration/index.html +3 -3
  210. package/docs/docs/core-principles/index.html +3 -3
  211. package/docs/docs/development/ai-assisted-development/index.html +3 -3
  212. package/docs/docs/development/index.html +3 -3
  213. package/docs/docs/development/llm-guide/index.html +3 -3
  214. package/docs/docs/development/local-development/index.html +3 -3
  215. package/docs/docs/development/project-setup/index.html +3 -3
  216. package/docs/docs/development/remote-bridge/index.html +3 -3
  217. package/docs/docs/development/type-generation/index.html +3 -3
  218. package/docs/docs/index.html +3 -3
  219. package/docs/docs/plugins/index.html +18 -8
  220. package/docs/docs/plugins.md +82 -4
  221. package/llms.txt +23 -1
  222. package/package.json +8 -4
  223. package/dist/connectors/lakebase/client.js +0 -362
  224. package/dist/connectors/lakebase/client.js.map +0 -1
  225. package/dist/connectors/lakebase/defaults.js +0 -13
  226. package/dist/connectors/lakebase/defaults.js.map +0 -1
  227. package/dist/utils/env-validator.js +0 -14
  228. package/dist/utils/env-validator.js.map +0 -1
@@ -0,0 +1,297 @@
1
+ import { createLogger } from "../logging/logger.js";
2
+ import { ConfigurationError } from "../errors/configuration.js";
3
+ import { init_errors } from "../errors/index.js";
4
+ import { PERMISSION_HIERARCHY_BY_TYPE } from "./types.js";
5
+ import { getPluginManifest } from "./manifest-loader.js";
6
+
7
+ //#region src/registry/resource-registry.ts
8
+ init_errors();
9
+ const logger = createLogger("resource-registry");
10
+ /**
11
+ * Dedup key for registry: type + resourceKey (machine-stable).
12
+ * alias is for UI/display only.
13
+ */
14
+ function getDedupKey(type, resourceKey) {
15
+ return `${type}:${resourceKey}`;
16
+ }
17
+ /**
18
+ * Returns the most permissive permission for a given resource type.
19
+ * Uses per-type hierarchy; unknown permissions are treated as least permissive.
20
+ */
21
+ function getMostPermissivePermission(resourceType, p1, p2) {
22
+ const hierarchy = PERMISSION_HIERARCHY_BY_TYPE[resourceType];
23
+ return (hierarchy?.indexOf(p1) ?? -1) > (hierarchy?.indexOf(p2) ?? -1) ? p1 : p2;
24
+ }
25
+ /**
26
+ * Central registry for tracking plugin resource requirements.
27
+ * Deduplication uses type + resourceKey (machine-stable); alias is for display only.
28
+ */
29
+ var ResourceRegistry = class ResourceRegistry {
30
+ resources = /* @__PURE__ */ new Map();
31
+ /**
32
+ * Registers a resource requirement for a plugin.
33
+ * If a resource with the same type+resourceKey already exists, merges them:
34
+ * - Combines plugin names (comma-separated)
35
+ * - Uses the most permissive permission (per-type hierarchy)
36
+ * - Marks as required if any plugin requires it
37
+ * - Combines descriptions if they differ
38
+ * - Merges fields; warns when same field name uses different env vars
39
+ *
40
+ * @param plugin - Name of the plugin registering the resource
41
+ * @param resource - Resource requirement specification
42
+ */
43
+ register(plugin, resource) {
44
+ const key = getDedupKey(resource.type, resource.resourceKey);
45
+ const existing = this.resources.get(key);
46
+ if (existing) {
47
+ const merged = this.mergeResources(existing, plugin, resource);
48
+ this.resources.set(key, merged);
49
+ } else {
50
+ const entry = {
51
+ ...resource,
52
+ plugin,
53
+ resolved: false,
54
+ permissionSources: { [plugin]: resource.permission }
55
+ };
56
+ this.resources.set(key, entry);
57
+ }
58
+ }
59
+ /**
60
+ * Collects and registers resource requirements from an array of plugins.
61
+ * For each plugin, loads its manifest (required) and runtime resource requirements.
62
+ *
63
+ * @param rawPlugins - Array of plugin data entries from createApp configuration
64
+ * @throws {ConfigurationError} If any plugin is missing a manifest or manifest is invalid
65
+ */
66
+ collectResources(rawPlugins) {
67
+ for (const pluginData of rawPlugins) {
68
+ if (!pluginData?.plugin) continue;
69
+ const pluginName = pluginData.name;
70
+ const manifest = getPluginManifest(pluginData.plugin);
71
+ for (const resource of manifest.resources.required) this.register(pluginName, {
72
+ ...resource,
73
+ required: true
74
+ });
75
+ for (const resource of manifest.resources.optional || []) this.register(pluginName, {
76
+ ...resource,
77
+ required: false
78
+ });
79
+ if (typeof pluginData.plugin.getResourceRequirements === "function") {
80
+ const runtimeResources = pluginData.plugin.getResourceRequirements(pluginData.config);
81
+ for (const resource of runtimeResources) this.register(pluginName, resource);
82
+ }
83
+ logger.debug("Collected resources from plugin %s: %d total", pluginName, this.getByPlugin(pluginName).length);
84
+ }
85
+ }
86
+ /**
87
+ * Merges a new resource requirement with an existing entry.
88
+ * Applies intelligent merging logic for conflicting properties.
89
+ */
90
+ mergeResources(existing, newPlugin, newResource) {
91
+ const plugins = existing.plugin.split(", ");
92
+ if (!plugins.includes(newPlugin)) plugins.push(newPlugin);
93
+ const permissionSources = {
94
+ ...existing.permissionSources ?? {},
95
+ [newPlugin]: newResource.permission
96
+ };
97
+ const permission = getMostPermissivePermission(existing.type, existing.permission, newResource.permission);
98
+ if (permission !== existing.permission) logger.warn("Resource %s:%s permission escalated from \"%s\" to \"%s\" due to plugin \"%s\" (previously requested by: %s). Review plugin permissions to ensure least-privilege.", existing.type, existing.resourceKey, existing.permission, permission, newPlugin, existing.plugin);
99
+ const required = existing.required || newResource.required;
100
+ let description = existing.description;
101
+ if (newResource.description && newResource.description !== existing.description) {
102
+ if (!existing.description.includes(newResource.description)) description = `${existing.description}; ${newResource.description}`;
103
+ }
104
+ const fields = { ...existing.fields ?? {} };
105
+ for (const [fieldName, newField] of Object.entries(newResource.fields ?? {})) {
106
+ const existingField = fields[fieldName];
107
+ if (existingField) {
108
+ if (existingField.env !== newField.env) logger.warn("Resource %s:%s field \"%s\": conflicting env vars \"%s\" (from %s) vs \"%s\" (from %s). Using first.", existing.type, existing.resourceKey, fieldName, existingField.env, existing.plugin, newField.env, newPlugin);
109
+ } else fields[fieldName] = newField;
110
+ }
111
+ return {
112
+ ...existing,
113
+ plugin: plugins.join(", "),
114
+ permission,
115
+ permissionSources,
116
+ required,
117
+ description,
118
+ fields
119
+ };
120
+ }
121
+ /**
122
+ * Retrieves all registered resources.
123
+ * Returns a copy of the array to prevent external mutations.
124
+ *
125
+ * @returns Array of all registered resource entries
126
+ */
127
+ getAll() {
128
+ return Array.from(this.resources.values());
129
+ }
130
+ /**
131
+ * Gets a specific resource by type and resourceKey (dedup key).
132
+ *
133
+ * @param type - Resource type
134
+ * @param resourceKey - Stable machine key (not alias; alias is for display only)
135
+ * @returns The resource entry if found, undefined otherwise
136
+ */
137
+ get(type, resourceKey) {
138
+ return this.resources.get(getDedupKey(type, resourceKey));
139
+ }
140
+ /**
141
+ * Clears all registered resources.
142
+ * Useful for testing or when rebuilding the registry.
143
+ */
144
+ clear() {
145
+ this.resources.clear();
146
+ }
147
+ /**
148
+ * Returns the number of registered resources.
149
+ */
150
+ size() {
151
+ return this.resources.size;
152
+ }
153
+ /**
154
+ * Gets all resources required by a specific plugin.
155
+ *
156
+ * @param pluginName - Name of the plugin
157
+ * @returns Array of resources where the plugin is listed as a requester
158
+ */
159
+ getByPlugin(pluginName) {
160
+ return this.getAll().filter((entry) => entry.plugin.split(", ").includes(pluginName));
161
+ }
162
+ /**
163
+ * Gets all required resources (where required=true).
164
+ *
165
+ * @returns Array of required resource entries
166
+ */
167
+ getRequired() {
168
+ return this.getAll().filter((entry) => entry.required);
169
+ }
170
+ /**
171
+ * Gets all optional resources (where required=false).
172
+ *
173
+ * @returns Array of optional resource entries
174
+ */
175
+ getOptional() {
176
+ return this.getAll().filter((entry) => !entry.required);
177
+ }
178
+ /**
179
+ * Validates all registered resources against the environment.
180
+ *
181
+ * Checks each resource's field environment variables to determine if it's resolved.
182
+ * Updates the `resolved` and `values` fields on each resource entry.
183
+ *
184
+ * Only required resources affect the `valid` status - optional resources
185
+ * are checked but don't cause validation failure.
186
+ *
187
+ * @returns ValidationResult with validity status, missing resources, and all resources
188
+ *
189
+ * @example
190
+ * ```typescript
191
+ * const registry = ResourceRegistry.getInstance();
192
+ * const result = registry.validate();
193
+ *
194
+ * if (!result.valid) {
195
+ * console.error("Missing resources:", result.missing.map(r => Object.values(r.fields).map(f => f.env)));
196
+ * }
197
+ * ```
198
+ */
199
+ validate() {
200
+ const missing = [];
201
+ for (const entry of this.resources.values()) {
202
+ const values = {};
203
+ let allSet = true;
204
+ for (const [fieldName, fieldDef] of Object.entries(entry.fields)) {
205
+ const val = process.env[fieldDef.env];
206
+ if (val !== void 0 && val !== "") values[fieldName] = val;
207
+ else allSet = false;
208
+ }
209
+ if (allSet) {
210
+ entry.resolved = true;
211
+ entry.values = values;
212
+ logger.debug("Resource %s:%s resolved from fields", entry.type, entry.alias);
213
+ } else {
214
+ entry.resolved = false;
215
+ entry.values = Object.keys(values).length > 0 ? values : void 0;
216
+ if (entry.required) {
217
+ missing.push(entry);
218
+ logger.debug("Required resource %s:%s missing (fields: %s)", entry.type, entry.alias, Object.keys(entry.fields).join(", "));
219
+ } else logger.debug("Optional resource %s:%s not configured (fields: %s)", entry.type, entry.alias, Object.keys(entry.fields).join(", "));
220
+ }
221
+ }
222
+ return {
223
+ valid: missing.length === 0,
224
+ missing,
225
+ all: this.getAll()
226
+ };
227
+ }
228
+ /**
229
+ * Validates all registered resources and enforces the result.
230
+ *
231
+ * - In production: throws a {@link ConfigurationError} if any required resources are missing.
232
+ * - In development (`NODE_ENV=development`): logs a warning but continues, unless
233
+ * `APPKIT_STRICT_VALIDATION=true` is set, in which case throws like production.
234
+ * - When all resources are valid: logs a debug message with the count.
235
+ *
236
+ * @returns ValidationResult with validity status, missing resources, and all resources
237
+ * @throws {ConfigurationError} In production when required resources are missing, or in dev when APPKIT_STRICT_VALIDATION=true
238
+ */
239
+ enforceValidation() {
240
+ const validation = this.validate();
241
+ const isDevelopment = process.env.NODE_ENV === "development";
242
+ const strictValidation = process.env.APPKIT_STRICT_VALIDATION === "true" || process.env.APPKIT_STRICT_VALIDATION === "1";
243
+ if (!validation.valid) {
244
+ const errorMessage = ResourceRegistry.formatMissingResources(validation.missing);
245
+ if (!isDevelopment || strictValidation) throw new ConfigurationError(errorMessage, { context: { missingResources: validation.missing.map((r) => ({
246
+ type: r.type,
247
+ alias: r.alias,
248
+ plugin: r.plugin,
249
+ envVars: Object.values(r.fields).map((f) => f.env)
250
+ })) } });
251
+ const banner = ResourceRegistry.formatDevWarningBanner(validation.missing);
252
+ logger.warn("\n%s", banner);
253
+ } else if (this.size() > 0) logger.debug("All %d resources validated successfully", this.size());
254
+ return validation;
255
+ }
256
+ /**
257
+ * Formats missing resources into a human-readable error message.
258
+ *
259
+ * @param missing - Array of missing resource entries
260
+ * @returns Formatted error message string
261
+ */
262
+ static formatMissingResources(missing) {
263
+ if (missing.length === 0) return "No missing resources";
264
+ return `Missing required resources:\n${missing.map((entry) => {
265
+ const envHint = ` (set ${Object.values(entry.fields).map((f) => f.env).join(", ")})`;
266
+ return ` - ${entry.type}:${entry.alias} [${entry.plugin}]${envHint}`;
267
+ }).join("\n")}`;
268
+ }
269
+ /**
270
+ * Formats a highly visible warning banner for dev-mode missing resources.
271
+ * Uses box drawing to ensure the message is impossible to miss in scrolling logs.
272
+ *
273
+ * @param missing - Array of missing resource entries
274
+ * @returns Formatted banner string
275
+ */
276
+ static formatDevWarningBanner(missing) {
277
+ const contentLines = ["MISSING REQUIRED RESOURCES (dev mode — would fail in production)", ""];
278
+ for (const entry of missing) {
279
+ const envVars = Object.values(entry.fields).map((f) => f.env);
280
+ contentLines.push(` ${entry.type}:${entry.alias} (plugin: ${entry.plugin})`);
281
+ contentLines.push(` Set: ${envVars.join(", ")}`);
282
+ }
283
+ contentLines.push("");
284
+ contentLines.push("Add these to your .env file or environment to suppress this warning.");
285
+ const maxLen = Math.max(...contentLines.map((l) => l.length));
286
+ const border = "=".repeat(maxLen + 4);
287
+ return [
288
+ border,
289
+ ...contentLines.map((line) => `| ${line.padEnd(maxLen)} |`),
290
+ border
291
+ ].join("\n");
292
+ }
293
+ };
294
+
295
+ //#endregion
296
+ export { ResourceRegistry };
297
+ //# sourceMappingURL=resource-registry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resource-registry.js","names":[],"sources":["../../src/registry/resource-registry.ts"],"sourcesContent":["/**\n * Resource Registry\n *\n * Central registry that tracks all resource requirements across all plugins.\n * Provides visibility into Databricks resources needed by the application\n * and handles deduplication when multiple plugins require the same resource\n * (dedup key: type + resourceKey).\n *\n * Use `new ResourceRegistry()` for instance-scoped usage (e.g. createApp).\n * getInstance() / resetInstance() remain for backward compatibility in tests.\n */\n\nimport type { BasePluginConfig, PluginConstructor, PluginData } from \"shared\";\nimport { ConfigurationError } from \"../errors\";\nimport { createLogger } from \"../logging/logger\";\nimport { getPluginManifest } from \"./manifest-loader\";\nimport type {\n ResourceEntry,\n ResourcePermission,\n ResourceRequirement,\n ValidationResult,\n} from \"./types\";\nimport { PERMISSION_HIERARCHY_BY_TYPE, type ResourceType } from \"./types\";\n\nconst logger = createLogger(\"resource-registry\");\n\n/**\n * Dedup key for registry: type + resourceKey (machine-stable).\n * alias is for UI/display only.\n */\nfunction getDedupKey(type: string, resourceKey: string): string {\n return `${type}:${resourceKey}`;\n}\n\n/**\n * Returns the most permissive permission for a given resource type.\n * Uses per-type hierarchy; unknown permissions are treated as least permissive.\n */\nfunction getMostPermissivePermission(\n resourceType: ResourceType,\n p1: ResourcePermission,\n p2: ResourcePermission,\n): ResourcePermission {\n const hierarchy = PERMISSION_HIERARCHY_BY_TYPE[resourceType as ResourceType];\n const index1 = hierarchy?.indexOf(p1) ?? -1;\n const index2 = hierarchy?.indexOf(p2) ?? -1;\n return index1 > index2 ? p1 : p2;\n}\n\n/**\n * Central registry for tracking plugin resource requirements.\n * Deduplication uses type + resourceKey (machine-stable); alias is for display only.\n */\nexport class ResourceRegistry {\n private resources: Map<string, ResourceEntry> = new Map();\n\n /**\n * Registers a resource requirement for a plugin.\n * If a resource with the same type+resourceKey already exists, merges them:\n * - Combines plugin names (comma-separated)\n * - Uses the most permissive permission (per-type hierarchy)\n * - Marks as required if any plugin requires it\n * - Combines descriptions if they differ\n * - Merges fields; warns when same field name uses different env vars\n *\n * @param plugin - Name of the plugin registering the resource\n * @param resource - Resource requirement specification\n */\n public register(plugin: string, resource: ResourceRequirement): void {\n const key = getDedupKey(resource.type, resource.resourceKey);\n const existing = this.resources.get(key);\n\n if (existing) {\n // Merge with existing resource\n const merged = this.mergeResources(existing, plugin, resource);\n this.resources.set(key, merged);\n } else {\n // Create new resource entry with permission source tracking\n const entry: ResourceEntry = {\n ...resource,\n plugin,\n resolved: false,\n permissionSources: { [plugin]: resource.permission },\n };\n this.resources.set(key, entry);\n }\n }\n\n /**\n * Collects and registers resource requirements from an array of plugins.\n * For each plugin, loads its manifest (required) and runtime resource requirements.\n *\n * @param rawPlugins - Array of plugin data entries from createApp configuration\n * @throws {ConfigurationError} If any plugin is missing a manifest or manifest is invalid\n */\n public collectResources(\n rawPlugins: PluginData<PluginConstructor, unknown, string>[],\n ): void {\n for (const pluginData of rawPlugins) {\n if (!pluginData?.plugin) continue;\n\n const pluginName = pluginData.name;\n const manifest = getPluginManifest(pluginData.plugin);\n\n // Register required resources\n for (const resource of manifest.resources.required) {\n this.register(pluginName, { ...resource, required: true });\n }\n\n // Register optional resources\n for (const resource of manifest.resources.optional || []) {\n this.register(pluginName, { ...resource, required: false });\n }\n\n // Check for runtime resource requirements\n if (typeof pluginData.plugin.getResourceRequirements === \"function\") {\n const runtimeResources = pluginData.plugin.getResourceRequirements(\n pluginData.config as BasePluginConfig,\n );\n for (const resource of runtimeResources) {\n this.register(pluginName, resource as ResourceRequirement);\n }\n }\n\n logger.debug(\n \"Collected resources from plugin %s: %d total\",\n pluginName,\n this.getByPlugin(pluginName).length,\n );\n }\n }\n\n /**\n * Merges a new resource requirement with an existing entry.\n * Applies intelligent merging logic for conflicting properties.\n */\n private mergeResources(\n existing: ResourceEntry,\n newPlugin: string,\n newResource: ResourceRequirement,\n ): ResourceEntry {\n // Combine plugin names if not already included\n const plugins = existing.plugin.split(\", \");\n if (!plugins.includes(newPlugin)) {\n plugins.push(newPlugin);\n }\n\n // Track per-plugin permission sources\n const permissionSources: Record<string, ResourcePermission> = {\n ...(existing.permissionSources ?? {}),\n [newPlugin]: newResource.permission,\n };\n\n // Use the most permissive permission for this resource type; warn when escalating\n const permission = getMostPermissivePermission(\n existing.type as ResourceType,\n existing.permission,\n newResource.permission,\n );\n\n if (permission !== existing.permission) {\n logger.warn(\n 'Resource %s:%s permission escalated from \"%s\" to \"%s\" due to plugin \"%s\" ' +\n \"(previously requested by: %s). Review plugin permissions to ensure least-privilege.\",\n existing.type,\n existing.resourceKey,\n existing.permission,\n permission,\n newPlugin,\n existing.plugin,\n );\n }\n\n // Mark as required if any plugin requires it\n const required = existing.required || newResource.required;\n\n // Combine descriptions if they differ\n let description = existing.description;\n if (\n newResource.description &&\n newResource.description !== existing.description\n ) {\n if (!existing.description.includes(newResource.description)) {\n description = `${existing.description}; ${newResource.description}`;\n }\n }\n\n // Merge fields: union of field names; warn when same field name uses different env\n const fields = { ...(existing.fields ?? {}) };\n for (const [fieldName, newField] of Object.entries(\n newResource.fields ?? {},\n )) {\n const existingField = fields[fieldName];\n if (existingField) {\n if (existingField.env !== newField.env) {\n logger.warn(\n 'Resource %s:%s field \"%s\": conflicting env vars \"%s\" (from %s) vs \"%s\" (from %s). Using first.',\n existing.type,\n existing.resourceKey,\n fieldName,\n existingField.env,\n existing.plugin,\n newField.env,\n newPlugin,\n );\n }\n // keep existing\n } else {\n fields[fieldName] = newField;\n }\n }\n\n return {\n ...existing,\n plugin: plugins.join(\", \"),\n permission,\n permissionSources,\n required,\n description,\n fields,\n };\n }\n\n /**\n * Retrieves all registered resources.\n * Returns a copy of the array to prevent external mutations.\n *\n * @returns Array of all registered resource entries\n */\n public getAll(): ResourceEntry[] {\n return Array.from(this.resources.values());\n }\n\n /**\n * Gets a specific resource by type and resourceKey (dedup key).\n *\n * @param type - Resource type\n * @param resourceKey - Stable machine key (not alias; alias is for display only)\n * @returns The resource entry if found, undefined otherwise\n */\n public get(type: string, resourceKey: string): ResourceEntry | undefined {\n return this.resources.get(getDedupKey(type, resourceKey));\n }\n\n /**\n * Clears all registered resources.\n * Useful for testing or when rebuilding the registry.\n */\n public clear(): void {\n this.resources.clear();\n }\n\n /**\n * Returns the number of registered resources.\n */\n public size(): number {\n return this.resources.size;\n }\n\n /**\n * Gets all resources required by a specific plugin.\n *\n * @param pluginName - Name of the plugin\n * @returns Array of resources where the plugin is listed as a requester\n */\n public getByPlugin(pluginName: string): ResourceEntry[] {\n return this.getAll().filter((entry) =>\n entry.plugin.split(\", \").includes(pluginName),\n );\n }\n\n /**\n * Gets all required resources (where required=true).\n *\n * @returns Array of required resource entries\n */\n public getRequired(): ResourceEntry[] {\n return this.getAll().filter((entry) => entry.required);\n }\n\n /**\n * Gets all optional resources (where required=false).\n *\n * @returns Array of optional resource entries\n */\n public getOptional(): ResourceEntry[] {\n return this.getAll().filter((entry) => !entry.required);\n }\n\n /**\n * Validates all registered resources against the environment.\n *\n * Checks each resource's field environment variables to determine if it's resolved.\n * Updates the `resolved` and `values` fields on each resource entry.\n *\n * Only required resources affect the `valid` status - optional resources\n * are checked but don't cause validation failure.\n *\n * @returns ValidationResult with validity status, missing resources, and all resources\n *\n * @example\n * ```typescript\n * const registry = ResourceRegistry.getInstance();\n * const result = registry.validate();\n *\n * if (!result.valid) {\n * console.error(\"Missing resources:\", result.missing.map(r => Object.values(r.fields).map(f => f.env)));\n * }\n * ```\n */\n public validate(): ValidationResult {\n const missing: ResourceEntry[] = [];\n\n for (const entry of this.resources.values()) {\n const values: Record<string, string> = {};\n let allSet = true;\n for (const [fieldName, fieldDef] of Object.entries(entry.fields)) {\n const val = process.env[fieldDef.env];\n if (val !== undefined && val !== \"\") {\n values[fieldName] = val;\n } else {\n allSet = false;\n }\n }\n if (allSet) {\n entry.resolved = true;\n entry.values = values;\n logger.debug(\n \"Resource %s:%s resolved from fields\",\n entry.type,\n entry.alias,\n );\n } else {\n entry.resolved = false;\n entry.values = Object.keys(values).length > 0 ? values : undefined;\n if (entry.required) {\n missing.push(entry);\n logger.debug(\n \"Required resource %s:%s missing (fields: %s)\",\n entry.type,\n entry.alias,\n Object.keys(entry.fields).join(\", \"),\n );\n } else {\n logger.debug(\n \"Optional resource %s:%s not configured (fields: %s)\",\n entry.type,\n entry.alias,\n Object.keys(entry.fields).join(\", \"),\n );\n }\n }\n }\n\n return {\n valid: missing.length === 0,\n missing,\n all: this.getAll(),\n };\n }\n\n /**\n * Validates all registered resources and enforces the result.\n *\n * - In production: throws a {@link ConfigurationError} if any required resources are missing.\n * - In development (`NODE_ENV=development`): logs a warning but continues, unless\n * `APPKIT_STRICT_VALIDATION=true` is set, in which case throws like production.\n * - When all resources are valid: logs a debug message with the count.\n *\n * @returns ValidationResult with validity status, missing resources, and all resources\n * @throws {ConfigurationError} In production when required resources are missing, or in dev when APPKIT_STRICT_VALIDATION=true\n */\n public enforceValidation(): ValidationResult {\n const validation = this.validate();\n const isDevelopment = process.env.NODE_ENV === \"development\";\n const strictValidation =\n process.env.APPKIT_STRICT_VALIDATION === \"true\" ||\n process.env.APPKIT_STRICT_VALIDATION === \"1\";\n\n if (!validation.valid) {\n const errorMessage = ResourceRegistry.formatMissingResources(\n validation.missing,\n );\n\n const shouldThrow = !isDevelopment || strictValidation;\n\n if (shouldThrow) {\n throw new ConfigurationError(errorMessage, {\n context: {\n missingResources: validation.missing.map((r) => ({\n type: r.type,\n alias: r.alias,\n plugin: r.plugin,\n envVars: Object.values(r.fields).map((f) => f.env),\n })),\n },\n });\n }\n\n // Dev mode without strict: use a visually prominent box so the warning can't be missed\n const banner = ResourceRegistry.formatDevWarningBanner(\n validation.missing,\n );\n logger.warn(\"\\n%s\", banner);\n } else if (this.size() > 0) {\n logger.debug(\"All %d resources validated successfully\", this.size());\n }\n\n return validation;\n }\n\n /**\n * Formats missing resources into a human-readable error message.\n *\n * @param missing - Array of missing resource entries\n * @returns Formatted error message string\n */\n public static formatMissingResources(missing: ResourceEntry[]): string {\n if (missing.length === 0) {\n return \"No missing resources\";\n }\n\n const lines = missing.map((entry) => {\n const envVars = Object.values(entry.fields).map((f) => f.env);\n const envHint = ` (set ${envVars.join(\", \")})`;\n return ` - ${entry.type}:${entry.alias} [${entry.plugin}]${envHint}`;\n });\n\n return `Missing required resources:\\n${lines.join(\"\\n\")}`;\n }\n\n /**\n * Formats a highly visible warning banner for dev-mode missing resources.\n * Uses box drawing to ensure the message is impossible to miss in scrolling logs.\n *\n * @param missing - Array of missing resource entries\n * @returns Formatted banner string\n */\n public static formatDevWarningBanner(missing: ResourceEntry[]): string {\n const contentLines: string[] = [\n \"MISSING REQUIRED RESOURCES (dev mode — would fail in production)\",\n \"\",\n ];\n\n for (const entry of missing) {\n const envVars = Object.values(entry.fields).map((f) => f.env);\n contentLines.push(\n ` ${entry.type}:${entry.alias} (plugin: ${entry.plugin})`,\n );\n contentLines.push(` Set: ${envVars.join(\", \")}`);\n }\n\n contentLines.push(\"\");\n contentLines.push(\n \"Add these to your .env file or environment to suppress this warning.\",\n );\n\n const maxLen = Math.max(...contentLines.map((l) => l.length));\n const border = \"=\".repeat(maxLen + 4);\n\n const boxed = contentLines.map((line) => `| ${line.padEnd(maxLen)} |`);\n\n return [border, ...boxed, border].join(\"\\n\");\n }\n}\n"],"mappings":"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"}
@@ -0,0 +1,181 @@
1
+ import { JSONSchema7 } from "json-schema";
2
+
3
+ //#region src/registry/types.d.ts
4
+
5
+ /**
6
+ * Resource Registry Type System
7
+ *
8
+ * This module defines the type system for the AppKit Resource Registry,
9
+ * which enables plugins to declare their Databricks resource requirements
10
+ * in a machine-readable format.
11
+ *
12
+ * Resource types are exposed as first-class citizens with their specific
13
+ * permissions, making it simple for users to declare dependencies.
14
+ * Internal tooling handles conversion to Databricks app.yaml format.
15
+ */
16
+ /**
17
+ * Supported resource types that plugins can depend on.
18
+ * Each type has its own set of valid permissions.
19
+ */
20
+ declare enum ResourceType {
21
+ /** Secret scope for secure credential storage */
22
+ SECRET = "secret",
23
+ /** Databricks Job for scheduled or triggered workflows */
24
+ JOB = "job",
25
+ /** Databricks SQL Warehouse for query execution */
26
+ SQL_WAREHOUSE = "sql_warehouse",
27
+ /** Model serving endpoint for ML inference */
28
+ SERVING_ENDPOINT = "serving_endpoint",
29
+ /** Unity Catalog Volume for file storage */
30
+ VOLUME = "volume",
31
+ /** Vector Search Index for similarity search */
32
+ VECTOR_SEARCH_INDEX = "vector_search_index",
33
+ /** Unity Catalog Function */
34
+ UC_FUNCTION = "uc_function",
35
+ /** Unity Catalog Connection for external data sources */
36
+ UC_CONNECTION = "uc_connection",
37
+ /** Database (Lakebase) for persistent storage */
38
+ DATABASE = "database",
39
+ /** Genie Space for AI assistant */
40
+ GENIE_SPACE = "genie_space",
41
+ /** MLflow Experiment for ML tracking */
42
+ EXPERIMENT = "experiment",
43
+ /** Databricks App dependency */
44
+ APP = "app",
45
+ }
46
+ /** Permissions for SECRET resources */
47
+ type SecretPermission = "MANAGE" | "READ" | "WRITE";
48
+ /** Permissions for JOB resources */
49
+ type JobPermission = "CAN_MANAGE" | "CAN_MANAGE_RUN" | "CAN_VIEW";
50
+ /** Permissions for SQL_WAREHOUSE resources */
51
+ type SqlWarehousePermission = "CAN_MANAGE" | "CAN_USE";
52
+ /** Permissions for SERVING_ENDPOINT resources */
53
+ type ServingEndpointPermission = "CAN_MANAGE" | "CAN_QUERY" | "CAN_VIEW";
54
+ /** Permissions for VOLUME resources */
55
+ type VolumePermission = "READ_VOLUME" | "WRITE_VOLUME";
56
+ /** Permissions for VECTOR_SEARCH_INDEX resources */
57
+ type VectorSearchIndexPermission = "SELECT";
58
+ /** Permissions for UC_FUNCTION resources */
59
+ type UcFunctionPermission = "EXECUTE";
60
+ /** Permissions for UC_CONNECTION resources */
61
+ type UcConnectionPermission = "USE_CONNECTION";
62
+ /** Permissions for DATABASE resources */
63
+ type DatabasePermission = "CAN_CONNECT_AND_CREATE";
64
+ /** Permissions for GENIE_SPACE resources */
65
+ type GenieSpacePermission = "CAN_EDIT" | "CAN_VIEW" | "CAN_RUN" | "CAN_MANAGE";
66
+ /** Permissions for EXPERIMENT resources */
67
+ type ExperimentPermission = "CAN_READ" | "CAN_EDIT" | "CAN_MANAGE";
68
+ /** Permissions for APP resources */
69
+ type AppPermission = "CAN_USE";
70
+ /**
71
+ * Union of all possible permission levels across all resource types.
72
+ */
73
+ type ResourcePermission = SecretPermission | JobPermission | SqlWarehousePermission | ServingEndpointPermission | VolumePermission | VectorSearchIndexPermission | UcFunctionPermission | UcConnectionPermission | DatabasePermission | GenieSpacePermission | ExperimentPermission | AppPermission;
74
+ /**
75
+ * Defines a single field for a resource. Each field has its own environment variable and optional description.
76
+ * 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).
77
+ */
78
+ interface ResourceFieldEntry {
79
+ /** Environment variable name for this field */
80
+ env: string;
81
+ /** Human-readable description for this field */
82
+ description?: string;
83
+ }
84
+ /**
85
+ * Declares a resource requirement for a plugin.
86
+ * Can be defined statically in a manifest or dynamically via getResourceRequirements().
87
+ */
88
+ interface ResourceRequirement {
89
+ /** Type of Databricks resource required */
90
+ type: ResourceType;
91
+ /** Unique alias for this resource within the plugin (e.g., 'warehouse', 'secrets'). Used for UI/display. */
92
+ alias: string;
93
+ /** Stable key for machine use (env naming, composite keys, app.yaml). Required. */
94
+ resourceKey: string;
95
+ /** Human-readable description of why this resource is needed */
96
+ description: string;
97
+ /** Required permission level for the resource */
98
+ permission: ResourcePermission;
99
+ /**
100
+ * Map of field name to env and optional description.
101
+ * Single-value types use one key (e.g. id); multi-value (database, secret) use multiple keys.
102
+ */
103
+ fields: Record<string, ResourceFieldEntry>;
104
+ /** Whether this resource is required (true) or optional (false) */
105
+ required: boolean;
106
+ }
107
+ /**
108
+ * Internal representation of a resource in the registry.
109
+ * Extends ResourceRequirement with resolution state and plugin ownership.
110
+ */
111
+ interface ResourceEntry extends ResourceRequirement {
112
+ /** Plugin(s) that require this resource (comma-separated if multiple) */
113
+ plugin: string;
114
+ /** Whether the resource has been resolved (all field env vars set) */
115
+ resolved: boolean;
116
+ /** Resolved value per field name. Populated by validate() when all field env vars are set. */
117
+ values?: Record<string, string>;
118
+ /**
119
+ * Per-plugin permission tracking.
120
+ * Maps plugin name to the permission it originally requested.
121
+ * Populated when multiple plugins share the same resource.
122
+ */
123
+ permissionSources?: Record<string, ResourcePermission>;
124
+ }
125
+ /**
126
+ * Result of validating all registered resources against the environment.
127
+ */
128
+ interface ValidationResult {
129
+ /** Whether all required resources are available */
130
+ valid: boolean;
131
+ /** List of missing required resources */
132
+ missing: ResourceEntry[];
133
+ /** Complete list of all registered resources (required and optional) */
134
+ all: ResourceEntry[];
135
+ }
136
+ /**
137
+ * Configuration schema definition for plugin config.
138
+ * Re-exported from the standard JSON Schema Draft 7 types.
139
+ *
140
+ * @see {@link https://json-schema.org/draft-07/json-schema-release-notes | JSON Schema Draft 7}
141
+ */
142
+ type ConfigSchema = JSONSchema7;
143
+ /**
144
+ * Plugin manifest that declares metadata and resource requirements.
145
+ * Attached to plugin classes as a static property.
146
+ */
147
+ interface PluginManifest {
148
+ /** Plugin identifier (matches plugin.name) */
149
+ name: string;
150
+ /** Human-readable display name for UI/CLI */
151
+ displayName: string;
152
+ /** Brief description of what the plugin does */
153
+ description: string;
154
+ /**
155
+ * Resource requirements declaration
156
+ */
157
+ resources: {
158
+ /** Resources that must be available for the plugin to function */
159
+ required: Omit<ResourceRequirement, "required">[];
160
+ /** Resources that enhance functionality but are not mandatory */
161
+ optional: Omit<ResourceRequirement, "required">[];
162
+ };
163
+ /**
164
+ * Configuration schema for the plugin.
165
+ * Defines the shape and validation rules for plugin config.
166
+ */
167
+ config?: {
168
+ schema: ConfigSchema;
169
+ };
170
+ /**
171
+ * Optional metadata for community plugins
172
+ */
173
+ author?: string;
174
+ version?: string;
175
+ repository?: string;
176
+ keywords?: string[];
177
+ license?: string;
178
+ }
179
+ //#endregion
180
+ export { ConfigSchema, PluginManifest, ResourceEntry, ResourceFieldEntry, ResourcePermission, ResourceRequirement, ResourceType, ValidationResult };
181
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","names":[],"sources":["../../src/registry/types.ts"],"sourcesContent":[],"mappings":";;;;;;;AAgBA;AA2CA;AAGA;AAGA;AAGA;AAGA;AAGA;AAGA;AAGA;AAGA;AAGA;AAOA;AAGY,aAhFA,YAAA;EAqFA;EAAkB,MAAA,GAAA,QAAA;;KAE1B,GAAA,KAAA;;eAEA,GAAA,eAAA;;kBAEA,GAAA,kBAAA;;QAEA,GAAA,QAAA;;qBAEA,GAAA,qBAAA;;aAEA,GAAA,aAAA;EAAa;EAmCA,aAAA,GAAA,eAAkB;EAWlB;EAAmB,QAAA,GAAA,UAAA;;aActB,GAAA,aAAA;;YAMJ,GAAA,YAAA;EAAM;EAUC,GAAA,GAAA,KAAA;;;AAeoB,KAjJzB,gBAAA,GAiJyB,QAAA,GAAA,MAAA,GAAA,OAAA;;AAfE,KA/H3B,aAAA,GA+H2B,YAAA,GAAA,gBAAA,GAAA,UAAA;;AAqBtB,KAjJL,sBAAA,GAiJqB,YAAA,GAAA,SAAA;;AAKtB,KAnJC,yBAAA,GAmJD,YAAA,GAAA,WAAA,GAAA,UAAA;;AAGS,KAnJR,gBAAA,GAmJQ,aAAA,GAAA,cAAA;AAWpB;AAMiB,KAjKL,2BAAA,GAiKmB,QAAA;;AAeZ,KA7KP,oBAAA,GA6KO,SAAA;;AAGA,KA7KP,sBAAA,GA6KO,gBAAA;;AAQP,KAlLA,kBAAA,GAkLA,wBAAA;;KA/KA,oBAAA;;KAOA,oBAAA;;KAGA,aAAA;;;;KAKA,kBAAA,GACR,mBACA,gBACA,yBACA,4BACA,mBACA,8BACA,uBACA,yBACA,qBACA,uBACA,uBACA;;;;;UAmCa,kBAAA;;;;;;;;;;UAWA,mBAAA;;QAET;;;;;;;;cAYM;;;;;UAMJ,eAAe;;;;;;;;UAUR,aAAA,SAAsB;;;;;;WAQ5B;;;;;;sBAOW,eAAe;;;;;UAMpB,gBAAA;;;;WAKN;;OAGJ;;;;;;;;KAWK,YAAA,GAAe;;;;;UAMV,cAAA;;;;;;;;;;;;cAeH,KAAK;;cAGL,KAAK;;;;;;;YAQP"}
@@ -0,0 +1,89 @@
1
+ //#region src/registry/types.ts
2
+ /**
3
+ * Resource Registry Type System
4
+ *
5
+ * This module defines the type system for the AppKit Resource Registry,
6
+ * which enables plugins to declare their Databricks resource requirements
7
+ * in a machine-readable format.
8
+ *
9
+ * Resource types are exposed as first-class citizens with their specific
10
+ * permissions, making it simple for users to declare dependencies.
11
+ * Internal tooling handles conversion to Databricks app.yaml format.
12
+ */
13
+ /**
14
+ * Supported resource types that plugins can depend on.
15
+ * Each type has its own set of valid permissions.
16
+ */
17
+ let ResourceType = /* @__PURE__ */ function(ResourceType) {
18
+ /** Secret scope for secure credential storage */
19
+ ResourceType["SECRET"] = "secret";
20
+ /** Databricks Job for scheduled or triggered workflows */
21
+ ResourceType["JOB"] = "job";
22
+ /** Databricks SQL Warehouse for query execution */
23
+ ResourceType["SQL_WAREHOUSE"] = "sql_warehouse";
24
+ /** Model serving endpoint for ML inference */
25
+ ResourceType["SERVING_ENDPOINT"] = "serving_endpoint";
26
+ /** Unity Catalog Volume for file storage */
27
+ ResourceType["VOLUME"] = "volume";
28
+ /** Vector Search Index for similarity search */
29
+ ResourceType["VECTOR_SEARCH_INDEX"] = "vector_search_index";
30
+ /** Unity Catalog Function */
31
+ ResourceType["UC_FUNCTION"] = "uc_function";
32
+ /** Unity Catalog Connection for external data sources */
33
+ ResourceType["UC_CONNECTION"] = "uc_connection";
34
+ /** Database (Lakebase) for persistent storage */
35
+ ResourceType["DATABASE"] = "database";
36
+ /** Genie Space for AI assistant */
37
+ ResourceType["GENIE_SPACE"] = "genie_space";
38
+ /** MLflow Experiment for ML tracking */
39
+ ResourceType["EXPERIMENT"] = "experiment";
40
+ /** Databricks App dependency */
41
+ ResourceType["APP"] = "app";
42
+ return ResourceType;
43
+ }({});
44
+ /**
45
+ * Permission hierarchy per resource type (weakest to strongest).
46
+ * Used to compare permissions when merging; higher index = more permissive.
47
+ * Unknown permissions are treated as less than any known permission.
48
+ */
49
+ const PERMISSION_HIERARCHY_BY_TYPE = {
50
+ [ResourceType.SECRET]: [
51
+ "READ",
52
+ "WRITE",
53
+ "MANAGE"
54
+ ],
55
+ [ResourceType.JOB]: [
56
+ "CAN_VIEW",
57
+ "CAN_MANAGE_RUN",
58
+ "CAN_MANAGE"
59
+ ],
60
+ [ResourceType.SQL_WAREHOUSE]: ["CAN_USE", "CAN_MANAGE"],
61
+ [ResourceType.SERVING_ENDPOINT]: [
62
+ "CAN_VIEW",
63
+ "CAN_QUERY",
64
+ "CAN_MANAGE"
65
+ ],
66
+ [ResourceType.VOLUME]: ["READ_VOLUME", "WRITE_VOLUME"],
67
+ [ResourceType.VECTOR_SEARCH_INDEX]: ["SELECT"],
68
+ [ResourceType.UC_FUNCTION]: ["EXECUTE"],
69
+ [ResourceType.UC_CONNECTION]: ["USE_CONNECTION"],
70
+ [ResourceType.DATABASE]: ["CAN_CONNECT_AND_CREATE"],
71
+ [ResourceType.GENIE_SPACE]: [
72
+ "CAN_VIEW",
73
+ "CAN_RUN",
74
+ "CAN_EDIT",
75
+ "CAN_MANAGE"
76
+ ],
77
+ [ResourceType.EXPERIMENT]: [
78
+ "CAN_READ",
79
+ "CAN_EDIT",
80
+ "CAN_MANAGE"
81
+ ],
82
+ [ResourceType.APP]: ["CAN_USE"]
83
+ };
84
+ /** Set of valid permissions per type (for validation). */
85
+ const PERMISSIONS_BY_TYPE = PERMISSION_HIERARCHY_BY_TYPE;
86
+
87
+ //#endregion
88
+ export { PERMISSIONS_BY_TYPE, PERMISSION_HIERARCHY_BY_TYPE, ResourceType };
89
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","names":[],"sources":["../../src/registry/types.ts"],"sourcesContent":["/**\n * Resource Registry Type System\n *\n * This module defines the type system for the AppKit Resource Registry,\n * which enables plugins to declare their Databricks resource requirements\n * in a machine-readable format.\n *\n * Resource types are exposed as first-class citizens with their specific\n * permissions, making it simple for users to declare dependencies.\n * Internal tooling handles conversion to Databricks app.yaml format.\n */\n\n/**\n * Supported resource types that plugins can depend on.\n * Each type has its own set of valid permissions.\n */\nexport enum ResourceType {\n /** Secret scope for secure credential storage */\n SECRET = \"secret\",\n\n /** Databricks Job for scheduled or triggered workflows */\n JOB = \"job\",\n\n /** Databricks SQL Warehouse for query execution */\n SQL_WAREHOUSE = \"sql_warehouse\",\n\n /** Model serving endpoint for ML inference */\n SERVING_ENDPOINT = \"serving_endpoint\",\n\n /** Unity Catalog Volume for file storage */\n VOLUME = \"volume\",\n\n /** Vector Search Index for similarity search */\n VECTOR_SEARCH_INDEX = \"vector_search_index\",\n\n /** Unity Catalog Function */\n UC_FUNCTION = \"uc_function\",\n\n /** Unity Catalog Connection for external data sources */\n UC_CONNECTION = \"uc_connection\",\n\n /** Database (Lakebase) for persistent storage */\n DATABASE = \"database\",\n\n /** Genie Space for AI assistant */\n GENIE_SPACE = \"genie_space\",\n\n /** MLflow Experiment for ML tracking */\n EXPERIMENT = \"experiment\",\n\n /** Databricks App dependency */\n APP = \"app\",\n}\n\n// ============================================================================\n// Permissions per resource type\n// ============================================================================\n\n/** Permissions for SECRET resources */\nexport type SecretPermission = \"MANAGE\" | \"READ\" | \"WRITE\";\n\n/** Permissions for JOB resources */\nexport type JobPermission = \"CAN_MANAGE\" | \"CAN_MANAGE_RUN\" | \"CAN_VIEW\";\n\n/** Permissions for SQL_WAREHOUSE resources */\nexport type SqlWarehousePermission = \"CAN_MANAGE\" | \"CAN_USE\";\n\n/** Permissions for SERVING_ENDPOINT resources */\nexport type ServingEndpointPermission = \"CAN_MANAGE\" | \"CAN_QUERY\" | \"CAN_VIEW\";\n\n/** Permissions for VOLUME resources */\nexport type VolumePermission = \"READ_VOLUME\" | \"WRITE_VOLUME\";\n\n/** Permissions for VECTOR_SEARCH_INDEX resources */\nexport type VectorSearchIndexPermission = \"SELECT\";\n\n/** Permissions for UC_FUNCTION resources */\nexport type UcFunctionPermission = \"EXECUTE\";\n\n/** Permissions for UC_CONNECTION resources */\nexport type UcConnectionPermission = \"USE_CONNECTION\";\n\n/** Permissions for DATABASE resources */\nexport type DatabasePermission = \"CAN_CONNECT_AND_CREATE\";\n\n/** Permissions for GENIE_SPACE resources */\nexport type GenieSpacePermission =\n | \"CAN_EDIT\"\n | \"CAN_VIEW\"\n | \"CAN_RUN\"\n | \"CAN_MANAGE\";\n\n/** Permissions for EXPERIMENT resources */\nexport type ExperimentPermission = \"CAN_READ\" | \"CAN_EDIT\" | \"CAN_MANAGE\";\n\n/** Permissions for APP resources */\nexport type AppPermission = \"CAN_USE\";\n\n/**\n * Union of all possible permission levels across all resource types.\n */\nexport type ResourcePermission =\n | SecretPermission\n | JobPermission\n | SqlWarehousePermission\n | ServingEndpointPermission\n | VolumePermission\n | VectorSearchIndexPermission\n | UcFunctionPermission\n | UcConnectionPermission\n | DatabasePermission\n | GenieSpacePermission\n | ExperimentPermission\n | AppPermission;\n\n/**\n * Permission hierarchy per resource type (weakest to strongest).\n * Used to compare permissions when merging; higher index = more permissive.\n * Unknown permissions are treated as less than any known permission.\n */\nexport const PERMISSION_HIERARCHY_BY_TYPE: Record<\n ResourceType,\n readonly ResourcePermission[]\n> = {\n [ResourceType.SECRET]: [\"READ\", \"WRITE\", \"MANAGE\"],\n [ResourceType.JOB]: [\"CAN_VIEW\", \"CAN_MANAGE_RUN\", \"CAN_MANAGE\"],\n [ResourceType.SQL_WAREHOUSE]: [\"CAN_USE\", \"CAN_MANAGE\"],\n [ResourceType.SERVING_ENDPOINT]: [\"CAN_VIEW\", \"CAN_QUERY\", \"CAN_MANAGE\"],\n [ResourceType.VOLUME]: [\"READ_VOLUME\", \"WRITE_VOLUME\"],\n [ResourceType.VECTOR_SEARCH_INDEX]: [\"SELECT\"],\n [ResourceType.UC_FUNCTION]: [\"EXECUTE\"],\n [ResourceType.UC_CONNECTION]: [\"USE_CONNECTION\"],\n [ResourceType.DATABASE]: [\"CAN_CONNECT_AND_CREATE\"],\n [ResourceType.GENIE_SPACE]: [\"CAN_VIEW\", \"CAN_RUN\", \"CAN_EDIT\", \"CAN_MANAGE\"],\n [ResourceType.EXPERIMENT]: [\"CAN_READ\", \"CAN_EDIT\", \"CAN_MANAGE\"],\n [ResourceType.APP]: [\"CAN_USE\"],\n} as const;\n\n/** Set of valid permissions per type (for validation). */\nexport const PERMISSIONS_BY_TYPE: Record<\n ResourceType,\n readonly ResourcePermission[]\n> = PERMISSION_HIERARCHY_BY_TYPE;\n\n/**\n * Defines a single field for a resource. Each field has its own environment variable and optional description.\n * 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).\n */\nexport interface ResourceFieldEntry {\n /** Environment variable name for this field */\n env: string;\n /** Human-readable description for this field */\n description?: string;\n}\n\n/**\n * Declares a resource requirement for a plugin.\n * Can be defined statically in a manifest or dynamically via getResourceRequirements().\n */\nexport interface ResourceRequirement {\n /** Type of Databricks resource required */\n type: ResourceType;\n\n /** Unique alias for this resource within the plugin (e.g., 'warehouse', 'secrets'). Used for UI/display. */\n alias: string;\n\n /** Stable key for machine use (env naming, composite keys, app.yaml). Required. */\n resourceKey: string;\n\n /** Human-readable description of why this resource is needed */\n description: string;\n\n /** Required permission level for the resource */\n permission: ResourcePermission;\n\n /**\n * Map of field name to env and optional description.\n * Single-value types use one key (e.g. id); multi-value (database, secret) use multiple keys.\n */\n fields: Record<string, ResourceFieldEntry>;\n\n /** Whether this resource is required (true) or optional (false) */\n required: boolean;\n}\n\n/**\n * Internal representation of a resource in the registry.\n * Extends ResourceRequirement with resolution state and plugin ownership.\n */\nexport interface ResourceEntry extends ResourceRequirement {\n /** Plugin(s) that require this resource (comma-separated if multiple) */\n plugin: string;\n\n /** Whether the resource has been resolved (all field env vars set) */\n resolved: boolean;\n\n /** Resolved value per field name. Populated by validate() when all field env vars are set. */\n values?: Record<string, string>;\n\n /**\n * Per-plugin permission tracking.\n * Maps plugin name to the permission it originally requested.\n * Populated when multiple plugins share the same resource.\n */\n permissionSources?: Record<string, ResourcePermission>;\n}\n\n/**\n * Result of validating all registered resources against the environment.\n */\nexport interface ValidationResult {\n /** Whether all required resources are available */\n valid: boolean;\n\n /** List of missing required resources */\n missing: ResourceEntry[];\n\n /** Complete list of all registered resources (required and optional) */\n all: ResourceEntry[];\n}\n\nimport type { JSONSchema7 } from \"json-schema\";\n\n/**\n * Configuration schema definition for plugin config.\n * Re-exported from the standard JSON Schema Draft 7 types.\n *\n * @see {@link https://json-schema.org/draft-07/json-schema-release-notes | JSON Schema Draft 7}\n */\nexport type ConfigSchema = JSONSchema7;\n\n/**\n * Plugin manifest that declares metadata and resource requirements.\n * Attached to plugin classes as a static property.\n */\nexport interface PluginManifest {\n /** Plugin identifier (matches plugin.name) */\n name: string;\n\n /** Human-readable display name for UI/CLI */\n displayName: string;\n\n /** Brief description of what the plugin does */\n description: string;\n\n /**\n * Resource requirements declaration\n */\n resources: {\n /** Resources that must be available for the plugin to function */\n required: Omit<ResourceRequirement, \"required\">[];\n\n /** Resources that enhance functionality but are not mandatory */\n optional: Omit<ResourceRequirement, \"required\">[];\n };\n\n /**\n * Configuration schema for the plugin.\n * Defines the shape and validation rules for plugin config.\n */\n config?: {\n schema: ConfigSchema;\n };\n\n /**\n * Optional metadata for community plugins\n */\n author?: string;\n version?: string;\n repository?: string;\n keywords?: string[];\n license?: string;\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAgBA,IAAY,sDAAL;;AAEL;;AAGA;;AAGA;;AAGA;;AAGA;;AAGA;;AAGA;;AAGA;;AAGA;;AAGA;;AAGA;;AAGA;;;;;;;;AAqEF,MAAa,+BAGT;EACD,aAAa,SAAS;EAAC;EAAQ;EAAS;EAAS;EACjD,aAAa,MAAM;EAAC;EAAY;EAAkB;EAAa;EAC/D,aAAa,gBAAgB,CAAC,WAAW,aAAa;EACtD,aAAa,mBAAmB;EAAC;EAAY;EAAa;EAAa;EACvE,aAAa,SAAS,CAAC,eAAe,eAAe;EACrD,aAAa,sBAAsB,CAAC,SAAS;EAC7C,aAAa,cAAc,CAAC,UAAU;EACtC,aAAa,gBAAgB,CAAC,iBAAiB;EAC/C,aAAa,WAAW,CAAC,yBAAyB;EAClD,aAAa,cAAc;EAAC;EAAY;EAAW;EAAY;EAAa;EAC5E,aAAa,aAAa;EAAC;EAAY;EAAY;EAAa;EAChE,aAAa,MAAM,CAAC,UAAU;CAChC;;AAGD,MAAa,sBAGT"}