@databricks/appkit 0.36.0 → 0.38.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CLAUDE.md +3 -2
- package/NOTICE.md +1 -0
- package/dist/appkit/package.js +1 -1
- package/dist/cache/index.js +1 -2
- package/dist/cache/index.js.map +1 -1
- package/dist/cache/storage/persistent.js +1 -2
- package/dist/cache/storage/persistent.js.map +1 -1
- package/dist/cli/commands/plugin/add-resource/add-resource.js.map +1 -1
- package/dist/cli/commands/plugin/create/resource-defaults.js +2 -1
- package/dist/cli/commands/plugin/create/resource-defaults.js.map +1 -1
- package/dist/cli/commands/plugin/schema-resources.js +34 -51
- package/dist/cli/commands/plugin/schema-resources.js.map +1 -1
- package/dist/cli/commands/plugin/sync/sync.js +20 -6
- package/dist/cli/commands/plugin/sync/sync.js.map +1 -1
- package/dist/cli/commands/plugin/validate/validate-manifest.js +71 -157
- package/dist/cli/commands/plugin/validate/validate-manifest.js.map +1 -1
- package/dist/cli/commands/plugin/validate/validate.js +2 -2
- package/dist/cli/commands/plugin/validate/validate.js.map +1 -1
- package/dist/cli/commands/setup.js +2 -2
- package/dist/cli/commands/setup.js.map +1 -1
- package/dist/connectors/index.js +0 -1
- package/dist/connectors/jobs/client.js +1 -2
- package/dist/connectors/jobs/client.js.map +1 -1
- package/dist/connectors/lakebase/routing-pool.js +1 -2
- package/dist/connectors/lakebase/routing-pool.js.map +1 -1
- package/dist/connectors/sql-warehouse/client.js +1 -2
- package/dist/connectors/sql-warehouse/client.js.map +1 -1
- package/dist/context/execution-context.js +9 -13
- package/dist/context/execution-context.js.map +1 -1
- package/dist/context/index.js +3 -13
- package/dist/context/service-context.js +137 -136
- package/dist/context/service-context.js.map +1 -1
- package/dist/context/user-context.js +1 -5
- package/dist/context/user-context.js.map +1 -1
- package/dist/core/agent/create-agent.js +1 -2
- package/dist/core/agent/create-agent.js.map +1 -1
- package/dist/core/appkit.d.ts.map +1 -1
- package/dist/core/appkit.js +9 -37
- package/dist/core/appkit.js.map +1 -1
- package/dist/errors/authentication.js +44 -40
- package/dist/errors/authentication.js.map +1 -1
- package/dist/errors/base.js +86 -70
- package/dist/errors/base.js.map +1 -1
- package/dist/errors/configuration.js +70 -66
- package/dist/errors/configuration.js.map +1 -1
- package/dist/errors/connection.js +50 -46
- package/dist/errors/connection.js.map +1 -1
- package/dist/errors/execution.js +47 -43
- package/dist/errors/execution.js.map +1 -1
- package/dist/errors/index.js +10 -27
- package/dist/errors/initialization.js +38 -34
- package/dist/errors/initialization.js.map +1 -1
- package/dist/errors/server.js +34 -31
- package/dist/errors/server.js.map +1 -1
- package/dist/errors/tunnel.js +47 -43
- package/dist/errors/tunnel.js.map +1 -1
- package/dist/errors/validation.js +41 -37
- package/dist/errors/validation.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +3 -9
- package/dist/plugin/dev-reader.js +1 -2
- package/dist/plugin/dev-reader.js.map +1 -1
- package/dist/plugin/interceptors/retry.js +1 -2
- package/dist/plugin/interceptors/retry.js.map +1 -1
- package/dist/plugin/interceptors/telemetry.js +1 -2
- package/dist/plugin/interceptors/telemetry.js.map +1 -1
- package/dist/plugin/plugin.d.ts +12 -4
- package/dist/plugin/plugin.d.ts.map +1 -1
- package/dist/plugin/plugin.js +59 -28
- package/dist/plugin/plugin.js.map +1 -1
- package/dist/plugins/agents/agents.d.ts +56 -3
- package/dist/plugins/agents/agents.d.ts.map +1 -1
- package/dist/plugins/agents/agents.js +160 -8
- package/dist/plugins/agents/agents.js.map +1 -1
- package/dist/plugins/agents/schemas.js +0 -1
- package/dist/plugins/agents/schemas.js.map +1 -1
- package/dist/plugins/analytics/analytics.js +1 -2
- package/dist/plugins/analytics/analytics.js.map +1 -1
- package/dist/plugins/analytics/manifest.js +9 -1
- package/dist/plugins/analytics/query.js +2 -4
- package/dist/plugins/analytics/query.js.map +1 -1
- package/dist/plugins/files/manifest.js +7 -1
- package/dist/plugins/files/plugin.js +3 -6
- package/dist/plugins/files/plugin.js.map +1 -1
- package/dist/plugins/genie/genie.js +1 -2
- package/dist/plugins/genie/genie.js.map +1 -1
- package/dist/plugins/genie/manifest.js +7 -1
- package/dist/plugins/jobs/plugin.js +2 -4
- package/dist/plugins/jobs/plugin.js.map +1 -1
- package/dist/plugins/lakebase/lakebase.js +1 -2
- package/dist/plugins/lakebase/lakebase.js.map +1 -1
- package/dist/plugins/lakebase/manifest.js +26 -4
- package/dist/plugins/server/index.js +1 -2
- package/dist/plugins/server/index.js.map +1 -1
- package/dist/plugins/server/vite-dev-server.js +1 -2
- package/dist/plugins/server/vite-dev-server.js.map +1 -1
- package/dist/plugins/serving/serving.js +1 -2
- package/dist/plugins/serving/serving.js.map +1 -1
- package/dist/registry/index.d.ts +1 -1
- package/dist/registry/manifest-loader.d.ts +4 -4
- package/dist/registry/manifest-loader.d.ts.map +1 -1
- package/dist/registry/manifest-loader.js +1 -2
- package/dist/registry/manifest-loader.js.map +1 -1
- package/dist/registry/resource-registry.js +1 -2
- package/dist/registry/resource-registry.js.map +1 -1
- package/dist/registry/types.d.ts +21 -7
- package/dist/registry/types.d.ts.map +1 -1
- package/dist/registry/types.generated.d.ts +1 -1
- package/dist/registry/types.generated.js +1 -1
- package/dist/registry/types.generated.js.map +1 -1
- package/dist/registry/types.js +3 -3
- package/dist/registry/types.js.map +1 -1
- package/dist/schemas/manifest.d.ts +1139 -0
- package/dist/schemas/manifest.d.ts.map +1 -0
- package/dist/schemas/manifest.js +524 -0
- package/dist/schemas/manifest.js.map +1 -0
- package/dist/shared/src/index.d.ts +1 -1
- package/dist/shared/src/plugin.d.ts +38 -7
- package/dist/shared/src/plugin.d.ts.map +1 -1
- package/dist/shared/src/schemas/manifest.d.ts +1110 -0
- package/dist/shared/src/schemas/manifest.d.ts.map +1 -0
- package/dist/stream/arrow-stream-processor.js +1 -2
- package/dist/stream/arrow-stream-processor.js.map +1 -1
- package/dist/stream/buffers.js +1 -2
- package/dist/stream/buffers.js.map +1 -1
- package/docs/api/appkit/Enumeration.ResourceType.md +1 -1
- package/docs/api/appkit/Interface.PluginManifest.md +57 -3
- package/docs/api/appkit/Interface.ResourceEntry.md +6 -4
- package/docs/api/appkit/Interface.ResourceRequirement.md +7 -61
- package/docs/api/appkit/TypeAlias.ResourceFieldEntry.md +6 -0
- package/docs/api/appkit/Variable.agents.md +1 -1
- package/docs/api/appkit.md +12 -12
- package/docs/app-management.md +1 -1
- package/docs/development/ai-assisted-development.md +2 -2
- package/docs/development/local-development.md +1 -1
- package/docs/development/remote-bridge.md +1 -1
- package/docs/development/templates.md +118 -12
- package/docs/development.md +1 -1
- package/docs/plugins/agents.md +8 -4
- package/docs/plugins/custom-plugins.md +33 -23
- package/docs/plugins/lakebase.md +1 -1
- package/docs/plugins/manifest.md +293 -0
- package/docs.md +2 -2
- package/llms.txt +3 -2
- package/package.json +3 -3
- package/sbom.cdx.json +1 -1
- package/dist/_virtual/_rolldown/runtime.js +0 -7
- package/dist/connectors/lakebase-v1/client.js +0 -15
- package/dist/connectors/lakebase-v1/client.js.map +0 -1
- package/dist/connectors/lakebase-v1/index.js +0 -3
- package/dist/context/index.js.map +0 -1
- package/dist/errors/index.js.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/schemas/plugin-manifest.generated.d.ts +0 -182
- package/dist/schemas/plugin-manifest.generated.d.ts.map +0 -1
- package/dist/schemas/plugin-manifest.schema.json +0 -489
- package/dist/schemas/template-plugins.schema.json +0 -113
- package/dist/shared/src/schemas/plugin-manifest.generated.d.ts +0 -182
- package/dist/shared/src/schemas/plugin-manifest.generated.d.ts.map +0 -1
- package/docs/api/appkit/Interface.ResourceFieldEntry.md +0 -82
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"setup.js","names":[],"sources":["../../../src/cli/commands/setup.ts"],"sourcesContent":["import fs from \"node:fs\";\nimport path from \"node:path\";\nimport { Command } from \"commander\";\n\nconst PACKAGES = [\n { name: \"@databricks/appkit\", description: \"Backend SDK\" },\n {\n name: \"@databricks/appkit-ui\",\n description: \"UI Integration, Charts, Tables, SSE, and more.\",\n },\n];\n\nconst SECTION_START = \"<!-- appkit-instructions-start -->\";\nconst SECTION_END = \"<!-- appkit-instructions-end -->\";\n\n/**\n * Find which AppKit packages are installed by checking for package.json\n */\nfunction findInstalledPackages() {\n const cwd = process.cwd();\n const installed = [];\n\n for (const pkg of PACKAGES) {\n const packagePath = path.join(\n cwd,\n \"node_modules\",\n pkg.name,\n \"package.json\",\n );\n if (fs.existsSync(packagePath)) {\n installed.push(pkg);\n }\n }\n\n return installed;\n}\n\n/**\n * Generate the AppKit section content\n */\nfunction generateSection(packages: typeof PACKAGES) {\n const links = packages\n .map((pkg) => {\n const docPath = `./node_modules/${pkg.name}/CLAUDE.md`;\n return `- **${pkg.name}** (${pkg.description}): [${docPath}](${docPath})`;\n })\n .join(\"\\n\");\n\n return `${SECTION_START}\n## Databricks AppKit\n\nThis project uses Databricks AppKit packages. For AI assistant guidance on using these packages, refer to:\n\n${links}\n\n### Databricks Skills\n\nFor enhanced AI assistance with Databricks CLI operations, authentication, data exploration, and app development, install the Databricks skills:\n\n\\`\\`\\`bash\ndatabricks
|
|
1
|
+
{"version":3,"file":"setup.js","names":[],"sources":["../../../src/cli/commands/setup.ts"],"sourcesContent":["import fs from \"node:fs\";\nimport path from \"node:path\";\nimport { Command } from \"commander\";\n\nconst PACKAGES = [\n { name: \"@databricks/appkit\", description: \"Backend SDK\" },\n {\n name: \"@databricks/appkit-ui\",\n description: \"UI Integration, Charts, Tables, SSE, and more.\",\n },\n];\n\nconst SECTION_START = \"<!-- appkit-instructions-start -->\";\nconst SECTION_END = \"<!-- appkit-instructions-end -->\";\n\n/**\n * Find which AppKit packages are installed by checking for package.json\n */\nfunction findInstalledPackages() {\n const cwd = process.cwd();\n const installed = [];\n\n for (const pkg of PACKAGES) {\n const packagePath = path.join(\n cwd,\n \"node_modules\",\n pkg.name,\n \"package.json\",\n );\n if (fs.existsSync(packagePath)) {\n installed.push(pkg);\n }\n }\n\n return installed;\n}\n\n/**\n * Generate the AppKit section content\n */\nfunction generateSection(packages: typeof PACKAGES) {\n const links = packages\n .map((pkg) => {\n const docPath = `./node_modules/${pkg.name}/CLAUDE.md`;\n return `- **${pkg.name}** (${pkg.description}): [${docPath}](${docPath})`;\n })\n .join(\"\\n\");\n\n return `${SECTION_START}\n## Databricks AppKit\n\nThis project uses Databricks AppKit packages. For AI assistant guidance on using these packages, refer to:\n\n${links}\n\n### Databricks Skills\n\nFor enhanced AI assistance with Databricks CLI operations, authentication, data exploration, and app development, install the Databricks skills:\n\n\\`\\`\\`bash\ndatabricks aitools install\n\\`\\`\\`\n${SECTION_END}`;\n}\n\n/**\n * Generate standalone CLAUDE.md content (when no existing file)\n */\nfunction generateStandalone(packages: typeof PACKAGES) {\n const links = packages\n .map((pkg) => {\n const docPath = `./node_modules/${pkg.name}/CLAUDE.md`;\n return `- **${pkg.name}** (${pkg.description}): [${docPath}](${docPath})`;\n })\n .join(\"\\n\");\n\n return `# AI Assistant Instructions\n\n${SECTION_START}\n## Databricks AppKit\n\nThis project uses Databricks AppKit packages. For AI assistant guidance on using these packages, refer to:\n\n${links}\n\n### Databricks Skills\n\nFor enhanced AI assistance with Databricks CLI operations, authentication, data exploration, and app development, install the Databricks skills:\n\n\\`\\`\\`bash\ndatabricks aitools install\n\\`\\`\\`\n${SECTION_END}\n`;\n}\n\n/**\n * Update existing content with AppKit section\n */\nfunction updateContent(existingContent: string, packages: typeof PACKAGES) {\n const newSection = generateSection(packages);\n\n // Check if AppKit section already exists\n const startIndex = existingContent.indexOf(SECTION_START);\n const endIndex = existingContent.indexOf(SECTION_END);\n\n if (startIndex !== -1 && endIndex !== -1) {\n // Replace existing section\n const before = existingContent.substring(0, startIndex);\n const after = existingContent.substring(endIndex + SECTION_END.length);\n return before + newSection + after;\n }\n\n // Append section to end\n return `${existingContent.trimEnd()}\\n\\n${newSection}\\n`;\n}\n\n/**\n * Setup command implementation\n */\nfunction runSetup(options: { write?: boolean }) {\n const shouldWrite = options.write;\n\n // Find installed packages\n const installed = findInstalledPackages();\n\n if (installed.length === 0) {\n console.log(\"No @databricks/appkit packages found in node_modules.\");\n console.log(\"\\nInstall at least one of:\");\n for (const pkg of PACKAGES) {\n console.log(` npm install ${pkg.name}`);\n }\n process.exit(1);\n }\n\n console.log(\"Detected packages:\");\n installed.forEach((pkg) => {\n console.log(` ✓ ${pkg.name}`);\n });\n\n const claudePath = path.join(process.cwd(), \"CLAUDE.md\");\n const existingContent = fs.existsSync(claudePath)\n ? fs.readFileSync(claudePath, \"utf-8\")\n : null;\n\n let finalContent: string;\n let action: string;\n\n if (existingContent) {\n finalContent = updateContent(existingContent, installed);\n action = existingContent.includes(SECTION_START) ? \"Updated\" : \"Added to\";\n } else {\n finalContent = generateStandalone(installed);\n action = \"Created\";\n }\n\n if (shouldWrite) {\n fs.writeFileSync(claudePath, finalContent);\n console.log(`\\n✓ ${action} CLAUDE.md`);\n console.log(` Path: ${claudePath}`);\n } else {\n console.log(\"\\nTo create/update CLAUDE.md, run:\");\n console.log(\" npx appkit setup --write\\n\");\n\n if (existingContent) {\n console.log(\n `This will ${\n existingContent.includes(SECTION_START)\n ? \"update the existing\"\n : \"add a new\"\n } AppKit section.\\n`,\n );\n }\n\n console.log(\"Preview of AppKit section:\\n\");\n console.log(\"─\".repeat(50));\n console.log(generateSection(installed));\n console.log(\"─\".repeat(50));\n }\n}\n\nexport const setupCommand = new Command(\"setup\")\n .description(\"Setup CLAUDE.md with AppKit package references\")\n .option(\"-w, --write\", \"Create or update CLAUDE.md file in current directory\")\n .addHelpText(\n \"after\",\n `\nExamples:\n $ appkit setup\n $ appkit setup --write`,\n )\n .action(runSetup);\n"],"mappings":"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"}
|
package/dist/connectors/index.js
CHANGED
|
@@ -8,7 +8,6 @@ import { GenieConnector } from "./genie/client.js";
|
|
|
8
8
|
import "./genie/index.js";
|
|
9
9
|
import { JobsConnector } from "./jobs/client.js";
|
|
10
10
|
import "./jobs/index.js";
|
|
11
|
-
import "./lakebase-v1/index.js";
|
|
12
11
|
import { buildMcpHostPolicy } from "./mcp/host-policy.js";
|
|
13
12
|
import { AppKitMcpClient } from "./mcp/client.js";
|
|
14
13
|
import "./mcp/index.js";
|
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
import { createLogger } from "../../logging/logger.js";
|
|
2
2
|
import { AppKitError } from "../../errors/base.js";
|
|
3
3
|
import { ExecutionError } from "../../errors/execution.js";
|
|
4
|
-
import
|
|
4
|
+
import "../../errors/index.js";
|
|
5
5
|
import { TelemetryManager } from "../../telemetry/telemetry-manager.js";
|
|
6
6
|
import { SpanKind, SpanStatusCode } from "../../telemetry/index.js";
|
|
7
7
|
import { Context } from "@databricks/sdk-experimental";
|
|
8
8
|
|
|
9
9
|
//#region src/connectors/jobs/client.ts
|
|
10
|
-
init_errors();
|
|
11
10
|
const logger = createLogger("connectors:jobs");
|
|
12
11
|
var JobsConnector = class {
|
|
13
12
|
name = "jobs";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.js","names":[],"sources":["../../../src/connectors/jobs/client.ts"],"sourcesContent":["import {\n Context,\n type jobs,\n type WorkspaceClient,\n} from \"@databricks/sdk-experimental\";\nimport { AppKitError, ExecutionError } from \"../../errors\";\nimport { createLogger } from \"../../logging/logger\";\nimport type { TelemetryProvider } from \"../../telemetry\";\nimport {\n type Counter,\n type Histogram,\n type Span,\n SpanKind,\n SpanStatusCode,\n TelemetryManager,\n} from \"../../telemetry\";\nimport type { JobsConnectorConfig } from \"./types\";\n\nconst logger = createLogger(\"connectors:jobs\");\n\nexport class JobsConnector {\n private readonly name = \"jobs\";\n private readonly config: JobsConnectorConfig;\n private readonly telemetry: TelemetryProvider;\n private readonly telemetryMetrics: {\n apiCallCount: Counter;\n apiCallDuration: Histogram;\n };\n\n constructor(config: JobsConnectorConfig) {\n this.config = config;\n this.telemetry = TelemetryManager.getProvider(\n this.name,\n this.config.telemetry,\n );\n this.telemetryMetrics = {\n apiCallCount: this.telemetry\n .getMeter()\n .createCounter(\"jobs.api_call.count\", {\n description: \"Total number of Jobs API calls\",\n unit: \"1\",\n }),\n apiCallDuration: this.telemetry\n .getMeter()\n .createHistogram(\"jobs.api_call.duration\", {\n description: \"Duration of Jobs API calls\",\n unit: \"ms\",\n }),\n };\n }\n\n async submitRun(\n workspaceClient: WorkspaceClient,\n request: jobs.SubmitRun,\n signal?: AbortSignal,\n ): Promise<jobs.SubmitRunResponse> {\n return this._callApi(\"submit\", async () => {\n return workspaceClient.jobs.submit(request, this._createContext(signal));\n });\n }\n\n async runNow(\n workspaceClient: WorkspaceClient,\n request: jobs.RunNow,\n signal?: AbortSignal,\n ): Promise<jobs.RunNowResponse> {\n return this._callApi(\"runNow\", async () => {\n return workspaceClient.jobs.runNow(request, this._createContext(signal));\n });\n }\n\n async getRun(\n workspaceClient: WorkspaceClient,\n request: jobs.GetRunRequest,\n signal?: AbortSignal,\n ): Promise<jobs.Run> {\n return this._callApi(\"getRun\", async () => {\n return workspaceClient.jobs.getRun(request, this._createContext(signal));\n });\n }\n\n async getRunOutput(\n workspaceClient: WorkspaceClient,\n request: jobs.GetRunOutputRequest,\n signal?: AbortSignal,\n ): Promise<jobs.RunOutput> {\n return this._callApi(\"getRunOutput\", async () => {\n return workspaceClient.jobs.getRunOutput(\n request,\n this._createContext(signal),\n );\n });\n }\n\n async cancelRun(\n workspaceClient: WorkspaceClient,\n request: jobs.CancelRun,\n signal?: AbortSignal,\n ): Promise<void> {\n await this._callApi(\"cancelRun\", async () => {\n return workspaceClient.jobs.cancelRun(\n request,\n this._createContext(signal),\n );\n });\n }\n\n async listRuns(\n workspaceClient: WorkspaceClient,\n request: jobs.ListRunsRequest,\n signal?: AbortSignal,\n ): Promise<jobs.BaseRun[]> {\n return this._callApi(\"listRuns\", async () => {\n const runs: jobs.BaseRun[] = [];\n const limit = Math.max(1, Math.min(request.limit ?? 100, 100));\n for await (const run of workspaceClient.jobs.listRuns(\n { ...request, limit },\n this._createContext(signal),\n )) {\n runs.push(run);\n if (runs.length >= limit) break;\n }\n return runs;\n });\n }\n\n async getJob(\n workspaceClient: WorkspaceClient,\n request: jobs.GetJobRequest,\n signal?: AbortSignal,\n ): Promise<jobs.Job> {\n return this._callApi(\"getJob\", async () => {\n return workspaceClient.jobs.get(request, this._createContext(signal));\n });\n }\n\n private async _callApi<T>(\n operation: string,\n fn: () => Promise<T>,\n ): Promise<T> {\n const startTime = Date.now();\n let success = false;\n\n return this.telemetry.startActiveSpan(\n `jobs.${operation}`,\n {\n kind: SpanKind.CLIENT,\n attributes: {\n \"jobs.operation\": operation,\n },\n },\n async (span: Span) => {\n try {\n const result = await fn();\n success = true;\n span.setStatus({ code: SpanStatusCode.OK });\n return result;\n } catch (error) {\n span.recordException(error as Error);\n span.setStatus({\n code: SpanStatusCode.ERROR,\n message: error instanceof Error ? error.message : String(error),\n });\n if (error instanceof AppKitError) {\n throw error;\n }\n // Preserve SDK ApiError (and any error with a numeric statusCode)\n // so Plugin.execute() can map it to the correct HTTP status.\n if (\n error instanceof Error &&\n \"statusCode\" in error &&\n typeof (error as Record<string, unknown>).statusCode === \"number\"\n ) {\n throw error;\n }\n throw new ExecutionError(\n `Jobs API call failed: ${error instanceof Error ? error.message : String(error)}`,\n );\n } finally {\n const duration = Date.now() - startTime;\n span.end();\n this.telemetryMetrics.apiCallCount.add(1, {\n operation,\n success: success.toString(),\n });\n this.telemetryMetrics.apiCallDuration.record(duration, {\n operation,\n success: success.toString(),\n });\n\n logger.event()?.setContext(\"jobs\", {\n operation,\n duration_ms: duration,\n success,\n });\n }\n },\n { name: this.name, includePrefix: true },\n );\n }\n\n private _createContext(signal?: AbortSignal) {\n return new Context({\n cancellationToken: {\n // Getter — evaluated on every read so SDK code paths that poll\n // (rather than subscribe) observe cancellation live.\n get isCancellationRequested() {\n return signal?.aborted ?? false;\n },\n onCancellationRequested: (cb: () => void) => {\n signal?.addEventListener(\"abort\", cb, { once: true });\n },\n },\n });\n }\n}\n"],"mappings":";;;;;;;;;
|
|
1
|
+
{"version":3,"file":"client.js","names":[],"sources":["../../../src/connectors/jobs/client.ts"],"sourcesContent":["import {\n Context,\n type jobs,\n type WorkspaceClient,\n} from \"@databricks/sdk-experimental\";\nimport { AppKitError, ExecutionError } from \"../../errors\";\nimport { createLogger } from \"../../logging/logger\";\nimport type { TelemetryProvider } from \"../../telemetry\";\nimport {\n type Counter,\n type Histogram,\n type Span,\n SpanKind,\n SpanStatusCode,\n TelemetryManager,\n} from \"../../telemetry\";\nimport type { JobsConnectorConfig } from \"./types\";\n\nconst logger = createLogger(\"connectors:jobs\");\n\nexport class JobsConnector {\n private readonly name = \"jobs\";\n private readonly config: JobsConnectorConfig;\n private readonly telemetry: TelemetryProvider;\n private readonly telemetryMetrics: {\n apiCallCount: Counter;\n apiCallDuration: Histogram;\n };\n\n constructor(config: JobsConnectorConfig) {\n this.config = config;\n this.telemetry = TelemetryManager.getProvider(\n this.name,\n this.config.telemetry,\n );\n this.telemetryMetrics = {\n apiCallCount: this.telemetry\n .getMeter()\n .createCounter(\"jobs.api_call.count\", {\n description: \"Total number of Jobs API calls\",\n unit: \"1\",\n }),\n apiCallDuration: this.telemetry\n .getMeter()\n .createHistogram(\"jobs.api_call.duration\", {\n description: \"Duration of Jobs API calls\",\n unit: \"ms\",\n }),\n };\n }\n\n async submitRun(\n workspaceClient: WorkspaceClient,\n request: jobs.SubmitRun,\n signal?: AbortSignal,\n ): Promise<jobs.SubmitRunResponse> {\n return this._callApi(\"submit\", async () => {\n return workspaceClient.jobs.submit(request, this._createContext(signal));\n });\n }\n\n async runNow(\n workspaceClient: WorkspaceClient,\n request: jobs.RunNow,\n signal?: AbortSignal,\n ): Promise<jobs.RunNowResponse> {\n return this._callApi(\"runNow\", async () => {\n return workspaceClient.jobs.runNow(request, this._createContext(signal));\n });\n }\n\n async getRun(\n workspaceClient: WorkspaceClient,\n request: jobs.GetRunRequest,\n signal?: AbortSignal,\n ): Promise<jobs.Run> {\n return this._callApi(\"getRun\", async () => {\n return workspaceClient.jobs.getRun(request, this._createContext(signal));\n });\n }\n\n async getRunOutput(\n workspaceClient: WorkspaceClient,\n request: jobs.GetRunOutputRequest,\n signal?: AbortSignal,\n ): Promise<jobs.RunOutput> {\n return this._callApi(\"getRunOutput\", async () => {\n return workspaceClient.jobs.getRunOutput(\n request,\n this._createContext(signal),\n );\n });\n }\n\n async cancelRun(\n workspaceClient: WorkspaceClient,\n request: jobs.CancelRun,\n signal?: AbortSignal,\n ): Promise<void> {\n await this._callApi(\"cancelRun\", async () => {\n return workspaceClient.jobs.cancelRun(\n request,\n this._createContext(signal),\n );\n });\n }\n\n async listRuns(\n workspaceClient: WorkspaceClient,\n request: jobs.ListRunsRequest,\n signal?: AbortSignal,\n ): Promise<jobs.BaseRun[]> {\n return this._callApi(\"listRuns\", async () => {\n const runs: jobs.BaseRun[] = [];\n const limit = Math.max(1, Math.min(request.limit ?? 100, 100));\n for await (const run of workspaceClient.jobs.listRuns(\n { ...request, limit },\n this._createContext(signal),\n )) {\n runs.push(run);\n if (runs.length >= limit) break;\n }\n return runs;\n });\n }\n\n async getJob(\n workspaceClient: WorkspaceClient,\n request: jobs.GetJobRequest,\n signal?: AbortSignal,\n ): Promise<jobs.Job> {\n return this._callApi(\"getJob\", async () => {\n return workspaceClient.jobs.get(request, this._createContext(signal));\n });\n }\n\n private async _callApi<T>(\n operation: string,\n fn: () => Promise<T>,\n ): Promise<T> {\n const startTime = Date.now();\n let success = false;\n\n return this.telemetry.startActiveSpan(\n `jobs.${operation}`,\n {\n kind: SpanKind.CLIENT,\n attributes: {\n \"jobs.operation\": operation,\n },\n },\n async (span: Span) => {\n try {\n const result = await fn();\n success = true;\n span.setStatus({ code: SpanStatusCode.OK });\n return result;\n } catch (error) {\n span.recordException(error as Error);\n span.setStatus({\n code: SpanStatusCode.ERROR,\n message: error instanceof Error ? error.message : String(error),\n });\n if (error instanceof AppKitError) {\n throw error;\n }\n // Preserve SDK ApiError (and any error with a numeric statusCode)\n // so Plugin.execute() can map it to the correct HTTP status.\n if (\n error instanceof Error &&\n \"statusCode\" in error &&\n typeof (error as Record<string, unknown>).statusCode === \"number\"\n ) {\n throw error;\n }\n throw new ExecutionError(\n `Jobs API call failed: ${error instanceof Error ? error.message : String(error)}`,\n );\n } finally {\n const duration = Date.now() - startTime;\n span.end();\n this.telemetryMetrics.apiCallCount.add(1, {\n operation,\n success: success.toString(),\n });\n this.telemetryMetrics.apiCallDuration.record(duration, {\n operation,\n success: success.toString(),\n });\n\n logger.event()?.setContext(\"jobs\", {\n operation,\n duration_ms: duration,\n success,\n });\n }\n },\n { name: this.name, includePrefix: true },\n );\n }\n\n private _createContext(signal?: AbortSignal) {\n return new Context({\n cancellationToken: {\n // Getter — evaluated on every read so SDK code paths that poll\n // (rather than subscribe) observe cancellation live.\n get isCancellationRequested() {\n return signal?.aborted ?? false;\n },\n onCancellationRequested: (cb: () => void) => {\n signal?.addEventListener(\"abort\", cb, { once: true });\n },\n },\n });\n }\n}\n"],"mappings":"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"}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
import { getUserContext
|
|
1
|
+
import { getUserContext } from "../../context/execution-context.js";
|
|
2
2
|
|
|
3
3
|
//#region src/connectors/lakebase/routing-pool.ts
|
|
4
|
-
init_execution_context();
|
|
5
4
|
/**
|
|
6
5
|
* A `pg.Pool`-like wrapper that routes queries to the appropriate pool
|
|
7
6
|
* based on the current execution context.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"routing-pool.js","names":[],"sources":["../../../src/connectors/lakebase/routing-pool.ts"],"sourcesContent":["import type { Pool, PoolClient, QueryResult, QueryResultRow } from \"pg\";\nimport { getUserContext } from \"../../context/execution-context\";\nimport type { UserContext } from \"../../context/user-context\";\n\n/**\n * Subset of `pg.Pool` exposed by the Lakebase plugin.\n *\n * RoutingPool does not extend EventEmitter — event listener methods\n * like `on('error', ...)` are not available. Use `query()`, `connect()`,\n * and `end()` for all pool operations.\n */\nexport interface LakebasePool {\n query<T extends QueryResultRow = any>(\n text: string,\n values?: unknown[],\n ): Promise<QueryResult<T>>;\n connect(): Promise<PoolClient>;\n end(): Promise<void>;\n readonly totalCount: number;\n readonly idleCount: number;\n readonly waitingCount: number;\n}\n\n/**\n * A `pg.Pool`-like wrapper that routes queries to the appropriate pool\n * based on the current execution context.\n *\n * When called inside `runInUserContext()` (set up by `Plugin.asUser(req)`),\n * queries route to the per-user pool returned by `resolveUserPool`.\n * Otherwise, queries route to the service-principal pool.\n *\n * This enables OBO (On-Behalf-Of) without custom `asUser()` overrides —\n * the base class sets up AsyncLocalStorage context, and the RoutingPool\n * reads it transparently.\n */\nexport class RoutingPool implements LakebasePool {\n constructor(\n private spPool: Pool,\n private resolveUserPool: (ctx: UserContext) => Pool,\n ) {}\n\n private activePool(): Pool {\n const userCtx = getUserContext();\n return userCtx ? this.resolveUserPool(userCtx) : this.spPool;\n }\n\n query<T extends QueryResultRow = any>(\n text: string,\n values?: unknown[],\n ): Promise<QueryResult<T>> {\n return this.activePool().query<T>(text, values);\n }\n\n connect(): Promise<PoolClient> {\n return this.activePool().connect();\n }\n\n async end(): Promise<void> {\n await this.spPool.end();\n }\n\n get totalCount() {\n return this.spPool.totalCount;\n }\n get idleCount() {\n return this.spPool.idleCount;\n }\n get waitingCount() {\n return this.spPool.waitingCount;\n }\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"routing-pool.js","names":[],"sources":["../../../src/connectors/lakebase/routing-pool.ts"],"sourcesContent":["import type { Pool, PoolClient, QueryResult, QueryResultRow } from \"pg\";\nimport { getUserContext } from \"../../context/execution-context\";\nimport type { UserContext } from \"../../context/user-context\";\n\n/**\n * Subset of `pg.Pool` exposed by the Lakebase plugin.\n *\n * RoutingPool does not extend EventEmitter — event listener methods\n * like `on('error', ...)` are not available. Use `query()`, `connect()`,\n * and `end()` for all pool operations.\n */\nexport interface LakebasePool {\n query<T extends QueryResultRow = any>(\n text: string,\n values?: unknown[],\n ): Promise<QueryResult<T>>;\n connect(): Promise<PoolClient>;\n end(): Promise<void>;\n readonly totalCount: number;\n readonly idleCount: number;\n readonly waitingCount: number;\n}\n\n/**\n * A `pg.Pool`-like wrapper that routes queries to the appropriate pool\n * based on the current execution context.\n *\n * When called inside `runInUserContext()` (set up by `Plugin.asUser(req)`),\n * queries route to the per-user pool returned by `resolveUserPool`.\n * Otherwise, queries route to the service-principal pool.\n *\n * This enables OBO (On-Behalf-Of) without custom `asUser()` overrides —\n * the base class sets up AsyncLocalStorage context, and the RoutingPool\n * reads it transparently.\n */\nexport class RoutingPool implements LakebasePool {\n constructor(\n private spPool: Pool,\n private resolveUserPool: (ctx: UserContext) => Pool,\n ) {}\n\n private activePool(): Pool {\n const userCtx = getUserContext();\n return userCtx ? this.resolveUserPool(userCtx) : this.spPool;\n }\n\n query<T extends QueryResultRow = any>(\n text: string,\n values?: unknown[],\n ): Promise<QueryResult<T>> {\n return this.activePool().query<T>(text, values);\n }\n\n connect(): Promise<PoolClient> {\n return this.activePool().connect();\n }\n\n async end(): Promise<void> {\n await this.spPool.end();\n }\n\n get totalCount() {\n return this.spPool.totalCount;\n }\n get idleCount() {\n return this.spPool.idleCount;\n }\n get waitingCount() {\n return this.spPool.waitingCount;\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;AAmCA,IAAa,cAAb,MAAiD;CAC/C,YACE,AAAQ,QACR,AAAQ,iBACR;EAFQ;EACA;;CAGV,AAAQ,aAAmB;EACzB,MAAM,UAAU,gBAAgB;AAChC,SAAO,UAAU,KAAK,gBAAgB,QAAQ,GAAG,KAAK;;CAGxD,MACE,MACA,QACyB;AACzB,SAAO,KAAK,YAAY,CAAC,MAAS,MAAM,OAAO;;CAGjD,UAA+B;AAC7B,SAAO,KAAK,YAAY,CAAC,SAAS;;CAGpC,MAAM,MAAqB;AACzB,QAAM,KAAK,OAAO,KAAK;;CAGzB,IAAI,aAAa;AACf,SAAO,KAAK,OAAO;;CAErB,IAAI,YAAY;AACd,SAAO,KAAK,OAAO;;CAErB,IAAI,eAAe;AACjB,SAAO,KAAK,OAAO"}
|
|
@@ -3,7 +3,7 @@ import { AppKitError } from "../../errors/base.js";
|
|
|
3
3
|
import { ConnectionError } from "../../errors/connection.js";
|
|
4
4
|
import { ExecutionError } from "../../errors/execution.js";
|
|
5
5
|
import { ValidationError } from "../../errors/validation.js";
|
|
6
|
-
import
|
|
6
|
+
import "../../errors/index.js";
|
|
7
7
|
import { TelemetryManager } from "../../telemetry/telemetry-manager.js";
|
|
8
8
|
import { SpanKind, SpanStatusCode } from "../../telemetry/index.js";
|
|
9
9
|
import { ArrowStreamProcessor } from "../../stream/arrow-stream-processor.js";
|
|
@@ -11,7 +11,6 @@ import { executeStatementDefaults } from "./defaults.js";
|
|
|
11
11
|
import { Context } from "@databricks/sdk-experimental";
|
|
12
12
|
|
|
13
13
|
//#region src/connectors/sql-warehouse/client.ts
|
|
14
|
-
init_errors();
|
|
15
14
|
const logger = createLogger("connectors:sql-warehouse");
|
|
16
15
|
var SQLWarehouseConnector = class {
|
|
17
16
|
name = "sql-warehouse";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.js","names":[],"sources":["../../../src/connectors/sql-warehouse/client.ts"],"sourcesContent":["import {\n Context,\n type sql,\n type WorkspaceClient,\n} from \"@databricks/sdk-experimental\";\nimport type { TelemetryOptions } from \"shared\";\nimport {\n AppKitError,\n ConnectionError,\n ExecutionError,\n ValidationError,\n} from \"../../errors\";\nimport { createLogger } from \"../../logging/logger\";\nimport { ArrowStreamProcessor } from \"../../stream/arrow-stream-processor\";\nimport type { TelemetryProvider } from \"../../telemetry\";\nimport {\n type Counter,\n type Histogram,\n type Span,\n SpanKind,\n SpanStatusCode,\n TelemetryManager,\n} from \"../../telemetry\";\nimport { executeStatementDefaults } from \"./defaults\";\n\nconst logger = createLogger(\"connectors:sql-warehouse\");\n\ninterface SQLWarehouseConfig {\n timeout?: number;\n telemetry?: TelemetryOptions;\n}\n\nexport class SQLWarehouseConnector {\n private readonly name = \"sql-warehouse\";\n\n private config: SQLWarehouseConfig;\n\n // Lazy-initialized: only created when Arrow format is used\n private _arrowProcessor: ArrowStreamProcessor | null = null;\n // telemetry\n private readonly telemetry: TelemetryProvider;\n private readonly telemetryMetrics: {\n queryCount: Counter;\n queryDuration: Histogram;\n };\n\n constructor(config: SQLWarehouseConfig) {\n this.config = config;\n\n this.telemetry = TelemetryManager.getProvider(\n this.name,\n this.config.telemetry,\n );\n this.telemetryMetrics = {\n queryCount: this.telemetry.getMeter().createCounter(\"query.count\", {\n description: \"Total number of queries executed\",\n unit: \"1\",\n }),\n queryDuration: this.telemetry\n .getMeter()\n .createHistogram(\"query.duration\", {\n description: \"Duration of queries executed\",\n unit: \"ms\",\n }),\n };\n }\n\n /**\n * Lazily initializes and returns the ArrowStreamProcessor.\n * Only created on first Arrow format query to avoid unnecessary allocation.\n */\n private get arrowProcessor(): ArrowStreamProcessor {\n if (!this._arrowProcessor) {\n this._arrowProcessor = new ArrowStreamProcessor({\n timeout: this.config.timeout || executeStatementDefaults.timeout,\n maxConcurrentDownloads:\n ArrowStreamProcessor.DEFAULT_MAX_CONCURRENT_DOWNLOADS,\n retries: ArrowStreamProcessor.DEFAULT_RETRIES,\n });\n }\n return this._arrowProcessor;\n }\n\n async executeStatement(\n workspaceClient: WorkspaceClient,\n input: sql.ExecuteStatementRequest,\n signal?: AbortSignal,\n ) {\n const startTime = Date.now();\n let success = false;\n\n // if signal is aborted, throw an error\n if (signal?.aborted) {\n throw ExecutionError.canceled();\n }\n\n return this.telemetry.startActiveSpan(\n \"sql.query\",\n {\n kind: SpanKind.CLIENT,\n attributes: {\n \"db.system\": \"databricks\",\n \"db.warehouse_id\": input.warehouse_id || \"\",\n \"db.catalog\": input.catalog ?? \"\",\n \"db.schema\": input.schema ?? \"\",\n \"db.statement\": input.statement?.substring(0, 500) || \"\",\n \"db.has_parameters\": !!input.parameters,\n },\n },\n async (span: Span) => {\n let abortHandler: (() => void) | undefined;\n let isAborted = false;\n\n if (signal) {\n abortHandler = () => {\n // abort span if not recording\n if (!span.isRecording()) return;\n isAborted = true;\n span.setAttribute(\"cancelled\", true);\n span.setStatus({\n code: SpanStatusCode.ERROR,\n message: \"Query cancelled by client\",\n });\n span.end();\n };\n signal.addEventListener(\"abort\", abortHandler, { once: true });\n }\n\n try {\n // validate required fields\n if (!input.statement) {\n throw ValidationError.missingField(\"statement\");\n }\n\n if (!input.warehouse_id) {\n throw ValidationError.missingField(\"warehouse_id\");\n }\n\n const body: sql.ExecuteStatementRequest = {\n statement: input.statement,\n parameters: input.parameters,\n warehouse_id: input.warehouse_id,\n catalog: input.catalog,\n schema: input.schema,\n wait_timeout:\n input.wait_timeout || executeStatementDefaults.wait_timeout,\n disposition:\n input.disposition || executeStatementDefaults.disposition,\n format: input.format || executeStatementDefaults.format,\n byte_limit: input.byte_limit,\n row_limit: input.row_limit,\n on_wait_timeout:\n input.on_wait_timeout || executeStatementDefaults.on_wait_timeout,\n };\n\n span.addEvent(\"statement.submitting\", {\n \"db.warehouse_id\": input.warehouse_id,\n });\n\n const response =\n await workspaceClient.statementExecution.executeStatement(\n body,\n this._createContext(signal),\n );\n\n if (!response) {\n throw ConnectionError.apiFailure(\"SQL Warehouse\");\n }\n const status = response.status;\n const statementId = response.statement_id as string;\n\n span.setAttribute(\"db.statement_id\", statementId);\n span.addEvent(\"statement.submitted\", {\n \"db.statement_id\": response.statement_id,\n \"db.status\": status?.state,\n });\n\n let result:\n | sql.StatementResponse\n | { result: { statement_id: string; status: sql.StatementStatus } };\n\n switch (status?.state) {\n case \"RUNNING\":\n case \"PENDING\":\n span.addEvent(\"statement.polling_started\", {\n \"db.status\": response.status?.state,\n });\n result = await this._pollForStatementResult(\n workspaceClient,\n statementId,\n this.config.timeout,\n signal,\n );\n break;\n case \"SUCCEEDED\":\n result = this._transformDataArray(response);\n break;\n case \"FAILED\":\n throw ExecutionError.statementFailed(status.error?.message);\n case \"CANCELED\":\n throw ExecutionError.canceled();\n case \"CLOSED\":\n throw ExecutionError.resultsClosed();\n default:\n throw ExecutionError.unknownState(\n String(status?.state ?? \"unknown\"),\n );\n }\n\n const resultData = result.result as any;\n const rowCount =\n resultData?.data?.length ?? resultData?.data_array?.length ?? 0;\n\n if (rowCount > 0) {\n span.setAttribute(\"db.result.row_count\", rowCount);\n }\n\n const duration = Date.now() - startTime;\n logger.event()?.setContext(\"sql-warehouse\", {\n warehouse_id: input.warehouse_id,\n rows_returned: rowCount,\n query_duration_ms: duration,\n });\n\n success = true;\n // only set success status if not aborted\n if (!isAborted) {\n span.setStatus({ code: SpanStatusCode.OK });\n }\n return result;\n } catch (error) {\n // only record error if not already handled by abort\n if (!isAborted) {\n span.recordException(error as Error);\n span.setStatus({\n code: SpanStatusCode.ERROR,\n message: error instanceof Error ? error.message : String(error),\n });\n\n logger.error(\n \"Statement execution failed: %s\",\n error instanceof Error ? error.message : String(error),\n );\n }\n\n if (error instanceof AppKitError) {\n throw error;\n }\n throw ExecutionError.statementFailed(\n error instanceof Error ? error.message : String(error),\n );\n } finally {\n // remove abort handler\n if (abortHandler && signal) {\n signal.removeEventListener(\"abort\", abortHandler);\n }\n\n const duration = Date.now() - startTime;\n\n // end span if not already ended by abort handler\n if (!isAborted) {\n span.end();\n }\n\n const attributes = {\n \"db.warehouse_id\": input.warehouse_id,\n \"db.catalog\": input.catalog ?? \"\",\n \"db.schema\": input.schema ?? \"\",\n \"db.statement\": input.statement?.substring(0, 500) || \"\",\n success: success.toString(),\n };\n\n this.telemetryMetrics.queryCount.add(1, attributes);\n this.telemetryMetrics.queryDuration.record(duration, attributes);\n }\n },\n { name: this.name, includePrefix: true },\n );\n }\n\n private async _pollForStatementResult(\n workspaceClient: WorkspaceClient,\n statementId: string,\n timeout = executeStatementDefaults.timeout,\n signal?: AbortSignal,\n ) {\n return this.telemetry.startActiveSpan(\n \"sql.poll\",\n {\n attributes: {\n \"db.statement_id\": statementId,\n \"db.polling.timeout\": timeout,\n },\n },\n async (span: Span) => {\n try {\n const startTime = Date.now();\n let delay = 1000;\n const maxDelayBetweenPolls = 5000; // max 5 seconds between polls\n let pollCount = 0;\n\n while (true) {\n pollCount++;\n span.setAttribute(\"db.polling.current_attempt\", pollCount);\n\n // check if timeout exceeded\n const elapsedTime = Date.now() - startTime;\n if (elapsedTime > timeout) {\n const error = ExecutionError.statementFailed(\n `Polling timeout exceeded after ${timeout}ms (elapsed: ${elapsedTime}ms)`,\n );\n span.recordException(error);\n span.setStatus({ code: SpanStatusCode.ERROR });\n throw error;\n }\n\n if (signal?.aborted) {\n const error = ExecutionError.canceled();\n span.recordException(error);\n span.setStatus({ code: SpanStatusCode.ERROR });\n throw error;\n }\n\n span.addEvent(\"polling.attempt\", {\n \"poll.attempt\": pollCount,\n \"poll.delay_ms\": delay,\n \"poll.elapsed_ms\": elapsedTime,\n });\n\n const response =\n await workspaceClient.statementExecution.getStatement(\n {\n statement_id: statementId,\n },\n this._createContext(signal),\n );\n if (!response) {\n throw ConnectionError.apiFailure(\"SQL Warehouse\");\n }\n\n const status = response.status;\n\n span.addEvent(\"polling.status_check\", {\n \"db.status\": status?.state,\n \"poll.attempt\": pollCount,\n });\n\n switch (status?.state) {\n case \"PENDING\":\n case \"RUNNING\":\n // continue polling\n break;\n case \"SUCCEEDED\":\n span.setAttribute(\"db.polling.attempts\", pollCount);\n span.setAttribute(\"db.polling.total_duration_ms\", elapsedTime);\n span.addEvent(\"polling.completed\", {\n \"poll.attempts\": pollCount,\n \"poll.duration_ms\": elapsedTime,\n });\n span.setStatus({ code: SpanStatusCode.OK });\n return this._transformDataArray(response);\n case \"FAILED\":\n throw ExecutionError.statementFailed(status.error?.message);\n case \"CANCELED\":\n throw ExecutionError.canceled();\n case \"CLOSED\":\n throw ExecutionError.resultsClosed();\n default:\n throw ExecutionError.unknownState(\n String(status?.state ?? \"unknown\"),\n );\n }\n\n // continue polling after delay\n await new Promise((resolve) => setTimeout(resolve, delay));\n delay = Math.min(delay * 2, maxDelayBetweenPolls);\n }\n } catch (error) {\n span.recordException(error as Error);\n span.setStatus({\n code: SpanStatusCode.ERROR,\n message: error instanceof Error ? error.message : String(error),\n });\n\n // error logging is handled by executeStatement's catch block (gated on isAborted)\n if (error instanceof AppKitError) {\n throw error;\n }\n throw ExecutionError.statementFailed(\n error instanceof Error ? error.message : String(error),\n );\n } finally {\n span.end();\n }\n },\n { name: this.name, includePrefix: true },\n );\n }\n\n private _transformDataArray(response: sql.StatementResponse) {\n if (response.manifest?.format === \"ARROW_STREAM\") {\n return this.updateWithArrowStatus(response);\n }\n\n if (!response.result?.data_array || !response.manifest?.schema?.columns) {\n return response;\n }\n\n const columns = response.manifest.schema.columns;\n\n const transformedData = response.result.data_array.map((row) => {\n const obj: Record<string, unknown> = {};\n row.forEach((value, index) => {\n const column = columns[index];\n const columnName = column?.name || `column_${index}`;\n\n // attempt to parse JSON strings for string columns\n if (\n column?.type_name === \"STRING\" &&\n typeof value === \"string\" &&\n value &&\n (value[0] === \"{\" || value[0] === \"[\")\n ) {\n try {\n obj[columnName] = JSON.parse(value);\n } catch {\n // if parsing fails, keep as string\n obj[columnName] = value;\n }\n } else {\n obj[columnName] = value;\n }\n });\n return obj;\n });\n\n // remove data_array\n const { data_array: _data_array, ...restResult } = response.result;\n return {\n ...response,\n result: {\n ...restResult,\n data: transformedData,\n },\n };\n }\n\n private updateWithArrowStatus(response: sql.StatementResponse): {\n result: { statement_id: string; status: sql.StatementStatus };\n } {\n return {\n result: {\n statement_id: response.statement_id as string,\n status: {\n state: response.status?.state,\n error: response.status?.error,\n } as sql.StatementStatus,\n },\n };\n }\n\n async getArrowData(\n workspaceClient: WorkspaceClient,\n jobId: string,\n signal?: AbortSignal,\n ): Promise<ReturnType<typeof this.arrowProcessor.processChunks>> {\n const startTime = Date.now();\n\n return this.telemetry.startActiveSpan(\n \"arrow.getData\",\n {\n kind: SpanKind.CLIENT,\n attributes: {\n \"db.system\": \"databricks\",\n \"arrow.job_id\": jobId,\n },\n },\n async (span: Span) => {\n try {\n const response =\n await workspaceClient.statementExecution.getStatement(\n { statement_id: jobId },\n this._createContext(signal),\n );\n\n const chunks = response.result?.external_links;\n const schema = response.manifest?.schema;\n\n if (!chunks || !schema) {\n throw ExecutionError.missingData(\"chunks or schema\");\n }\n\n span.setAttribute(\"arrow.chunk_count\", chunks.length);\n\n const result = await this.arrowProcessor.processChunks(\n chunks,\n schema,\n signal,\n );\n\n span.setAttribute(\"arrow.data_size_bytes\", result.data.length);\n span.setStatus({ code: SpanStatusCode.OK });\n\n const duration = Date.now() - startTime;\n this.telemetryMetrics.queryDuration.record(duration, {\n operation: \"arrow.getData\",\n status: \"success\",\n });\n\n logger.event()?.setContext(\"sql-warehouse\", {\n arrow_data_size_bytes: result.data.length,\n arrow_job_id: jobId,\n });\n\n return result;\n } catch (error) {\n span.setStatus({\n code: SpanStatusCode.ERROR,\n message: error instanceof Error ? error.message : \"Unknown error\",\n });\n span.recordException(error as Error);\n\n const duration = Date.now() - startTime;\n this.telemetryMetrics.queryDuration.record(duration, {\n operation: \"arrow.getData\",\n status: \"error\",\n });\n\n logger.error(\"Failed Arrow job: %s %O\", jobId, error);\n\n if (error instanceof AppKitError) {\n throw error;\n }\n throw ExecutionError.statementFailed(\n error instanceof Error ? error.message : String(error),\n );\n }\n },\n );\n }\n\n // create context for cancellation token\n private _createContext(signal?: AbortSignal) {\n return new Context({\n cancellationToken: {\n isCancellationRequested: signal?.aborted ?? false,\n onCancellationRequested: (cb: () => void) => {\n signal?.addEventListener(\"abort\", cb, { once: true });\n },\n },\n });\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"client.js","names":[],"sources":["../../../src/connectors/sql-warehouse/client.ts"],"sourcesContent":["import {\n Context,\n type sql,\n type WorkspaceClient,\n} from \"@databricks/sdk-experimental\";\nimport type { TelemetryOptions } from \"shared\";\nimport {\n AppKitError,\n ConnectionError,\n ExecutionError,\n ValidationError,\n} from \"../../errors\";\nimport { createLogger } from \"../../logging/logger\";\nimport { ArrowStreamProcessor } from \"../../stream/arrow-stream-processor\";\nimport type { TelemetryProvider } from \"../../telemetry\";\nimport {\n type Counter,\n type Histogram,\n type Span,\n SpanKind,\n SpanStatusCode,\n TelemetryManager,\n} from \"../../telemetry\";\nimport { executeStatementDefaults } from \"./defaults\";\n\nconst logger = createLogger(\"connectors:sql-warehouse\");\n\ninterface SQLWarehouseConfig {\n timeout?: number;\n telemetry?: TelemetryOptions;\n}\n\nexport class SQLWarehouseConnector {\n private readonly name = \"sql-warehouse\";\n\n private config: SQLWarehouseConfig;\n\n // Lazy-initialized: only created when Arrow format is used\n private _arrowProcessor: ArrowStreamProcessor | null = null;\n // telemetry\n private readonly telemetry: TelemetryProvider;\n private readonly telemetryMetrics: {\n queryCount: Counter;\n queryDuration: Histogram;\n };\n\n constructor(config: SQLWarehouseConfig) {\n this.config = config;\n\n this.telemetry = TelemetryManager.getProvider(\n this.name,\n this.config.telemetry,\n );\n this.telemetryMetrics = {\n queryCount: this.telemetry.getMeter().createCounter(\"query.count\", {\n description: \"Total number of queries executed\",\n unit: \"1\",\n }),\n queryDuration: this.telemetry\n .getMeter()\n .createHistogram(\"query.duration\", {\n description: \"Duration of queries executed\",\n unit: \"ms\",\n }),\n };\n }\n\n /**\n * Lazily initializes and returns the ArrowStreamProcessor.\n * Only created on first Arrow format query to avoid unnecessary allocation.\n */\n private get arrowProcessor(): ArrowStreamProcessor {\n if (!this._arrowProcessor) {\n this._arrowProcessor = new ArrowStreamProcessor({\n timeout: this.config.timeout || executeStatementDefaults.timeout,\n maxConcurrentDownloads:\n ArrowStreamProcessor.DEFAULT_MAX_CONCURRENT_DOWNLOADS,\n retries: ArrowStreamProcessor.DEFAULT_RETRIES,\n });\n }\n return this._arrowProcessor;\n }\n\n async executeStatement(\n workspaceClient: WorkspaceClient,\n input: sql.ExecuteStatementRequest,\n signal?: AbortSignal,\n ) {\n const startTime = Date.now();\n let success = false;\n\n // if signal is aborted, throw an error\n if (signal?.aborted) {\n throw ExecutionError.canceled();\n }\n\n return this.telemetry.startActiveSpan(\n \"sql.query\",\n {\n kind: SpanKind.CLIENT,\n attributes: {\n \"db.system\": \"databricks\",\n \"db.warehouse_id\": input.warehouse_id || \"\",\n \"db.catalog\": input.catalog ?? \"\",\n \"db.schema\": input.schema ?? \"\",\n \"db.statement\": input.statement?.substring(0, 500) || \"\",\n \"db.has_parameters\": !!input.parameters,\n },\n },\n async (span: Span) => {\n let abortHandler: (() => void) | undefined;\n let isAborted = false;\n\n if (signal) {\n abortHandler = () => {\n // abort span if not recording\n if (!span.isRecording()) return;\n isAborted = true;\n span.setAttribute(\"cancelled\", true);\n span.setStatus({\n code: SpanStatusCode.ERROR,\n message: \"Query cancelled by client\",\n });\n span.end();\n };\n signal.addEventListener(\"abort\", abortHandler, { once: true });\n }\n\n try {\n // validate required fields\n if (!input.statement) {\n throw ValidationError.missingField(\"statement\");\n }\n\n if (!input.warehouse_id) {\n throw ValidationError.missingField(\"warehouse_id\");\n }\n\n const body: sql.ExecuteStatementRequest = {\n statement: input.statement,\n parameters: input.parameters,\n warehouse_id: input.warehouse_id,\n catalog: input.catalog,\n schema: input.schema,\n wait_timeout:\n input.wait_timeout || executeStatementDefaults.wait_timeout,\n disposition:\n input.disposition || executeStatementDefaults.disposition,\n format: input.format || executeStatementDefaults.format,\n byte_limit: input.byte_limit,\n row_limit: input.row_limit,\n on_wait_timeout:\n input.on_wait_timeout || executeStatementDefaults.on_wait_timeout,\n };\n\n span.addEvent(\"statement.submitting\", {\n \"db.warehouse_id\": input.warehouse_id,\n });\n\n const response =\n await workspaceClient.statementExecution.executeStatement(\n body,\n this._createContext(signal),\n );\n\n if (!response) {\n throw ConnectionError.apiFailure(\"SQL Warehouse\");\n }\n const status = response.status;\n const statementId = response.statement_id as string;\n\n span.setAttribute(\"db.statement_id\", statementId);\n span.addEvent(\"statement.submitted\", {\n \"db.statement_id\": response.statement_id,\n \"db.status\": status?.state,\n });\n\n let result:\n | sql.StatementResponse\n | { result: { statement_id: string; status: sql.StatementStatus } };\n\n switch (status?.state) {\n case \"RUNNING\":\n case \"PENDING\":\n span.addEvent(\"statement.polling_started\", {\n \"db.status\": response.status?.state,\n });\n result = await this._pollForStatementResult(\n workspaceClient,\n statementId,\n this.config.timeout,\n signal,\n );\n break;\n case \"SUCCEEDED\":\n result = this._transformDataArray(response);\n break;\n case \"FAILED\":\n throw ExecutionError.statementFailed(status.error?.message);\n case \"CANCELED\":\n throw ExecutionError.canceled();\n case \"CLOSED\":\n throw ExecutionError.resultsClosed();\n default:\n throw ExecutionError.unknownState(\n String(status?.state ?? \"unknown\"),\n );\n }\n\n const resultData = result.result as any;\n const rowCount =\n resultData?.data?.length ?? resultData?.data_array?.length ?? 0;\n\n if (rowCount > 0) {\n span.setAttribute(\"db.result.row_count\", rowCount);\n }\n\n const duration = Date.now() - startTime;\n logger.event()?.setContext(\"sql-warehouse\", {\n warehouse_id: input.warehouse_id,\n rows_returned: rowCount,\n query_duration_ms: duration,\n });\n\n success = true;\n // only set success status if not aborted\n if (!isAborted) {\n span.setStatus({ code: SpanStatusCode.OK });\n }\n return result;\n } catch (error) {\n // only record error if not already handled by abort\n if (!isAborted) {\n span.recordException(error as Error);\n span.setStatus({\n code: SpanStatusCode.ERROR,\n message: error instanceof Error ? error.message : String(error),\n });\n\n logger.error(\n \"Statement execution failed: %s\",\n error instanceof Error ? error.message : String(error),\n );\n }\n\n if (error instanceof AppKitError) {\n throw error;\n }\n throw ExecutionError.statementFailed(\n error instanceof Error ? error.message : String(error),\n );\n } finally {\n // remove abort handler\n if (abortHandler && signal) {\n signal.removeEventListener(\"abort\", abortHandler);\n }\n\n const duration = Date.now() - startTime;\n\n // end span if not already ended by abort handler\n if (!isAborted) {\n span.end();\n }\n\n const attributes = {\n \"db.warehouse_id\": input.warehouse_id,\n \"db.catalog\": input.catalog ?? \"\",\n \"db.schema\": input.schema ?? \"\",\n \"db.statement\": input.statement?.substring(0, 500) || \"\",\n success: success.toString(),\n };\n\n this.telemetryMetrics.queryCount.add(1, attributes);\n this.telemetryMetrics.queryDuration.record(duration, attributes);\n }\n },\n { name: this.name, includePrefix: true },\n );\n }\n\n private async _pollForStatementResult(\n workspaceClient: WorkspaceClient,\n statementId: string,\n timeout = executeStatementDefaults.timeout,\n signal?: AbortSignal,\n ) {\n return this.telemetry.startActiveSpan(\n \"sql.poll\",\n {\n attributes: {\n \"db.statement_id\": statementId,\n \"db.polling.timeout\": timeout,\n },\n },\n async (span: Span) => {\n try {\n const startTime = Date.now();\n let delay = 1000;\n const maxDelayBetweenPolls = 5000; // max 5 seconds between polls\n let pollCount = 0;\n\n while (true) {\n pollCount++;\n span.setAttribute(\"db.polling.current_attempt\", pollCount);\n\n // check if timeout exceeded\n const elapsedTime = Date.now() - startTime;\n if (elapsedTime > timeout) {\n const error = ExecutionError.statementFailed(\n `Polling timeout exceeded after ${timeout}ms (elapsed: ${elapsedTime}ms)`,\n );\n span.recordException(error);\n span.setStatus({ code: SpanStatusCode.ERROR });\n throw error;\n }\n\n if (signal?.aborted) {\n const error = ExecutionError.canceled();\n span.recordException(error);\n span.setStatus({ code: SpanStatusCode.ERROR });\n throw error;\n }\n\n span.addEvent(\"polling.attempt\", {\n \"poll.attempt\": pollCount,\n \"poll.delay_ms\": delay,\n \"poll.elapsed_ms\": elapsedTime,\n });\n\n const response =\n await workspaceClient.statementExecution.getStatement(\n {\n statement_id: statementId,\n },\n this._createContext(signal),\n );\n if (!response) {\n throw ConnectionError.apiFailure(\"SQL Warehouse\");\n }\n\n const status = response.status;\n\n span.addEvent(\"polling.status_check\", {\n \"db.status\": status?.state,\n \"poll.attempt\": pollCount,\n });\n\n switch (status?.state) {\n case \"PENDING\":\n case \"RUNNING\":\n // continue polling\n break;\n case \"SUCCEEDED\":\n span.setAttribute(\"db.polling.attempts\", pollCount);\n span.setAttribute(\"db.polling.total_duration_ms\", elapsedTime);\n span.addEvent(\"polling.completed\", {\n \"poll.attempts\": pollCount,\n \"poll.duration_ms\": elapsedTime,\n });\n span.setStatus({ code: SpanStatusCode.OK });\n return this._transformDataArray(response);\n case \"FAILED\":\n throw ExecutionError.statementFailed(status.error?.message);\n case \"CANCELED\":\n throw ExecutionError.canceled();\n case \"CLOSED\":\n throw ExecutionError.resultsClosed();\n default:\n throw ExecutionError.unknownState(\n String(status?.state ?? \"unknown\"),\n );\n }\n\n // continue polling after delay\n await new Promise((resolve) => setTimeout(resolve, delay));\n delay = Math.min(delay * 2, maxDelayBetweenPolls);\n }\n } catch (error) {\n span.recordException(error as Error);\n span.setStatus({\n code: SpanStatusCode.ERROR,\n message: error instanceof Error ? error.message : String(error),\n });\n\n // error logging is handled by executeStatement's catch block (gated on isAborted)\n if (error instanceof AppKitError) {\n throw error;\n }\n throw ExecutionError.statementFailed(\n error instanceof Error ? error.message : String(error),\n );\n } finally {\n span.end();\n }\n },\n { name: this.name, includePrefix: true },\n );\n }\n\n private _transformDataArray(response: sql.StatementResponse) {\n if (response.manifest?.format === \"ARROW_STREAM\") {\n return this.updateWithArrowStatus(response);\n }\n\n if (!response.result?.data_array || !response.manifest?.schema?.columns) {\n return response;\n }\n\n const columns = response.manifest.schema.columns;\n\n const transformedData = response.result.data_array.map((row) => {\n const obj: Record<string, unknown> = {};\n row.forEach((value, index) => {\n const column = columns[index];\n const columnName = column?.name || `column_${index}`;\n\n // attempt to parse JSON strings for string columns\n if (\n column?.type_name === \"STRING\" &&\n typeof value === \"string\" &&\n value &&\n (value[0] === \"{\" || value[0] === \"[\")\n ) {\n try {\n obj[columnName] = JSON.parse(value);\n } catch {\n // if parsing fails, keep as string\n obj[columnName] = value;\n }\n } else {\n obj[columnName] = value;\n }\n });\n return obj;\n });\n\n // remove data_array\n const { data_array: _data_array, ...restResult } = response.result;\n return {\n ...response,\n result: {\n ...restResult,\n data: transformedData,\n },\n };\n }\n\n private updateWithArrowStatus(response: sql.StatementResponse): {\n result: { statement_id: string; status: sql.StatementStatus };\n } {\n return {\n result: {\n statement_id: response.statement_id as string,\n status: {\n state: response.status?.state,\n error: response.status?.error,\n } as sql.StatementStatus,\n },\n };\n }\n\n async getArrowData(\n workspaceClient: WorkspaceClient,\n jobId: string,\n signal?: AbortSignal,\n ): Promise<ReturnType<typeof this.arrowProcessor.processChunks>> {\n const startTime = Date.now();\n\n return this.telemetry.startActiveSpan(\n \"arrow.getData\",\n {\n kind: SpanKind.CLIENT,\n attributes: {\n \"db.system\": \"databricks\",\n \"arrow.job_id\": jobId,\n },\n },\n async (span: Span) => {\n try {\n const response =\n await workspaceClient.statementExecution.getStatement(\n { statement_id: jobId },\n this._createContext(signal),\n );\n\n const chunks = response.result?.external_links;\n const schema = response.manifest?.schema;\n\n if (!chunks || !schema) {\n throw ExecutionError.missingData(\"chunks or schema\");\n }\n\n span.setAttribute(\"arrow.chunk_count\", chunks.length);\n\n const result = await this.arrowProcessor.processChunks(\n chunks,\n schema,\n signal,\n );\n\n span.setAttribute(\"arrow.data_size_bytes\", result.data.length);\n span.setStatus({ code: SpanStatusCode.OK });\n\n const duration = Date.now() - startTime;\n this.telemetryMetrics.queryDuration.record(duration, {\n operation: \"arrow.getData\",\n status: \"success\",\n });\n\n logger.event()?.setContext(\"sql-warehouse\", {\n arrow_data_size_bytes: result.data.length,\n arrow_job_id: jobId,\n });\n\n return result;\n } catch (error) {\n span.setStatus({\n code: SpanStatusCode.ERROR,\n message: error instanceof Error ? error.message : \"Unknown error\",\n });\n span.recordException(error as Error);\n\n const duration = Date.now() - startTime;\n this.telemetryMetrics.queryDuration.record(duration, {\n operation: \"arrow.getData\",\n status: \"error\",\n });\n\n logger.error(\"Failed Arrow job: %s %O\", jobId, error);\n\n if (error instanceof AppKitError) {\n throw error;\n }\n throw ExecutionError.statementFailed(\n error instanceof Error ? error.message : String(error),\n );\n }\n },\n );\n }\n\n // create context for cancellation token\n private _createContext(signal?: AbortSignal) {\n return new Context({\n cancellationToken: {\n isCancellationRequested: signal?.aborted ?? false,\n onCancellationRequested: (cb: () => void) => {\n signal?.addEventListener(\"abort\", cb, { once: true });\n },\n },\n });\n }\n}\n"],"mappings":"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"}
|
|
@@ -1,12 +1,16 @@
|
|
|
1
|
-
import { __esmMin } from "../_virtual/_rolldown/runtime.js";
|
|
2
1
|
import { ConfigurationError } from "../errors/configuration.js";
|
|
3
|
-
import
|
|
4
|
-
import { ServiceContext
|
|
5
|
-
import {
|
|
2
|
+
import "../errors/index.js";
|
|
3
|
+
import { ServiceContext } from "./service-context.js";
|
|
4
|
+
import { isUserContext } from "./user-context.js";
|
|
6
5
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
7
6
|
|
|
8
7
|
//#region src/context/execution-context.ts
|
|
9
8
|
/**
|
|
9
|
+
* AsyncLocalStorage for execution context.
|
|
10
|
+
* Used to pass user context through the call stack without explicit parameters.
|
|
11
|
+
*/
|
|
12
|
+
const executionContextStorage = new AsyncLocalStorage();
|
|
13
|
+
/**
|
|
10
14
|
* Run a function in the context of a user.
|
|
11
15
|
* All calls within the function will have access to the user context.
|
|
12
16
|
*
|
|
@@ -74,15 +78,7 @@ function isInUserContext() {
|
|
|
74
78
|
function getUserContext() {
|
|
75
79
|
return executionContextStorage.getStore();
|
|
76
80
|
}
|
|
77
|
-
var executionContextStorage;
|
|
78
|
-
var init_execution_context = __esmMin((() => {
|
|
79
|
-
init_errors();
|
|
80
|
-
init_service_context();
|
|
81
|
-
init_user_context();
|
|
82
|
-
executionContextStorage = new AsyncLocalStorage();
|
|
83
|
-
}));
|
|
84
81
|
|
|
85
82
|
//#endregion
|
|
86
|
-
|
|
87
|
-
export { getCurrentUserId, getExecutionContext, getUserContext, getWarehouseId, getWorkspaceClient, getWorkspaceId, init_execution_context, isInUserContext, runInUserContext };
|
|
83
|
+
export { getCurrentUserId, getExecutionContext, getUserContext, getWarehouseId, getWorkspaceClient, getWorkspaceId, isInUserContext, runInUserContext };
|
|
88
84
|
//# sourceMappingURL=execution-context.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"execution-context.js","names":[],"sources":["../../src/context/execution-context.ts"],"sourcesContent":["import { AsyncLocalStorage } from \"node:async_hooks\";\nimport { ConfigurationError } from \"../errors\";\nimport { ServiceContext } from \"./service-context\";\nimport {\n type ExecutionContext,\n isUserContext,\n type UserContext,\n} from \"./user-context\";\n\n/**\n * AsyncLocalStorage for execution context.\n * Used to pass user context through the call stack without explicit parameters.\n */\nconst executionContextStorage = new AsyncLocalStorage<UserContext>();\n\n/**\n * Run a function in the context of a user.\n * All calls within the function will have access to the user context.\n *\n * @param userContext - The user context to use\n * @param fn - The function to run\n * @returns The result of the function\n */\nexport function runInUserContext<T>(userContext: UserContext, fn: () => T): T {\n return executionContextStorage.run(userContext, fn);\n}\n\n/**\n * Get the current execution context.\n *\n * - If running inside a user context (via asUser), returns the user context\n * - Otherwise, returns the service context\n *\n * @throws Error if ServiceContext is not initialized\n */\nexport function getExecutionContext(): ExecutionContext {\n const userContext = executionContextStorage.getStore();\n if (userContext) {\n return userContext;\n }\n return ServiceContext.get();\n}\n\n/**\n * Get the current user ID for cache keying and telemetry.\n *\n * Returns the user ID if in user context, otherwise the service user ID.\n */\nexport function getCurrentUserId(): string {\n const ctx = getExecutionContext();\n if (isUserContext(ctx)) {\n return ctx.userId;\n }\n return ctx.serviceUserId;\n}\n\n/**\n * Get the WorkspaceClient for the current execution context.\n */\nexport function getWorkspaceClient() {\n return getExecutionContext().client;\n}\n\n/**\n * Get the warehouse ID promise.\n */\nexport function getWarehouseId(): Promise<string> {\n const ctx = getExecutionContext();\n if (!ctx.warehouseId) {\n throw ConfigurationError.resourceNotFound(\n \"Warehouse ID\",\n \"No plugin requires a SQL Warehouse. Add a sql_warehouse resource to your plugin manifest, or set DATABRICKS_WAREHOUSE_ID\",\n );\n }\n return ctx.warehouseId;\n}\n\n/**\n * Get the workspace ID promise.\n */\nexport function getWorkspaceId(): Promise<string> {\n return getExecutionContext().workspaceId;\n}\n\n/**\n * Check if currently running in a user context.\n */\nexport function isInUserContext(): boolean {\n const ctx = executionContextStorage.getStore();\n return ctx !== undefined;\n}\n\n/**\n * Get the user context if one is active, otherwise `undefined`.\n * Unlike `getExecutionContext()`, this does not require `ServiceContext`\n * to be initialized and never throws.\n */\nexport function getUserContext(): UserContext | undefined {\n return executionContextStorage.getStore();\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"execution-context.js","names":[],"sources":["../../src/context/execution-context.ts"],"sourcesContent":["import { AsyncLocalStorage } from \"node:async_hooks\";\nimport { ConfigurationError } from \"../errors\";\nimport { ServiceContext } from \"./service-context\";\nimport {\n type ExecutionContext,\n isUserContext,\n type UserContext,\n} from \"./user-context\";\n\n/**\n * AsyncLocalStorage for execution context.\n * Used to pass user context through the call stack without explicit parameters.\n */\nconst executionContextStorage = new AsyncLocalStorage<UserContext>();\n\n/**\n * Run a function in the context of a user.\n * All calls within the function will have access to the user context.\n *\n * @param userContext - The user context to use\n * @param fn - The function to run\n * @returns The result of the function\n */\nexport function runInUserContext<T>(userContext: UserContext, fn: () => T): T {\n return executionContextStorage.run(userContext, fn);\n}\n\n/**\n * Get the current execution context.\n *\n * - If running inside a user context (via asUser), returns the user context\n * - Otherwise, returns the service context\n *\n * @throws Error if ServiceContext is not initialized\n */\nexport function getExecutionContext(): ExecutionContext {\n const userContext = executionContextStorage.getStore();\n if (userContext) {\n return userContext;\n }\n return ServiceContext.get();\n}\n\n/**\n * Get the current user ID for cache keying and telemetry.\n *\n * Returns the user ID if in user context, otherwise the service user ID.\n */\nexport function getCurrentUserId(): string {\n const ctx = getExecutionContext();\n if (isUserContext(ctx)) {\n return ctx.userId;\n }\n return ctx.serviceUserId;\n}\n\n/**\n * Get the WorkspaceClient for the current execution context.\n */\nexport function getWorkspaceClient() {\n return getExecutionContext().client;\n}\n\n/**\n * Get the warehouse ID promise.\n */\nexport function getWarehouseId(): Promise<string> {\n const ctx = getExecutionContext();\n if (!ctx.warehouseId) {\n throw ConfigurationError.resourceNotFound(\n \"Warehouse ID\",\n \"No plugin requires a SQL Warehouse. Add a sql_warehouse resource to your plugin manifest, or set DATABRICKS_WAREHOUSE_ID\",\n );\n }\n return ctx.warehouseId;\n}\n\n/**\n * Get the workspace ID promise.\n */\nexport function getWorkspaceId(): Promise<string> {\n return getExecutionContext().workspaceId;\n}\n\n/**\n * Check if currently running in a user context.\n */\nexport function isInUserContext(): boolean {\n const ctx = executionContextStorage.getStore();\n return ctx !== undefined;\n}\n\n/**\n * Get the user context if one is active, otherwise `undefined`.\n * Unlike `getExecutionContext()`, this does not require `ServiceContext`\n * to be initialized and never throws.\n */\nexport function getUserContext(): UserContext | undefined {\n return executionContextStorage.getStore();\n}\n"],"mappings":";;;;;;;;;;;AAaA,MAAM,0BAA0B,IAAI,mBAAgC;;;;;;;;;AAUpE,SAAgB,iBAAoB,aAA0B,IAAgB;AAC5E,QAAO,wBAAwB,IAAI,aAAa,GAAG;;;;;;;;;;AAWrD,SAAgB,sBAAwC;CACtD,MAAM,cAAc,wBAAwB,UAAU;AACtD,KAAI,YACF,QAAO;AAET,QAAO,eAAe,KAAK;;;;;;;AAQ7B,SAAgB,mBAA2B;CACzC,MAAM,MAAM,qBAAqB;AACjC,KAAI,cAAc,IAAI,CACpB,QAAO,IAAI;AAEb,QAAO,IAAI;;;;;AAMb,SAAgB,qBAAqB;AACnC,QAAO,qBAAqB,CAAC;;;;;AAM/B,SAAgB,iBAAkC;CAChD,MAAM,MAAM,qBAAqB;AACjC,KAAI,CAAC,IAAI,YACP,OAAM,mBAAmB,iBACvB,gBACA,2HACD;AAEH,QAAO,IAAI;;;;;AAMb,SAAgB,iBAAkC;AAChD,QAAO,qBAAqB,CAAC;;;;;AAM/B,SAAgB,kBAA2B;AAEzC,QADY,wBAAwB,UAAU,KAC/B;;;;;;;AAQjB,SAAgB,iBAA0C;AACxD,QAAO,wBAAwB,UAAU"}
|
package/dist/context/index.js
CHANGED
|
@@ -1,14 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import { getCurrentUserId, getExecutionContext, getWarehouseId, getWorkspaceClient, getWorkspaceId, init_execution_context, runInUserContext } from "./execution-context.js";
|
|
1
|
+
import { ServiceContext } from "./service-context.js";
|
|
2
|
+
import { getCurrentUserId, getExecutionContext, getWarehouseId, getWorkspaceClient, getWorkspaceId, runInUserContext } from "./execution-context.js";
|
|
4
3
|
|
|
5
|
-
|
|
6
|
-
var init_context = __esmMin((() => {
|
|
7
|
-
init_execution_context();
|
|
8
|
-
init_service_context();
|
|
9
|
-
}));
|
|
10
|
-
|
|
11
|
-
//#endregion
|
|
12
|
-
init_context();
|
|
13
|
-
export { getWorkspaceClient, init_context };
|
|
14
|
-
//# sourceMappingURL=index.js.map
|
|
4
|
+
export { getWorkspaceClient };
|