@databricks/appkit 0.37.0 → 0.38.1

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 (156) hide show
  1. package/CLAUDE.md +3 -2
  2. package/NOTICE.md +1 -2
  3. package/dist/appkit/package.js +1 -1
  4. package/dist/cache/index.d.ts +27 -5
  5. package/dist/cache/index.d.ts.map +1 -1
  6. package/dist/cache/index.js +88 -16
  7. package/dist/cache/index.js.map +1 -1
  8. package/dist/cache/storage/persistent.js +1 -2
  9. package/dist/cache/storage/persistent.js.map +1 -1
  10. package/dist/cli/commands/plugin/add-resource/add-resource.js.map +1 -1
  11. package/dist/cli/commands/plugin/create/resource-defaults.js +2 -1
  12. package/dist/cli/commands/plugin/create/resource-defaults.js.map +1 -1
  13. package/dist/cli/commands/plugin/schema-resources.js +34 -51
  14. package/dist/cli/commands/plugin/schema-resources.js.map +1 -1
  15. package/dist/cli/commands/plugin/sync/sync.js +20 -6
  16. package/dist/cli/commands/plugin/sync/sync.js.map +1 -1
  17. package/dist/cli/commands/plugin/validate/validate-manifest.js +71 -157
  18. package/dist/cli/commands/plugin/validate/validate-manifest.js.map +1 -1
  19. package/dist/cli/commands/plugin/validate/validate.js +2 -2
  20. package/dist/cli/commands/plugin/validate/validate.js.map +1 -1
  21. package/dist/cli/commands/setup.js +2 -2
  22. package/dist/cli/commands/setup.js.map +1 -1
  23. package/dist/connectors/index.js +0 -1
  24. package/dist/connectors/jobs/client.js +1 -2
  25. package/dist/connectors/jobs/client.js.map +1 -1
  26. package/dist/connectors/lakebase/routing-pool.js +1 -2
  27. package/dist/connectors/lakebase/routing-pool.js.map +1 -1
  28. package/dist/connectors/sql-warehouse/client.js +1 -2
  29. package/dist/connectors/sql-warehouse/client.js.map +1 -1
  30. package/dist/context/execution-context.js +9 -13
  31. package/dist/context/execution-context.js.map +1 -1
  32. package/dist/context/index.js +3 -13
  33. package/dist/context/service-context.js +137 -136
  34. package/dist/context/service-context.js.map +1 -1
  35. package/dist/context/user-context.js +1 -5
  36. package/dist/context/user-context.js.map +1 -1
  37. package/dist/core/agent/create-agent.js +1 -2
  38. package/dist/core/agent/create-agent.js.map +1 -1
  39. package/dist/core/appkit.js +1 -2
  40. package/dist/core/appkit.js.map +1 -1
  41. package/dist/errors/authentication.js +44 -40
  42. package/dist/errors/authentication.js.map +1 -1
  43. package/dist/errors/base.js +86 -70
  44. package/dist/errors/base.js.map +1 -1
  45. package/dist/errors/configuration.js +70 -66
  46. package/dist/errors/configuration.js.map +1 -1
  47. package/dist/errors/connection.js +50 -46
  48. package/dist/errors/connection.js.map +1 -1
  49. package/dist/errors/execution.js +47 -43
  50. package/dist/errors/execution.js.map +1 -1
  51. package/dist/errors/index.js +10 -27
  52. package/dist/errors/initialization.js +38 -34
  53. package/dist/errors/initialization.js.map +1 -1
  54. package/dist/errors/server.js +34 -31
  55. package/dist/errors/server.js.map +1 -1
  56. package/dist/errors/tunnel.js +47 -43
  57. package/dist/errors/tunnel.js.map +1 -1
  58. package/dist/errors/validation.js +41 -37
  59. package/dist/errors/validation.js.map +1 -1
  60. package/dist/index.d.ts +1 -1
  61. package/dist/index.js +3 -9
  62. package/dist/plugin/dev-reader.js +1 -2
  63. package/dist/plugin/dev-reader.js.map +1 -1
  64. package/dist/plugin/interceptors/cache.js +13 -1
  65. package/dist/plugin/interceptors/cache.js.map +1 -1
  66. package/dist/plugin/interceptors/retry.js +1 -2
  67. package/dist/plugin/interceptors/retry.js.map +1 -1
  68. package/dist/plugin/interceptors/telemetry.js +1 -2
  69. package/dist/plugin/interceptors/telemetry.js.map +1 -1
  70. package/dist/plugin/plugin.js +2 -4
  71. package/dist/plugin/plugin.js.map +1 -1
  72. package/dist/plugins/analytics/analytics.js +1 -2
  73. package/dist/plugins/analytics/analytics.js.map +1 -1
  74. package/dist/plugins/analytics/manifest.js +9 -1
  75. package/dist/plugins/analytics/query.js +2 -4
  76. package/dist/plugins/analytics/query.js.map +1 -1
  77. package/dist/plugins/files/manifest.js +7 -1
  78. package/dist/plugins/files/plugin.js +3 -6
  79. package/dist/plugins/files/plugin.js.map +1 -1
  80. package/dist/plugins/genie/genie.js +1 -2
  81. package/dist/plugins/genie/genie.js.map +1 -1
  82. package/dist/plugins/genie/manifest.js +7 -1
  83. package/dist/plugins/jobs/plugin.js +2 -4
  84. package/dist/plugins/jobs/plugin.js.map +1 -1
  85. package/dist/plugins/lakebase/lakebase.js +1 -2
  86. package/dist/plugins/lakebase/lakebase.js.map +1 -1
  87. package/dist/plugins/lakebase/manifest.js +26 -4
  88. package/dist/plugins/server/index.js +1 -2
  89. package/dist/plugins/server/index.js.map +1 -1
  90. package/dist/plugins/server/vite-dev-server.js +1 -2
  91. package/dist/plugins/server/vite-dev-server.js.map +1 -1
  92. package/dist/plugins/serving/serving.js +1 -2
  93. package/dist/plugins/serving/serving.js.map +1 -1
  94. package/dist/registry/index.d.ts +1 -1
  95. package/dist/registry/manifest-loader.d.ts +4 -4
  96. package/dist/registry/manifest-loader.d.ts.map +1 -1
  97. package/dist/registry/manifest-loader.js +1 -2
  98. package/dist/registry/manifest-loader.js.map +1 -1
  99. package/dist/registry/resource-registry.js +1 -2
  100. package/dist/registry/resource-registry.js.map +1 -1
  101. package/dist/registry/types.d.ts +21 -7
  102. package/dist/registry/types.d.ts.map +1 -1
  103. package/dist/registry/types.generated.d.ts +1 -1
  104. package/dist/registry/types.generated.js +1 -1
  105. package/dist/registry/types.generated.js.map +1 -1
  106. package/dist/registry/types.js +3 -3
  107. package/dist/registry/types.js.map +1 -1
  108. package/dist/schemas/manifest.d.ts +1139 -0
  109. package/dist/schemas/manifest.d.ts.map +1 -0
  110. package/dist/schemas/manifest.js +524 -0
  111. package/dist/schemas/manifest.js.map +1 -0
  112. package/dist/shared/src/index.d.ts +1 -1
  113. package/dist/shared/src/plugin.d.ts +38 -7
  114. package/dist/shared/src/plugin.d.ts.map +1 -1
  115. package/dist/shared/src/schemas/manifest.d.ts +1110 -0
  116. package/dist/shared/src/schemas/manifest.d.ts.map +1 -0
  117. package/dist/stream/arrow-stream-processor.js +1 -2
  118. package/dist/stream/arrow-stream-processor.js.map +1 -1
  119. package/dist/stream/buffers.js +1 -2
  120. package/dist/stream/buffers.js.map +1 -1
  121. package/dist/stream/stream-manager.d.ts.map +1 -1
  122. package/dist/stream/stream-manager.js +3 -3
  123. package/dist/stream/stream-manager.js.map +1 -1
  124. package/docs/api/appkit/Enumeration.ResourceType.md +1 -1
  125. package/docs/api/appkit/Interface.PluginManifest.md +57 -3
  126. package/docs/api/appkit/Interface.ResourceEntry.md +6 -4
  127. package/docs/api/appkit/Interface.ResourceRequirement.md +7 -61
  128. package/docs/api/appkit/TypeAlias.ResourceFieldEntry.md +6 -0
  129. package/docs/api/appkit.md +6 -6
  130. package/docs/app-management.md +1 -1
  131. package/docs/development/ai-assisted-development.md +2 -2
  132. package/docs/development/local-development.md +1 -1
  133. package/docs/development/remote-bridge.md +1 -1
  134. package/docs/development/templates.md +118 -12
  135. package/docs/development.md +1 -1
  136. package/docs/plugins/custom-plugins.md +33 -23
  137. package/docs/plugins/lakebase.md +1 -1
  138. package/docs/plugins/manifest.md +293 -0
  139. package/docs.md +2 -2
  140. package/llms.txt +3 -2
  141. package/package.json +3 -3
  142. package/sbom.cdx.json +1 -1
  143. package/dist/_virtual/_rolldown/runtime.js +0 -7
  144. package/dist/connectors/lakebase-v1/client.js +0 -15
  145. package/dist/connectors/lakebase-v1/client.js.map +0 -1
  146. package/dist/connectors/lakebase-v1/index.js +0 -3
  147. package/dist/context/index.js.map +0 -1
  148. package/dist/errors/index.js.map +0 -1
  149. package/dist/index.js.map +0 -1
  150. package/dist/schemas/plugin-manifest.generated.d.ts +0 -182
  151. package/dist/schemas/plugin-manifest.generated.d.ts.map +0 -1
  152. package/dist/schemas/plugin-manifest.schema.json +0 -489
  153. package/dist/schemas/template-plugins.schema.json +0 -113
  154. package/dist/shared/src/schemas/plugin-manifest.generated.d.ts +0 -182
  155. package/dist/shared/src/schemas/plugin-manifest.generated.d.ts.map +0 -1
  156. package/docs/api/appkit/Interface.ResourceFieldEntry.md +0 -82
@@ -4,7 +4,7 @@ import { ServiceContext } from "../context/service-context.js";
4
4
  import { TelemetryManager } from "../telemetry/telemetry-manager.js";
5
5
  import "../telemetry/index.js";
6
6
  import { CacheManager } from "../cache/index.js";
7
- import { init_context } from "../context/index.js";
7
+ import "../context/index.js";
8
8
  import { isInternalTelemetryEnabled } from "../internal-telemetry/config.js";
9
9
  import { TelemetryReporter } from "../internal-telemetry/reporter.js";
10
10
  import "../internal-telemetry/index.js";
@@ -15,7 +15,6 @@ import "../registry/index.js";
15
15
  import { PluginContext, isToolProvider } from "./plugin-context.js";
16
16
 
17
17
  //#region src/core/appkit.ts
18
- init_context();
19
18
  const logger = createLogger("appkit");
20
19
  var AppKit = class AppKit {
21
20
  #pluginInstances = {};
@@ -1 +1 @@
1
- {"version":3,"file":"appkit.js","names":["#context","#pluginInstances","#setupPromises","productVersion"],"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 { version as productVersion } from \"../../package.json\";\nimport { CacheManager } from \"../cache\";\nimport { ServiceContext } from \"../context\";\nimport {\n isInternalTelemetryEnabled,\n TelemetryReporter,\n} from \"../internal-telemetry\";\nimport { createLogger } from \"../logging/logger\";\nimport { isPlainObject } from \"../plugin/plugin\";\nimport { ResourceRegistry, ResourceType } from \"../registry\";\nimport type { TelemetryConfig } from \"../telemetry\";\nimport { TelemetryManager } from \"../telemetry\";\nimport { isToolProvider, PluginContext } from \"./plugin-context\";\n\nconst logger = createLogger(\"appkit\");\n\nexport class AppKit<TPlugins extends InputPluginMap> {\n #pluginInstances: Record<string, BasePlugin> = {};\n #setupPromises: Promise<void>[] = [];\n #context: PluginContext;\n\n private constructor(config: { plugins: TPlugins }) {\n const { plugins, ...globalConfig } = config;\n\n this.#context = new PluginContext();\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 context: this.#context,\n });\n }\n }\n\n for (const [name, pluginData] of normalPlugins) {\n if (pluginData) {\n this.createAndRegisterPlugin(globalConfig, name, pluginData, {\n context: this.#context,\n });\n }\n }\n\n for (const [name, pluginData] of deferredPlugins) {\n if (pluginData) {\n this.createAndRegisterPlugin(globalConfig, name, pluginData, {\n context: this.#context,\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 if (typeof pluginInstance.attachContext === \"function\") {\n pluginInstance.attachContext({\n context: this.#context,\n telemetryConfig: baseConfig.telemetry,\n });\n }\n\n this.#pluginInstances[name] = pluginInstance;\n\n this.#context.registerPlugin(name, pluginInstance);\n if (isToolProvider(pluginInstance)) {\n this.#context.registerToolProvider(name, pluginInstance);\n }\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 * Recurses into plain objects to handle nested APIs (e.g., volume APIs).\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)) continue;\n const val = exports[key];\n if (typeof val === \"function\") {\n exports[key] = (val as (...args: unknown[]) => unknown).bind(context);\n } else if (isPlainObject(val)) {\n this.bindExportMethods(val as Record<string, unknown>, context);\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 * When `exports()` returns a callable (function), it is returned as-is\n * since the plugin manages its own `asUser` per-call (e.g. files plugin).\n * When it returns a plain object, the standard `asUser` wrapper is added.\n *\n * The OBO-side wrapping lives inside `Plugin.asUser` — calling\n * `plugin.asUser(req).exports()` returns exports whose functions already\n * run inside the user's AsyncLocalStorage scope. AppKit only adapts the\n * shape; it does not own the user-context concept.\n */\n private wrapWithAsUser<T extends BasePlugin>(plugin: T) {\n // If plugin doesn't implement exports(), return empty object\n const pluginExports = plugin.exports?.() ?? {};\n\n // If exports is a function, the plugin manages its own asUser pattern\n if (typeof pluginExports === \"function\") {\n return pluginExports;\n }\n\n const objExports = pluginExports as Record<string, unknown>;\n this.bindExportMethods(objExports, 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 objExports;\n }\n\n return {\n ...objExports,\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 (plugin as any).asUser(req).exports() as Record<string, unknown>,\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 onPluginsReady?: (appkit: PluginMap<T>) => void | Promise<void>;\n disableInternalTelemetry?: boolean;\n } = {},\n ): Promise<PluginMap<T>> {\n // Initialize core services\n TelemetryManager.initialize(config?.telemetry);\n await CacheManager.getInstance(config?.cache);\n\n const rawPlugins = config.plugins as T;\n\n // Collect manifest resources via registry\n const registry = new ResourceRegistry();\n registry.collectResources(rawPlugins);\n\n // Derive ServiceContext needs from what manifests declared\n const needsWarehouse = registry\n .getRequired()\n .some((r) => r.type === ResourceType.SQL_WAREHOUSE);\n await ServiceContext.initialize(\n { warehouseId: needsWarehouse },\n config?.client,\n );\n\n // Validate env vars\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 await instance.#context.emitLifecycle(\"setup:complete\");\n\n const handle = instance as unknown as PluginMap<T>;\n\n if (config.onPluginsReady) {\n logger.debug(\"Running onPluginsReady hook\");\n await config.onPluginsReady(handle);\n logger.debug(\"onPluginsReady hook completed\");\n }\n\n if (isInternalTelemetryEnabled(config)) {\n AppKit.bootstrapInternalTelemetry();\n }\n\n const serverPlugin = instance.#pluginInstances.server;\n if (serverPlugin && typeof (serverPlugin as any).start === \"function\") {\n await (serverPlugin as any).start();\n }\n\n return handle;\n }\n\n private static bootstrapInternalTelemetry(): void {\n const serviceCtx = ServiceContext.get();\n const reporter = TelemetryReporter.initialize({\n workspaceId: serviceCtx.workspaceId,\n client: serviceCtx.client,\n appId: process.env.DATABRICKS_CLIENT_ID || \"\",\n appkitVersion: productVersion,\n });\n reporter.start();\n reporter.sendStartup().catch(() => {});\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 *\n * Initializes telemetry, cache, and service context, then registers plugins\n * in phase order (core, normal, deferred) and awaits their setup.\n * If a `onPluginsReady` callback is provided it runs after plugin setup but\n * before the server starts, giving you access to the full appkit handle\n * for registering custom routes or performing async setup.\n * The returned object maps each plugin name to its `exports()` API,\n * with an `asUser(req)` method for user-scoped execution.\n *\n * @returns A `PluginMap` keyed by plugin name with typed exports\n *\n * @example Minimal server\n * ```ts\n * import { createApp, server } from \"@databricks/appkit\";\n *\n * await createApp({\n * plugins: [server()],\n * });\n * ```\n *\n * @example Server with custom routes via onPluginsReady\n * ```ts\n * import { createApp, server, analytics } from \"@databricks/appkit\";\n *\n * await createApp({\n * plugins: [server(), analytics({})],\n * onPluginsReady(appkit) {\n * appkit.server.extend((app) => {\n * app.get(\"/custom\", (_req, res) => res.json({ ok: true }));\n * });\n * },\n * });\n * ```\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 onPluginsReady?: (appkit: PluginMap<T>) => void | Promise<void>;\n disableInternalTelemetry?: boolean;\n } = {},\n): Promise<PluginMap<T>> {\n return AppKit._createApp(config);\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"appkit.js","names":["#context","#pluginInstances","#setupPromises","productVersion"],"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 { version as productVersion } from \"../../package.json\";\nimport { CacheManager } from \"../cache\";\nimport { ServiceContext } from \"../context\";\nimport {\n isInternalTelemetryEnabled,\n TelemetryReporter,\n} from \"../internal-telemetry\";\nimport { createLogger } from \"../logging/logger\";\nimport { isPlainObject } from \"../plugin/plugin\";\nimport { ResourceRegistry, ResourceType } from \"../registry\";\nimport type { TelemetryConfig } from \"../telemetry\";\nimport { TelemetryManager } from \"../telemetry\";\nimport { isToolProvider, PluginContext } from \"./plugin-context\";\n\nconst logger = createLogger(\"appkit\");\n\nexport class AppKit<TPlugins extends InputPluginMap> {\n #pluginInstances: Record<string, BasePlugin> = {};\n #setupPromises: Promise<void>[] = [];\n #context: PluginContext;\n\n private constructor(config: { plugins: TPlugins }) {\n const { plugins, ...globalConfig } = config;\n\n this.#context = new PluginContext();\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 context: this.#context,\n });\n }\n }\n\n for (const [name, pluginData] of normalPlugins) {\n if (pluginData) {\n this.createAndRegisterPlugin(globalConfig, name, pluginData, {\n context: this.#context,\n });\n }\n }\n\n for (const [name, pluginData] of deferredPlugins) {\n if (pluginData) {\n this.createAndRegisterPlugin(globalConfig, name, pluginData, {\n context: this.#context,\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 if (typeof pluginInstance.attachContext === \"function\") {\n pluginInstance.attachContext({\n context: this.#context,\n telemetryConfig: baseConfig.telemetry,\n });\n }\n\n this.#pluginInstances[name] = pluginInstance;\n\n this.#context.registerPlugin(name, pluginInstance);\n if (isToolProvider(pluginInstance)) {\n this.#context.registerToolProvider(name, pluginInstance);\n }\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 * Recurses into plain objects to handle nested APIs (e.g., volume APIs).\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)) continue;\n const val = exports[key];\n if (typeof val === \"function\") {\n exports[key] = (val as (...args: unknown[]) => unknown).bind(context);\n } else if (isPlainObject(val)) {\n this.bindExportMethods(val as Record<string, unknown>, context);\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 * When `exports()` returns a callable (function), it is returned as-is\n * since the plugin manages its own `asUser` per-call (e.g. files plugin).\n * When it returns a plain object, the standard `asUser` wrapper is added.\n *\n * The OBO-side wrapping lives inside `Plugin.asUser` — calling\n * `plugin.asUser(req).exports()` returns exports whose functions already\n * run inside the user's AsyncLocalStorage scope. AppKit only adapts the\n * shape; it does not own the user-context concept.\n */\n private wrapWithAsUser<T extends BasePlugin>(plugin: T) {\n // If plugin doesn't implement exports(), return empty object\n const pluginExports = plugin.exports?.() ?? {};\n\n // If exports is a function, the plugin manages its own asUser pattern\n if (typeof pluginExports === \"function\") {\n return pluginExports;\n }\n\n const objExports = pluginExports as Record<string, unknown>;\n this.bindExportMethods(objExports, 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 objExports;\n }\n\n return {\n ...objExports,\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 (plugin as any).asUser(req).exports() as Record<string, unknown>,\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 onPluginsReady?: (appkit: PluginMap<T>) => void | Promise<void>;\n disableInternalTelemetry?: boolean;\n } = {},\n ): Promise<PluginMap<T>> {\n // Initialize core services\n TelemetryManager.initialize(config?.telemetry);\n await CacheManager.getInstance(config?.cache);\n\n const rawPlugins = config.plugins as T;\n\n // Collect manifest resources via registry\n const registry = new ResourceRegistry();\n registry.collectResources(rawPlugins);\n\n // Derive ServiceContext needs from what manifests declared\n const needsWarehouse = registry\n .getRequired()\n .some((r) => r.type === ResourceType.SQL_WAREHOUSE);\n await ServiceContext.initialize(\n { warehouseId: needsWarehouse },\n config?.client,\n );\n\n // Validate env vars\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 await instance.#context.emitLifecycle(\"setup:complete\");\n\n const handle = instance as unknown as PluginMap<T>;\n\n if (config.onPluginsReady) {\n logger.debug(\"Running onPluginsReady hook\");\n await config.onPluginsReady(handle);\n logger.debug(\"onPluginsReady hook completed\");\n }\n\n if (isInternalTelemetryEnabled(config)) {\n AppKit.bootstrapInternalTelemetry();\n }\n\n const serverPlugin = instance.#pluginInstances.server;\n if (serverPlugin && typeof (serverPlugin as any).start === \"function\") {\n await (serverPlugin as any).start();\n }\n\n return handle;\n }\n\n private static bootstrapInternalTelemetry(): void {\n const serviceCtx = ServiceContext.get();\n const reporter = TelemetryReporter.initialize({\n workspaceId: serviceCtx.workspaceId,\n client: serviceCtx.client,\n appId: process.env.DATABRICKS_CLIENT_ID || \"\",\n appkitVersion: productVersion,\n });\n reporter.start();\n reporter.sendStartup().catch(() => {});\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 *\n * Initializes telemetry, cache, and service context, then registers plugins\n * in phase order (core, normal, deferred) and awaits their setup.\n * If a `onPluginsReady` callback is provided it runs after plugin setup but\n * before the server starts, giving you access to the full appkit handle\n * for registering custom routes or performing async setup.\n * The returned object maps each plugin name to its `exports()` API,\n * with an `asUser(req)` method for user-scoped execution.\n *\n * @returns A `PluginMap` keyed by plugin name with typed exports\n *\n * @example Minimal server\n * ```ts\n * import { createApp, server } from \"@databricks/appkit\";\n *\n * await createApp({\n * plugins: [server()],\n * });\n * ```\n *\n * @example Server with custom routes via onPluginsReady\n * ```ts\n * import { createApp, server, analytics } from \"@databricks/appkit\";\n *\n * await createApp({\n * plugins: [server(), analytics({})],\n * onPluginsReady(appkit) {\n * appkit.server.extend((app) => {\n * app.get(\"/custom\", (_req, res) => res.json({ ok: true }));\n * });\n * },\n * });\n * ```\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 onPluginsReady?: (appkit: PluginMap<T>) => void | Promise<void>;\n disableInternalTelemetry?: boolean;\n } = {},\n): Promise<PluginMap<T>> {\n return AppKit._createApp(config);\n}\n"],"mappings":"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"}
@@ -1,45 +1,49 @@
1
- import { __esmMin } from "../_virtual/_rolldown/runtime.js";
2
- import { AppKitError, init_base } from "./base.js";
1
+ import { AppKitError } from "./base.js";
3
2
 
4
3
  //#region src/errors/authentication.ts
5
- var AuthenticationError;
6
- var init_authentication = __esmMin((() => {
7
- init_base();
8
- AuthenticationError = class AuthenticationError extends AppKitError {
9
- code = "AUTHENTICATION_ERROR";
10
- statusCode = 401;
11
- isRetryable = false;
12
- /**
13
- * Create an authentication error for missing token
14
- */
15
- static missingToken(tokenType = "access token") {
16
- return new AuthenticationError(`Missing ${tokenType} in request headers`, { context: { tokenType } });
17
- }
18
- /**
19
- * Create an authentication error for missing user identity
20
- */
21
- static missingUserId() {
22
- return new AuthenticationError("User ID not available in request headers. Ensure the request has the x-forwarded-user header.");
23
- }
24
- /**
25
- * Create an authentication error for credential generation failure
26
- */
27
- static credentialsFailed(instance, cause) {
28
- return new AuthenticationError(`Failed to generate credentials for instance: ${instance}`, {
29
- cause,
30
- context: { instance }
31
- });
32
- }
33
- /**
34
- * Create an authentication error for failed user lookup
35
- */
36
- static userLookupFailed(cause) {
37
- return new AuthenticationError("Failed to get current user from Databricks workspace", { cause });
38
- }
39
- };
40
- }));
4
+ /**
5
+ * Error thrown when authentication fails.
6
+ * Use for missing tokens, invalid credentials, or authorization failures.
7
+ *
8
+ * @example
9
+ * ```typescript
10
+ * throw new AuthenticationError("User token is required");
11
+ * throw new AuthenticationError("Failed to generate credentials", { cause: originalError });
12
+ * ```
13
+ */
14
+ var AuthenticationError = class AuthenticationError extends AppKitError {
15
+ code = "AUTHENTICATION_ERROR";
16
+ statusCode = 401;
17
+ isRetryable = false;
18
+ /**
19
+ * Create an authentication error for missing token
20
+ */
21
+ static missingToken(tokenType = "access token") {
22
+ return new AuthenticationError(`Missing ${tokenType} in request headers`, { context: { tokenType } });
23
+ }
24
+ /**
25
+ * Create an authentication error for missing user identity
26
+ */
27
+ static missingUserId() {
28
+ return new AuthenticationError("User ID not available in request headers. Ensure the request has the x-forwarded-user header.");
29
+ }
30
+ /**
31
+ * Create an authentication error for credential generation failure
32
+ */
33
+ static credentialsFailed(instance, cause) {
34
+ return new AuthenticationError(`Failed to generate credentials for instance: ${instance}`, {
35
+ cause,
36
+ context: { instance }
37
+ });
38
+ }
39
+ /**
40
+ * Create an authentication error for failed user lookup
41
+ */
42
+ static userLookupFailed(cause) {
43
+ return new AuthenticationError("Failed to get current user from Databricks workspace", { cause });
44
+ }
45
+ };
41
46
 
42
47
  //#endregion
43
- init_authentication();
44
- export { AuthenticationError, init_authentication };
48
+ export { AuthenticationError };
45
49
  //# sourceMappingURL=authentication.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"authentication.js","names":[],"sources":["../../src/errors/authentication.ts"],"sourcesContent":["import { AppKitError } from \"./base\";\n\n/**\n * Error thrown when authentication fails.\n * Use for missing tokens, invalid credentials, or authorization failures.\n *\n * @example\n * ```typescript\n * throw new AuthenticationError(\"User token is required\");\n * throw new AuthenticationError(\"Failed to generate credentials\", { cause: originalError });\n * ```\n */\nexport class AuthenticationError extends AppKitError {\n readonly code = \"AUTHENTICATION_ERROR\";\n readonly statusCode = 401;\n readonly isRetryable = false;\n\n /**\n * Create an authentication error for missing token\n */\n static missingToken(tokenType = \"access token\"): AuthenticationError {\n return new AuthenticationError(`Missing ${tokenType} in request headers`, {\n context: { tokenType },\n });\n }\n\n /**\n * Create an authentication error for missing user identity\n */\n static missingUserId(): AuthenticationError {\n return new AuthenticationError(\n \"User ID not available in request headers. \" +\n \"Ensure the request has the x-forwarded-user header.\",\n );\n }\n\n /**\n * Create an authentication error for credential generation failure\n */\n static credentialsFailed(\n instance: string,\n cause?: Error,\n ): AuthenticationError {\n return new AuthenticationError(\n `Failed to generate credentials for instance: ${instance}`,\n { cause, context: { instance } },\n );\n }\n\n /**\n * Create an authentication error for failed user lookup\n */\n static userLookupFailed(cause?: Error): AuthenticationError {\n return new AuthenticationError(\n \"Failed to get current user from Databricks workspace\",\n { cause },\n );\n }\n}\n"],"mappings":";;;;;;YAAqC;CAYxB,sBAAb,MAAa,4BAA4B,YAAY;EACnD,AAAS,OAAO;EAChB,AAAS,aAAa;EACtB,AAAS,cAAc;;;;EAKvB,OAAO,aAAa,YAAY,gBAAqC;AACnE,UAAO,IAAI,oBAAoB,WAAW,UAAU,sBAAsB,EACxE,SAAS,EAAE,WAAW,EACvB,CAAC;;;;;EAMJ,OAAO,gBAAqC;AAC1C,UAAO,IAAI,oBACT,gGAED;;;;;EAMH,OAAO,kBACL,UACA,OACqB;AACrB,UAAO,IAAI,oBACT,gDAAgD,YAChD;IAAE;IAAO,SAAS,EAAE,UAAU;IAAE,CACjC;;;;;EAMH,OAAO,iBAAiB,OAAoC;AAC1D,UAAO,IAAI,oBACT,wDACA,EAAE,OAAO,CACV"}
1
+ {"version":3,"file":"authentication.js","names":[],"sources":["../../src/errors/authentication.ts"],"sourcesContent":["import { AppKitError } from \"./base\";\n\n/**\n * Error thrown when authentication fails.\n * Use for missing tokens, invalid credentials, or authorization failures.\n *\n * @example\n * ```typescript\n * throw new AuthenticationError(\"User token is required\");\n * throw new AuthenticationError(\"Failed to generate credentials\", { cause: originalError });\n * ```\n */\nexport class AuthenticationError extends AppKitError {\n readonly code = \"AUTHENTICATION_ERROR\";\n readonly statusCode = 401;\n readonly isRetryable = false;\n\n /**\n * Create an authentication error for missing token\n */\n static missingToken(tokenType = \"access token\"): AuthenticationError {\n return new AuthenticationError(`Missing ${tokenType} in request headers`, {\n context: { tokenType },\n });\n }\n\n /**\n * Create an authentication error for missing user identity\n */\n static missingUserId(): AuthenticationError {\n return new AuthenticationError(\n \"User ID not available in request headers. \" +\n \"Ensure the request has the x-forwarded-user header.\",\n );\n }\n\n /**\n * Create an authentication error for credential generation failure\n */\n static credentialsFailed(\n instance: string,\n cause?: Error,\n ): AuthenticationError {\n return new AuthenticationError(\n `Failed to generate credentials for instance: ${instance}`,\n { cause, context: { instance } },\n );\n }\n\n /**\n * Create an authentication error for failed user lookup\n */\n static userLookupFailed(cause?: Error): AuthenticationError {\n return new AuthenticationError(\n \"Failed to get current user from Databricks workspace\",\n { cause },\n );\n }\n}\n"],"mappings":";;;;;;;;;;;;;AAYA,IAAa,sBAAb,MAAa,4BAA4B,YAAY;CACnD,AAAS,OAAO;CAChB,AAAS,aAAa;CACtB,AAAS,cAAc;;;;CAKvB,OAAO,aAAa,YAAY,gBAAqC;AACnE,SAAO,IAAI,oBAAoB,WAAW,UAAU,sBAAsB,EACxE,SAAS,EAAE,WAAW,EACvB,CAAC;;;;;CAMJ,OAAO,gBAAqC;AAC1C,SAAO,IAAI,oBACT,gGAED;;;;;CAMH,OAAO,kBACL,UACA,OACqB;AACrB,SAAO,IAAI,oBACT,gDAAgD,YAChD;GAAE;GAAO,SAAS,EAAE,UAAU;GAAE,CACjC;;;;;CAMH,OAAO,iBAAiB,OAAoC;AAC1D,SAAO,IAAI,oBACT,wDACA,EAAE,OAAO,CACV"}
@@ -1,74 +1,90 @@
1
- import { __esmMin } from "../_virtual/_rolldown/runtime.js";
2
-
3
1
  //#region src/errors/base.ts
4
- var SENSITIVE_FIELD_PATTERNS, AppKitError;
5
- var init_base = __esmMin((() => {
6
- SENSITIVE_FIELD_PATTERNS = [
7
- /token/i,
8
- /password/i,
9
- /secret/i,
10
- /credential/i,
11
- /auth/i,
12
- /key$/i,
13
- /apikey/i
14
- ];
15
- AppKitError = class extends Error {
16
- /** Optional cause of the error */
17
- cause;
18
- /** Additional context for the error */
19
- context;
20
- constructor(message, options) {
21
- super(message);
22
- this.name = this.constructor.name;
23
- this.cause = options?.cause;
24
- this.context = options?.context;
25
- if (Error.captureStackTrace) Error.captureStackTrace(this, this.constructor);
26
- }
27
- /**
28
- * Convert error to JSON for logging/serialization.
29
- * Sensitive values in context are automatically redacted.
30
- */
31
- toJSON() {
32
- return {
33
- name: this.name,
34
- code: this.code,
35
- message: this.message,
36
- statusCode: this.statusCode,
37
- isRetryable: this.isRetryable,
38
- context: this.sanitizeContext(this.context),
39
- cause: this.cause?.message,
40
- stack: this.stack
41
- };
42
- }
43
- /**
44
- * Create a human-readable string representation
45
- */
46
- toString() {
47
- let str = `${this.name} [${this.code}]: ${this.message}`;
48
- if (this.cause) str += ` (caused by: ${this.cause.message})`;
49
- return str;
50
- }
51
- /**
52
- * Sanitize context by redacting sensitive field values
53
- */
54
- sanitizeContext(context) {
55
- if (!context) return void 0;
56
- const sanitized = {};
57
- for (const [key, value] of Object.entries(context)) if (this.isSensitiveField(key)) sanitized[key] = "[REDACTED]";
58
- else if (typeof value === "object" && value !== null) sanitized[key] = Array.isArray(value) ? `[Array(${value.length})]` : "[Object]";
59
- else sanitized[key] = value;
60
- return sanitized;
61
- }
62
- /**
63
- * Check if a field name matches sensitive patterns
64
- */
65
- isSensitiveField(fieldName) {
66
- return SENSITIVE_FIELD_PATTERNS.some((pattern) => pattern.test(fieldName));
67
- }
68
- };
69
- }));
2
+ /** Fields that should be redacted in logs/serialization for security */
3
+ const SENSITIVE_FIELD_PATTERNS = [
4
+ /token/i,
5
+ /password/i,
6
+ /secret/i,
7
+ /credential/i,
8
+ /auth/i,
9
+ /key$/i,
10
+ /apikey/i
11
+ ];
12
+ /**
13
+ * Base error class for all AppKit errors.
14
+ * Provides a consistent structure for error handling across the framework.
15
+ *
16
+ * @example
17
+ * ```typescript
18
+ * // Catching errors by type
19
+ * try {
20
+ * await lakebase.query("...");
21
+ * } catch (e) {
22
+ * if (e instanceof AuthenticationError) {
23
+ * // Re-authenticate
24
+ * } else if (e instanceof ConnectionError && e.isRetryable) {
25
+ * // Retry with backoff
26
+ * }
27
+ * }
28
+ *
29
+ * // Logging errors
30
+ * console.error(error.toJSON()); // Safe for logging, sensitive values redacted
31
+ * ```
32
+ */
33
+ var AppKitError = class extends Error {
34
+ /** Optional cause of the error */
35
+ cause;
36
+ /** Additional context for the error */
37
+ context;
38
+ constructor(message, options) {
39
+ super(message);
40
+ this.name = this.constructor.name;
41
+ this.cause = options?.cause;
42
+ this.context = options?.context;
43
+ if (Error.captureStackTrace) Error.captureStackTrace(this, this.constructor);
44
+ }
45
+ /**
46
+ * Convert error to JSON for logging/serialization.
47
+ * Sensitive values in context are automatically redacted.
48
+ */
49
+ toJSON() {
50
+ return {
51
+ name: this.name,
52
+ code: this.code,
53
+ message: this.message,
54
+ statusCode: this.statusCode,
55
+ isRetryable: this.isRetryable,
56
+ context: this.sanitizeContext(this.context),
57
+ cause: this.cause?.message,
58
+ stack: this.stack
59
+ };
60
+ }
61
+ /**
62
+ * Create a human-readable string representation
63
+ */
64
+ toString() {
65
+ let str = `${this.name} [${this.code}]: ${this.message}`;
66
+ if (this.cause) str += ` (caused by: ${this.cause.message})`;
67
+ return str;
68
+ }
69
+ /**
70
+ * Sanitize context by redacting sensitive field values
71
+ */
72
+ sanitizeContext(context) {
73
+ if (!context) return void 0;
74
+ const sanitized = {};
75
+ for (const [key, value] of Object.entries(context)) if (this.isSensitiveField(key)) sanitized[key] = "[REDACTED]";
76
+ else if (typeof value === "object" && value !== null) sanitized[key] = Array.isArray(value) ? `[Array(${value.length})]` : "[Object]";
77
+ else sanitized[key] = value;
78
+ return sanitized;
79
+ }
80
+ /**
81
+ * Check if a field name matches sensitive patterns
82
+ */
83
+ isSensitiveField(fieldName) {
84
+ return SENSITIVE_FIELD_PATTERNS.some((pattern) => pattern.test(fieldName));
85
+ }
86
+ };
70
87
 
71
88
  //#endregion
72
- init_base();
73
- export { AppKitError, init_base };
89
+ export { AppKitError };
74
90
  //# sourceMappingURL=base.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"base.js","names":[],"sources":["../../src/errors/base.ts"],"sourcesContent":["/** Fields that should be redacted in logs/serialization for security */\nconst SENSITIVE_FIELD_PATTERNS = [\n /token/i,\n /password/i,\n /secret/i,\n /credential/i,\n /auth/i,\n /key$/i,\n /apikey/i,\n];\n\n/**\n * Base error class for all AppKit errors.\n * Provides a consistent structure for error handling across the framework.\n *\n * @example\n * ```typescript\n * // Catching errors by type\n * try {\n * await lakebase.query(\"...\");\n * } catch (e) {\n * if (e instanceof AuthenticationError) {\n * // Re-authenticate\n * } else if (e instanceof ConnectionError && e.isRetryable) {\n * // Retry with backoff\n * }\n * }\n *\n * // Logging errors\n * console.error(error.toJSON()); // Safe for logging, sensitive values redacted\n * ```\n */\nexport abstract class AppKitError extends Error {\n /** Error code for programmatic error handling */\n abstract readonly code: string;\n\n /** HTTP status code suggestion (can be overridden) */\n abstract readonly statusCode: number;\n\n /** Whether this error type is generally safe to retry */\n abstract readonly isRetryable: boolean;\n\n /** Optional cause of the error */\n readonly cause?: Error;\n\n /** Additional context for the error */\n readonly context?: Record<string, unknown>;\n\n constructor(\n message: string,\n options?: { cause?: Error; context?: Record<string, unknown> },\n ) {\n super(message);\n this.name = this.constructor.name;\n this.cause = options?.cause;\n this.context = options?.context;\n\n // Maintains proper stack trace for where the error was thrown\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, this.constructor);\n }\n }\n\n /**\n * Convert error to JSON for logging/serialization.\n * Sensitive values in context are automatically redacted.\n */\n toJSON(): Record<string, unknown> {\n return {\n name: this.name,\n code: this.code,\n message: this.message,\n statusCode: this.statusCode,\n isRetryable: this.isRetryable,\n context: this.sanitizeContext(this.context),\n cause: this.cause?.message,\n stack: this.stack,\n };\n }\n\n /**\n * Create a human-readable string representation\n */\n toString(): string {\n let str = `${this.name} [${this.code}]: ${this.message}`;\n if (this.cause) {\n str += ` (caused by: ${this.cause.message})`;\n }\n return str;\n }\n\n /**\n * Sanitize context by redacting sensitive field values\n */\n private sanitizeContext(\n context?: Record<string, unknown>,\n ): Record<string, unknown> | undefined {\n if (!context) return undefined;\n\n const sanitized: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(context)) {\n if (this.isSensitiveField(key)) {\n sanitized[key] = \"[REDACTED]\";\n } else if (typeof value === \"object\" && value !== null) {\n // Don't deep-sanitize nested objects, just indicate their type\n sanitized[key] = Array.isArray(value)\n ? `[Array(${value.length})]`\n : \"[Object]\";\n } else {\n sanitized[key] = value;\n }\n }\n return sanitized;\n }\n\n /**\n * Check if a field name matches sensitive patterns\n */\n private isSensitiveField(fieldName: string): boolean {\n return SENSITIVE_FIELD_PATTERNS.some((pattern) => pattern.test(fieldName));\n }\n}\n"],"mappings":";;;;;CACM,2BAA2B;EAC/B;EACA;EACA;EACA;EACA;EACA;EACA;EACD;CAuBqB,cAAtB,cAA0C,MAAM;;EAW9C,AAAS;;EAGT,AAAS;EAET,YACE,SACA,SACA;AACA,SAAM,QAAQ;AACd,QAAK,OAAO,KAAK,YAAY;AAC7B,QAAK,QAAQ,SAAS;AACtB,QAAK,UAAU,SAAS;AAGxB,OAAI,MAAM,kBACR,OAAM,kBAAkB,MAAM,KAAK,YAAY;;;;;;EAQnD,SAAkC;AAChC,UAAO;IACL,MAAM,KAAK;IACX,MAAM,KAAK;IACX,SAAS,KAAK;IACd,YAAY,KAAK;IACjB,aAAa,KAAK;IAClB,SAAS,KAAK,gBAAgB,KAAK,QAAQ;IAC3C,OAAO,KAAK,OAAO;IACnB,OAAO,KAAK;IACb;;;;;EAMH,WAAmB;GACjB,IAAI,MAAM,GAAG,KAAK,KAAK,IAAI,KAAK,KAAK,KAAK,KAAK;AAC/C,OAAI,KAAK,MACP,QAAO,gBAAgB,KAAK,MAAM,QAAQ;AAE5C,UAAO;;;;;EAMT,AAAQ,gBACN,SACqC;AACrC,OAAI,CAAC,QAAS,QAAO;GAErB,MAAM,YAAqC,EAAE;AAC7C,QAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,QAAQ,CAChD,KAAI,KAAK,iBAAiB,IAAI,CAC5B,WAAU,OAAO;YACR,OAAO,UAAU,YAAY,UAAU,KAEhD,WAAU,OAAO,MAAM,QAAQ,MAAM,GACjC,UAAU,MAAM,OAAO,MACvB;OAEJ,WAAU,OAAO;AAGrB,UAAO;;;;;EAMT,AAAQ,iBAAiB,WAA4B;AACnD,UAAO,yBAAyB,MAAM,YAAY,QAAQ,KAAK,UAAU,CAAC"}
1
+ {"version":3,"file":"base.js","names":[],"sources":["../../src/errors/base.ts"],"sourcesContent":["/** Fields that should be redacted in logs/serialization for security */\nconst SENSITIVE_FIELD_PATTERNS = [\n /token/i,\n /password/i,\n /secret/i,\n /credential/i,\n /auth/i,\n /key$/i,\n /apikey/i,\n];\n\n/**\n * Base error class for all AppKit errors.\n * Provides a consistent structure for error handling across the framework.\n *\n * @example\n * ```typescript\n * // Catching errors by type\n * try {\n * await lakebase.query(\"...\");\n * } catch (e) {\n * if (e instanceof AuthenticationError) {\n * // Re-authenticate\n * } else if (e instanceof ConnectionError && e.isRetryable) {\n * // Retry with backoff\n * }\n * }\n *\n * // Logging errors\n * console.error(error.toJSON()); // Safe for logging, sensitive values redacted\n * ```\n */\nexport abstract class AppKitError extends Error {\n /** Error code for programmatic error handling */\n abstract readonly code: string;\n\n /** HTTP status code suggestion (can be overridden) */\n abstract readonly statusCode: number;\n\n /** Whether this error type is generally safe to retry */\n abstract readonly isRetryable: boolean;\n\n /** Optional cause of the error */\n readonly cause?: Error;\n\n /** Additional context for the error */\n readonly context?: Record<string, unknown>;\n\n constructor(\n message: string,\n options?: { cause?: Error; context?: Record<string, unknown> },\n ) {\n super(message);\n this.name = this.constructor.name;\n this.cause = options?.cause;\n this.context = options?.context;\n\n // Maintains proper stack trace for where the error was thrown\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, this.constructor);\n }\n }\n\n /**\n * Convert error to JSON for logging/serialization.\n * Sensitive values in context are automatically redacted.\n */\n toJSON(): Record<string, unknown> {\n return {\n name: this.name,\n code: this.code,\n message: this.message,\n statusCode: this.statusCode,\n isRetryable: this.isRetryable,\n context: this.sanitizeContext(this.context),\n cause: this.cause?.message,\n stack: this.stack,\n };\n }\n\n /**\n * Create a human-readable string representation\n */\n toString(): string {\n let str = `${this.name} [${this.code}]: ${this.message}`;\n if (this.cause) {\n str += ` (caused by: ${this.cause.message})`;\n }\n return str;\n }\n\n /**\n * Sanitize context by redacting sensitive field values\n */\n private sanitizeContext(\n context?: Record<string, unknown>,\n ): Record<string, unknown> | undefined {\n if (!context) return undefined;\n\n const sanitized: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(context)) {\n if (this.isSensitiveField(key)) {\n sanitized[key] = \"[REDACTED]\";\n } else if (typeof value === \"object\" && value !== null) {\n // Don't deep-sanitize nested objects, just indicate their type\n sanitized[key] = Array.isArray(value)\n ? `[Array(${value.length})]`\n : \"[Object]\";\n } else {\n sanitized[key] = value;\n }\n }\n return sanitized;\n }\n\n /**\n * Check if a field name matches sensitive patterns\n */\n private isSensitiveField(fieldName: string): boolean {\n return SENSITIVE_FIELD_PATTERNS.some((pattern) => pattern.test(fieldName));\n }\n}\n"],"mappings":";;AACA,MAAM,2BAA2B;CAC/B;CACA;CACA;CACA;CACA;CACA;CACA;CACD;;;;;;;;;;;;;;;;;;;;;;AAuBD,IAAsB,cAAtB,cAA0C,MAAM;;CAW9C,AAAS;;CAGT,AAAS;CAET,YACE,SACA,SACA;AACA,QAAM,QAAQ;AACd,OAAK,OAAO,KAAK,YAAY;AAC7B,OAAK,QAAQ,SAAS;AACtB,OAAK,UAAU,SAAS;AAGxB,MAAI,MAAM,kBACR,OAAM,kBAAkB,MAAM,KAAK,YAAY;;;;;;CAQnD,SAAkC;AAChC,SAAO;GACL,MAAM,KAAK;GACX,MAAM,KAAK;GACX,SAAS,KAAK;GACd,YAAY,KAAK;GACjB,aAAa,KAAK;GAClB,SAAS,KAAK,gBAAgB,KAAK,QAAQ;GAC3C,OAAO,KAAK,OAAO;GACnB,OAAO,KAAK;GACb;;;;;CAMH,WAAmB;EACjB,IAAI,MAAM,GAAG,KAAK,KAAK,IAAI,KAAK,KAAK,KAAK,KAAK;AAC/C,MAAI,KAAK,MACP,QAAO,gBAAgB,KAAK,MAAM,QAAQ;AAE5C,SAAO;;;;;CAMT,AAAQ,gBACN,SACqC;AACrC,MAAI,CAAC,QAAS,QAAO;EAErB,MAAM,YAAqC,EAAE;AAC7C,OAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,QAAQ,CAChD,KAAI,KAAK,iBAAiB,IAAI,CAC5B,WAAU,OAAO;WACR,OAAO,UAAU,YAAY,UAAU,KAEhD,WAAU,OAAO,MAAM,QAAQ,MAAM,GACjC,UAAU,MAAM,OAAO,MACvB;MAEJ,WAAU,OAAO;AAGrB,SAAO;;;;;CAMT,AAAQ,iBAAiB,WAA4B;AACnD,SAAO,yBAAyB,MAAM,YAAY,QAAQ,KAAK,UAAU,CAAC"}
@@ -1,5 +1,4 @@
1
- import { __esmMin } from "../_virtual/_rolldown/runtime.js";
2
- import { AppKitError, init_base } from "./base.js";
1
+ import { AppKitError } from "./base.js";
3
2
  import pc from "picocolors";
4
3
 
5
4
  //#region src/errors/configuration.ts
@@ -26,70 +25,75 @@ function pinUserFacingAuthError(err) {
26
25
  configurable: true
27
26
  });
28
27
  }
29
- var ConfigurationError;
30
- var init_configuration = __esmMin((() => {
31
- init_base();
32
- ConfigurationError = class ConfigurationError extends AppKitError {
33
- code = "CONFIGURATION_ERROR";
34
- statusCode = 500;
35
- isRetryable = false;
36
- /**
37
- * Create a configuration error for missing environment variable
38
- */
39
- static missingEnvVar(varName) {
40
- return new ConfigurationError(`${varName} environment variable is required`, { context: { envVar: varName } });
41
- }
42
- /**
43
- * Create a configuration error for missing resource
44
- */
45
- static resourceNotFound(resource, hint) {
46
- return new ConfigurationError(hint ? `${resource} not found. ${hint}` : `${resource} not found`, { context: { resource } });
47
- }
48
- /**
49
- * Create a configuration error for invalid connection config
50
- */
51
- static invalidConnection(service, details) {
52
- return new ConfigurationError(details ? `${service} connection not configured. ${details}` : `${service} connection not configured`, { context: { service } });
53
- }
54
- /**
55
- * Create a configuration error for missing connection string parameter
56
- */
57
- static missingConnectionParam(param) {
58
- return new ConfigurationError(`Connection string must include ${param} parameter`, { context: { parameter: param } });
59
- }
60
- /**
61
- * Databricks CLI / token auth failed while creating the workspace client.
62
- *
63
- * By default the message is short; key lines use **picocolors** when the
64
- * terminal supports it (also respects `NO_COLOR`). `console.error` won’t show
65
- * stacks or `{ code, context, … }`. Set `APPKIT_VERBOSE_AUTH_ERRORS=1` for full
66
- * `cause`, stack, and the raw SDK message (verbose appendix is unstyled).
67
- */
68
- static databricksAuthenticationSetupFailed(detail, options) {
69
- const verbose = authSetupVerbose();
70
- const host = process.env.DATABRICKS_HOST ?? "(not set)";
71
- const warehouseId = process.env.DATABRICKS_WAREHOUSE_ID;
72
- const d = detail.trim();
73
- const cli = suggestedDatabricksCliCommand(d);
74
- const lines = [
75
- pc.bold(pc.red("Databricks authentication failed.")),
76
- "",
77
- cli ? `${pc.bold("Run this, then try again:")}\n ${pc.cyan(cli)}` : pc.yellow("Log in with the Databricks CLI (for example, databricks auth login for this workspace), then try again."),
78
- "",
79
- pc.dim("Or set DATABRICKS_TOKEN and DATABRICKS_HOST instead of CLI-based auth."),
80
- "",
81
- `${pc.green("DATABRICKS_HOST")}: ${host}`
82
- ];
83
- if (warehouseId) lines.push(`${pc.green("DATABRICKS_WAREHOUSE_ID")}: ${warehouseId}`);
84
- if (verbose) lines.push("", d);
85
- const err = new ConfigurationError(lines.join("\n"), { cause: verbose ? options?.cause : void 0 });
86
- if (!verbose) pinUserFacingAuthError(err);
87
- return err;
88
- }
89
- };
90
- }));
28
+ /**
29
+ * Error thrown when configuration is missing or invalid.
30
+ * Use for missing environment variables, invalid settings, or setup issues.
31
+ *
32
+ * @example
33
+ * ```typescript
34
+ * throw new ConfigurationError("DATABRICKS_HOST environment variable is required");
35
+ * throw new ConfigurationError("Warehouse ID not found", { context: { env: "production" } });
36
+ * ```
37
+ */
38
+ var ConfigurationError = class ConfigurationError extends AppKitError {
39
+ code = "CONFIGURATION_ERROR";
40
+ statusCode = 500;
41
+ isRetryable = false;
42
+ /**
43
+ * Create a configuration error for missing environment variable
44
+ */
45
+ static missingEnvVar(varName) {
46
+ return new ConfigurationError(`${varName} environment variable is required`, { context: { envVar: varName } });
47
+ }
48
+ /**
49
+ * Create a configuration error for missing resource
50
+ */
51
+ static resourceNotFound(resource, hint) {
52
+ return new ConfigurationError(hint ? `${resource} not found. ${hint}` : `${resource} not found`, { context: { resource } });
53
+ }
54
+ /**
55
+ * Create a configuration error for invalid connection config
56
+ */
57
+ static invalidConnection(service, details) {
58
+ return new ConfigurationError(details ? `${service} connection not configured. ${details}` : `${service} connection not configured`, { context: { service } });
59
+ }
60
+ /**
61
+ * Create a configuration error for missing connection string parameter
62
+ */
63
+ static missingConnectionParam(param) {
64
+ return new ConfigurationError(`Connection string must include ${param} parameter`, { context: { parameter: param } });
65
+ }
66
+ /**
67
+ * Databricks CLI / token auth failed while creating the workspace client.
68
+ *
69
+ * By default the message is short; key lines use **picocolors** when the
70
+ * terminal supports it (also respects `NO_COLOR`). `console.error` won’t show
71
+ * stacks or `{ code, context, … }`. Set `APPKIT_VERBOSE_AUTH_ERRORS=1` for full
72
+ * `cause`, stack, and the raw SDK message (verbose appendix is unstyled).
73
+ */
74
+ static databricksAuthenticationSetupFailed(detail, options) {
75
+ const verbose = authSetupVerbose();
76
+ const host = process.env.DATABRICKS_HOST ?? "(not set)";
77
+ const warehouseId = process.env.DATABRICKS_WAREHOUSE_ID;
78
+ const d = detail.trim();
79
+ const cli = suggestedDatabricksCliCommand(d);
80
+ const lines = [
81
+ pc.bold(pc.red("Databricks authentication failed.")),
82
+ "",
83
+ cli ? `${pc.bold("Run this, then try again:")}\n ${pc.cyan(cli)}` : pc.yellow("Log in with the Databricks CLI (for example, databricks auth login for this workspace), then try again."),
84
+ "",
85
+ pc.dim("Or set DATABRICKS_TOKEN and DATABRICKS_HOST instead of CLI-based auth."),
86
+ "",
87
+ `${pc.green("DATABRICKS_HOST")}: ${host}`
88
+ ];
89
+ if (warehouseId) lines.push(`${pc.green("DATABRICKS_WAREHOUSE_ID")}: ${warehouseId}`);
90
+ if (verbose) lines.push("", d);
91
+ const err = new ConfigurationError(lines.join("\n"), { cause: verbose ? options?.cause : void 0 });
92
+ if (!verbose) pinUserFacingAuthError(err);
93
+ return err;
94
+ }
95
+ };
91
96
 
92
97
  //#endregion
93
- init_configuration();
94
- export { ConfigurationError, init_configuration };
98
+ export { ConfigurationError };
95
99
  //# sourceMappingURL=configuration.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"configuration.js","names":[],"sources":["../../src/errors/configuration.ts"],"sourcesContent":["import pc from \"picocolors\";\nimport { AppKitError } from \"./base\";\n\nfunction authSetupVerbose(): boolean {\n return (\n process.env.APPKIT_VERBOSE_AUTH_ERRORS === \"1\" ||\n process.env.APPKIT_VERBOSE_AUTH_ERRORS === \"true\"\n );\n}\n\n/** Pulls ` $ databricks ...` from SDK text when present. */\nfunction suggestedDatabricksCliCommand(detail: string): string | undefined {\n const m = detail.match(/\\$\\s*(databricks[^\\n]+)/);\n return m?.[1]?.trim();\n}\n\n/** Makes `console.error` show only the message (no stack, no extra fields). */\nfunction pinUserFacingAuthError(err: ConfigurationError): void {\n Object.defineProperty(err, \"stack\", {\n value: \"\",\n configurable: true,\n enumerable: false,\n writable: true,\n });\n Object.defineProperty(err, Symbol.for(\"nodejs.util.inspect.custom\"), {\n value: function (this: ConfigurationError): string {\n return this.message;\n },\n enumerable: false,\n configurable: true,\n });\n}\n\n/**\n * Error thrown when configuration is missing or invalid.\n * Use for missing environment variables, invalid settings, or setup issues.\n *\n * @example\n * ```typescript\n * throw new ConfigurationError(\"DATABRICKS_HOST environment variable is required\");\n * throw new ConfigurationError(\"Warehouse ID not found\", { context: { env: \"production\" } });\n * ```\n */\nexport class ConfigurationError extends AppKitError {\n readonly code = \"CONFIGURATION_ERROR\";\n readonly statusCode = 500;\n readonly isRetryable = false;\n\n /**\n * Create a configuration error for missing environment variable\n */\n static missingEnvVar(varName: string): ConfigurationError {\n return new ConfigurationError(\n `${varName} environment variable is required`,\n { context: { envVar: varName } },\n );\n }\n\n /**\n * Create a configuration error for missing resource\n */\n static resourceNotFound(resource: string, hint?: string): ConfigurationError {\n const message = hint\n ? `${resource} not found. ${hint}`\n : `${resource} not found`;\n return new ConfigurationError(message, { context: { resource } });\n }\n\n /**\n * Create a configuration error for invalid connection config\n */\n static invalidConnection(\n service: string,\n details?: string,\n ): ConfigurationError {\n const message = details\n ? `${service} connection not configured. ${details}`\n : `${service} connection not configured`;\n return new ConfigurationError(message, { context: { service } });\n }\n\n /**\n * Create a configuration error for missing connection string parameter\n */\n static missingConnectionParam(param: string): ConfigurationError {\n return new ConfigurationError(\n `Connection string must include ${param} parameter`,\n { context: { parameter: param } },\n );\n }\n\n /**\n * Databricks CLI / token auth failed while creating the workspace client.\n *\n * By default the message is short; key lines use **picocolors** when the\n * terminal supports it (also respects `NO_COLOR`). `console.error` won’t show\n * stacks or `{ code, context, … }`. Set `APPKIT_VERBOSE_AUTH_ERRORS=1` for full\n * `cause`, stack, and the raw SDK message (verbose appendix is unstyled).\n */\n static databricksAuthenticationSetupFailed(\n detail: string,\n options?: { cause?: Error },\n ): ConfigurationError {\n const verbose = authSetupVerbose();\n const host = process.env.DATABRICKS_HOST ?? \"(not set)\";\n const warehouseId = process.env.DATABRICKS_WAREHOUSE_ID;\n const d = detail.trim();\n const cli = suggestedDatabricksCliCommand(d);\n\n const title = pc.bold(pc.red(\"Databricks authentication failed.\"));\n const action = cli\n ? `${pc.bold(\"Run this, then try again:\")}\\n ${pc.cyan(cli)}`\n : pc.yellow(\n \"Log in with the Databricks CLI (for example, databricks auth login for this workspace), then try again.\",\n );\n const tokenHint = pc.dim(\n \"Or set DATABRICKS_TOKEN and DATABRICKS_HOST instead of CLI-based auth.\",\n );\n\n const lines: string[] = [\n title,\n \"\",\n action,\n \"\",\n tokenHint,\n \"\",\n `${pc.green(\"DATABRICKS_HOST\")}: ${host}`,\n ];\n if (warehouseId) {\n lines.push(`${pc.green(\"DATABRICKS_WAREHOUSE_ID\")}: ${warehouseId}`);\n }\n if (verbose) {\n lines.push(\"\", d);\n }\n\n const err = new ConfigurationError(lines.join(\"\\n\"), {\n cause: verbose ? options?.cause : undefined,\n });\n\n if (!verbose) {\n pinUserFacingAuthError(err);\n }\n return err;\n }\n}\n"],"mappings":";;;;;AAGA,SAAS,mBAA4B;AACnC,QACE,QAAQ,IAAI,+BAA+B,OAC3C,QAAQ,IAAI,+BAA+B;;;AAK/C,SAAS,8BAA8B,QAAoC;AAEzE,QADU,OAAO,MAAM,0BAA0B,GACtC,IAAI,MAAM;;;AAIvB,SAAS,uBAAuB,KAA+B;AAC7D,QAAO,eAAe,KAAK,SAAS;EAClC,OAAO;EACP,cAAc;EACd,YAAY;EACZ,UAAU;EACX,CAAC;AACF,QAAO,eAAe,KAAK,OAAO,IAAI,6BAA6B,EAAE;EACnE,OAAO,WAA4C;AACjD,UAAO,KAAK;;EAEd,YAAY;EACZ,cAAc;EACf,CAAC;;;;YA7BiC;CA0CxB,qBAAb,MAAa,2BAA2B,YAAY;EAClD,AAAS,OAAO;EAChB,AAAS,aAAa;EACtB,AAAS,cAAc;;;;EAKvB,OAAO,cAAc,SAAqC;AACxD,UAAO,IAAI,mBACT,GAAG,QAAQ,oCACX,EAAE,SAAS,EAAE,QAAQ,SAAS,EAAE,CACjC;;;;;EAMH,OAAO,iBAAiB,UAAkB,MAAmC;AAI3E,UAAO,IAAI,mBAHK,OACZ,GAAG,SAAS,cAAc,SAC1B,GAAG,SAAS,aACuB,EAAE,SAAS,EAAE,UAAU,EAAE,CAAC;;;;;EAMnE,OAAO,kBACL,SACA,SACoB;AAIpB,UAAO,IAAI,mBAHK,UACZ,GAAG,QAAQ,8BAA8B,YACzC,GAAG,QAAQ,6BACwB,EAAE,SAAS,EAAE,SAAS,EAAE,CAAC;;;;;EAMlE,OAAO,uBAAuB,OAAmC;AAC/D,UAAO,IAAI,mBACT,kCAAkC,MAAM,aACxC,EAAE,SAAS,EAAE,WAAW,OAAO,EAAE,CAClC;;;;;;;;;;EAWH,OAAO,oCACL,QACA,SACoB;GACpB,MAAM,UAAU,kBAAkB;GAClC,MAAM,OAAO,QAAQ,IAAI,mBAAmB;GAC5C,MAAM,cAAc,QAAQ,IAAI;GAChC,MAAM,IAAI,OAAO,MAAM;GACvB,MAAM,MAAM,8BAA8B,EAAE;GAY5C,MAAM,QAAkB;IAVV,GAAG,KAAK,GAAG,IAAI,oCAAoC,CAAC;IAYhE;IAXa,MACX,GAAG,GAAG,KAAK,4BAA4B,CAAC,MAAM,GAAG,KAAK,IAAI,KAC1D,GAAG,OACD,0GACD;IASH;IARgB,GAAG,IACnB,yEACD;IAQC;IACA,GAAG,GAAG,MAAM,kBAAkB,CAAC,IAAI;IACpC;AACD,OAAI,YACF,OAAM,KAAK,GAAG,GAAG,MAAM,0BAA0B,CAAC,IAAI,cAAc;AAEtE,OAAI,QACF,OAAM,KAAK,IAAI,EAAE;GAGnB,MAAM,MAAM,IAAI,mBAAmB,MAAM,KAAK,KAAK,EAAE,EACnD,OAAO,UAAU,SAAS,QAAQ,QACnC,CAAC;AAEF,OAAI,CAAC,QACH,wBAAuB,IAAI;AAE7B,UAAO"}
1
+ {"version":3,"file":"configuration.js","names":[],"sources":["../../src/errors/configuration.ts"],"sourcesContent":["import pc from \"picocolors\";\nimport { AppKitError } from \"./base\";\n\nfunction authSetupVerbose(): boolean {\n return (\n process.env.APPKIT_VERBOSE_AUTH_ERRORS === \"1\" ||\n process.env.APPKIT_VERBOSE_AUTH_ERRORS === \"true\"\n );\n}\n\n/** Pulls ` $ databricks ...` from SDK text when present. */\nfunction suggestedDatabricksCliCommand(detail: string): string | undefined {\n const m = detail.match(/\\$\\s*(databricks[^\\n]+)/);\n return m?.[1]?.trim();\n}\n\n/** Makes `console.error` show only the message (no stack, no extra fields). */\nfunction pinUserFacingAuthError(err: ConfigurationError): void {\n Object.defineProperty(err, \"stack\", {\n value: \"\",\n configurable: true,\n enumerable: false,\n writable: true,\n });\n Object.defineProperty(err, Symbol.for(\"nodejs.util.inspect.custom\"), {\n value: function (this: ConfigurationError): string {\n return this.message;\n },\n enumerable: false,\n configurable: true,\n });\n}\n\n/**\n * Error thrown when configuration is missing or invalid.\n * Use for missing environment variables, invalid settings, or setup issues.\n *\n * @example\n * ```typescript\n * throw new ConfigurationError(\"DATABRICKS_HOST environment variable is required\");\n * throw new ConfigurationError(\"Warehouse ID not found\", { context: { env: \"production\" } });\n * ```\n */\nexport class ConfigurationError extends AppKitError {\n readonly code = \"CONFIGURATION_ERROR\";\n readonly statusCode = 500;\n readonly isRetryable = false;\n\n /**\n * Create a configuration error for missing environment variable\n */\n static missingEnvVar(varName: string): ConfigurationError {\n return new ConfigurationError(\n `${varName} environment variable is required`,\n { context: { envVar: varName } },\n );\n }\n\n /**\n * Create a configuration error for missing resource\n */\n static resourceNotFound(resource: string, hint?: string): ConfigurationError {\n const message = hint\n ? `${resource} not found. ${hint}`\n : `${resource} not found`;\n return new ConfigurationError(message, { context: { resource } });\n }\n\n /**\n * Create a configuration error for invalid connection config\n */\n static invalidConnection(\n service: string,\n details?: string,\n ): ConfigurationError {\n const message = details\n ? `${service} connection not configured. ${details}`\n : `${service} connection not configured`;\n return new ConfigurationError(message, { context: { service } });\n }\n\n /**\n * Create a configuration error for missing connection string parameter\n */\n static missingConnectionParam(param: string): ConfigurationError {\n return new ConfigurationError(\n `Connection string must include ${param} parameter`,\n { context: { parameter: param } },\n );\n }\n\n /**\n * Databricks CLI / token auth failed while creating the workspace client.\n *\n * By default the message is short; key lines use **picocolors** when the\n * terminal supports it (also respects `NO_COLOR`). `console.error` won’t show\n * stacks or `{ code, context, … }`. Set `APPKIT_VERBOSE_AUTH_ERRORS=1` for full\n * `cause`, stack, and the raw SDK message (verbose appendix is unstyled).\n */\n static databricksAuthenticationSetupFailed(\n detail: string,\n options?: { cause?: Error },\n ): ConfigurationError {\n const verbose = authSetupVerbose();\n const host = process.env.DATABRICKS_HOST ?? \"(not set)\";\n const warehouseId = process.env.DATABRICKS_WAREHOUSE_ID;\n const d = detail.trim();\n const cli = suggestedDatabricksCliCommand(d);\n\n const title = pc.bold(pc.red(\"Databricks authentication failed.\"));\n const action = cli\n ? `${pc.bold(\"Run this, then try again:\")}\\n ${pc.cyan(cli)}`\n : pc.yellow(\n \"Log in with the Databricks CLI (for example, databricks auth login for this workspace), then try again.\",\n );\n const tokenHint = pc.dim(\n \"Or set DATABRICKS_TOKEN and DATABRICKS_HOST instead of CLI-based auth.\",\n );\n\n const lines: string[] = [\n title,\n \"\",\n action,\n \"\",\n tokenHint,\n \"\",\n `${pc.green(\"DATABRICKS_HOST\")}: ${host}`,\n ];\n if (warehouseId) {\n lines.push(`${pc.green(\"DATABRICKS_WAREHOUSE_ID\")}: ${warehouseId}`);\n }\n if (verbose) {\n lines.push(\"\", d);\n }\n\n const err = new ConfigurationError(lines.join(\"\\n\"), {\n cause: verbose ? options?.cause : undefined,\n });\n\n if (!verbose) {\n pinUserFacingAuthError(err);\n }\n return err;\n }\n}\n"],"mappings":";;;;AAGA,SAAS,mBAA4B;AACnC,QACE,QAAQ,IAAI,+BAA+B,OAC3C,QAAQ,IAAI,+BAA+B;;;AAK/C,SAAS,8BAA8B,QAAoC;AAEzE,QADU,OAAO,MAAM,0BAA0B,GACtC,IAAI,MAAM;;;AAIvB,SAAS,uBAAuB,KAA+B;AAC7D,QAAO,eAAe,KAAK,SAAS;EAClC,OAAO;EACP,cAAc;EACd,YAAY;EACZ,UAAU;EACX,CAAC;AACF,QAAO,eAAe,KAAK,OAAO,IAAI,6BAA6B,EAAE;EACnE,OAAO,WAA4C;AACjD,UAAO,KAAK;;EAEd,YAAY;EACZ,cAAc;EACf,CAAC;;;;;;;;;;;;AAaJ,IAAa,qBAAb,MAAa,2BAA2B,YAAY;CAClD,AAAS,OAAO;CAChB,AAAS,aAAa;CACtB,AAAS,cAAc;;;;CAKvB,OAAO,cAAc,SAAqC;AACxD,SAAO,IAAI,mBACT,GAAG,QAAQ,oCACX,EAAE,SAAS,EAAE,QAAQ,SAAS,EAAE,CACjC;;;;;CAMH,OAAO,iBAAiB,UAAkB,MAAmC;AAI3E,SAAO,IAAI,mBAHK,OACZ,GAAG,SAAS,cAAc,SAC1B,GAAG,SAAS,aACuB,EAAE,SAAS,EAAE,UAAU,EAAE,CAAC;;;;;CAMnE,OAAO,kBACL,SACA,SACoB;AAIpB,SAAO,IAAI,mBAHK,UACZ,GAAG,QAAQ,8BAA8B,YACzC,GAAG,QAAQ,6BACwB,EAAE,SAAS,EAAE,SAAS,EAAE,CAAC;;;;;CAMlE,OAAO,uBAAuB,OAAmC;AAC/D,SAAO,IAAI,mBACT,kCAAkC,MAAM,aACxC,EAAE,SAAS,EAAE,WAAW,OAAO,EAAE,CAClC;;;;;;;;;;CAWH,OAAO,oCACL,QACA,SACoB;EACpB,MAAM,UAAU,kBAAkB;EAClC,MAAM,OAAO,QAAQ,IAAI,mBAAmB;EAC5C,MAAM,cAAc,QAAQ,IAAI;EAChC,MAAM,IAAI,OAAO,MAAM;EACvB,MAAM,MAAM,8BAA8B,EAAE;EAY5C,MAAM,QAAkB;GAVV,GAAG,KAAK,GAAG,IAAI,oCAAoC,CAAC;GAYhE;GAXa,MACX,GAAG,GAAG,KAAK,4BAA4B,CAAC,MAAM,GAAG,KAAK,IAAI,KAC1D,GAAG,OACD,0GACD;GASH;GARgB,GAAG,IACnB,yEACD;GAQC;GACA,GAAG,GAAG,MAAM,kBAAkB,CAAC,IAAI;GACpC;AACD,MAAI,YACF,OAAM,KAAK,GAAG,GAAG,MAAM,0BAA0B,CAAC,IAAI,cAAc;AAEtE,MAAI,QACF,OAAM,KAAK,IAAI,EAAE;EAGnB,MAAM,MAAM,IAAI,mBAAmB,MAAM,KAAK,KAAK,EAAE,EACnD,OAAO,UAAU,SAAS,QAAQ,QACnC,CAAC;AAEF,MAAI,CAAC,QACH,wBAAuB,IAAI;AAE7B,SAAO"}