@databricks/appkit 0.5.4 → 0.6.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 (195) hide show
  1. package/CLAUDE.md +12 -1
  2. package/NOTICE.md +2 -0
  3. package/bin/appkit.js +0 -0
  4. package/dist/appkit/package.js +1 -1
  5. package/dist/cache/index.js +2 -2
  6. package/dist/cache/index.js.map +1 -1
  7. package/dist/cache/storage/persistent.js.map +1 -1
  8. package/dist/cli/commands/plugins-sync.js +369 -0
  9. package/dist/cli/commands/plugins-sync.js.map +1 -0
  10. package/dist/cli/commands/plugins.js +19 -0
  11. package/dist/cli/commands/plugins.js.map +1 -0
  12. package/dist/cli/index.js +2 -0
  13. package/dist/cli/index.js.map +1 -1
  14. package/dist/connectors/index.js +2 -2
  15. package/dist/connectors/{lakebase → lakebase-v1}/client.js +31 -17
  16. package/dist/connectors/lakebase-v1/client.js.map +1 -0
  17. package/dist/connectors/lakebase-v1/defaults.js +18 -0
  18. package/dist/connectors/lakebase-v1/defaults.js.map +1 -0
  19. package/dist/connectors/lakebase-v1/index.js +3 -0
  20. package/dist/core/appkit.d.ts.map +1 -1
  21. package/dist/core/appkit.js +5 -1
  22. package/dist/core/appkit.js.map +1 -1
  23. package/dist/index.d.ts +4 -1
  24. package/dist/index.js +5 -1
  25. package/dist/index.js.map +1 -1
  26. package/dist/plugin/plugin.d.ts +95 -3
  27. package/dist/plugin/plugin.d.ts.map +1 -1
  28. package/dist/plugin/plugin.js +94 -6
  29. package/dist/plugin/plugin.js.map +1 -1
  30. package/dist/plugins/analytics/analytics.d.ts +3 -1
  31. package/dist/plugins/analytics/analytics.d.ts.map +1 -1
  32. package/dist/plugins/analytics/analytics.js +3 -1
  33. package/dist/plugins/analytics/analytics.js.map +1 -1
  34. package/dist/plugins/analytics/index.js +1 -0
  35. package/dist/plugins/analytics/manifest.js +21 -0
  36. package/dist/plugins/analytics/manifest.js.map +1 -0
  37. package/dist/plugins/analytics/manifest.json +36 -0
  38. package/dist/plugins/index.js +2 -0
  39. package/dist/plugins/server/index.d.ts +3 -1
  40. package/dist/plugins/server/index.d.ts.map +1 -1
  41. package/dist/plugins/server/index.js +3 -1
  42. package/dist/plugins/server/index.js.map +1 -1
  43. package/dist/plugins/server/manifest.js +21 -0
  44. package/dist/plugins/server/manifest.js.map +1 -0
  45. package/dist/plugins/server/manifest.json +36 -0
  46. package/dist/registry/index.js +5 -0
  47. package/dist/registry/manifest-loader.d.ts +44 -0
  48. package/dist/registry/manifest-loader.d.ts.map +1 -0
  49. package/dist/registry/manifest-loader.js +97 -0
  50. package/dist/registry/manifest-loader.js.map +1 -0
  51. package/dist/registry/resource-registry.d.ts +133 -0
  52. package/dist/registry/resource-registry.d.ts.map +1 -0
  53. package/dist/registry/resource-registry.js +297 -0
  54. package/dist/registry/resource-registry.js.map +1 -0
  55. package/dist/registry/types.d.ts +181 -0
  56. package/dist/registry/types.d.ts.map +1 -0
  57. package/dist/registry/types.js +89 -0
  58. package/dist/registry/types.js.map +1 -0
  59. package/dist/shared/src/plugin.d.ts +66 -1
  60. package/dist/shared/src/plugin.d.ts.map +1 -1
  61. package/docs/docs/api/appkit/Class.AppKitError/index.html +5 -5
  62. package/docs/docs/api/appkit/Class.AuthenticationError/index.html +4 -4
  63. package/docs/docs/api/appkit/Class.ConfigurationError/index.html +4 -4
  64. package/docs/docs/api/appkit/Class.ConnectionError/index.html +4 -4
  65. package/docs/docs/api/appkit/Class.ExecutionError/index.html +4 -4
  66. package/docs/docs/api/appkit/Class.InitializationError/index.html +4 -4
  67. package/docs/docs/api/appkit/Class.Plugin/index.html +28 -16
  68. package/docs/docs/api/appkit/Class.Plugin.md +90 -30
  69. package/docs/docs/api/appkit/Class.ResourceRegistry/index.html +150 -0
  70. package/docs/docs/api/appkit/Class.ResourceRegistry.md +301 -0
  71. package/docs/docs/api/appkit/Class.ServerError/index.html +5 -5
  72. package/docs/docs/api/appkit/Class.TunnelError/index.html +4 -4
  73. package/docs/docs/api/appkit/Class.ValidationError/index.html +4 -4
  74. package/docs/docs/api/appkit/Enumeration.ResourceType/index.html +66 -0
  75. package/docs/docs/api/appkit/Enumeration.ResourceType.md +135 -0
  76. package/docs/docs/api/appkit/Function.appKitTypesPlugin/index.html +4 -4
  77. package/docs/docs/api/appkit/Function.createApp/index.html +4 -4
  78. package/docs/docs/api/appkit/Function.getExecutionContext/index.html +5 -5
  79. package/docs/docs/api/appkit/Function.getPluginManifest/index.html +26 -0
  80. package/docs/docs/api/appkit/Function.getPluginManifest.md +24 -0
  81. package/docs/docs/api/appkit/Function.getResourceRequirements/index.html +28 -0
  82. package/docs/docs/api/appkit/Function.getResourceRequirements.md +42 -0
  83. package/docs/docs/api/appkit/Function.isSQLTypeMarker/index.html +5 -5
  84. package/docs/docs/api/appkit/Interface.BasePluginConfig/index.html +4 -4
  85. package/docs/docs/api/appkit/Interface.CacheConfig/index.html +4 -4
  86. package/docs/docs/api/appkit/Interface.ITelemetry/index.html +5 -5
  87. package/docs/docs/api/appkit/Interface.PluginManifest/index.html +63 -0
  88. package/docs/docs/api/appkit/Interface.PluginManifest.md +135 -0
  89. package/docs/docs/api/appkit/Interface.ResourceEntry/index.html +83 -0
  90. package/docs/docs/api/appkit/Interface.ResourceEntry.md +156 -0
  91. package/docs/docs/api/appkit/Interface.ResourceFieldEntry/index.html +26 -0
  92. package/docs/docs/api/appkit/Interface.ResourceFieldEntry.md +25 -0
  93. package/docs/docs/api/appkit/Interface.ResourceRequirement/index.html +51 -0
  94. package/docs/docs/api/appkit/Interface.ResourceRequirement.md +84 -0
  95. package/docs/docs/api/appkit/Interface.StreamExecutionSettings/index.html +5 -5
  96. package/docs/docs/api/appkit/Interface.TelemetryConfig/index.html +5 -5
  97. package/docs/docs/api/appkit/Interface.ValidationResult/index.html +29 -0
  98. package/docs/docs/api/appkit/Interface.ValidationResult.md +36 -0
  99. package/docs/docs/api/appkit/TypeAlias.ConfigSchema/index.html +21 -0
  100. package/docs/docs/api/appkit/TypeAlias.ConfigSchema.md +12 -0
  101. package/docs/docs/api/appkit/TypeAlias.IAppRouter/index.html +5 -5
  102. package/docs/docs/api/appkit/TypeAlias.ResourcePermission/index.html +18 -0
  103. package/docs/docs/api/appkit/TypeAlias.ResourcePermission.md +20 -0
  104. package/docs/docs/api/appkit/Variable.sql/index.html +5 -5
  105. package/docs/docs/api/appkit/index.html +10 -8
  106. package/docs/docs/api/appkit-ui/data/AreaChart/index.html +3 -3
  107. package/docs/docs/api/appkit-ui/data/BarChart/index.html +3 -3
  108. package/docs/docs/api/appkit-ui/data/DataTable/index.html +3 -3
  109. package/docs/docs/api/appkit-ui/data/DonutChart/index.html +3 -3
  110. package/docs/docs/api/appkit-ui/data/HeatmapChart/index.html +3 -3
  111. package/docs/docs/api/appkit-ui/data/LineChart/index.html +3 -3
  112. package/docs/docs/api/appkit-ui/data/PieChart/index.html +3 -3
  113. package/docs/docs/api/appkit-ui/data/RadarChart/index.html +3 -3
  114. package/docs/docs/api/appkit-ui/data/ScatterChart/index.html +3 -3
  115. package/docs/docs/api/appkit-ui/index.html +3 -3
  116. package/docs/docs/api/appkit-ui/styling/index.html +3 -3
  117. package/docs/docs/api/appkit-ui/ui/Accordion/index.html +3 -3
  118. package/docs/docs/api/appkit-ui/ui/Alert/index.html +3 -3
  119. package/docs/docs/api/appkit-ui/ui/AlertDialog/index.html +3 -3
  120. package/docs/docs/api/appkit-ui/ui/AspectRatio/index.html +3 -3
  121. package/docs/docs/api/appkit-ui/ui/Avatar/index.html +3 -3
  122. package/docs/docs/api/appkit-ui/ui/Badge/index.html +3 -3
  123. package/docs/docs/api/appkit-ui/ui/Breadcrumb/index.html +3 -3
  124. package/docs/docs/api/appkit-ui/ui/Button/index.html +3 -3
  125. package/docs/docs/api/appkit-ui/ui/ButtonGroup/index.html +3 -3
  126. package/docs/docs/api/appkit-ui/ui/Calendar/index.html +3 -3
  127. package/docs/docs/api/appkit-ui/ui/Card/index.html +3 -3
  128. package/docs/docs/api/appkit-ui/ui/Carousel/index.html +3 -3
  129. package/docs/docs/api/appkit-ui/ui/ChartContainer/index.html +3 -3
  130. package/docs/docs/api/appkit-ui/ui/Checkbox/index.html +3 -3
  131. package/docs/docs/api/appkit-ui/ui/Collapsible/index.html +3 -3
  132. package/docs/docs/api/appkit-ui/ui/Command/index.html +3 -3
  133. package/docs/docs/api/appkit-ui/ui/ContextMenu/index.html +3 -3
  134. package/docs/docs/api/appkit-ui/ui/Dialog/index.html +3 -3
  135. package/docs/docs/api/appkit-ui/ui/Drawer/index.html +3 -3
  136. package/docs/docs/api/appkit-ui/ui/DropdownMenu/index.html +3 -3
  137. package/docs/docs/api/appkit-ui/ui/Empty/index.html +3 -3
  138. package/docs/docs/api/appkit-ui/ui/Field/index.html +3 -3
  139. package/docs/docs/api/appkit-ui/ui/FormControl/index.html +3 -3
  140. package/docs/docs/api/appkit-ui/ui/HoverCard/index.html +3 -3
  141. package/docs/docs/api/appkit-ui/ui/Input/index.html +3 -3
  142. package/docs/docs/api/appkit-ui/ui/InputGroup/index.html +3 -3
  143. package/docs/docs/api/appkit-ui/ui/InputOTP/index.html +3 -3
  144. package/docs/docs/api/appkit-ui/ui/Item/index.html +3 -3
  145. package/docs/docs/api/appkit-ui/ui/Kbd/index.html +3 -3
  146. package/docs/docs/api/appkit-ui/ui/Label/index.html +3 -3
  147. package/docs/docs/api/appkit-ui/ui/Menubar/index.html +3 -3
  148. package/docs/docs/api/appkit-ui/ui/NavigationMenu/index.html +3 -3
  149. package/docs/docs/api/appkit-ui/ui/Pagination/index.html +3 -3
  150. package/docs/docs/api/appkit-ui/ui/Popover/index.html +3 -3
  151. package/docs/docs/api/appkit-ui/ui/Progress/index.html +3 -3
  152. package/docs/docs/api/appkit-ui/ui/RadioGroup/index.html +3 -3
  153. package/docs/docs/api/appkit-ui/ui/ResizableHandle/index.html +3 -3
  154. package/docs/docs/api/appkit-ui/ui/ScrollArea/index.html +3 -3
  155. package/docs/docs/api/appkit-ui/ui/Select/index.html +3 -3
  156. package/docs/docs/api/appkit-ui/ui/Separator/index.html +3 -3
  157. package/docs/docs/api/appkit-ui/ui/Sheet/index.html +3 -3
  158. package/docs/docs/api/appkit-ui/ui/Sidebar/index.html +3 -3
  159. package/docs/docs/api/appkit-ui/ui/Skeleton/index.html +3 -3
  160. package/docs/docs/api/appkit-ui/ui/Slider/index.html +3 -3
  161. package/docs/docs/api/appkit-ui/ui/Spinner/index.html +3 -3
  162. package/docs/docs/api/appkit-ui/ui/Switch/index.html +3 -3
  163. package/docs/docs/api/appkit-ui/ui/Table/index.html +3 -3
  164. package/docs/docs/api/appkit-ui/ui/Tabs/index.html +3 -3
  165. package/docs/docs/api/appkit-ui/ui/Textarea/index.html +3 -3
  166. package/docs/docs/api/appkit-ui/ui/Toaster/index.html +3 -3
  167. package/docs/docs/api/appkit-ui/ui/Toggle/index.html +3 -3
  168. package/docs/docs/api/appkit-ui/ui/ToggleGroup/index.html +3 -3
  169. package/docs/docs/api/appkit-ui/ui/Tooltip/index.html +3 -3
  170. package/docs/docs/api/appkit.md +44 -28
  171. package/docs/docs/api/index.html +3 -3
  172. package/docs/docs/app-management/index.html +3 -3
  173. package/docs/docs/architecture/index.html +4 -4
  174. package/docs/docs/architecture.md +1 -1
  175. package/docs/docs/category/development/index.html +3 -3
  176. package/docs/docs/configuration/index.html +3 -3
  177. package/docs/docs/core-principles/index.html +3 -3
  178. package/docs/docs/development/ai-assisted-development/index.html +3 -3
  179. package/docs/docs/development/index.html +3 -3
  180. package/docs/docs/development/llm-guide/index.html +3 -3
  181. package/docs/docs/development/local-development/index.html +3 -3
  182. package/docs/docs/development/project-setup/index.html +3 -3
  183. package/docs/docs/development/remote-bridge/index.html +3 -3
  184. package/docs/docs/development/type-generation/index.html +3 -3
  185. package/docs/docs/index.html +3 -3
  186. package/docs/docs/plugins/index.html +18 -8
  187. package/docs/docs/plugins.md +82 -4
  188. package/llms.txt +12 -1
  189. package/package.json +4 -1
  190. package/dist/connectors/lakebase/client.js.map +0 -1
  191. package/dist/connectors/lakebase/defaults.js +0 -13
  192. package/dist/connectors/lakebase/defaults.js.map +0 -1
  193. package/dist/connectors/lakebase/index.js +0 -3
  194. package/dist/utils/env-validator.js +0 -14
  195. package/dist/utils/env-validator.js.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugins-sync.js","names":[],"sources":["../../../src/cli/commands/plugins-sync.ts"],"sourcesContent":["import fs from \"node:fs\";\nimport path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { Lang, parse, type SgNode } from \"@ast-grep/napi\";\nimport Ajv, { type ErrorObject } from \"ajv\";\nimport addFormats from \"ajv-formats\";\nimport { Command } from \"commander\";\n\nconst __dirname = path.dirname(fileURLToPath(import.meta.url));\n// Resolve to package schemas: from dist/cli/commands -> dist/schemas, from src/cli/commands -> shared/schemas\nconst PLUGIN_MANIFEST_SCHEMA_PATH = path.join(\n __dirname,\n \"..\",\n \"..\",\n \"..\",\n \"schemas\",\n \"plugin-manifest.schema.json\",\n);\n\n/**\n * Field entry in a resource requirement (env var + optional description)\n */\ninterface ResourceFieldEntry {\n env: string;\n description?: string;\n}\n\n/**\n * Resource requirement as defined in plugin manifests.\n * Uses fields (single key e.g. id, or multiple e.g. instance_name/database_name, scope/key).\n */\ninterface ResourceRequirement {\n type: string;\n alias: string;\n resourceKey: string;\n description: string;\n permission: string;\n fields: Record<string, ResourceFieldEntry>;\n}\n\n/**\n * Plugin manifest structure (from SDK plugin manifest.json files)\n */\ninterface PluginManifest {\n name: string;\n displayName: string;\n description: string;\n resources: {\n required: ResourceRequirement[];\n optional: ResourceRequirement[];\n };\n config?: { schema: unknown };\n}\n\n/**\n * Plugin entry in the template manifest (includes package source)\n */\ninterface TemplatePlugin extends Omit<PluginManifest, \"config\"> {\n package: string;\n /** When true, this plugin is required by the template and cannot be deselected during CLI init. */\n requiredByTemplate?: boolean;\n}\n\n/**\n * Template plugins manifest structure\n */\ninterface TemplatePluginsManifest {\n $schema: string;\n version: string;\n plugins: Record<string, TemplatePlugin>;\n}\n\n/**\n * Checks whether a resolved file path is within a given directory boundary.\n * Uses path.resolve + startsWith to prevent directory traversal.\n *\n * @param filePath - The path to check (will be resolved to absolute)\n * @param boundary - The directory that must contain filePath\n * @returns true if filePath is inside boundary (or equal to it)\n */\nfunction isWithinDirectory(filePath: string, boundary: string): boolean {\n const resolvedPath = path.resolve(filePath);\n const resolvedBoundary = path.resolve(boundary);\n // Append separator to avoid prefix false-positives (e.g. /foo-bar matching /foo)\n return (\n resolvedPath === resolvedBoundary ||\n resolvedPath.startsWith(`${resolvedBoundary}${path.sep}`)\n );\n}\n\nlet pluginManifestValidator: ReturnType<Ajv[\"compile\"]> | null = null;\n\n/**\n * Loads and compiles the plugin-manifest JSON schema (cached).\n * Returns the compiled validate function or null if the schema cannot be loaded.\n */\nfunction getPluginManifestValidator(): ReturnType<Ajv[\"compile\"]> | null {\n if (pluginManifestValidator) return pluginManifestValidator;\n try {\n const schemaRaw = fs.readFileSync(PLUGIN_MANIFEST_SCHEMA_PATH, \"utf-8\");\n const schema = JSON.parse(schemaRaw) as object;\n const ajv = new Ajv({ allErrors: true, strict: false });\n addFormats(ajv);\n pluginManifestValidator = ajv.compile(schema);\n return pluginManifestValidator;\n } catch (err) {\n console.warn(\n \"Warning: Could not load plugin-manifest schema for validation:\",\n err instanceof Error ? err.message : err,\n );\n return null;\n }\n}\n\n/**\n * Validates a parsed JSON object against the plugin-manifest JSON schema.\n * Returns the manifest if valid, or null and logs schema errors.\n *\n * @param obj - The parsed JSON object to validate\n * @param sourcePath - Path to the manifest file (for warning messages)\n * @returns A valid PluginManifest or null\n */\nfunction validateManifestWithSchema(\n obj: unknown,\n sourcePath: string,\n): PluginManifest | null {\n if (!obj || typeof obj !== \"object\") {\n console.warn(`Warning: Manifest at ${sourcePath} is not a valid object`);\n return null;\n }\n\n const validate = getPluginManifestValidator();\n if (!validate) {\n // Schema not available (e.g. dev without build); fall back to basic shape check\n const m = obj as Record<string, unknown>;\n if (\n typeof m.name === \"string\" &&\n m.name.length > 0 &&\n typeof m.displayName === \"string\" &&\n m.displayName.length > 0 &&\n typeof m.description === \"string\" &&\n m.description.length > 0 &&\n m.resources &&\n typeof m.resources === \"object\" &&\n Array.isArray((m.resources as { required?: unknown }).required)\n ) {\n return obj as PluginManifest;\n }\n console.warn(`Warning: Manifest at ${sourcePath} has invalid structure`);\n return null;\n }\n\n const valid = validate(obj);\n if (valid) return obj as PluginManifest;\n\n const errors: ErrorObject[] = validate.errors ?? [];\n const message = errors\n .map(\n (e: ErrorObject) =>\n ` ${e.instancePath || \"/\"} ${e.message}${e.params ? ` (${JSON.stringify(e.params)})` : \"\"}`,\n )\n .join(\"\\n\");\n console.warn(\n `Warning: Manifest at ${sourcePath} failed schema validation:\\n${message}`,\n );\n return null;\n}\n\n/**\n * Known packages that may contain AppKit plugins.\n * Always scanned for manifests, even if not imported in the server file.\n */\nconst KNOWN_PLUGIN_PACKAGES = [\"@databricks/appkit\"];\n\n/**\n * Candidate paths for the server entry file, relative to cwd.\n * Checked in order; the first that exists is used.\n */\nconst SERVER_FILE_CANDIDATES = [\"server/server.ts\"];\n\n/**\n * Find the server entry file by checking candidate paths in order.\n *\n * @param cwd - Current working directory\n * @returns Absolute path to the server file, or null if none found\n */\nfunction findServerFile(cwd: string): string | null {\n for (const candidate of SERVER_FILE_CANDIDATES) {\n const fullPath = path.join(cwd, candidate);\n if (fs.existsSync(fullPath)) {\n return fullPath;\n }\n }\n return null;\n}\n\n/**\n * Represents a single named import extracted from the server file.\n */\ninterface ParsedImport {\n /** The imported name (or local alias if renamed) */\n name: string;\n /** The original exported name (differs from name when using `import { foo as bar }`) */\n originalName: string;\n /** The module specifier (package name or relative path) */\n source: string;\n}\n\n/**\n * Extract all named imports from the AST root using structural node traversal.\n * Handles single/double quotes, multiline imports, and aliased imports.\n *\n * @param root - AST root node\n * @returns Array of parsed imports with name, original name, and source\n */\nfunction parseImports(root: SgNode): ParsedImport[] {\n const imports: ParsedImport[] = [];\n\n // Find all import_statement nodes in the AST\n const importStatements = root.findAll({\n rule: { kind: \"import_statement\" },\n });\n\n for (const stmt of importStatements) {\n // Extract the module specifier (the string node, e.g. '@databricks/appkit')\n const sourceNode = stmt.find({ rule: { kind: \"string\" } });\n if (!sourceNode) continue;\n\n // Strip surrounding quotes from the string node text\n const source = sourceNode.text().replace(/^['\"]|['\"]$/g, \"\");\n\n // Find named_imports block: { createApp, analytics, server }\n const namedImports = stmt.find({ rule: { kind: \"named_imports\" } });\n if (!namedImports) continue;\n\n // Extract each import_specifier\n const specifiers = namedImports.findAll({\n rule: { kind: \"import_specifier\" },\n });\n\n for (const specifier of specifiers) {\n const children = specifier.children();\n if (children.length >= 3) {\n // Aliased import: `foo as bar` — children are [name, \"as\", alias]\n const originalName = children[0].text();\n const localName = children[children.length - 1].text();\n imports.push({ name: localName, originalName, source });\n } else {\n // Simple import: `foo`\n const name = specifier.text();\n imports.push({ name, originalName: name, source });\n }\n }\n }\n\n return imports;\n}\n\n/**\n * Extract local names of plugins actually used in the `plugins: [...]` array\n * passed to `createApp()`. Uses structural AST traversal to find `pair` nodes\n * with key \"plugins\" and array values containing call expressions.\n *\n * @param root - AST root node\n * @returns Set of local variable names used as plugin calls in the plugins array\n */\nfunction parsePluginUsages(root: SgNode): Set<string> {\n const usedNames = new Set<string>();\n\n // Find all property pairs in the AST\n const pairs = root.findAll({ rule: { kind: \"pair\" } });\n\n for (const pair of pairs) {\n // Check if the property key is \"plugins\"\n const key = pair.find({ rule: { kind: \"property_identifier\" } });\n if (!key || key.text() !== \"plugins\") continue;\n\n // Find the array value\n const arrayNode = pair.find({ rule: { kind: \"array\" } });\n if (!arrayNode) continue;\n\n // Iterate direct children of the array to find call expressions\n for (const child of arrayNode.children()) {\n if (child.kind() === \"call_expression\") {\n // The callee is the first child (the identifier being called)\n const callee = child.children()[0];\n if (callee?.kind() === \"identifier\") {\n usedNames.add(callee.text());\n }\n }\n }\n }\n\n return usedNames;\n}\n\n/**\n * File extensions to try when resolving a relative import to a file path.\n */\nconst RESOLVE_EXTENSIONS = [\".ts\", \".tsx\", \".js\", \".jsx\"];\n\n/**\n * Resolve a relative import source to the plugin directory containing a manifest.json.\n * Follows the convention that plugins live in their own directory with a manifest.json.\n *\n * Resolution strategy:\n * 1. If the import path is a directory, look for manifest.json directly in it\n * 2. If the import path + extension is a file, look for manifest.json in its parent directory\n * 3. If the import path is a directory with an index file, look for manifest.json in that directory\n *\n * @param importSource - The relative import specifier (e.g. \"./plugins/my-plugin\")\n * @param serverFileDir - Absolute path to the directory containing the server file\n * @returns Absolute path to manifest.json, or null if not found\n */\nfunction resolveLocalManifest(\n importSource: string,\n serverFileDir: string,\n projectRoot?: string,\n): string | null {\n const resolved = path.resolve(serverFileDir, importSource);\n\n // Security: Reject paths that escape the project root\n const boundary = projectRoot || serverFileDir;\n if (!isWithinDirectory(resolved, boundary)) {\n console.warn(\n `Warning: Skipping import \"${importSource}\" — resolves outside the project directory`,\n );\n return null;\n }\n\n // Case 1: Import path is a directory with manifest.json\n // e.g. ./plugins/my-plugin → ./plugins/my-plugin/manifest.json\n if (fs.existsSync(resolved) && fs.statSync(resolved).isDirectory()) {\n const manifestPath = path.join(resolved, \"manifest.json\");\n if (fs.existsSync(manifestPath)) return manifestPath;\n }\n\n // Case 2: Import path + extension resolves to a file\n // e.g. ./plugins/my-plugin → ./plugins/my-plugin.ts\n // Look for manifest.json in the same directory\n for (const ext of RESOLVE_EXTENSIONS) {\n const filePath = `${resolved}${ext}`;\n if (fs.existsSync(filePath) && fs.statSync(filePath).isFile()) {\n const dir = path.dirname(filePath);\n const manifestPath = path.join(dir, \"manifest.json\");\n if (fs.existsSync(manifestPath)) return manifestPath;\n break;\n }\n }\n\n // Case 3: Import path is a directory with an index file\n // e.g. ./plugins/my-plugin → ./plugins/my-plugin/index.ts\n for (const ext of RESOLVE_EXTENSIONS) {\n const indexPath = path.join(resolved, `index${ext}`);\n if (fs.existsSync(indexPath)) {\n const manifestPath = path.join(resolved, \"manifest.json\");\n if (fs.existsSync(manifestPath)) return manifestPath;\n break;\n }\n }\n\n return null;\n}\n\n/**\n * Discover plugin manifests from local (relative) imports in the server file.\n * Resolves each relative import to a directory and looks for manifest.json.\n *\n * @param relativeImports - Parsed imports with relative sources (starting with . or /)\n * @param serverFileDir - Absolute path to the directory containing the server file\n * @param cwd - Current working directory (for computing relative paths in output)\n * @returns Map of plugin name to template plugin entry for local plugins\n */\nfunction discoverLocalPlugins(\n relativeImports: ParsedImport[],\n serverFileDir: string,\n cwd: string,\n): TemplatePluginsManifest[\"plugins\"] {\n const plugins: TemplatePluginsManifest[\"plugins\"] = {};\n\n for (const imp of relativeImports) {\n const manifestPath = resolveLocalManifest(imp.source, serverFileDir, cwd);\n if (!manifestPath) continue;\n\n try {\n const content = fs.readFileSync(manifestPath, \"utf-8\");\n const parsed = JSON.parse(content);\n const manifest = validateManifestWithSchema(parsed, manifestPath);\n if (!manifest) continue;\n\n const relativePath = path.relative(cwd, path.dirname(manifestPath));\n\n plugins[manifest.name] = {\n name: manifest.name,\n displayName: manifest.displayName,\n description: manifest.description,\n package: `./${relativePath}`,\n resources: manifest.resources,\n };\n } catch (error) {\n console.warn(\n `Warning: Failed to parse manifest at ${manifestPath}:`,\n error instanceof Error ? error.message : error,\n );\n }\n }\n\n return plugins;\n}\n\n/**\n * Discover plugin manifests from a package's dist folder.\n * Looks for manifest.json files in dist/plugins/{plugin-name}/ directories.\n *\n * @param packagePath - Path to the package in node_modules\n * @returns Array of plugin manifests found in the package\n */\nfunction discoverPluginManifests(packagePath: string): PluginManifest[] {\n const pluginsDir = path.join(packagePath, \"dist\", \"plugins\");\n const manifests: PluginManifest[] = [];\n\n if (!fs.existsSync(pluginsDir)) {\n return manifests;\n }\n\n const entries = fs.readdirSync(pluginsDir, { withFileTypes: true });\n for (const entry of entries) {\n if (entry.isDirectory()) {\n const manifestPath = path.join(pluginsDir, entry.name, \"manifest.json\");\n if (fs.existsSync(manifestPath)) {\n try {\n const content = fs.readFileSync(manifestPath, \"utf-8\");\n const parsed = JSON.parse(content);\n const manifest = validateManifestWithSchema(parsed, manifestPath);\n if (manifest) {\n manifests.push(manifest);\n }\n } catch (error) {\n console.warn(\n `Warning: Failed to parse manifest at ${manifestPath}:`,\n error instanceof Error ? error.message : error,\n );\n }\n }\n }\n }\n\n return manifests;\n}\n\n/**\n * Scan node_modules for packages with plugin manifests.\n *\n * @param cwd - Current working directory to search from\n * @param packages - Set of npm package names to scan for plugin manifests\n * @returns Map of plugin name to template plugin entry\n */\nfunction scanForPlugins(\n cwd: string,\n packages: Iterable<string>,\n): TemplatePluginsManifest[\"plugins\"] {\n const plugins: TemplatePluginsManifest[\"plugins\"] = {};\n\n for (const packageName of packages) {\n const packagePath = path.join(cwd, \"node_modules\", packageName);\n if (!fs.existsSync(packagePath)) {\n continue;\n }\n\n const manifests = discoverPluginManifests(packagePath);\n for (const manifest of manifests) {\n // Convert to template plugin format (exclude config schema)\n plugins[manifest.name] = {\n name: manifest.name,\n displayName: manifest.displayName,\n description: manifest.description,\n package: packageName,\n resources: manifest.resources,\n };\n }\n }\n\n return plugins;\n}\n\n/**\n * Run the plugins sync command.\n * Parses the server entry file to discover which packages to scan for plugin\n * manifests, then marks plugins that are actually used in the `plugins: [...]`\n * array as requiredByTemplate.\n */\nfunction runPluginsSync(options: { write?: boolean; output?: string }) {\n const cwd = process.cwd();\n const outputPath = path.resolve(cwd, options.output || \"appkit.plugins.json\");\n\n // Security: Reject output paths that escape the project root\n if (!isWithinDirectory(outputPath, cwd)) {\n console.error(\n `Error: Output path \"${options.output}\" resolves outside the project directory.`,\n );\n process.exit(1);\n }\n\n console.log(\"Scanning for AppKit plugins...\\n\");\n\n // Step 1: Parse server file to discover imports and plugin usages\n const serverFile = findServerFile(cwd);\n let serverImports: ParsedImport[] = [];\n let pluginUsages = new Set<string>();\n\n if (serverFile) {\n const relativePath = path.relative(cwd, serverFile);\n console.log(`Server entry file: ${relativePath}`);\n\n const content = fs.readFileSync(serverFile, \"utf-8\");\n const lang = serverFile.endsWith(\".tsx\") ? Lang.Tsx : Lang.TypeScript;\n const ast = parse(lang, content);\n const root = ast.root();\n\n serverImports = parseImports(root);\n pluginUsages = parsePluginUsages(root);\n } else {\n console.log(\n \"No server entry file found. Checked:\",\n SERVER_FILE_CANDIDATES.join(\", \"),\n );\n }\n\n // Step 2: Split imports into npm packages and local (relative) imports\n const npmImports = serverImports.filter(\n (i) => !i.source.startsWith(\".\") && !i.source.startsWith(\"/\"),\n );\n const localImports = serverImports.filter(\n (i) => i.source.startsWith(\".\") || i.source.startsWith(\"/\"),\n );\n\n // Step 3: Scan npm packages for plugin manifests\n const npmPackages = new Set([\n ...KNOWN_PLUGIN_PACKAGES,\n ...npmImports.map((i) => i.source),\n ]);\n const plugins = scanForPlugins(cwd, npmPackages);\n\n // Step 4: Discover local plugin manifests from relative imports\n if (serverFile && localImports.length > 0) {\n const serverFileDir = path.dirname(serverFile);\n const localPlugins = discoverLocalPlugins(localImports, serverFileDir, cwd);\n Object.assign(plugins, localPlugins);\n }\n\n const pluginCount = Object.keys(plugins).length;\n\n if (pluginCount === 0) {\n console.log(\"No plugins found.\");\n console.log(\"\\nMake sure you have plugin packages installed:\");\n for (const pkg of npmPackages) {\n console.log(` - ${pkg}`);\n }\n process.exit(1);\n }\n\n // Step 5: Mark plugins that are imported AND used in the plugins array as mandatory.\n // For npm imports, match by package name + plugin name.\n // For local imports, resolve both paths to absolute and compare.\n const serverFileDir = serverFile ? path.dirname(serverFile) : cwd;\n\n for (const imp of serverImports) {\n if (!pluginUsages.has(imp.name)) continue;\n\n const isLocal = imp.source.startsWith(\".\") || imp.source.startsWith(\"/\");\n let plugin: TemplatePlugin | undefined;\n\n if (isLocal) {\n // Resolve the import source to an absolute path from the server file directory\n const resolvedImportDir = path.resolve(serverFileDir, imp.source);\n plugin = Object.values(plugins).find((p) => {\n if (!p.package.startsWith(\".\")) return false;\n const resolvedPluginDir = path.resolve(cwd, p.package);\n return (\n resolvedPluginDir === resolvedImportDir && p.name === imp.originalName\n );\n });\n } else {\n // npm import: direct string comparison\n plugin = Object.values(plugins).find(\n (p) => p.package === imp.source && p.name === imp.originalName,\n );\n }\n\n if (plugin) {\n plugin.requiredByTemplate = true;\n }\n }\n\n console.log(`\\nFound ${pluginCount} plugin(s):`);\n for (const [name, manifest] of Object.entries(plugins)) {\n const resourceCount =\n manifest.resources.required.length + manifest.resources.optional.length;\n const resourceInfo =\n resourceCount > 0 ? ` [${resourceCount} resource(s)]` : \"\";\n const mandatoryTag = manifest.requiredByTemplate ? \" (mandatory)\" : \"\";\n console.log(\n ` ${manifest.requiredByTemplate ? \"●\" : \"○\"} ${manifest.displayName} (${name}) from ${manifest.package}${resourceInfo}${mandatoryTag}`,\n );\n }\n\n const templateManifest: TemplatePluginsManifest = {\n $schema:\n \"https://databricks.github.io/appkit/schemas/template-plugins.schema.json\",\n version: \"1.0\",\n plugins,\n };\n\n if (options.write) {\n fs.writeFileSync(\n outputPath,\n `${JSON.stringify(templateManifest, null, 2)}\\n`,\n );\n console.log(`\\n✓ Wrote ${outputPath}`);\n } else {\n console.log(\"\\nTo write the manifest, run:\");\n console.log(\" npx appkit plugins sync --write\\n\");\n console.log(\"Preview:\");\n console.log(\"─\".repeat(60));\n console.log(JSON.stringify(templateManifest, null, 2));\n console.log(\"─\".repeat(60));\n }\n}\n\n/** Exported for testing: path boundary check, AST parsing. */\nexport { isWithinDirectory, parseImports, parsePluginUsages };\n\nexport const pluginsSyncCommand = new Command(\"sync\")\n .description(\n \"Sync plugin manifests from installed packages into appkit.plugins.json\",\n )\n .option(\"-w, --write\", \"Write the manifest file\")\n .option(\n \"-o, --output <path>\",\n \"Output file path (default: ./appkit.plugins.json)\",\n )\n .action(runPluginsSync);\n"],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ import { pluginsSyncCommand } from "./plugins-sync.js";
2
+ import { Command } from "commander";
3
+
4
+ //#region src/cli/commands/plugins.ts
5
+ /**
6
+ * Parent command for plugin management operations.
7
+ * Subcommands:
8
+ * - sync: Aggregate plugin manifests into appkit.plugins.json
9
+ *
10
+ * Future subcommands may include:
11
+ * - add: Add a plugin to an existing project
12
+ * - remove: Remove a plugin from a project
13
+ * - list: List available plugins
14
+ */
15
+ const pluginsCommand = new Command("plugins").description("Plugin management commands").addCommand(pluginsSyncCommand);
16
+
17
+ //#endregion
18
+ export { pluginsCommand };
19
+ //# sourceMappingURL=plugins.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugins.js","names":[],"sources":["../../../src/cli/commands/plugins.ts"],"sourcesContent":["import { Command } from \"commander\";\nimport { pluginsSyncCommand } from \"./plugins-sync.js\";\n\n/**\n * Parent command for plugin management operations.\n * Subcommands:\n * - sync: Aggregate plugin manifests into appkit.plugins.json\n *\n * Future subcommands may include:\n * - add: Add a plugin to an existing project\n * - remove: Remove a plugin from a project\n * - list: List available plugins\n */\nexport const pluginsCommand = new Command(\"plugins\")\n .description(\"Plugin management commands\")\n .addCommand(pluginsSyncCommand);\n"],"mappings":";;;;;;;;;;;;;;AAaA,MAAa,iBAAiB,IAAI,QAAQ,UAAU,CACjD,YAAY,6BAA6B,CACzC,WAAW,mBAAmB"}
package/dist/cli/index.js CHANGED
@@ -2,6 +2,7 @@
2
2
  import { docsCommand } from "./commands/docs.js";
3
3
  import { generateTypesCommand } from "./commands/generate-types.js";
4
4
  import { lintCommand } from "./commands/lint.js";
5
+ import { pluginsCommand } from "./commands/plugins.js";
5
6
  import { setupCommand } from "./commands/setup.js";
6
7
  import { readFileSync } from "node:fs";
7
8
  import { dirname, join } from "node:path";
@@ -17,6 +18,7 @@ cmd.addCommand(setupCommand);
17
18
  cmd.addCommand(generateTypesCommand);
18
19
  cmd.addCommand(lintCommand);
19
20
  cmd.addCommand(docsCommand);
21
+ cmd.addCommand(pluginsCommand);
20
22
  cmd.parse();
21
23
 
22
24
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../src/cli/index.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport { readFileSync } from \"node:fs\";\nimport { dirname, join } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { Command } from \"commander\";\nimport { docsCommand } from \"./commands/docs.js\";\nimport { generateTypesCommand } from \"./commands/generate-types.js\";\nimport { lintCommand } from \"./commands/lint.js\";\nimport { setupCommand } from \"./commands/setup.js\";\n\nconst __dirname = dirname(fileURLToPath(import.meta.url));\nconst pkgPath = join(__dirname, \"../../package.json\");\nconst pkg = JSON.parse(readFileSync(pkgPath, \"utf-8\"));\n\nconst cmd = new Command();\n\ncmd\n .name(\"appkit\")\n .description(\"CLI tools for Databricks AppKit\")\n .version(pkg.version);\n\ncmd.addCommand(setupCommand);\ncmd.addCommand(generateTypesCommand);\ncmd.addCommand(lintCommand);\ncmd.addCommand(docsCommand);\n\ncmd.parse();\n"],"mappings":";;;;;;;;;;;AAYA,MAAM,UAAU,KADE,QAAQ,cAAc,OAAO,KAAK,IAAI,CAAC,EACzB,qBAAqB;AACrD,MAAM,MAAM,KAAK,MAAM,aAAa,SAAS,QAAQ,CAAC;AAEtD,MAAM,MAAM,IAAI,SAAS;AAEzB,IACG,KAAK,SAAS,CACd,YAAY,kCAAkC,CAC9C,QAAQ,IAAI,QAAQ;AAEvB,IAAI,WAAW,aAAa;AAC5B,IAAI,WAAW,qBAAqB;AACpC,IAAI,WAAW,YAAY;AAC3B,IAAI,WAAW,YAAY;AAE3B,IAAI,OAAO"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../src/cli/index.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport { readFileSync } from \"node:fs\";\nimport { dirname, join } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { Command } from \"commander\";\nimport { docsCommand } from \"./commands/docs.js\";\nimport { generateTypesCommand } from \"./commands/generate-types.js\";\nimport { lintCommand } from \"./commands/lint.js\";\nimport { pluginsCommand } from \"./commands/plugins.js\";\nimport { setupCommand } from \"./commands/setup.js\";\n\nconst __dirname = dirname(fileURLToPath(import.meta.url));\nconst pkgPath = join(__dirname, \"../../package.json\");\nconst pkg = JSON.parse(readFileSync(pkgPath, \"utf-8\"));\n\nconst cmd = new Command();\n\ncmd\n .name(\"appkit\")\n .description(\"CLI tools for Databricks AppKit\")\n .version(pkg.version);\n\ncmd.addCommand(setupCommand);\ncmd.addCommand(generateTypesCommand);\ncmd.addCommand(lintCommand);\ncmd.addCommand(docsCommand);\ncmd.addCommand(pluginsCommand);\n\ncmd.parse();\n"],"mappings":";;;;;;;;;;;;AAaA,MAAM,UAAU,KADE,QAAQ,cAAc,OAAO,KAAK,IAAI,CAAC,EACzB,qBAAqB;AACrD,MAAM,MAAM,KAAK,MAAM,aAAa,SAAS,QAAQ,CAAC;AAEtD,MAAM,MAAM,IAAI,SAAS;AAEzB,IACG,KAAK,SAAS,CACd,YAAY,kCAAkC,CAC9C,QAAQ,IAAI,QAAQ;AAEvB,IAAI,WAAW,aAAa;AAC5B,IAAI,WAAW,qBAAqB;AACpC,IAAI,WAAW,YAAY;AAC3B,IAAI,WAAW,YAAY;AAC3B,IAAI,WAAW,eAAe;AAE9B,IAAI,OAAO"}
@@ -1,5 +1,5 @@
1
- import { LakebaseConnector } from "./lakebase/client.js";
2
- import "./lakebase/index.js";
1
+ import { LakebaseV1Connector } from "./lakebase-v1/client.js";
2
+ import "./lakebase-v1/index.js";
3
3
  import { SQLWarehouseConnector } from "./sql-warehouse/client.js";
4
4
  import "./sql-warehouse/index.js";
5
5
 
@@ -9,32 +9,46 @@ import { ConnectionError } from "../../errors/connection.js";
9
9
  import { ValidationError } from "../../errors/validation.js";
10
10
  import { init_errors } from "../../errors/index.js";
11
11
  import { deepMerge } from "../../utils/merge.js";
12
- import { lakebaseDefaults } from "./defaults.js";
12
+ import { lakebaseV1Defaults } from "./defaults.js";
13
13
  import { context_exports, init_context } from "../../context/index.js";
14
14
  import { randomUUID } from "node:crypto";
15
15
  import { ApiClient, Config } from "@databricks/sdk-experimental";
16
16
  import pg from "pg";
17
17
 
18
- //#region src/connectors/lakebase/client.ts
18
+ //#region src/connectors/lakebase-v1/client.ts
19
19
  init_errors();
20
- const logger = createLogger("connectors:lakebase");
20
+ const logger = createLogger("connectors:lakebase-v1");
21
21
  /**
22
- * Enterprise-grade connector for Databricks Lakebase
22
+ * Enterprise-grade connector for Databricks Lakebase Provisioned
23
+ *
24
+ * @deprecated This connector is for Lakebase Provisioned only.
25
+ * For new projects, use Lakebase Autoscaling instead: https://docs.databricks.com/aws/en/oltp/projects/
26
+ *
27
+ * This connector is compatible with Lakebase Provisioned: https://docs.databricks.com/aws/en/oltp/instances/
28
+ *
29
+ * Lakebase Autoscaling offers:
30
+ * - Automatic compute scaling
31
+ * - Scale-to-zero for cost optimization
32
+ * - Database branching for development
33
+ * - Instant restore capabilities
34
+ *
35
+ * Use the new LakebaseConnector (coming in a future release) for Lakebase Autoscaling support.
36
+ *
23
37
  * @example Simplest - everything from env/context
24
38
  * ```typescript
25
- * const connector = new LakebaseConnector();
39
+ * const connector = new LakebaseV1Connector();
26
40
  * await connector.query('SELECT * FROM users');
27
41
  * ```
28
42
  *
29
43
  * @example With explicit connection string
30
44
  * ```typescript
31
- * const connector = new LakebaseConnector({
45
+ * const connector = new LakebaseV1Connector({
32
46
  * connectionString: 'postgresql://...'
33
47
  * });
34
48
  * ```
35
49
  */
36
- var LakebaseConnector = class {
37
- name = "lakebase";
50
+ var LakebaseV1Connector = class {
51
+ name = "lakebase-v1";
38
52
  CACHE_BUFFER_MS = 120 * 1e3;
39
53
  config;
40
54
  connectionConfig;
@@ -43,15 +57,15 @@ var LakebaseConnector = class {
43
57
  telemetry;
44
58
  telemetryMetrics;
45
59
  constructor(userConfig) {
46
- this.config = deepMerge(lakebaseDefaults, userConfig);
60
+ this.config = deepMerge(lakebaseV1Defaults, userConfig);
47
61
  this.connectionConfig = this.parseConnectionConfig();
48
62
  this.telemetry = TelemetryManager.getProvider(this.name, this.config.telemetry);
49
63
  this.telemetryMetrics = {
50
- queryCount: this.telemetry.getMeter().createCounter("lakebase.query.count", {
64
+ queryCount: this.telemetry.getMeter().createCounter("lakebase.v1.query.count", {
51
65
  description: "Total number of queries executed",
52
66
  unit: "1"
53
67
  }),
54
- queryDuration: this.telemetry.getMeter().createHistogram("lakebase.query.duration", {
68
+ queryDuration: this.telemetry.getMeter().createHistogram("lakebase.v1.query.duration", {
55
69
  description: "Duration of queries executed",
56
70
  unit: "ms"
57
71
  })
@@ -69,8 +83,8 @@ var LakebaseConnector = class {
69
83
  */
70
84
  async query(sql, params, retryCount = 0) {
71
85
  const startTime = Date.now();
72
- return this.telemetry.startActiveSpan("lakebase.query", { attributes: {
73
- "db.system": "lakebase",
86
+ return this.telemetry.startActiveSpan("lakebase.v1.query", { attributes: {
87
+ "db.system": "lakebase-v1",
74
88
  "db.statement": sql.substring(0, 500),
75
89
  "db.retry_count": retryCount
76
90
  } }, async (span) => {
@@ -121,8 +135,8 @@ var LakebaseConnector = class {
121
135
  */
122
136
  async transaction(callback, retryCount = 0) {
123
137
  const startTime = Date.now();
124
- return this.telemetry.startActiveSpan("lakebase.transaction", { attributes: {
125
- "db.system": "lakebase",
138
+ return this.telemetry.startActiveSpan("lakebase.v1.transaction", { attributes: {
139
+ "db.system": "lakebase-v1",
126
140
  "db.retry_count": retryCount
127
141
  } }, async (span) => {
128
142
  const client = await (await this.getPool()).connect();
@@ -177,7 +191,7 @@ var LakebaseConnector = class {
177
191
  }
178
192
  /** Check if database connection is healthy */
179
193
  async healthCheck() {
180
- return this.telemetry.startActiveSpan("lakebase.healthCheck", {}, async (span) => {
194
+ return this.telemetry.startActiveSpan("lakebase.v1.healthCheck", {}, async (span) => {
181
195
  try {
182
196
  const healthy = (await this.query("SELECT 1 as result")).rows[0]?.result === 1;
183
197
  span.setAttribute("db.healthy", healthy);
@@ -358,5 +372,5 @@ var LakebaseConnector = class {
358
372
  };
359
373
 
360
374
  //#endregion
361
- export { LakebaseConnector };
375
+ export { LakebaseV1Connector };
362
376
  //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","names":[],"sources":["../../../src/connectors/lakebase-v1/client.ts"],"sourcesContent":["import { randomUUID } from \"node:crypto\";\nimport type { WorkspaceClient } from \"@databricks/sdk-experimental\";\nimport { ApiClient, Config } from \"@databricks/sdk-experimental\";\nimport pg from \"pg\";\nimport {\n type Counter,\n type Histogram,\n SpanStatusCode,\n TelemetryManager,\n type TelemetryProvider,\n} from \"@/telemetry\";\nimport {\n AppKitError,\n AuthenticationError,\n ConfigurationError,\n ConnectionError,\n ValidationError,\n} from \"../../errors\";\nimport { createLogger } from \"../../logging/logger\";\nimport { deepMerge } from \"../../utils\";\nimport { lakebaseV1Defaults } from \"./defaults\";\nimport type {\n LakebaseV1Config,\n LakebaseV1ConnectionConfig,\n LakebaseV1Credentials,\n} from \"./types\";\n\nconst logger = createLogger(\"connectors:lakebase-v1\");\n\n/**\n * Enterprise-grade connector for Databricks Lakebase Provisioned\n *\n * @deprecated This connector is for Lakebase Provisioned only.\n * For new projects, use Lakebase Autoscaling instead: https://docs.databricks.com/aws/en/oltp/projects/\n *\n * This connector is compatible with Lakebase Provisioned: https://docs.databricks.com/aws/en/oltp/instances/\n *\n * Lakebase Autoscaling offers:\n * - Automatic compute scaling\n * - Scale-to-zero for cost optimization\n * - Database branching for development\n * - Instant restore capabilities\n *\n * Use the new LakebaseConnector (coming in a future release) for Lakebase Autoscaling support.\n *\n * @example Simplest - everything from env/context\n * ```typescript\n * const connector = new LakebaseV1Connector();\n * await connector.query('SELECT * FROM users');\n * ```\n *\n * @example With explicit connection string\n * ```typescript\n * const connector = new LakebaseV1Connector({\n * connectionString: 'postgresql://...'\n * });\n * ```\n */\nexport class LakebaseV1Connector {\n private readonly name: string = \"lakebase-v1\";\n private readonly CACHE_BUFFER_MS = 2 * 60 * 1000;\n private readonly config: LakebaseV1Config;\n private readonly connectionConfig: LakebaseV1ConnectionConfig;\n private pool: pg.Pool | null = null;\n private credentials: LakebaseV1Credentials | null = null;\n\n // telemetry\n private readonly telemetry: TelemetryProvider;\n private readonly telemetryMetrics: {\n queryCount: Counter;\n queryDuration: Histogram;\n };\n\n constructor(userConfig?: Partial<LakebaseV1Config>) {\n this.config = deepMerge(lakebaseV1Defaults, userConfig);\n this.connectionConfig = this.parseConnectionConfig();\n\n this.telemetry = TelemetryManager.getProvider(\n this.name,\n this.config.telemetry,\n );\n this.telemetryMetrics = {\n queryCount: this.telemetry\n .getMeter()\n .createCounter(\"lakebase.v1.query.count\", {\n description: \"Total number of queries executed\",\n unit: \"1\",\n }),\n queryDuration: this.telemetry\n .getMeter()\n .createHistogram(\"lakebase.v1.query.duration\", {\n description: \"Duration of queries executed\",\n unit: \"ms\",\n }),\n };\n\n // validate configuration\n if (this.config.maxPoolSize < 1) {\n throw ValidationError.invalidValue(\n \"maxPoolSize\",\n this.config.maxPoolSize,\n \"at least 1\",\n );\n }\n }\n\n /**\n * Execute a SQL query\n *\n * @example\n * ```typescript\n * const users = await connector.query('SELECT * FROM users');\n * const user = await connector.query('SELECT * FROM users WHERE id = $1', [123]);\n * ```\n */\n async query<T extends pg.QueryResultRow>(\n sql: string,\n params?: any[],\n retryCount: number = 0,\n ): Promise<pg.QueryResult<T>> {\n const startTime = Date.now();\n\n return this.telemetry.startActiveSpan(\n \"lakebase.v1.query\",\n {\n attributes: {\n \"db.system\": \"lakebase-v1\",\n \"db.statement\": sql.substring(0, 500),\n \"db.retry_count\": retryCount,\n },\n },\n async (span) => {\n try {\n const pool = await this.getPool();\n const result = await pool.query<T>(sql, params);\n span.setAttribute(\"db.rows_affected\", result.rowCount ?? 0);\n span.setStatus({ code: SpanStatusCode.OK });\n return result;\n } catch (error) {\n // retry on auth failure\n if (this.isAuthError(error)) {\n span.addEvent(\"auth_error_retry\");\n await this.rotateCredentials();\n const newPool = await this.getPool();\n const result = await newPool.query<T>(sql, params);\n span.setAttribute(\"db.rows_affected\", result.rowCount ?? 0);\n span.setStatus({ code: SpanStatusCode.OK });\n return result;\n }\n\n // retry on transient errors, but only once\n if (this.isTransientError(error) && retryCount < 1) {\n span.addEvent(\"transient_error_retry\");\n await new Promise((resolve) => setTimeout(resolve, 100));\n return await this.query<T>(sql, params, retryCount + 1);\n }\n\n span.recordException(error as Error);\n span.setStatus({ code: SpanStatusCode.ERROR });\n\n if (error instanceof AppKitError) {\n throw error;\n }\n throw ConnectionError.queryFailed(error as Error);\n } finally {\n const duration = Date.now() - startTime;\n this.telemetryMetrics.queryCount.add(1);\n this.telemetryMetrics.queryDuration.record(duration);\n span.end();\n }\n },\n );\n }\n\n /**\n * Execute a transaction\n *\n * COMMIT and ROLLBACK are automatically managed by the transaction function.\n *\n * @param callback - Callback function to execute within the transaction context\n * @example\n * ```typescript\n * await connector.transaction(async (client) => {\n * await client.query('INSERT INTO accounts (name) VALUES ($1)', ['Alice']);\n * await client.query('INSERT INTO logs (action) VALUES ($1)', ['Created Alice']);\n * });\n * ```\n */\n async transaction<T>(\n callback: (client: pg.PoolClient) => Promise<T>,\n retryCount: number = 0,\n ): Promise<T> {\n const startTime = Date.now();\n return this.telemetry.startActiveSpan(\n \"lakebase.v1.transaction\",\n {\n attributes: {\n \"db.system\": \"lakebase-v1\",\n \"db.retry_count\": retryCount,\n },\n },\n async (span) => {\n const pool = await this.getPool();\n const client = await pool.connect();\n try {\n await client.query(\"BEGIN\");\n const result = await callback(client);\n await client.query(\"COMMIT\");\n span.setStatus({ code: SpanStatusCode.OK });\n return result;\n } catch (error) {\n try {\n await client.query(\"ROLLBACK\");\n } catch {}\n // retry on auth failure\n if (this.isAuthError(error)) {\n span.addEvent(\"auth_error_retry\");\n client.release();\n await this.rotateCredentials();\n const newPool = await this.getPool();\n const retryClient = await newPool.connect();\n try {\n await client.query(\"BEGIN\");\n const result = await callback(retryClient);\n await client.query(\"COMMIT\");\n span.setStatus({ code: SpanStatusCode.OK });\n return result;\n } catch (retryError) {\n try {\n await retryClient.query(\"ROLLBACK\");\n } catch {}\n throw retryError;\n } finally {\n retryClient.release();\n }\n }\n\n // retry on transient errors, but only once\n if (this.isTransientError(error) && retryCount < 1) {\n span.addEvent(\"transaction_error_retry\");\n client.release();\n await new Promise((resolve) => setTimeout(resolve, 100));\n return await this.transaction<T>(callback, retryCount + 1);\n }\n span.recordException(error as Error);\n span.setStatus({ code: SpanStatusCode.ERROR });\n\n if (error instanceof AppKitError) {\n throw error;\n }\n throw ConnectionError.transactionFailed(error as Error);\n } finally {\n client.release();\n const duration = Date.now() - startTime;\n this.telemetryMetrics.queryCount.add(1);\n this.telemetryMetrics.queryDuration.record(duration);\n span.end();\n }\n },\n );\n }\n\n /** Check if database connection is healthy */\n async healthCheck(): Promise<boolean> {\n return this.telemetry.startActiveSpan(\n \"lakebase.v1.healthCheck\",\n {},\n async (span) => {\n try {\n const result = await this.query<{ result: number }>(\n \"SELECT 1 as result\",\n );\n const healthy = result.rows[0]?.result === 1;\n span.setAttribute(\"db.healthy\", healthy);\n span.setStatus({ code: SpanStatusCode.OK });\n return healthy;\n } catch {\n span.setAttribute(\"db.healthy\", false);\n span.setStatus({ code: SpanStatusCode.ERROR });\n return false;\n } finally {\n span.end();\n }\n },\n );\n }\n\n /** Close connection pool (call on shutdown) */\n async close(): Promise<void> {\n if (this.pool) {\n await this.pool.end().catch((error: unknown) => {\n logger.error(\"Error closing connection pool: %O\", error);\n });\n this.pool = null;\n }\n this.credentials = null;\n }\n\n /** Setup graceful shutdown to close connection pools */\n shutdown(): void {\n process.on(\"SIGTERM\", () => this.close());\n process.on(\"SIGINT\", () => this.close());\n this.close();\n }\n\n /** Get Databricks workspace client - from config or execution context */\n private getWorkspaceClient(): WorkspaceClient {\n if (this.config.workspaceClient) {\n return this.config.workspaceClient;\n }\n\n try {\n const { getWorkspaceClient: getClient } = require(\"../../context\");\n const client = getClient();\n\n // cache it for subsequent calls\n this.config.workspaceClient = client;\n return client;\n } catch (_error) {\n throw ConnectionError.clientUnavailable(\n \"Databricks workspace client\",\n \"Either pass it in config or ensure ServiceContext is initialized\",\n );\n }\n }\n\n /** Get or create connection pool */\n private async getPool(): Promise<pg.Pool> {\n if (!this.connectionConfig) {\n throw ConfigurationError.invalidConnection(\n \"Lakebase\",\n \"Set PGHOST, PGDATABASE, PGAPPNAME env vars, provide a connectionString, or pass explicit config\",\n );\n }\n\n if (!this.pool) {\n const creds = await this.getCredentials();\n this.pool = this.createPool(creds);\n }\n return this.pool;\n }\n\n /** Create PostgreSQL pool */\n private createPool(credentials: {\n username: string;\n password: string;\n }): pg.Pool {\n const { host, database, port, sslMode } = this.connectionConfig;\n\n const pool = new pg.Pool({\n host,\n port,\n database,\n user: credentials.username,\n password: credentials.password,\n max: this.config.maxPoolSize,\n idleTimeoutMillis: this.config.idleTimeoutMs,\n connectionTimeoutMillis: this.config.connectionTimeoutMs,\n ssl: sslMode === \"require\" ? { rejectUnauthorized: true } : false,\n });\n\n pool.on(\"error\", (error: Error & { code?: string }) => {\n logger.error(\n \"Connection pool error: %s (code: %s)\",\n error.message,\n error.code,\n );\n });\n\n return pool;\n }\n\n /** Get or fetch credentials with caching */\n private async getCredentials(): Promise<{\n username: string;\n password: string;\n }> {\n const now = Date.now();\n\n // return cached if still valid\n if (\n this.credentials &&\n now < this.credentials.expiresAt - this.CACHE_BUFFER_MS\n ) {\n return this.credentials;\n }\n\n // fetch new credentials\n const username = await this.fetchUsername();\n const { token, expiresAt } = await this.fetchPassword();\n\n this.credentials = {\n username,\n password: token,\n expiresAt,\n };\n\n return { username, password: token };\n }\n\n /** Rotate credentials and recreate pool */\n private async rotateCredentials(): Promise<void> {\n // clear cached credentials\n this.credentials = null;\n\n if (this.pool) {\n const oldPool = this.pool;\n this.pool = null;\n oldPool.end().catch((error: unknown) => {\n logger.error(\n \"Error closing old connection pool during rotation: %O\",\n error,\n );\n });\n }\n }\n\n /** Fetch username from Databricks */\n private async fetchUsername(): Promise<string> {\n const workspaceClient = this.getWorkspaceClient();\n const user = await workspaceClient.currentUser.me();\n if (!user.userName) {\n throw AuthenticationError.userLookupFailed();\n }\n return user.userName;\n }\n\n /** Fetch password (OAuth token) from Databricks */\n private async fetchPassword(): Promise<{ token: string; expiresAt: number }> {\n const workspaceClient = this.getWorkspaceClient();\n const config = new Config({ host: workspaceClient.config.host });\n const apiClient = new ApiClient(config);\n\n if (!this.connectionConfig.appName) {\n throw ConfigurationError.resourceNotFound(\"Database app name\");\n }\n\n const credentials = await apiClient.request({\n path: `/api/2.0/database/credentials`,\n method: \"POST\",\n headers: new Headers(),\n raw: false,\n payload: {\n instance_names: [this.connectionConfig.appName],\n request_id: randomUUID(),\n },\n });\n\n if (!this.validateCredentials(credentials)) {\n throw AuthenticationError.credentialsFailed(\n this.connectionConfig.appName,\n );\n }\n\n const expiresAt = new Date(credentials.expiration_time).getTime();\n\n return { token: credentials.token, expiresAt };\n }\n\n /** Check if error is auth failure */\n private isAuthError(error: unknown): boolean {\n return (\n typeof error === \"object\" &&\n error !== null &&\n \"code\" in error &&\n (error as any).code === \"28P01\"\n );\n }\n\n /** Check if error is transient */\n private isTransientError(error: unknown): boolean {\n if (typeof error !== \"object\" || error === null || !(\"code\" in error)) {\n return false;\n }\n\n const code = (error as any).code;\n return (\n code === \"ECONNRESET\" ||\n code === \"ECONNREFUSED\" ||\n code === \"ETIMEDOUT\" ||\n code === \"57P01\" || // admin_shutdown\n code === \"57P03\" || // cannot_connect_now\n code === \"08006\" || // connection_failure\n code === \"08003\" || // connection_does_not_exist\n code === \"08000\" // connection_exception\n );\n }\n\n /** Type guard for credentials */\n private validateCredentials(\n value: unknown,\n ): value is { token: string; expiration_time: string } {\n if (typeof value !== \"object\" || value === null) {\n return false;\n }\n\n const credentials = value as { token: string; expiration_time: string };\n return (\n \"token\" in credentials &&\n typeof credentials.token === \"string\" &&\n \"expiration_time\" in credentials &&\n typeof credentials.expiration_time === \"string\" &&\n new Date(credentials.expiration_time).getTime() > Date.now()\n );\n }\n\n /** Parse connection configuration from config or environment */\n private parseConnectionConfig(): LakebaseV1ConnectionConfig {\n if (this.config.connectionString) {\n return this.parseConnectionString(this.config.connectionString);\n }\n\n // get connection from config\n if (this.config.host && this.config.database && this.config.appName) {\n return {\n host: this.config.host,\n database: this.config.database,\n port: this.config.port ?? 5432,\n sslMode: this.config.sslMode ?? \"require\",\n appName: this.config.appName,\n };\n }\n\n // get connection from environment variables\n const pgHost = process.env.PGHOST;\n const pgDatabase = process.env.PGDATABASE;\n const pgAppName = process.env.PGAPPNAME;\n if (!pgHost || !pgDatabase || !pgAppName) {\n throw ConfigurationError.invalidConnection(\n \"Lakebase\",\n \"Required env vars: PGHOST, PGDATABASE, PGAPPNAME. Optional: PGPORT (default: 5432), PGSSLMODE (default: require)\",\n );\n }\n const pgPort = process.env.PGPORT;\n const port = pgPort ? parseInt(pgPort, 10) : 5432;\n\n if (Number.isNaN(port)) {\n throw ValidationError.invalidValue(\"port\", pgPort, \"a number\");\n }\n\n const pgSSLMode = process.env.PGSSLMODE;\n const sslMode =\n (pgSSLMode as \"require\" | \"disable\" | \"prefer\") || \"require\";\n\n return {\n host: pgHost,\n database: pgDatabase,\n port,\n sslMode,\n appName: pgAppName,\n };\n }\n\n private parseConnectionString(\n connectionString: string,\n ): LakebaseV1ConnectionConfig {\n const url = new URL(connectionString);\n const appName = url.searchParams.get(\"appName\");\n if (!appName) {\n throw ConfigurationError.missingConnectionParam(\"appName\");\n }\n\n return {\n host: url.hostname,\n database: url.pathname.slice(1), // remove leading slash\n port: url.port ? parseInt(url.port, 10) : 5432,\n sslMode:\n (url.searchParams.get(\"sslmode\") as \"require\" | \"disable\" | \"prefer\") ??\n \"require\",\n appName: appName,\n };\n }\n}\n"],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ //#region src/connectors/lakebase-v1/defaults.ts
2
+ /**
3
+ * Default configuration for Lakebase V1 connector
4
+ *
5
+ * @deprecated This connector is for Lakebase Provisioned only.
6
+ * For new projects, use Lakebase Autoscaling: https://docs.databricks.com/aws/en/oltp/projects/
7
+ */
8
+ const lakebaseV1Defaults = {
9
+ port: 5432,
10
+ sslMode: "require",
11
+ maxPoolSize: 10,
12
+ idleTimeoutMs: 3e4,
13
+ connectionTimeoutMs: 1e4
14
+ };
15
+
16
+ //#endregion
17
+ export { lakebaseV1Defaults };
18
+ //# sourceMappingURL=defaults.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"defaults.js","names":[],"sources":["../../../src/connectors/lakebase-v1/defaults.ts"],"sourcesContent":["import type { LakebaseV1Config } from \"./types\";\n\n/**\n * Default configuration for Lakebase V1 connector\n *\n * @deprecated This connector is for Lakebase Provisioned only.\n * For new projects, use Lakebase Autoscaling: https://docs.databricks.com/aws/en/oltp/projects/\n */\nexport const lakebaseV1Defaults: LakebaseV1Config = {\n port: 5432,\n sslMode: \"require\",\n maxPoolSize: 10,\n idleTimeoutMs: 30_000,\n connectionTimeoutMs: 10_000,\n};\n"],"mappings":";;;;;;;AAQA,MAAa,qBAAuC;CAClD,MAAM;CACN,SAAS;CACT,aAAa;CACb,eAAe;CACf,qBAAqB;CACtB"}
@@ -0,0 +1,3 @@
1
+ import { LakebaseV1Connector } from "./client.js";
2
+
3
+ export { };
@@ -1 +1 @@
1
- {"version":3,"file":"appkit.d.ts","names":[],"sources":["../../src/core/appkit.ts"],"sourcesContent":[],"mappings":";;;;;;;;;;iBAyLsB,oBACV,WAAW;YAGT;cACE;UACJ;WACC;IAEV,QAAQ,UAAU"}
1
+ {"version":3,"file":"appkit.d.ts","names":[],"sources":["../../src/core/appkit.ts"],"sourcesContent":[],"mappings":";;;;;;;;;;iBA6LsB,oBACV,WAAW;YAGT;cACE;UACJ;WACC;IAEV,QAAQ,UAAU"}
@@ -3,6 +3,8 @@ import "../telemetry/index.js";
3
3
  import { ServiceContext } from "../context/service-context.js";
4
4
  import { init_context } from "../context/index.js";
5
5
  import { CacheManager } from "../cache/index.js";
6
+ import { ResourceRegistry } from "../registry/resource-registry.js";
7
+ import "../registry/index.js";
6
8
 
7
9
  //#region src/core/appkit.ts
8
10
  init_context();
@@ -31,7 +33,6 @@ var AppKit = class AppKit {
31
33
  ...extraData
32
34
  });
33
35
  this.#pluginInstances[name] = pluginInstance;
34
- pluginInstance.validateEnv();
35
36
  this.#setupPromises.push(pluginInstance.setup());
36
37
  const self = this;
37
38
  Object.defineProperty(this, name, {
@@ -71,6 +72,9 @@ var AppKit = class AppKit {
71
72
  await CacheManager.getInstance(config?.cache);
72
73
  await ServiceContext.initialize(config?.client);
73
74
  const rawPlugins = config.plugins;
75
+ const registry = new ResourceRegistry();
76
+ registry.collectResources(rawPlugins);
77
+ registry.enforceValidation();
74
78
  const instance = new AppKit({ plugins: AppKit.preparePlugins(rawPlugins) });
75
79
  await Promise.all(instance.#setupPromises);
76
80
  return instance;
@@ -1 +1 @@
1
- {"version":3,"file":"appkit.js","names":["#pluginInstances","#setupPromises"],"sources":["../../src/core/appkit.ts"],"sourcesContent":["import type { WorkspaceClient } from \"@databricks/sdk-experimental\";\nimport type {\n BasePlugin,\n CacheConfig,\n InputPluginMap,\n OptionalConfigPluginDef,\n PluginConstructor,\n PluginData,\n PluginMap,\n} from \"shared\";\nimport { CacheManager } from \"../cache\";\nimport { ServiceContext } from \"../context\";\nimport type { TelemetryConfig } from \"../telemetry\";\nimport { TelemetryManager } from \"../telemetry\";\n\nexport class AppKit<TPlugins extends InputPluginMap> {\n #pluginInstances: Record<string, BasePlugin> = {};\n #setupPromises: Promise<void>[] = [];\n\n private constructor(config: { plugins: TPlugins }) {\n const { plugins, ...globalConfig } = config;\n\n const pluginEntries = Object.entries(plugins);\n\n const corePlugins = pluginEntries.filter(([_, p]) => {\n return (p?.plugin?.phase ?? \"normal\") === \"core\";\n });\n const normalPlugins = pluginEntries.filter(\n ([_, p]) => (p?.plugin?.phase ?? \"normal\") === \"normal\",\n );\n const deferredPlugins = pluginEntries.filter(\n ([_, p]) => (p?.plugin?.phase ?? \"normal\") === \"deferred\",\n );\n\n for (const [name, pluginData] of corePlugins) {\n if (pluginData) {\n this.createAndRegisterPlugin(globalConfig, name, pluginData);\n }\n }\n\n for (const [name, pluginData] of normalPlugins) {\n if (pluginData) {\n this.createAndRegisterPlugin(globalConfig, name, pluginData);\n }\n }\n\n for (const [name, pluginData] of deferredPlugins) {\n if (pluginData) {\n this.createAndRegisterPlugin(globalConfig, name, pluginData, {\n plugins: this.#pluginInstances,\n });\n }\n }\n }\n\n private createAndRegisterPlugin<T extends PluginConstructor>(\n config: Omit<{ plugins: TPlugins }, \"plugins\">,\n name: string,\n pluginData: OptionalConfigPluginDef<T>,\n extraData?: Record<string, unknown>,\n ) {\n const { plugin: Plugin, config: pluginConfig } = pluginData;\n const baseConfig = {\n ...config,\n ...Plugin.DEFAULT_CONFIG,\n ...pluginConfig,\n name,\n ...extraData,\n };\n const pluginInstance = new Plugin(baseConfig);\n\n this.#pluginInstances[name] = pluginInstance;\n\n pluginInstance.validateEnv();\n\n this.#setupPromises.push(pluginInstance.setup());\n\n const self = this;\n\n Object.defineProperty(this, name, {\n get() {\n const plugin = self.#pluginInstances[name];\n return self.wrapWithAsUser(plugin);\n },\n enumerable: true,\n });\n }\n\n /**\n * Binds all function properties in an exports object to the given context.\n */\n private bindExportMethods(\n exports: Record<string, unknown>,\n context: BasePlugin,\n ) {\n for (const key in exports) {\n if (Object.hasOwn(exports, key) && typeof exports[key] === \"function\") {\n exports[key] = (exports[key] as (...args: unknown[]) => unknown).bind(\n context,\n );\n }\n }\n }\n\n /**\n * Wraps a plugin's exports with an `asUser` method that returns\n * a user-scoped version of the exports.\n */\n private wrapWithAsUser<T extends BasePlugin>(plugin: T) {\n // If plugin doesn't implement exports(), return empty object\n const pluginExports = (plugin.exports?.() ?? {}) as Record<string, unknown>;\n this.bindExportMethods(pluginExports, plugin);\n\n // If plugin doesn't support asUser (no asUser method), return exports as-is\n if (typeof (plugin as any).asUser !== \"function\") {\n return pluginExports;\n }\n\n return {\n ...pluginExports,\n /**\n * Execute operations using the user's identity from the request.\n * Returns user-scoped exports where all methods execute with the\n * user's Databricks credentials instead of the service principal.\n */\n asUser: (req: import(\"express\").Request) => {\n const userPlugin = (plugin as any).asUser(req);\n const userExports = (userPlugin.exports?.() ?? {}) as Record<\n string,\n unknown\n >;\n this.bindExportMethods(userExports, userPlugin);\n return userExports;\n },\n };\n }\n\n static async _createApp<\n T extends PluginData<PluginConstructor, unknown, string>[],\n >(\n config: {\n plugins?: T;\n telemetry?: TelemetryConfig;\n cache?: CacheConfig;\n client?: WorkspaceClient;\n } = {},\n ): Promise<PluginMap<T>> {\n // Initialize core services\n TelemetryManager.initialize(config?.telemetry);\n await CacheManager.getInstance(config?.cache);\n\n // Initialize ServiceContext for Databricks client management\n // This provides the service principal client and shared resources\n await ServiceContext.initialize(config?.client);\n\n const rawPlugins = config.plugins as T;\n const preparedPlugins = AppKit.preparePlugins(rawPlugins);\n const mergedConfig = {\n plugins: preparedPlugins,\n };\n\n const instance = new AppKit(mergedConfig);\n\n await Promise.all(instance.#setupPromises);\n\n return instance as unknown as PluginMap<T>;\n }\n\n private static preparePlugins(\n plugins: PluginData<PluginConstructor, unknown, string>[],\n ) {\n const result: InputPluginMap = {};\n for (const currentPlugin of plugins) {\n result[currentPlugin.name] = {\n plugin: currentPlugin.plugin,\n config: currentPlugin.config as Record<string, unknown>,\n };\n }\n return result;\n }\n}\n\n/**\n * Bootstraps AppKit with the provided configuration.\n */\nexport async function createApp<\n T extends PluginData<PluginConstructor, unknown, string>[],\n>(\n config: {\n plugins?: T;\n telemetry?: TelemetryConfig;\n cache?: CacheConfig;\n client?: WorkspaceClient;\n } = {},\n): Promise<PluginMap<T>> {\n return AppKit._createApp(config);\n}\n"],"mappings":";;;;;;;cAW4C;AAI5C,IAAa,SAAb,MAAa,OAAwC;CACnD,mBAA+C,EAAE;CACjD,iBAAkC,EAAE;CAEpC,AAAQ,YAAY,QAA+B;EACjD,MAAM,EAAE,SAAS,GAAG,iBAAiB;EAErC,MAAM,gBAAgB,OAAO,QAAQ,QAAQ;EAE7C,MAAM,cAAc,cAAc,QAAQ,CAAC,GAAG,OAAO;AACnD,WAAQ,GAAG,QAAQ,SAAS,cAAc;IAC1C;EACF,MAAM,gBAAgB,cAAc,QACjC,CAAC,GAAG,QAAQ,GAAG,QAAQ,SAAS,cAAc,SAChD;EACD,MAAM,kBAAkB,cAAc,QACnC,CAAC,GAAG,QAAQ,GAAG,QAAQ,SAAS,cAAc,WAChD;AAED,OAAK,MAAM,CAAC,MAAM,eAAe,YAC/B,KAAI,WACF,MAAK,wBAAwB,cAAc,MAAM,WAAW;AAIhE,OAAK,MAAM,CAAC,MAAM,eAAe,cAC/B,KAAI,WACF,MAAK,wBAAwB,cAAc,MAAM,WAAW;AAIhE,OAAK,MAAM,CAAC,MAAM,eAAe,gBAC/B,KAAI,WACF,MAAK,wBAAwB,cAAc,MAAM,YAAY,EAC3D,SAAS,MAAKA,iBACf,CAAC;;CAKR,AAAQ,wBACN,QACA,MACA,YACA,WACA;EACA,MAAM,EAAE,QAAQ,QAAQ,QAAQ,iBAAiB;EAQjD,MAAM,iBAAiB,IAAI,OAPR;GACjB,GAAG;GACH,GAAG,OAAO;GACV,GAAG;GACH;GACA,GAAG;GACJ,CAC4C;AAE7C,QAAKA,gBAAiB,QAAQ;AAE9B,iBAAe,aAAa;AAE5B,QAAKC,cAAe,KAAK,eAAe,OAAO,CAAC;EAEhD,MAAM,OAAO;AAEb,SAAO,eAAe,MAAM,MAAM;GAChC,MAAM;IACJ,MAAM,SAAS,MAAKD,gBAAiB;AACrC,WAAO,KAAK,eAAe,OAAO;;GAEpC,YAAY;GACb,CAAC;;;;;CAMJ,AAAQ,kBACN,SACA,SACA;AACA,OAAK,MAAM,OAAO,QAChB,KAAI,OAAO,OAAO,SAAS,IAAI,IAAI,OAAO,QAAQ,SAAS,WACzD,SAAQ,OAAQ,QAAQ,KAAyC,KAC/D,QACD;;;;;;CASP,AAAQ,eAAqC,QAAW;EAEtD,MAAM,gBAAiB,OAAO,WAAW,IAAI,EAAE;AAC/C,OAAK,kBAAkB,eAAe,OAAO;AAG7C,MAAI,OAAQ,OAAe,WAAW,WACpC,QAAO;AAGT,SAAO;GACL,GAAG;GAMH,SAAS,QAAmC;IAC1C,MAAM,aAAc,OAAe,OAAO,IAAI;IAC9C,MAAM,cAAe,WAAW,WAAW,IAAI,EAAE;AAIjD,SAAK,kBAAkB,aAAa,WAAW;AAC/C,WAAO;;GAEV;;CAGH,aAAa,WAGX,SAKI,EAAE,EACiB;AAEvB,mBAAiB,WAAW,QAAQ,UAAU;AAC9C,QAAM,aAAa,YAAY,QAAQ,MAAM;AAI7C,QAAM,eAAe,WAAW,QAAQ,OAAO;EAE/C,MAAM,aAAa,OAAO;EAM1B,MAAM,WAAW,IAAI,OAJA,EACnB,SAFsB,OAAO,eAAe,WAAW,EAGxD,CAEwC;AAEzC,QAAM,QAAQ,IAAI,UAASC,cAAe;AAE1C,SAAO;;CAGT,OAAe,eACb,SACA;EACA,MAAM,SAAyB,EAAE;AACjC,OAAK,MAAM,iBAAiB,QAC1B,QAAO,cAAc,QAAQ;GAC3B,QAAQ,cAAc;GACtB,QAAQ,cAAc;GACvB;AAEH,SAAO;;;;;;AAOX,eAAsB,UAGpB,SAKI,EAAE,EACiB;AACvB,QAAO,OAAO,WAAW,OAAO"}
1
+ {"version":3,"file":"appkit.js","names":["#pluginInstances","#setupPromises"],"sources":["../../src/core/appkit.ts"],"sourcesContent":["import type { WorkspaceClient } from \"@databricks/sdk-experimental\";\nimport type {\n BasePlugin,\n CacheConfig,\n InputPluginMap,\n OptionalConfigPluginDef,\n PluginConstructor,\n PluginData,\n PluginMap,\n} from \"shared\";\nimport { CacheManager } from \"../cache\";\nimport { ServiceContext } from \"../context\";\nimport { ResourceRegistry } from \"../registry\";\nimport type { TelemetryConfig } from \"../telemetry\";\nimport { TelemetryManager } from \"../telemetry\";\n\nexport class AppKit<TPlugins extends InputPluginMap> {\n #pluginInstances: Record<string, BasePlugin> = {};\n #setupPromises: Promise<void>[] = [];\n\n private constructor(config: { plugins: TPlugins }) {\n const { plugins, ...globalConfig } = config;\n\n const pluginEntries = Object.entries(plugins);\n\n const corePlugins = pluginEntries.filter(([_, p]) => {\n return (p?.plugin?.phase ?? \"normal\") === \"core\";\n });\n const normalPlugins = pluginEntries.filter(\n ([_, p]) => (p?.plugin?.phase ?? \"normal\") === \"normal\",\n );\n const deferredPlugins = pluginEntries.filter(\n ([_, p]) => (p?.plugin?.phase ?? \"normal\") === \"deferred\",\n );\n\n for (const [name, pluginData] of corePlugins) {\n if (pluginData) {\n this.createAndRegisterPlugin(globalConfig, name, pluginData);\n }\n }\n\n for (const [name, pluginData] of normalPlugins) {\n if (pluginData) {\n this.createAndRegisterPlugin(globalConfig, name, pluginData);\n }\n }\n\n for (const [name, pluginData] of deferredPlugins) {\n if (pluginData) {\n this.createAndRegisterPlugin(globalConfig, name, pluginData, {\n plugins: this.#pluginInstances,\n });\n }\n }\n }\n\n private createAndRegisterPlugin<T extends PluginConstructor>(\n config: Omit<{ plugins: TPlugins }, \"plugins\">,\n name: string,\n pluginData: OptionalConfigPluginDef<T>,\n extraData?: Record<string, unknown>,\n ) {\n const { plugin: Plugin, config: pluginConfig } = pluginData;\n const baseConfig = {\n ...config,\n ...Plugin.DEFAULT_CONFIG,\n ...pluginConfig,\n name,\n ...extraData,\n };\n const pluginInstance = new Plugin(baseConfig);\n\n this.#pluginInstances[name] = pluginInstance;\n\n this.#setupPromises.push(pluginInstance.setup());\n\n const self = this;\n\n Object.defineProperty(this, name, {\n get() {\n const plugin = self.#pluginInstances[name];\n return self.wrapWithAsUser(plugin);\n },\n enumerable: true,\n });\n }\n\n /**\n * Binds all function properties in an exports object to the given context.\n */\n private bindExportMethods(\n exports: Record<string, unknown>,\n context: BasePlugin,\n ) {\n for (const key in exports) {\n if (Object.hasOwn(exports, key) && typeof exports[key] === \"function\") {\n exports[key] = (exports[key] as (...args: unknown[]) => unknown).bind(\n context,\n );\n }\n }\n }\n\n /**\n * Wraps a plugin's exports with an `asUser` method that returns\n * a user-scoped version of the exports.\n */\n private wrapWithAsUser<T extends BasePlugin>(plugin: T) {\n // If plugin doesn't implement exports(), return empty object\n const pluginExports = (plugin.exports?.() ?? {}) as Record<string, unknown>;\n this.bindExportMethods(pluginExports, plugin);\n\n // If plugin doesn't support asUser (no asUser method), return exports as-is\n if (typeof (plugin as any).asUser !== \"function\") {\n return pluginExports;\n }\n\n return {\n ...pluginExports,\n /**\n * Execute operations using the user's identity from the request.\n * Returns user-scoped exports where all methods execute with the\n * user's Databricks credentials instead of the service principal.\n */\n asUser: (req: import(\"express\").Request) => {\n const userPlugin = (plugin as any).asUser(req);\n const userExports = (userPlugin.exports?.() ?? {}) as Record<\n string,\n unknown\n >;\n this.bindExportMethods(userExports, userPlugin);\n return userExports;\n },\n };\n }\n\n static async _createApp<\n T extends PluginData<PluginConstructor, unknown, string>[],\n >(\n config: {\n plugins?: T;\n telemetry?: TelemetryConfig;\n cache?: CacheConfig;\n client?: WorkspaceClient;\n } = {},\n ): Promise<PluginMap<T>> {\n // Initialize core services\n TelemetryManager.initialize(config?.telemetry);\n await CacheManager.getInstance(config?.cache);\n\n // Initialize ServiceContext for Databricks client management\n // This provides the service principal client and shared resources\n await ServiceContext.initialize(config?.client);\n\n const rawPlugins = config.plugins as T;\n\n const registry = new ResourceRegistry();\n registry.collectResources(rawPlugins);\n registry.enforceValidation();\n\n const preparedPlugins = AppKit.preparePlugins(rawPlugins);\n const mergedConfig = {\n plugins: preparedPlugins,\n };\n\n const instance = new AppKit(mergedConfig);\n\n await Promise.all(instance.#setupPromises);\n\n return instance as unknown as PluginMap<T>;\n }\n\n private static preparePlugins(\n plugins: PluginData<PluginConstructor, unknown, string>[],\n ) {\n const result: InputPluginMap = {};\n for (const currentPlugin of plugins) {\n result[currentPlugin.name] = {\n plugin: currentPlugin.plugin,\n config: currentPlugin.config as Record<string, unknown>,\n };\n }\n return result;\n }\n}\n\n/**\n * Bootstraps AppKit with the provided configuration.\n */\nexport async function createApp<\n T extends PluginData<PluginConstructor, unknown, string>[],\n>(\n config: {\n plugins?: T;\n telemetry?: TelemetryConfig;\n cache?: CacheConfig;\n client?: WorkspaceClient;\n } = {},\n): Promise<PluginMap<T>> {\n return AppKit._createApp(config);\n}\n"],"mappings":";;;;;;;;;cAW4C;AAK5C,IAAa,SAAb,MAAa,OAAwC;CACnD,mBAA+C,EAAE;CACjD,iBAAkC,EAAE;CAEpC,AAAQ,YAAY,QAA+B;EACjD,MAAM,EAAE,SAAS,GAAG,iBAAiB;EAErC,MAAM,gBAAgB,OAAO,QAAQ,QAAQ;EAE7C,MAAM,cAAc,cAAc,QAAQ,CAAC,GAAG,OAAO;AACnD,WAAQ,GAAG,QAAQ,SAAS,cAAc;IAC1C;EACF,MAAM,gBAAgB,cAAc,QACjC,CAAC,GAAG,QAAQ,GAAG,QAAQ,SAAS,cAAc,SAChD;EACD,MAAM,kBAAkB,cAAc,QACnC,CAAC,GAAG,QAAQ,GAAG,QAAQ,SAAS,cAAc,WAChD;AAED,OAAK,MAAM,CAAC,MAAM,eAAe,YAC/B,KAAI,WACF,MAAK,wBAAwB,cAAc,MAAM,WAAW;AAIhE,OAAK,MAAM,CAAC,MAAM,eAAe,cAC/B,KAAI,WACF,MAAK,wBAAwB,cAAc,MAAM,WAAW;AAIhE,OAAK,MAAM,CAAC,MAAM,eAAe,gBAC/B,KAAI,WACF,MAAK,wBAAwB,cAAc,MAAM,YAAY,EAC3D,SAAS,MAAKA,iBACf,CAAC;;CAKR,AAAQ,wBACN,QACA,MACA,YACA,WACA;EACA,MAAM,EAAE,QAAQ,QAAQ,QAAQ,iBAAiB;EAQjD,MAAM,iBAAiB,IAAI,OAPR;GACjB,GAAG;GACH,GAAG,OAAO;GACV,GAAG;GACH;GACA,GAAG;GACJ,CAC4C;AAE7C,QAAKA,gBAAiB,QAAQ;AAE9B,QAAKC,cAAe,KAAK,eAAe,OAAO,CAAC;EAEhD,MAAM,OAAO;AAEb,SAAO,eAAe,MAAM,MAAM;GAChC,MAAM;IACJ,MAAM,SAAS,MAAKD,gBAAiB;AACrC,WAAO,KAAK,eAAe,OAAO;;GAEpC,YAAY;GACb,CAAC;;;;;CAMJ,AAAQ,kBACN,SACA,SACA;AACA,OAAK,MAAM,OAAO,QAChB,KAAI,OAAO,OAAO,SAAS,IAAI,IAAI,OAAO,QAAQ,SAAS,WACzD,SAAQ,OAAQ,QAAQ,KAAyC,KAC/D,QACD;;;;;;CASP,AAAQ,eAAqC,QAAW;EAEtD,MAAM,gBAAiB,OAAO,WAAW,IAAI,EAAE;AAC/C,OAAK,kBAAkB,eAAe,OAAO;AAG7C,MAAI,OAAQ,OAAe,WAAW,WACpC,QAAO;AAGT,SAAO;GACL,GAAG;GAMH,SAAS,QAAmC;IAC1C,MAAM,aAAc,OAAe,OAAO,IAAI;IAC9C,MAAM,cAAe,WAAW,WAAW,IAAI,EAAE;AAIjD,SAAK,kBAAkB,aAAa,WAAW;AAC/C,WAAO;;GAEV;;CAGH,aAAa,WAGX,SAKI,EAAE,EACiB;AAEvB,mBAAiB,WAAW,QAAQ,UAAU;AAC9C,QAAM,aAAa,YAAY,QAAQ,MAAM;AAI7C,QAAM,eAAe,WAAW,QAAQ,OAAO;EAE/C,MAAM,aAAa,OAAO;EAE1B,MAAM,WAAW,IAAI,kBAAkB;AACvC,WAAS,iBAAiB,WAAW;AACrC,WAAS,mBAAmB;EAO5B,MAAM,WAAW,IAAI,OAJA,EACnB,SAFsB,OAAO,eAAe,WAAW,EAGxD,CAEwC;AAEzC,QAAM,QAAQ,IAAI,UAASC,cAAe;AAE1C,SAAO;;CAGT,OAAe,eACb,SACA;EACA,MAAM,SAAyB,EAAE;AACjC,OAAK,MAAM,iBAAiB,QAC1B,QAAO,cAAc,QAAQ;GAC3B,QAAQ,cAAc;GACtB,QAAQ,cAAc;GACvB;AAEH,SAAO;;;;;;AAOX,eAAsB,UAGpB,SAKI,EAAE,EACiB;AACvB,QAAO,OAAO,WAAW,OAAO"}
package/dist/index.d.ts CHANGED
@@ -19,6 +19,9 @@ import { ValidationError } from "./errors/validation.js";
19
19
  import { Plugin } from "./plugin/plugin.js";
20
20
  import { toPlugin } from "./plugin/to-plugin.js";
21
21
  import { analytics } from "./plugins/analytics/analytics.js";
22
+ import { ConfigSchema, PluginManifest, ResourceEntry, ResourceFieldEntry, ResourcePermission, ResourceRequirement, ResourceType, ValidationResult } from "./registry/types.js";
23
+ import { getPluginManifest, getResourceRequirements } from "./registry/manifest-loader.js";
24
+ import { ResourceRegistry } from "./registry/resource-registry.js";
22
25
  import { server } from "./plugins/server/index.js";
23
26
  import { appKitTypesPlugin } from "./type-generator/vite-plugin.js";
24
- export { AppKitError, AuthenticationError, type BasePluginConfig, type CacheConfig, CacheManager, ConfigurationError, ConnectionError, type Counter, ExecutionError, type Histogram, type IAppRouter, type ITelemetry, InitializationError, Plugin, ServerError, SeverityNumber, type Span, SpanStatusCode, type StreamExecutionSettings, type TelemetryConfig, TunnelError, ValidationError, analytics, appKitTypesPlugin, createApp, getExecutionContext, isSQLTypeMarker, server, sql, toPlugin };
27
+ export { AppKitError, AuthenticationError, type BasePluginConfig, type CacheConfig, CacheManager, type ConfigSchema, ConfigurationError, ConnectionError, type Counter, ExecutionError, type Histogram, type IAppRouter, type ITelemetry, InitializationError, Plugin, type PluginManifest, type ResourceEntry, type ResourceFieldEntry, type ResourcePermission, ResourceRegistry, type ResourceRequirement, ResourceType, ServerError, SeverityNumber, type Span, SpanStatusCode, type StreamExecutionSettings, type TelemetryConfig, TunnelError, ValidationError, type ValidationResult, analytics, appKitTypesPlugin, createApp, getExecutionContext, getPluginManifest, getResourceRequirements, isSQLTypeMarker, server, sql, toPlugin };
package/dist/index.js CHANGED
@@ -13,6 +13,10 @@ import { init_errors } from "./errors/index.js";
13
13
  import { getExecutionContext } from "./context/execution-context.js";
14
14
  import { init_context } from "./context/index.js";
15
15
  import { CacheManager } from "./cache/index.js";
16
+ import { ResourceType } from "./registry/types.js";
17
+ import { getPluginManifest, getResourceRequirements } from "./registry/manifest-loader.js";
18
+ import { ResourceRegistry } from "./registry/resource-registry.js";
19
+ import "./registry/index.js";
16
20
  import { createApp } from "./core/appkit.js";
17
21
  import "./core/index.js";
18
22
  import { Plugin } from "./plugin/plugin.js";
@@ -28,5 +32,5 @@ init_context();
28
32
  init_errors();
29
33
 
30
34
  //#endregion
31
- export { AppKitError, AuthenticationError, CacheManager, ConfigurationError, ConnectionError, ExecutionError, InitializationError, Plugin, ServerError, SeverityNumber, SpanStatusCode, TunnelError, ValidationError, analytics, appKitTypesPlugin, createApp, getExecutionContext, isSQLTypeMarker, server, sql, toPlugin };
35
+ export { AppKitError, AuthenticationError, CacheManager, ConfigurationError, ConnectionError, ExecutionError, InitializationError, Plugin, ResourceRegistry, ResourceType, ServerError, SeverityNumber, SpanStatusCode, TunnelError, ValidationError, analytics, appKitTypesPlugin, createApp, getExecutionContext, getPluginManifest, getResourceRequirements, isSQLTypeMarker, server, sql, toPlugin };
32
36
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../src/index.ts"],"sourcesContent":["/**\n * @packageDocumentation\n *\n * Core library for building Databricks applications with type-safe SQL queries,\n * plugin architecture, and React integration.\n */\n\n// Types from shared\nexport type {\n BasePluginConfig,\n CacheConfig,\n IAppRouter,\n StreamExecutionSettings,\n} from \"shared\";\nexport { isSQLTypeMarker, sql } from \"shared\";\nexport { CacheManager } from \"./cache\";\nexport { getExecutionContext } from \"./context\";\nexport { createApp } from \"./core\";\n// Errors\nexport {\n AppKitError,\n AuthenticationError,\n ConfigurationError,\n ConnectionError,\n ExecutionError,\n InitializationError,\n ServerError,\n TunnelError,\n ValidationError,\n} from \"./errors\";\n// Plugin authoring\nexport { Plugin, toPlugin } from \"./plugin\";\nexport { analytics, server } from \"./plugins\";\n// Telemetry (for advanced custom telemetry)\nexport {\n type Counter,\n type Histogram,\n type ITelemetry,\n SeverityNumber,\n type Span,\n SpanStatusCode,\n type TelemetryConfig,\n} from \"./telemetry\";\n// Vite plugin and type generation\nexport { appKitTypesPlugin } from \"./type-generator/vite-plugin\";\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;cAgBgD;aAa9B"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../src/index.ts"],"sourcesContent":["/**\n * @packageDocumentation\n *\n * Core library for building Databricks applications with type-safe SQL queries,\n * plugin architecture, and React integration.\n */\n\n// Types from shared\nexport type {\n BasePluginConfig,\n CacheConfig,\n IAppRouter,\n StreamExecutionSettings,\n} from \"shared\";\nexport { isSQLTypeMarker, sql } from \"shared\";\nexport { CacheManager } from \"./cache\";\nexport { getExecutionContext } from \"./context\";\nexport { createApp } from \"./core\";\n// Errors\nexport {\n AppKitError,\n AuthenticationError,\n ConfigurationError,\n ConnectionError,\n ExecutionError,\n InitializationError,\n ServerError,\n TunnelError,\n ValidationError,\n} from \"./errors\";\n// Plugin authoring\nexport { Plugin, toPlugin } from \"./plugin\";\nexport { analytics, server } from \"./plugins\";\n// Registry types and utilities for plugin manifests\nexport type {\n ConfigSchema,\n PluginManifest,\n ResourceEntry,\n ResourceFieldEntry,\n ResourcePermission,\n ResourceRequirement,\n ValidationResult,\n} from \"./registry\";\nexport {\n getPluginManifest,\n getResourceRequirements,\n ResourceRegistry,\n ResourceType,\n} from \"./registry\";\n// Telemetry (for advanced custom telemetry)\nexport {\n type Counter,\n type Histogram,\n type ITelemetry,\n SeverityNumber,\n type Span,\n SpanStatusCode,\n type TelemetryConfig,\n} from \"./telemetry\";\n// Vite plugin and type generation\nexport { appKitTypesPlugin } from \"./type-generator/vite-plugin\";\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cAgBgD;aAa9B"}
@@ -8,7 +8,92 @@ import { DevFileReader } from "./dev-reader.js";
8
8
  import express from "express";
9
9
 
10
10
  //#region src/plugin/plugin.d.ts
11
- /** Base abstract class for creating AppKit plugins */
11
+
12
+ /**
13
+ * Base abstract class for creating AppKit plugins.
14
+ *
15
+ * All plugins must declare a static `manifest` property with their metadata
16
+ * and resource requirements. The manifest defines:
17
+ * - `required` resources: Always needed for the plugin to function
18
+ * - `optional` resources: May be needed depending on plugin configuration
19
+ *
20
+ * ## Static vs Runtime Resource Requirements
21
+ *
22
+ * The manifest is static and doesn't know the plugin's runtime configuration.
23
+ * For resources that become required based on config options, plugins can
24
+ * implement a static `getResourceRequirements(config)` method.
25
+ *
26
+ * At runtime, this method is called with the actual config to determine
27
+ * which "optional" resources should be treated as "required".
28
+ *
29
+ * @example Basic plugin with static requirements
30
+ * ```typescript
31
+ * import { Plugin, toPlugin, PluginManifest, ResourceType } from '@databricks/appkit';
32
+ *
33
+ * const myManifest: PluginManifest = {
34
+ * name: 'myPlugin',
35
+ * displayName: 'My Plugin',
36
+ * description: 'Does something awesome',
37
+ * resources: {
38
+ * required: [
39
+ * { type: ResourceType.SQL_WAREHOUSE, alias: 'warehouse', ... }
40
+ * ],
41
+ * optional: []
42
+ * }
43
+ * };
44
+ *
45
+ * class MyPlugin extends Plugin<MyConfig> {
46
+ * static manifest = myManifest;
47
+ * name = 'myPlugin';
48
+ * }
49
+ * ```
50
+ *
51
+ * @example Plugin with config-dependent resources
52
+ * ```typescript
53
+ * interface MyConfig extends BasePluginConfig {
54
+ * enableCaching?: boolean;
55
+ * }
56
+ *
57
+ * const myManifest: PluginManifest = {
58
+ * name: 'myPlugin',
59
+ * resources: {
60
+ * required: [
61
+ * { type: ResourceType.SQL_WAREHOUSE, alias: 'warehouse', ... }
62
+ * ],
63
+ * optional: [
64
+ * // Database is optional in the static manifest
65
+ * { type: ResourceType.DATABASE, alias: 'cache', description: 'Required if caching enabled', ... }
66
+ * ]
67
+ * }
68
+ * };
69
+ *
70
+ * class MyPlugin extends Plugin<MyConfig> {
71
+ * static manifest = myManifest;
72
+ * name = 'myPlugin';
73
+ *
74
+ * // Runtime method: converts optional resources to required based on config
75
+ * static getResourceRequirements(config: MyConfig) {
76
+ * const resources = [];
77
+ * if (config.enableCaching) {
78
+ * // When caching is enabled, Database becomes required
79
+ * resources.push({
80
+ * type: ResourceType.DATABASE,
81
+ * alias: 'cache',
82
+ * resourceKey: 'database',
83
+ * description: 'Cache storage for query results',
84
+ * permission: 'CAN_CONNECT_AND_CREATE',
85
+ * fields: {
86
+ * instance_name: { env: 'DATABRICKS_CACHE_INSTANCE' },
87
+ * database_name: { env: 'DATABRICKS_CACHE_DB' },
88
+ * },
89
+ * required: true // Mark as required at runtime
90
+ * });
91
+ * }
92
+ * return resources;
93
+ * }
94
+ * }
95
+ * ```
96
+ */
12
97
  declare abstract class Plugin<TConfig extends BasePluginConfig = BasePluginConfig> implements BasePlugin {
13
98
  protected config: TConfig;
14
99
  protected isReady: boolean;
@@ -17,13 +102,20 @@ declare abstract class Plugin<TConfig extends BasePluginConfig = BasePluginConfi
17
102
  protected devFileReader: DevFileReader;
18
103
  protected streamManager: StreamManager;
19
104
  protected telemetry: ITelemetry;
20
- protected abstract envVars: string[];
21
105
  /** Registered endpoints for this plugin */
22
106
  private registeredEndpoints;
107
+ /**
108
+ * Plugin initialization phase.
109
+ * - 'core': Initialized first (e.g., config plugins)
110
+ * - 'normal': Initialized second (most plugins)
111
+ * - 'deferred': Initialized last (e.g., server plugin)
112
+ */
23
113
  static phase: PluginPhase;
114
+ /**
115
+ * Plugin name identifier.
116
+ */
24
117
  name: string;
25
118
  constructor(config: TConfig);
26
- validateEnv(): void;
27
119
  injectRoutes(_: express.Router): void;
28
120
  setup(): Promise<void>;
29
121
  getEndpoints(): PluginEndpointMap;
@@ -1 +1 @@
1
- {"version":3,"file":"plugin.d.ts","names":[],"sources":["../../src/plugin/plugin.ts"],"sourcesContent":[],"mappings":";;;;;;;;;;;uBA8DsB,uBACJ,mBAAmB,6BACxB;oBAgBmB;EAlBV,UAAM,OAAA,EAAA,OAAA;EAAA,UAAA,KAAA,EAKT,YALS;YACV,GAAA,EAKD,UALC;YAAmB,aAAA,EAMV,aANU;YAiBL,aAAA,EAVL,aAUK;YAbb,SAAA,EAII,UAJJ;qBACF,OAAA,EAAA,MAAA,EAAA;;UAEU,mBAAA;SACJ,KAAA,EAMP,WANO;MAMP,EAAA,MAAA;aAGgB,CAAA,MAAA,EAAA,OAAA;aAeN,CAAA,CAAA,EAAA,IAAA;cAIb,CAAA,CAAA,EAJK,OAAA,CAAQ,MAIb,CAAA,EAAA,IAAA;OAEK,CAAA,CAAA,EAFL,OAEK,CAAA,IAAA,CAAA;cA0BI,CAAA,CAAA,EA1BJ,iBA0BI;uBA6Db,CAAA,CAAA,EAAA,IAAA;;;;;;SA8DiC,CAAA,CAAA,EAAA,OAAA;;;;;;;;;;cA3H5B,OAAA,CAAQ;;;;;;;kCA6Db,kBACD,qBAAqB,aAChB,4CACO;qCA2DF,gBAAgB,QAAQ,aAC7B,4CAER,QAAQ;;sCA0BD,OAAA,CAAQ,gBACR"}
1
+ {"version":3,"file":"plugin.d.ts","names":[],"sources":["../../src/plugin/plugin.ts"],"sourcesContent":[],"mappings":";;;;;;;;;;;;;;AAiJA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;uBAAsB,uBACJ,mBAAmB,6BACxB;oBAyBmB;;mBAtBb;iBACF;2BACU;2BACA;uBACJ;;;;;;;;;gBAWP;;;;;sBAOgB;kBAWd,OAAA,CAAQ;WAIb;kBAEK;;;;;;;;;;;;;;;;;cA0BJ,OAAA,CAAQ;;;;;;;kCA6Db,kBACD,qBAAqB,aAChB,4CACO;qCA2DF,gBAAgB,QAAQ,aAC7B,4CAER,QAAQ;;sCA0BD,OAAA,CAAQ,gBACR"}