@databricks/appkit 0.59.0 → 0.61.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (118) hide show
  1. package/NOTICE.md +11 -10
  2. package/dist/agents/databricks.js +1 -2
  3. package/dist/agents/databricks.js.map +1 -1
  4. package/dist/agents/supervisor-api.js +1 -2
  5. package/dist/agents/supervisor-api.js.map +1 -1
  6. package/dist/appkit/package.js +1 -1
  7. package/dist/cache/index.js +2 -3
  8. package/dist/cache/index.js.map +1 -1
  9. package/dist/cli/commands/doctor/bundle.js +3 -11
  10. package/dist/cli/commands/doctor/bundle.js.map +1 -1
  11. package/dist/cli/commands/doctor/databricks-client.js +18 -22
  12. package/dist/cli/commands/doctor/databricks-client.js.map +1 -1
  13. package/dist/cli/commands/registry/add.js +410 -0
  14. package/dist/cli/commands/registry/add.js.map +1 -0
  15. package/dist/cli/commands/registry/client.js +94 -0
  16. package/dist/cli/commands/registry/client.js.map +1 -0
  17. package/dist/cli/commands/registry/config-plan.js +110 -0
  18. package/dist/cli/commands/registry/config-plan.js.map +1 -0
  19. package/dist/cli/commands/registry/config-writer.js +176 -0
  20. package/dist/cli/commands/registry/config-writer.js.map +1 -0
  21. package/dist/cli/commands/registry/constants.js +62 -0
  22. package/dist/cli/commands/registry/constants.js.map +1 -0
  23. package/dist/cli/commands/registry/env-reconcile.js +116 -0
  24. package/dist/cli/commands/registry/env-reconcile.js.map +1 -0
  25. package/dist/cli/commands/registry/env-writer.js +198 -0
  26. package/dist/cli/commands/registry/env-writer.js.map +1 -0
  27. package/dist/cli/commands/registry/index.js +25 -0
  28. package/dist/cli/commands/registry/index.js.map +1 -0
  29. package/dist/cli/commands/registry/info.js +45 -0
  30. package/dist/cli/commands/registry/info.js.map +1 -0
  31. package/dist/cli/commands/registry/list.js +130 -0
  32. package/dist/cli/commands/registry/list.js.map +1 -0
  33. package/dist/cli/commands/registry/requirements.js +92 -0
  34. package/dist/cli/commands/registry/requirements.js.map +1 -0
  35. package/dist/cli/commands/registry/server-register.js +124 -0
  36. package/dist/cli/commands/registry/server-register.js.map +1 -0
  37. package/dist/cli/commands/registry/workspace-picker.js +353 -0
  38. package/dist/cli/commands/registry/workspace-picker.js.map +1 -0
  39. package/dist/cli/deploy-config.js +36 -0
  40. package/dist/cli/deploy-config.js.map +1 -0
  41. package/dist/cli/index.js +4 -0
  42. package/dist/cli/index.js.map +1 -1
  43. package/dist/connectors/context.js +1 -2
  44. package/dist/connectors/context.js.map +1 -1
  45. package/dist/connectors/files/client.js +1 -2
  46. package/dist/connectors/files/client.js.map +1 -1
  47. package/dist/connectors/genie/client.js +1 -2
  48. package/dist/connectors/genie/client.js.map +1 -1
  49. package/dist/connectors/jobs/client.js +1 -2
  50. package/dist/connectors/jobs/client.js.map +1 -1
  51. package/dist/connectors/sql-warehouse/client.js +1 -2
  52. package/dist/connectors/sql-warehouse/client.js.map +1 -1
  53. package/dist/context/execution-context.d.ts +0 -1
  54. package/dist/context/execution-context.d.ts.map +1 -1
  55. package/dist/context/service-context.d.ts +1 -2
  56. package/dist/context/service-context.d.ts.map +1 -1
  57. package/dist/context/service-context.js +2 -3
  58. package/dist/context/service-context.js.map +1 -1
  59. package/dist/core/appkit.d.ts +1 -2
  60. package/dist/core/appkit.d.ts.map +1 -1
  61. package/dist/index.d.ts +3 -5
  62. package/dist/index.js +2 -3
  63. package/dist/plugins/agents/agents.d.ts.map +1 -1
  64. package/dist/plugins/agents/agents.js +117 -80
  65. package/dist/plugins/agents/agents.js.map +1 -1
  66. package/dist/plugins/agents/manifest.js +10 -0
  67. package/dist/plugins/agents/mlflow.js +123 -0
  68. package/dist/plugins/agents/mlflow.js.map +1 -0
  69. package/dist/plugins/agents/schemas.js +4 -2
  70. package/dist/plugins/agents/schemas.js.map +1 -1
  71. package/dist/plugins/files/plugin.js +1 -2
  72. package/dist/plugins/files/plugin.js.map +1 -1
  73. package/dist/plugins/files/types.d.ts +1 -2
  74. package/dist/plugins/files/types.d.ts.map +1 -1
  75. package/dist/plugins/jobs/types.d.ts +1 -2
  76. package/dist/plugins/jobs/types.d.ts.map +1 -1
  77. package/dist/plugins/lakebase/lakebase.js +1 -2
  78. package/dist/plugins/lakebase/lakebase.js.map +1 -1
  79. package/dist/schemas/manifest.js +4 -4
  80. package/dist/schemas/manifest.js.map +1 -1
  81. package/dist/shared/src/index.d.ts +4 -1
  82. package/dist/shared/src/schemas/manifest.d.ts +6 -6
  83. package/dist/shared/src/workspace-client/client.js +57 -0
  84. package/dist/shared/src/workspace-client/client.js.map +1 -0
  85. package/dist/shared/src/workspace-client/errors.d.ts +2 -0
  86. package/dist/shared/src/workspace-client/errors.js +3 -0
  87. package/dist/shared/src/workspace-client/factory.d.ts +19 -0
  88. package/dist/shared/src/workspace-client/factory.d.ts.map +1 -0
  89. package/dist/shared/src/workspace-client/factory.js +24 -0
  90. package/dist/shared/src/workspace-client/factory.js.map +1 -0
  91. package/dist/shared/src/workspace-client/index.d.ts +4 -0
  92. package/dist/shared/src/workspace-client/legacy.d.ts +31 -0
  93. package/dist/shared/src/workspace-client/legacy.d.ts.map +1 -0
  94. package/dist/shared/src/workspace-client/legacy.js +23 -0
  95. package/dist/shared/src/workspace-client/legacy.js.map +1 -0
  96. package/dist/shared/src/workspace-client/types.d.ts +49 -0
  97. package/dist/shared/src/workspace-client/types.d.ts.map +1 -0
  98. package/dist/type-generator/index.js +1 -2
  99. package/dist/type-generator/index.js.map +1 -1
  100. package/dist/type-generator/query-registry.js +1 -2
  101. package/dist/type-generator/query-registry.js.map +1 -1
  102. package/dist/type-generator/serving/fetcher.js +1 -2
  103. package/dist/type-generator/serving/fetcher.js.map +1 -1
  104. package/dist/type-generator/serving/generator.js +1 -2
  105. package/dist/type-generator/serving/generator.js.map +1 -1
  106. package/dist/type-generator/vite-plugin.js +1 -2
  107. package/dist/type-generator/vite-plugin.js.map +1 -1
  108. package/dist/workspace-client/index.d.ts +4 -3
  109. package/dist/workspace-client/index.js +2 -2
  110. package/dist/workspace-client/legacy.d.ts +9 -4
  111. package/dist/workspace-client/legacy.d.ts.map +1 -1
  112. package/dist/workspace-client/legacy.js +3 -3
  113. package/dist/workspace-client/legacy.js.map +1 -1
  114. package/dist/workspace-client/types.d.ts +2 -2
  115. package/docs/api/appkit/Function.createWorkspaceClient.md +4 -4
  116. package/docs/api/appkit/Interface.WorkspaceClientOptions.md +11 -0
  117. package/package.json +6 -4
  118. package/sbom.cdx.json +1 -1
@@ -0,0 +1,31 @@
1
+ import { ClientOptions, WorkspaceClient } from "@databricks/sdk-experimental";
2
+ import "@databricks/sdk-experimental/dist/apis/dashboards";
3
+ import "@databricks/sdk-experimental/dist/wait";
4
+
5
+ //#region ../shared/src/workspace-client/legacy.d.ts
6
+ /** The concrete legacy SDK client type. */
7
+ type LegacyWorkspaceClient = WorkspaceClient;
8
+ /**
9
+ * Options used to construct the wrapper. Mirrors the subset of the old SDK's
10
+ * `Config` + `ClientOptions` that AppKit relies on today; we deliberately do
11
+ * NOT re-expose every old-SDK config knob.
12
+ */
13
+ interface WorkspaceClientOptions {
14
+ /** Databricks host, e.g. https://my-workspace.cloud.databricks.com. Defaults to DATABRICKS_HOST / profile resolution. */
15
+ host?: string;
16
+ /** `~/.databrickscfg` profile name. Used when no host/token is provided. */
17
+ profile?: string;
18
+ /** Bearer token. When set, `authType` defaults to "pat". */
19
+ token?: string;
20
+ /** Authentication strategy passed to the legacy client. */
21
+ authType?: "pat";
22
+ /**
23
+ * SDK client options (product / productVersion / userAgentExtra) used to
24
+ * stamp the outbound User-Agent. Produced by `getClientOptions()`; omitted
25
+ * by build-time callers that don't stamp a User-Agent.
26
+ */
27
+ clientOptions?: ClientOptions;
28
+ }
29
+ //#endregion
30
+ export { LegacyWorkspaceClient, WorkspaceClientOptions };
31
+ //# sourceMappingURL=legacy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"legacy.d.ts","names":[],"sources":["../../../../../shared/src/workspace-client/legacy.ts"],"mappings":";;;;;;KAqBY,qBAAA,GAAwB,eAAA;;;;;;UAOnB,sBAAA;EAcc;EAZ7B,IAAA;;EAEA,OAAA;;EAEA,KAAA;;EAEA,QAAA;;;;;;EAMA,aAAA,GAAgB,aAAA;AAAA"}
@@ -0,0 +1,23 @@
1
+ import * as SDK from "@databricks/sdk-experimental";
2
+
3
+ //#region ../shared/src/workspace-client/legacy.ts
4
+ const { WorkspaceClient: SdkWorkspaceClientCtor } = SDK;
5
+ /**
6
+ * Construct a legacy `WorkspaceClient` from wrapper options.
7
+ *
8
+ * Centralised so the wrapper facade, the `.toLegacyWorkspaceClient()` escape
9
+ * hatch, and any per-request OBO client all build it the same way.
10
+ */
11
+ function buildLegacyWorkspaceClient(opts) {
12
+ return new SdkWorkspaceClientCtor(opts.token !== void 0 ? {
13
+ host: opts.host,
14
+ token: opts.token,
15
+ authType: opts.authType ?? "pat"
16
+ } : opts.host ? { host: opts.host } : opts.profile ? { profile: opts.profile } : {}, opts.clientOptions);
17
+ }
18
+ const { ConfigError, Context, TimeUnits, loadConfigFile } = SDK;
19
+ const Time = SDK.Time ?? SDK.default.Time;
20
+
21
+ //#endregion
22
+ export { ConfigError, Context, Time, TimeUnits, buildLegacyWorkspaceClient };
23
+ //# sourceMappingURL=legacy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"legacy.js","names":[],"sources":["../../../../../shared/src/workspace-client/legacy.ts"],"sourcesContent":["/**\n * The single module in AppKit allowed to import `@databricks/sdk-experimental`\n * directly (enforced by the Biome `noRestrictedImports` boundary rule). Every\n * other AppKit module reaches the SDK through the wrapper's re-exports and the\n * {@link WorkspaceClient} facade.\n *\n * Isolating the SDK here is what makes the incremental migration to the modular\n * Databricks SDK a localized change: to migrate a service, swap its getter in\n * `client.ts` from the legacy delegate to the modular client — nothing else in\n * the codebase imports the SDK, so the blast radius is one connector + its test.\n */\n\nimport type {\n ClientOptions,\n WorkspaceClient as SdkWorkspaceClient,\n} from \"@databricks/sdk-experimental\";\nimport * as SDK from \"@databricks/sdk-experimental\";\n\nconst { WorkspaceClient: SdkWorkspaceClientCtor } = SDK;\n\n/** The concrete legacy SDK client type. */\nexport type LegacyWorkspaceClient = SdkWorkspaceClient;\n\n/**\n * Options used to construct the wrapper. Mirrors the subset of the old SDK's\n * `Config` + `ClientOptions` that AppKit relies on today; we deliberately do\n * NOT re-expose every old-SDK config knob.\n */\nexport interface WorkspaceClientOptions {\n /** Databricks host, e.g. https://my-workspace.cloud.databricks.com. Defaults to DATABRICKS_HOST / profile resolution. */\n host?: string;\n /** `~/.databrickscfg` profile name. Used when no host/token is provided. */\n profile?: string;\n /** Bearer token. When set, `authType` defaults to \"pat\". */\n token?: string;\n /** Authentication strategy passed to the legacy client. */\n authType?: \"pat\";\n /**\n * SDK client options (product / productVersion / userAgentExtra) used to\n * stamp the outbound User-Agent. Produced by `getClientOptions()`; omitted\n * by build-time callers that don't stamp a User-Agent.\n */\n clientOptions?: ClientOptions;\n}\n\n/**\n * Construct a legacy `WorkspaceClient` from wrapper options.\n *\n * Centralised so the wrapper facade, the `.toLegacyWorkspaceClient()` escape\n * hatch, and any per-request OBO client all build it the same way.\n */\nexport function buildLegacyWorkspaceClient(\n opts: WorkspaceClientOptions,\n): LegacyWorkspaceClient {\n // Check `token !== undefined`, NOT truthiness: an explicitly-passed token\n // must stick to the PAT path even when it's an empty string. Falling through\n // to the default-auth branch on an empty OBO token would silently\n // authenticate as the service principal instead of failing — a privilege\n // escalation in the OBO path. An invalid/empty token should blow up loudly.\n const cfg =\n opts.token !== undefined\n ? { host: opts.host, token: opts.token, authType: opts.authType ?? \"pat\" }\n : opts.host\n ? { host: opts.host }\n : opts.profile\n ? { profile: opts.profile }\n : {};\n return new SdkWorkspaceClientCtor(cfg, opts.clientOptions);\n}\n\n// ── SDK type re-exports ──────────────────────────────────────────────\nexport type {\n CancellationToken,\n ClientOptions,\n} from \"@databricks/sdk-experimental\";\n// ── SDK value re-exports ─────────────────────────────────────────────\n//\n// AppKit modules import these from the wrapper instead of the SDK so the\n// boundary rule holds. `Context` bridges AbortSignal → CancellationToken\n// (serving/jobs/sql-warehouse); `Time`/`TimeUnits` drive genie polling;\n// `ConfigError` is matched in service-context's auth-failure handling.\n//\n// These are sourced off the namespace import rather than `export { ... } from`\n// because the SDK is CommonJS: its `Time` export is emitted as a getter that\n// calls `__importDefault(...)`, which defeats Node's static named-export\n// detection — a direct `export { Time }` throws \"does not provide an export\n// named 'Time'\" at ESM link time. `Time` is only reachable via the module\n// object, so we fall back to `SDK.default.Time` (matching the original genie\n// connector's `SDK.Time ?? SDK.default.Time` guard).\nexport const { ConfigError, Context, TimeUnits, loadConfigFile } = SDK;\nexport const Time =\n SDK.Time ?? (SDK as unknown as { default: typeof SDK }).default.Time;\n\n// Deep-import types used by the genie connector's waiter idiom. Not exposed\n// on the SDK's top-level index, so re-exported here to keep the genie\n// connector off a direct `@databricks/sdk-experimental/dist/**` import.\nexport type { GenieMessage } from \"@databricks/sdk-experimental/dist/apis/dashboards\";\nexport type { Waiter } from \"@databricks/sdk-experimental/dist/wait\";\n"],"mappings":";;;AAkBA,MAAM,EAAE,iBAAiB,2BAA2B;;;;;;;AAiCpD,SAAgB,2BACd,MACuB;AAcvB,QAAO,IAAI,uBAPT,KAAK,UAAU,SACX;EAAE,MAAM,KAAK;EAAM,OAAO,KAAK;EAAO,UAAU,KAAK,YAAY;EAAO,GACxE,KAAK,OACH,EAAE,MAAM,KAAK,MAAM,GACnB,KAAK,UACH,EAAE,SAAS,KAAK,SAAS,GACzB,EAAE,EAC2B,KAAK,cAAc;;AAsB5D,MAAa,EAAE,aAAa,SAAS,WAAW,mBAAmB;AACnE,MAAa,OACX,IAAI,QAAS,IAA2C,QAAQ"}
@@ -0,0 +1,49 @@
1
+ import { LegacyWorkspaceClient } from "./legacy.js";
2
+ import "@databricks/sdk-experimental";
3
+
4
+ //#region ../shared/src/workspace-client/types.d.ts
5
+ /**
6
+ * AppKit's workspace client facade. Mirrors the multi-client shape of the
7
+ * modular Databricks SDK: each service is its own accessor, so services can be
8
+ * migrated one at a time behind this stable interface.
9
+ *
10
+ * Accessors are legacy-typed for now (delegated to the underlying legacy SDK
11
+ * client); see the module docblock.
12
+ */
13
+ interface WorkspaceClient$1 {
14
+ /** UC Volumes / Files API. */
15
+ readonly files: LegacyWorkspaceClient["files"];
16
+ /** SQL Warehouses. */
17
+ readonly warehouses: LegacyWorkspaceClient["warehouses"];
18
+ /** Genie / dashboards. */
19
+ readonly genie: LegacyWorkspaceClient["genie"];
20
+ /** Jobs. */
21
+ readonly jobs: LegacyWorkspaceClient["jobs"];
22
+ /** Statement Execution. */
23
+ readonly statementExecution: LegacyWorkspaceClient["statementExecution"];
24
+ /** Serving Endpoints. */
25
+ readonly servingEndpoints: LegacyWorkspaceClient["servingEndpoints"];
26
+ /** Current user. */
27
+ readonly currentUser: LegacyWorkspaceClient["currentUser"];
28
+ /**
29
+ * SDK `Config` — exposes `host` and `authenticate(headers)`. Used by the
30
+ * files-upload path and agents auth-header stamping, which bypass the typed
31
+ * services.
32
+ */
33
+ readonly config: LegacyWorkspaceClient["config"];
34
+ /**
35
+ * Low-level HTTP transport (`apiClient.request(...)`). Used for endpoints
36
+ * without a typed service method: SCIM header probe, warehouse listing,
37
+ * serving SSE streaming, vector search, internal telemetry.
38
+ */
39
+ readonly apiClient: LegacyWorkspaceClient["apiClient"];
40
+ /**
41
+ * Returns the underlying legacy `@databricks/sdk-experimental`
42
+ * `WorkspaceClient`, for handoff to code still typed against the old SDK
43
+ * (`@databricks/lakebase`). Transitional.
44
+ */
45
+ toLegacyWorkspaceClient(): LegacyWorkspaceClient;
46
+ }
47
+ //#endregion
48
+ export { WorkspaceClient$1 as WorkspaceClient };
49
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","names":[],"sources":["../../../../../shared/src/workspace-client/types.ts"],"mappings":";;;;;;;;;;;;UAkCiB,iBAAA;EAWA;EAAA,SATN,KAAA,EAAO,qBAAA;EAYa;EAAA,SATpB,UAAA,EAAY,qBAAA;EAYM;EAAA,SATlB,KAAA,EAAO,qBAAA;EAYM;EAAA,SATb,IAAA,EAAM,qBAAA;EAgBE;EAAA,SAbR,kBAAA,EAAoB,qBAAA;EAoBT;EAAA,SAjBX,gBAAA,EAAkB,qBAAA;EAwBA;EAAA,SArBlB,WAAA,EAAa,qBAAA;EAqB0B;;;;;EAAA,SAdvC,MAAA,EAAQ,qBAAA;;;;;;WAOR,SAAA,EAAW,qBAAA;;;;;;EAOpB,uBAAA,IAA2B,qBAAA;AAAA"}
@@ -1,6 +1,5 @@
1
+ import { createWorkspaceClient } from "../shared/src/workspace-client/factory.js";
1
2
  import { createLogger } from "../logging/logger.js";
2
- import { createWorkspaceClient } from "../workspace-client/factory.js";
3
- import "../workspace-client/index.js";
4
3
  import { METRIC_METADATA_FILE } from "../shared/src/schemas/metric-metadata-bundle.js";
5
4
  import { isRevivableMetricCacheEntry, loadCache, metricCacheHash, saveCache } from "./cache.js";
6
5
  import { classifyBlockingFailure, classifyEnvironmentalCause, getErrorDiagnostic, isConnectivityError } from "./errors.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["generateServingTypesImpl"],"sources":["../../src/type-generator/index.ts"],"sourcesContent":["import { existsSync } from \"node:fs\";\nimport fs from \"node:fs/promises\";\nimport path from \"node:path\";\nimport dotenv from \"dotenv\";\nimport pc from \"picocolors\";\nimport { METRIC_METADATA_FILE } from \"../../../shared/src/schemas/metric-metadata-bundle\";\nimport { createLogger } from \"../logging/logger\";\nimport {\n createWorkspaceClient,\n type WorkspaceClient,\n} from \"../workspace-client\";\nimport {\n isRevivableMetricCacheEntry,\n loadCache,\n type MetricCacheEntry,\n metricCacheHash,\n saveCache,\n} from \"./cache\";\nimport {\n classifyBlockingFailure,\n classifyEnvironmentalCause,\n getErrorDiagnostic,\n isConnectivityError,\n} from \"./errors\";\nimport {\n migrateProjectConfig,\n removeOldGeneratedTypes,\n resolveProjectRoot,\n} from \"./migration\";\nimport { readMetricConfig, resolveMetricConfig } from \"./mv-registry/config\";\nimport { createWorkspaceDescribeFetcher } from \"./mv-registry/describe\";\nimport {\n buildMetricMetadataBundle,\n generateMetricTypeDeclarations,\n} from \"./mv-registry/render-types\";\nimport { emptyMetricSchema, syncMetrics } from \"./mv-registry/sync\";\nimport type {\n DescribeFetcher,\n MetricColumnMetadata,\n MetricLane,\n MetricSchema,\n MetricSyncFailure,\n MetricSyncResult,\n} from \"./mv-registry/types\";\nimport { decidePreflight, type PreflightMode } from \"./preflight\";\nimport { generateQueriesFromDescribe } from \"./query-registry\";\nimport { generateServingTypes as generateServingTypesImpl } from \"./serving/generator\";\nimport type { QueryFatalError, QuerySchema, QuerySyntaxError } from \"./types\";\nimport {\n getWarehouseState,\n startWarehouse,\n type WarehouseState,\n waitUntilRunning,\n} from \"./warehouse-status\";\n\ndotenv.config();\n\nconst logger = createLogger(\"type-generator\");\n\n/**\n * Upper bound (~5 min) on how long the Metric Views path's `blocking`-mode preflight\n * waits for a warehouse to reach RUNNING. Mirrors the query path's (unexported)\n * `PREFLIGHT_WAIT_MAX_MS` in query-registry.ts.\n */\nconst MV_PREFLIGHT_WAIT_MAX_MS = 300_000;\n\nfunction determineWarningMessage(\n cause: \"auth\" | \"unreachable\" | \"unavailable\",\n warehouseId: string,\n): string {\n const causeLabel =\n cause === \"auth\"\n ? \"auth blocked\"\n : cause === \"unreachable\"\n ? \"warehouse unreachable\"\n : \"warehouse unavailable\";\n // Use a stable prefix for greppability and CI log matching.\n return `AppKit typegen: using committed types — warehouse ${warehouseId} ${causeLabel}; please check warehouse status and retry`;\n}\n\ntype TypegenFailure = QuerySyntaxError | QueryFatalError;\n\nfunction plural(count: number, singular: string, pluralForm = `${singular}s`) {\n return count === 1 ? singular : pluralForm;\n}\n\nfunction isQueryDegraded(schema: QuerySchema): boolean {\n return schema.degraded === true;\n}\n\nfunction hasAnyDegradedMetrics(schemas: MetricSchema[]): boolean {\n return schemas.some((s) => s.degraded === true);\n}\n\nfunction formatFailureRows(\n label: string,\n queries: TypegenFailure[],\n color: (value: string) => string,\n) {\n if (queries.length === 0) return [];\n\n // Group by message so a shared failure — e.g. a warehouse-level fatal that\n // hits every query identically — prints once instead of repeating per row.\n const byMessage = new Map<string, string[]>();\n for (const { name, message } of queries) {\n const names = byMessage.get(message);\n if (names) names.push(name);\n else byMessage.set(message, [name]);\n }\n\n const maxNameLen = Math.max(...queries.map((query) => query.name.length));\n const tag = color(label.padEnd(7));\n const rows: string[] = [];\n for (const [message, names] of byMessage) {\n if (names.length === 1) {\n rows.push(\n ` ${tag} ${pc.bold(names[0].padEnd(maxNameLen))} ${pc.dim(message)}`,\n );\n continue;\n }\n // Shared message → print it once, then list the affected query names.\n rows.push(\n ` ${tag} ${pc.dim(message)} ${pc.dim(`(${names.length} ${plural(names.length, \"query\", \"queries\")})`)}`,\n );\n rows.push(\n ` ${names.map((name) => pc.bold(name)).join(pc.dim(\", \"))}`,\n );\n }\n return rows;\n}\n\nfunction formatTypegenFailureMessage(options: {\n syntaxErrors: QuerySyntaxError[];\n fatalErrors?: QueryFatalError[];\n warehouseId?: string;\n title: string;\n causes: string[];\n nextStep: string;\n}) {\n const { syntaxErrors, fatalErrors = [], warehouseId, title } = options;\n const total = syntaxErrors.length + fatalErrors.length;\n const separator = pc.dim(\"─\".repeat(60));\n const warehouse = warehouseId\n ? ` against ${pc.dim(`warehouse ${warehouseId}`)}`\n : \"\";\n\n return [\n ` ${pc.bold(pc.red(\"Type generation failed\"))}`,\n ` ${separator}`,\n ` ${title}: ${total} ${plural(total, \"query\", \"queries\")} could not be described${warehouse}.`,\n ` AppKit wrote generated types with ${pc.bold(\"result: unknown\")} for the failed ${plural(total, \"query\", \"queries\")}.`,\n \"\",\n ...formatFailureRows(\"SQL ERR\", syntaxErrors, pc.red),\n ...(syntaxErrors.length > 0 && fatalErrors.length > 0 ? [\"\"] : []),\n ...formatFailureRows(\"FATAL\", fatalErrors, pc.red),\n \"\",\n ` ${pc.bold(\"Common causes\")}`,\n ...options.causes.map((cause) => ` - ${cause}`),\n \"\",\n ` ${pc.bold(\"Next step\")}`,\n ` ${options.nextStep}`,\n ].join(\"\\n\");\n}\n\n/**\n * Thrown when one or more queries fail `DESCRIBE QUERY` against a *reachable*\n * warehouse — i.e. genuine SQL errors (bad table, syntax, incompatible type),\n * as opposed to a connectivity failure (warehouse unreachable), which degrades\n * silently. Whether this is fatal is the caller's decision: the Vite plugin and\n * CLI fail the build in production and warn-only in development.\n */\nexport class TypegenSyntaxError extends Error {\n readonly queries: QuerySyntaxError[];\n readonly fatalQueries: QueryFatalError[];\n\n constructor(\n queries: QuerySyntaxError[],\n warehouseId?: string,\n fatalQueries: QueryFatalError[] = [],\n ) {\n super(\n formatTypegenFailureMessage({\n syntaxErrors: queries,\n fatalErrors: fatalQueries,\n warehouseId,\n title: \"DESCRIBE QUERY failed\",\n causes: [\n \"SQL syntax errors\",\n \"missing tables or views\",\n \"warehouse format incompatibilities\",\n ],\n nextStep: warehouseId\n ? `Run each SQL ERR query directly in a Databricks SQL editor against warehouse ${pc.bold(warehouseId)}.`\n : \"Run each SQL ERR query directly in a Databricks SQL editor.\",\n }),\n );\n this.name = \"TypegenSyntaxError\";\n this.queries = queries;\n this.fatalQueries = fatalQueries;\n }\n}\n\n/**\n * Thrown when DESCRIBE QUERY could not be requested because of a non-SQL fatal\n * setup/request problem, such as missing permissions, invalid warehouse IDs, or\n * malformed SDK configuration. Like TypegenSyntaxError, this is thrown only\n * after the declaration file has been written with `result: unknown` entries.\n */\nexport class TypegenFatalError extends Error {\n readonly queries: QueryFatalError[];\n\n constructor(queries: QueryFatalError[], warehouseId?: string) {\n super(\n formatTypegenFailureMessage({\n syntaxErrors: [],\n fatalErrors: queries,\n warehouseId,\n title: \"DESCRIBE QUERY could not be requested\",\n causes: [\n \"missing warehouse permissions\",\n \"invalid warehouse ID\",\n \"authentication failure\",\n \"SDK configuration errors\",\n ],\n nextStep: warehouseId\n ? `Verify access to warehouse ${pc.bold(warehouseId)} and rerun type generation.`\n : \"Verify warehouse access and rerun type generation.\",\n }),\n );\n this.name = \"TypegenFatalError\";\n this.queries = queries;\n }\n}\n\n/**\n * Generate type declarations for QueryRegistry\n * Create the d.ts file from the plugin routes and query schemas\n * @param querySchemas - the list of query schemas\n * @returns - the type declarations as a string\n */\nfunction generateTypeDeclarations(querySchemas: QuerySchema[] = []): string {\n const queryEntries = querySchemas\n .map(({ name, type }) => {\n const indentedType = type\n .split(\"\\n\")\n .map((line, i) => (i === 0 ? line : ` ${line}`))\n .join(\"\\n\");\n return ` ${name}: ${indentedType}`;\n })\n .join(\";\\n\");\n\n const querySection = queryEntries ? `\\n${queryEntries};\\n ` : \"\";\n\n return `// Auto-generated by AppKit - DO NOT EDIT\n// Generated by 'npx @databricks/appkit generate-types' or Vite plugin during build\nimport \"@databricks/appkit-ui/react\";\nimport type { SQLTypeMarker, SQLStringMarker, SQLNumberMarker, SQLBooleanMarker, SQLBinaryMarker, SQLDateMarker, SQLTimestampMarker } from \"@databricks/appkit-ui/js\";\n\ndeclare module \"@databricks/appkit-ui/react\" {\n interface QueryRegistry {${querySection}}\n}\n`;\n}\n\n/**\n * Status-only probe for the metric-view gate in {@link generateFromEntryPoint}\n *\n * Uses {@link getWarehouseState} (`warehouses.get`) —\n * a read-only GET that can never start the warehouse\n *\n * Takes the lazy client *getter* so the probe also absorbs client construction failure.\n * A connectivity blip returns `undefined`, which the gate reads as transient not-running;\n * a deterministic failure (auth, bad id) is re-thrown so the gate can classify it\n * fatal rather than silently degrading.\n */\nasync function probeWarehouseState(\n getClient: () => WorkspaceClient,\n warehouseId: string,\n): Promise<WarehouseState | undefined> {\n try {\n return await getWarehouseState(getClient(), warehouseId);\n } catch (err) {\n // Connectivity blip → undefined (gate degrades, retries next pass). A\n // deterministic failure (auth, bad warehouse id, client construction) must\n // not masquerade as not-running — re-throw so the gate pins it fatal, the\n // same split the query path's preflight makes.\n if (isConnectivityError(err)) return undefined;\n throw err;\n }\n}\n\n/**\n * Entry point for generating type declarations from all imported files\n * @param options - the options for the generation\n * @param options.entryPoint - the entry point file\n * @param options.outFile - the output file\n * @param options.noCache - skip the typegen cache entirely: every query is\n * re-described, and the metric path ignores its cached schemas (every\n * configured key becomes describe-needed) and overwrites the cache's\n * `metrics` section with this pass's results.\n * @param options.mode - preflight policy (see {@link PreflightMode}), default\n * `\"non-blocking\"`. For queries, `\"non-blocking\"` never touches the\n * warehouse. For metric views it makes one status-only probe and DESCRIBEs\n * only when the warehouse is already RUNNING, otherwise emits permissive\n * degraded types immediately. `\"blocking\"` waits for / starts the warehouse\n * first, failing the build only for a deleted/deleting one.\n * @param options.metricViewsFolder - folder that holds `definitions.json`\n * (`<root>/config/metric-views`). Optional and independent of `queryFolder`:\n * metric-view types generate whenever this folder holds a config, even if the\n * app has no `config/queries`. When omitted it defaults to a sibling\n * `metric-views` directory of `queryFolder` (so query-only callers keep\n * working); when neither is given, the metric path is skipped.\n * @param options.mvOutFile - optional output file for the MetricRegistry\n * augmentation. Defaults to a sibling `metric-views.ts` file under the same\n * directory as `outFile`. Skipped entirely if `definitions.json` is absent.\n * @param options.metricFetcher - optional DescribeFetcher used by\n * {@link syncMetrics} (tests inject a mock; production lazily builds a\n * default WorkspaceClient-backed one). An injected fetcher always runs: it\n * hits no warehouse, so it bypasses both the non-blocking gate and the\n * blocking preflight.\n */\nexport async function generateFromEntryPoint(options: {\n outFile: string;\n queryFolder?: string;\n metricViewsFolder?: string;\n warehouseId: string;\n noCache?: boolean;\n mode?: PreflightMode;\n mvOutFile?: string;\n metricFetcher?: DescribeFetcher;\n}) {\n const {\n outFile,\n queryFolder,\n warehouseId,\n noCache,\n mode = \"non-blocking\",\n mvOutFile,\n metricFetcher,\n } = options;\n\n // Metric config lives in `config/metric-views/`, a sibling of the queries\n // folder. Prefer the explicit option; otherwise derive the sibling of\n // `queryFolder` so callers that pass only `queryFolder` keep emitting metric\n // types. Undefined when neither is given → the metric path stays dormant.\n const metricViewsFolder =\n options.metricViewsFolder ??\n (queryFolder ? path.resolve(queryFolder, \"..\", \"metric-views\") : undefined);\n const resolvedMvFile =\n mvOutFile ?? path.join(path.dirname(outFile), METRIC_TYPES_FILE);\n\n const projectRoot = resolveProjectRoot(outFile);\n\n logger.debug(\"Starting type generation...\");\n\n let queryRegistry: QuerySchema[] = [];\n let syntaxErrors: QuerySyntaxError[] = [];\n // Deterministic fatal errors only (404/400).\n let fatalErrors: QueryFatalError[] = [];\n let queryHadEnvironmentalFailure = false;\n let metricsHadEnvironmentalFailure = false;\n // Track the coarse cause of the environmental failure for the warning message.\n let environmentalCause: \"auth\" | \"unreachable\" | \"unavailable\" | undefined;\n\n if (queryFolder) {\n const result = await generateQueriesFromDescribe(queryFolder, warehouseId, {\n noCache,\n mode,\n });\n queryRegistry = result.schemas;\n syntaxErrors = result.syntaxErrors ?? [];\n fatalErrors = result.fatalErrors ?? [];\n queryHadEnvironmentalFailure = result.hadEnvironmentalFailure ?? false;\n environmentalCause =\n environmentalCause ?? result.environmentalCause ?? undefined;\n }\n\n const typeDeclarations = generateTypeDeclarations(queryRegistry);\n\n // In blocking mode, never overwrite committed types with a schema explicitly\n // marked degraded. Leave the committed .d.ts as the fallback of record.\n // Non-blocking mode always writes.\n const hasAnyDegradedQuery = queryRegistry.some(isQueryDegraded);\n if (mode === \"blocking\" && hasAnyDegradedQuery) {\n // A degraded schema always participates in the committed-types gate. Keep\n // this invariant next to write suppression so a new producer cannot update\n // one decision without the other.\n queryHadEnvironmentalFailure = true;\n environmentalCause = environmentalCause ?? \"unavailable\";\n }\n const shouldWriteQueries = mode !== \"blocking\" || !hasAnyDegradedQuery;\n\n if (shouldWriteQueries) {\n await fs.mkdir(path.dirname(outFile), { recursive: true });\n await fs.writeFile(outFile, typeDeclarations, \"utf-8\");\n }\n\n // Metric-view types: emit whenever a metric-views folder is resolved (gated\n // on the metric config's own dir, NOT the queries folder — an app can declare\n // metric views without any `.sql` queries). `syncMetricViewsTypes` still\n // returns `noConfig` when the folder holds no `definitions.json`.\n if (metricViewsFolder) {\n let mvResult: SyncMetricViewsTypesResult;\n try {\n mvResult = await syncMetricViewsTypes({\n metricViewsFolder,\n warehouseId,\n metricOutFile: resolvedMvFile,\n cache: !noCache,\n metricFetcher,\n mode,\n // In blocking mode, never overwrite committed metric types with a\n // degraded result — including on runs that go on to throw, so a failing\n // build leaves the committed type file intact. Non-blocking always writes.\n suppressDegradedWrite: mode === \"blocking\",\n });\n } catch (configError) {\n // syncMetricViewsTypes only throws for a malformed definitions.json — re-throw as a message-only TypegenFatalError.\n throw new TypegenFatalError(\n [\n {\n name: \"config/metric-views/definitions.json\",\n message: getErrorDiagnostic(configError),\n },\n ],\n warehouseId,\n );\n }\n\n // Deleted/deleting-warehouse fatal preflight (blocking mode only);\n // empty (no-op) when definitions.json is absent or in non-blocking mode.\n // Only deterministic fatals are recorded in fatalErrors.\n for (const fe of mvResult.fatalErrors) {\n fatalErrors.push(fe);\n }\n\n metricsHadEnvironmentalFailure =\n (mvResult.hadEnvironmentalFailure ?? false) ||\n (mode === \"blocking\" && hasAnyDegradedMetrics(mvResult.schemas));\n environmentalCause =\n environmentalCause ?? mvResult.environmentalCause ?? undefined;\n\n // Blocking (`--wait` / prod Vite) escalates only deterministic per-key\n // DESCRIBE failures. Transient connectivity failures are already recorded\n // as environmental by syncMetricViewsTypes and fall through to the\n // committed-types gate below.\n if (mode === \"blocking\") {\n for (const failure of mvResult.failures) {\n if (failure.transient) continue;\n fatalErrors.push({\n name: failure.key,\n message: `metric view ${failure.key} (${failure.source}) could not be described: ${failure.reason}`,\n });\n }\n }\n }\n\n await removeOldGeneratedTypes(projectRoot, \"appKitTypes.d.ts\");\n await migrateProjectConfig(projectRoot);\n\n // Deterministic failures (SQL syntax errors or 404/400 HTTP) always crash regardless of mode.\n if (syntaxErrors.length > 0) {\n throw new TypegenSyntaxError(syntaxErrors, warehouseId, fatalErrors);\n }\n if (fatalErrors.length > 0) {\n throw new TypegenFatalError(fatalErrors, warehouseId);\n }\n\n if (\n mode === \"blocking\" &&\n (queryHadEnvironmentalFailure || metricsHadEnvironmentalFailure)\n ) {\n const missingCommittedTypes: string[] = [];\n if (queryHadEnvironmentalFailure && !existsSync(outFile)) {\n missingCommittedTypes.push(path.basename(outFile));\n }\n if (metricsHadEnvironmentalFailure && !existsSync(resolvedMvFile)) {\n missingCommittedTypes.push(path.basename(resolvedMvFile));\n }\n\n if (missingCommittedTypes.length === 0) {\n // Committed types present: emit loud warning and exit 0.\n const warningMessage = determineWarningMessage(\n environmentalCause ?? \"unavailable\",\n warehouseId,\n );\n logger.warn(warningMessage);\n } else {\n throw new TypegenFatalError(\n [\n {\n name: \"type-generator\",\n message: `Warehouse ${warehouseId} could not provide schemas and the required committed type ${plural(missingCommittedTypes.length, \"artifact is\", \"artifacts are\")} missing: ${missingCommittedTypes.join(\", \")}. Run 'npx @databricks/appkit generate-types --wait' locally and commit the generated type files.`,\n },\n ],\n warehouseId,\n );\n }\n }\n\n logger.debug(\"Type generation complete!\");\n}\n\n/**\n * Result of a {@link syncMetricViewsTypes} run, returned to the caller (the CLI\n * directly, or {@link generateFromEntryPoint} which delegates to it) so it can\n * report what happened and decide its exit code.\n */\nexport interface SyncMetricViewsTypesResult {\n metricOutFile?: string;\n schemas: MetricSchema[];\n failures: MetricSyncFailure[];\n /**\n * `true` when no `definitions.json` was found in the metric-views folder, so\n * nothing was synced.\n */\n noConfig: boolean;\n /**\n * Per-key fatal preflight errors (empty except in the `blocking`-mode\n * deleted/deleting-warehouse and deterministic-preflight-failure cases).\n * {@link generateFromEntryPoint} surfaces these by throwing\n * {@link TypegenFatalError}; when the run also degraded, `suppressDegradedWrite`\n * means no artifact was written and the committed types stand. A `\"describe-now\"`\n * run sets no blocking preflight, so for that mode this is always empty.\n * ONLY contains deterministic failures (404/400).\n */\n fatalErrors: Array<{ name: string; message: string }>;\n /**\n * `true` when an environmental failure occurred in blocking mode (auth, connectivity,\n * DELETED/DELETING, wait-timeout, or other unrecognized failures). Used by\n * {@link generateFromEntryPoint} to decide whether to apply the has-types gate.\n * Does not directly cause a throw — the gate decides that. Always false in\n * non-blocking or describe-now mode.\n */\n hadEnvironmentalFailure?: boolean;\n /**\n * Coarse cause label for the environmental failure, one of \"auth\" (401/403),\n * \"unreachable\" (connectivity), or \"unavailable\" (other). Only set when\n * hadEnvironmentalFailure is true; used by the warning message.\n */\n environmentalCause?: \"auth\" | \"unreachable\" | \"unavailable\";\n}\n\n/**\n * Unified metric-view type-generation pipeline behind {@link\n * generateFromEntryPoint}'s metric section (which forwards its\n * `\"non-blocking\"`/`\"blocking\"` mode). Also directly callable with the default\n * `\"describe-now\"` mode for a focused, always-converge metric refresh.\n *\n *\n * @param options.metricViewsFolder - folder that holds `definitions.json` (`<root>/config/metric-views`).\n * @param options.warehouseId - SQL warehouse used for `DESCRIBE TABLE EXTENDED`.\n * @param options.metricOutFile - output path for the MetricRegistry `.ts` (the\n * generated source carries both the `declare module` augmentation and the\n * runtime `metricViewsMetadata` const).\n * @param options.cache - cache toggle, default ON. Only `cache === false` disables it (so `undefined`/`true` keep caching).\n * @param options.metricFetcher - optional injected {@link DescribeFetcher}\n * @param options.mode - preflight/gate policy, default `\"describe-now\"`. When set to `\"blocking\"`,\n * metric-view `.ts` writes are suppressed if any metric is degraded (to preserve committed files).\n * @param options.suppressDegradedWrite - when true (only in `mode === \"blocking\"` context), skip\n * the metricOutFile write if any metric schema has `degraded === true`. Used to prevent\n * overwriting committed type files with degraded types in blocking mode.\n */\nexport async function syncMetricViewsTypes(options: {\n metricViewsFolder: string;\n warehouseId: string;\n metricOutFile: string;\n cache?: boolean;\n metricFetcher?: DescribeFetcher;\n mode?: \"describe-now\" | \"non-blocking\" | \"blocking\";\n suppressDegradedWrite?: boolean;\n}): Promise<SyncMetricViewsTypesResult> {\n const {\n metricViewsFolder,\n warehouseId,\n metricOutFile,\n cache: cacheEnabled,\n metricFetcher,\n mode = \"describe-now\",\n suppressDegradedWrite,\n } = options;\n\n // Only `cache === false` disables caching; `undefined`/`true` keep it on.\n const noCache = cacheEnabled === false;\n\n const mvConfig = await readMetricConfig(metricViewsFolder);\n if (!mvConfig) {\n // No definitions.json — additive path stays dormant. The CLI turns this\n // into a friendly \"nothing to sync\" message and exits 0;\n // generateFromEntryPoint simply ignores `noConfig`.\n return { schemas: [], failures: [], fatalErrors: [], noConfig: true };\n }\n\n const resolution = resolveMetricConfig(mvConfig);\n\n const fatalErrors: Array<{ name: string; message: string }> = [];\n\n // Load the shared typegen cache and copy its `metrics` section into a null-prototype map.\n const cache = await loadCache();\n const mvCacheSection: Record<string, MetricCacheEntry> = Object.create(null);\n if (!noCache && cache.metrics) {\n for (const key of Object.keys(cache.metrics)) {\n mvCacheSection[key] = cache.metrics[key];\n }\n }\n\n // Partition BEFORE any gate/preflight decision: a hit (a structurally valid,\n // hash-matching, NON-degraded cached entry) is served from cache no matter\n // what the warehouse is doing. The cache only ever holds successful describes\n // (a degraded outcome is never persisted — see the write block below), so the\n // `degraded !== true` guard is normally moot; it also defends against a stale\n // degraded entry left by an older writer, which re-describes instead of\n // serving. Everything else (new, edited, unrevivable, or degraded) is eligible\n // for DESCRIBE, so a fully-warm pass makes zero warehouse calls and constructs\n // zero clients. Mirrors the query path: only a good result is cache-servable.\n const hitSchemas = new Map<string, MetricSchema>();\n const describeNeeded: typeof resolution.entries = [];\n for (const entry of resolution.entries) {\n const prior = mvCacheSection[entry.key];\n if (\n prior !== undefined &&\n isRevivableMetricCacheEntry(prior) &&\n prior.hash === metricCacheHash(entry.source, entry.lane) &&\n prior.schema.degraded !== true\n ) {\n hitSchemas.set(entry.key, prior.schema);\n } else {\n describeNeeded.push(entry);\n }\n }\n\n let mvClient: WorkspaceClient | undefined;\n const getMvClient = (): WorkspaceClient => {\n mvClient ??= createWorkspaceClient();\n return mvClient;\n };\n\n // Blocking-mode preflight: ensure the warehouse is running before the MV DESCRIBE\n // batch (probe → decide → wait / start+wait; only DELETED/DELETING is fatal). Two softenings vs the query preflight: a failed probe and a timed-out wait are NOT fatal here — we fall through to syncMetrics, which classifies a still-not-ready warehouse as degraded rather than failing the build. Skipped for `describe-now`/`non-blocking` (only `mode === \"blocking\"` enters here).\n let preflightFatalMessage: string | undefined;\n let hadEnvironmentalFailure = false;\n let environmentalCause: \"auth\" | \"unreachable\" | \"unavailable\" | undefined;\n if (\n mode === \"blocking\" &&\n metricFetcher === undefined &&\n describeNeeded.length > 0\n ) {\n try {\n const state = await getWarehouseState(getMvClient(), warehouseId);\n const decision = decidePreflight(state, mode);\n if (decision === \"fatal\") {\n preflightFatalMessage = `warehouse ${warehouseId} is ${state}`;\n // State-based DELETED/DELETING is environmental, not deterministic.\n hadEnvironmentalFailure = true;\n environmentalCause = \"unavailable\";\n } else if (decision === \"startWaitProceed\") {\n // treatStoppedAsTransient rides out the stale pre-start STOPPED/STOPPING\n // reading, same as the query preflight.\n await startWarehouse(getMvClient(), warehouseId);\n const settled = await waitUntilRunning(getMvClient(), warehouseId, {\n maxMs: MV_PREFLIGHT_WAIT_MAX_MS,\n treatStoppedAsTransient: true,\n });\n if (settled !== \"RUNNING\") {\n // With treatStoppedAsTransient, a non-RUNNING resolve is exactly\n // DELETED/DELETING — the warehouse was deleted while we waited.\n preflightFatalMessage = `warehouse ${warehouseId} is ${settled}`;\n hadEnvironmentalFailure = true;\n }\n } else if (decision === \"waitThenProceed\") {\n const settled = await waitUntilRunning(getMvClient(), warehouseId, {\n maxMs: MV_PREFLIGHT_WAIT_MAX_MS,\n });\n if (settled === \"DELETED\" || settled === \"DELETING\") {\n // Deleted mid-wait: fatal. Environmental (state-based).\n preflightFatalMessage = `warehouse ${warehouseId} is ${settled}`;\n hadEnvironmentalFailure = true;\n }\n }\n } catch (err) {\n // Connectivity blip: fall through to syncMetrics, whose DESCRIBEs degrade\n // a not-ready / unreachable warehouse rather than throwing.\n if (!isConnectivityError(err)) {\n // Deterministic failures become fatal errors; environmental failures\n // degrade for the committed-types gate.\n const classification = classifyBlockingFailure(err);\n if (classification === \"deterministic\") {\n preflightFatalMessage = `warehouse ${warehouseId}: ${getErrorDiagnostic(err)}`;\n } else {\n preflightFatalMessage = `warehouse ${warehouseId}: ${getErrorDiagnostic(err)}`;\n hadEnvironmentalFailure = true;\n environmentalCause = classifyEnvironmentalCause(err);\n }\n }\n }\n }\n\n let gateState: WarehouseState | undefined;\n let describeNow =\n metricFetcher !== undefined ||\n mode !== \"non-blocking\" ||\n describeNeeded.length === 0;\n if (!describeNow) {\n try {\n gateState = await probeWarehouseState(getMvClient, warehouseId);\n } catch (err) {\n preflightFatalMessage = `warehouse ${warehouseId}: ${getErrorDiagnostic(err)}`;\n }\n describeNow = gateState === \"RUNNING\";\n }\n\n let described: MetricSchema[];\n let failures: MetricSyncFailure[] = [];\n if (preflightFatalMessage !== undefined) {\n // Environmental failures degrade for the committed-types gate; deterministic\n // failures record one fatal error per key. Degraded schemas are not cached.\n described = describeNeeded.map(emptyMetricSchema);\n if (!hadEnvironmentalFailure) {\n for (const entry of describeNeeded) {\n fatalErrors.push({ name: entry.key, message: preflightFatalMessage });\n }\n }\n } else if (describeNeeded.length === 0) {\n // Nothing left to describe — every configured key was a cache hit.\n // syncMetrics would be a no-op (and building its fetcher would construct a\n // client for nothing); artifacts regenerate from cache.\n described = [];\n } else if (describeNow) {\n const fetcher =\n metricFetcher ??\n createWorkspaceDescribeFetcher(getMvClient(), warehouseId);\n ({ schemas: described, failures } = await syncMetrics(\n { entries: describeNeeded },\n fetcher,\n ));\n\n // Surface DESCRIBE failures loudly: a misconfigured definitions.json would\n // otherwise silently ship an empty entry that the runtime fail-closed gate\n // 503s in production. syncMetrics is log-free; this caller is the single\n // owner of failure logging.\n if (failures.length > 0) {\n for (const f of failures) {\n logger.warn(\n \"metric sync failed for %s (%s): %s\",\n f.key,\n f.source,\n f.reason,\n );\n }\n }\n\n // A rejected DESCRIBE with a connectivity signal is expected to recover on\n // a later pass. In blocking mode, route it through the same committed-types\n // gate as preflight outages instead of treating it as a configuration error.\n if (mode === \"blocking\" && failures.some((failure) => failure.transient)) {\n hadEnvironmentalFailure = true;\n environmentalCause = environmentalCause ?? \"unreachable\";\n }\n\n // Degraded-but-not-failed keys: the warehouse answered with a non-terminal\n // state (stopped / cold-starting), so their schemas are unknown.\n const failedKeys = new Set(failures.map((f) => f.key));\n const degradedKeys = described\n .filter((s) => s.degraded && !failedKeys.has(s.key))\n .map((s) => s.key);\n if (degradedKeys.length > 0) {\n logger.info(\n \"Warehouse %s did not return schemas for %d metric view(s) (%s) — wrote degraded metric types (permissive); they will refresh once the warehouse is available.\",\n warehouseId,\n degradedKeys.length,\n degradedKeys.join(\", \"),\n );\n hadEnvironmentalFailure = true;\n environmentalCause = environmentalCause ?? \"unavailable\";\n }\n } else {\n // Un-probed DESCRIBEs emit degraded schemas; cache hits remain last-known-good.\n described = describeNeeded.map(emptyMetricSchema);\n logger.info(\n \"Warehouse %s is not running — wrote degraded metric types (permissive) for %d metric view(s) (%s); they will refresh once the warehouse is available.\",\n warehouseId,\n describeNeeded.length,\n describeNeeded.map((e) => e.key).join(\", \"),\n );\n hadEnvironmentalFailure = true;\n environmentalCause = environmentalCause ?? \"unavailable\";\n }\n\n // Cache only successful schema results for describe-needed keys; remove stale cache for degraded ones.\n for (let i = 0; i < describeNeeded.length; i++) {\n // syncMetrics return one schema per entry in entry order, so described[i] always belongs to describeNeeded[i].\n const entry = describeNeeded[i];\n if (described[i].degraded === true) {\n delete mvCacheSection[entry.key];\n continue;\n }\n mvCacheSection[entry.key] = {\n hash: metricCacheHash(entry.source, entry.lane),\n schema: described[i],\n // Vestigial, mirrors the query path's only cache write (always false): a\n // persisted entry is by construction a good result, so it never needs a\n // re-describe flag. Kept for on-disk shape compatibility with existing\n // version-3 caches (isRevivableMetricCacheEntry gates on a boolean).\n retry: false,\n };\n }\n\n // Prune entries whose key is no longer configured\n const configuredKeys = new Set(resolution.entries.map((e) => e.key));\n let prunedCount = 0;\n for (const key of Object.keys(mvCacheSection)) {\n if (!configuredKeys.has(key)) {\n delete mvCacheSection[key];\n prunedCount++;\n }\n }\n\n // Save when this pass produced outcomes, bypassed the cache, or pruned.\n if (describeNeeded.length > 0 || noCache || prunedCount > 0) {\n cache.metrics = mvCacheSection;\n await saveCache(cache);\n }\n\n // Merge cached hits with fresh results back into config order.\n const describedByKey = new Map<string, MetricSchema>();\n for (const schema of described) {\n describedByKey.set(schema.key, schema);\n }\n const schemas = resolution.entries.map((entry) => {\n const schema = hitSchemas.get(entry.key) ?? describedByKey.get(entry.key);\n if (schema !== undefined) return schema;\n logger.warn(\n \"no schema resolved for metric key %s — emitting degraded types (should not happen)\",\n entry.key,\n );\n return emptyMetricSchema(entry);\n });\n\n // Same anti-clobber rule as the query path: when suppressDegradedWrite is set\n // (blocking mode), skip the write if any metric degraded, preserving the\n // committed metric-views.d.ts. Non-blocking mode always writes.\n const shouldWriteMetrics =\n !suppressDegradedWrite || !hasAnyDegradedMetrics(schemas);\n\n if (shouldWriteMetrics) {\n await fs.mkdir(path.dirname(metricOutFile), { recursive: true });\n await fs.writeFile(\n metricOutFile,\n generateMetricTypeDeclarations(schemas),\n \"utf-8\",\n );\n\n const bundlePath = path.join(metricViewsFolder, METRIC_METADATA_FILE);\n await fs.writeFile(\n bundlePath,\n `${JSON.stringify(buildMetricMetadataBundle(schemas), null, 2)}\\n`,\n \"utf-8\",\n );\n logger.debug(\"Wrote metric metadata bundle to %s\", bundlePath);\n }\n // Sweep the `metric-views.ts` an interim version left behind, which would\n // otherwise duplicate the augmentation the `.d.ts` emits. Skipped unless the\n // replacement was actually written, so a degraded blocking pass leaves an\n // app's only committed metric types in place.\n if (metricOutFile.endsWith(\".d.ts\") && existsSync(metricOutFile)) {\n const staleTs = `${metricOutFile.slice(0, -\".d.ts\".length)}.ts`;\n try {\n await fs.unlink(staleTs);\n logger.debug(\"Removed stale generated types at %s\", staleTs);\n } catch {\n // No stale sibling — nothing to clean up.\n }\n }\n\n logger.debug(\n \"Wrote MetricRegistry augmentation for %d metric(s)%s\",\n schemas.length,\n failures.length > 0 ? ` (${failures.length} failure(s))` : \"\",\n );\n\n return {\n metricOutFile,\n schemas,\n failures,\n fatalErrors,\n noConfig: false,\n hadEnvironmentalFailure:\n mode === \"blocking\" ? hadEnvironmentalFailure : undefined,\n environmentalCause:\n mode === \"blocking\" && hadEnvironmentalFailure\n ? environmentalCause\n : undefined,\n };\n}\n\n// Rolldown tree-shaking only preserves \"own exports\" (locally defined) — not re-exports.\n// A local binding ensures the serving vite plugin's import keeps this in the dependency graph,\n// mirroring how generateFromEntryPoint (also defined here) is preserved via the analytics vite plugin.\nexport const generateServingTypes = generateServingTypesImpl;\n\n// Re-export the mv-registry types so consumers (CLI, the type-generator\n// .d.ts shim in `packages/shared`) can pick them up from this entry point —\n// the .d.ts shim documents these as part of the package's public surface.\nexport type {\n MetricColumnMetadata,\n MetricLane,\n MetricSchema,\n MetricSyncFailure,\n MetricSyncResult,\n};\n\nexport const TYPES_DIR = \"appkit-types\";\nexport const ANALYTICS_TYPES_FILE = \"analytics.d.ts\";\nexport const SERVING_TYPES_FILE = \"serving.d.ts\";\nexport const METRIC_TYPES_FILE = \"metric-views.d.ts\";\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":["generateServingTypesImpl"],"sources":["../../src/type-generator/index.ts"],"sourcesContent":["import { existsSync } from \"node:fs\";\nimport fs from \"node:fs/promises\";\nimport path from \"node:path\";\nimport dotenv from \"dotenv\";\nimport pc from \"picocolors\";\nimport { METRIC_METADATA_FILE } from \"../../../shared/src/schemas/metric-metadata-bundle\";\nimport { createLogger } from \"../logging/logger\";\nimport {\n createWorkspaceClient,\n type WorkspaceClient,\n} from \"../workspace-client\";\nimport {\n isRevivableMetricCacheEntry,\n loadCache,\n type MetricCacheEntry,\n metricCacheHash,\n saveCache,\n} from \"./cache\";\nimport {\n classifyBlockingFailure,\n classifyEnvironmentalCause,\n getErrorDiagnostic,\n isConnectivityError,\n} from \"./errors\";\nimport {\n migrateProjectConfig,\n removeOldGeneratedTypes,\n resolveProjectRoot,\n} from \"./migration\";\nimport { readMetricConfig, resolveMetricConfig } from \"./mv-registry/config\";\nimport { createWorkspaceDescribeFetcher } from \"./mv-registry/describe\";\nimport {\n buildMetricMetadataBundle,\n generateMetricTypeDeclarations,\n} from \"./mv-registry/render-types\";\nimport { emptyMetricSchema, syncMetrics } from \"./mv-registry/sync\";\nimport type {\n DescribeFetcher,\n MetricColumnMetadata,\n MetricLane,\n MetricSchema,\n MetricSyncFailure,\n MetricSyncResult,\n} from \"./mv-registry/types\";\nimport { decidePreflight, type PreflightMode } from \"./preflight\";\nimport { generateQueriesFromDescribe } from \"./query-registry\";\nimport { generateServingTypes as generateServingTypesImpl } from \"./serving/generator\";\nimport type { QueryFatalError, QuerySchema, QuerySyntaxError } from \"./types\";\nimport {\n getWarehouseState,\n startWarehouse,\n type WarehouseState,\n waitUntilRunning,\n} from \"./warehouse-status\";\n\ndotenv.config();\n\nconst logger = createLogger(\"type-generator\");\n\n/**\n * Upper bound (~5 min) on how long the Metric Views path's `blocking`-mode preflight\n * waits for a warehouse to reach RUNNING. Mirrors the query path's (unexported)\n * `PREFLIGHT_WAIT_MAX_MS` in query-registry.ts.\n */\nconst MV_PREFLIGHT_WAIT_MAX_MS = 300_000;\n\nfunction determineWarningMessage(\n cause: \"auth\" | \"unreachable\" | \"unavailable\",\n warehouseId: string,\n): string {\n const causeLabel =\n cause === \"auth\"\n ? \"auth blocked\"\n : cause === \"unreachable\"\n ? \"warehouse unreachable\"\n : \"warehouse unavailable\";\n // Use a stable prefix for greppability and CI log matching.\n return `AppKit typegen: using committed types — warehouse ${warehouseId} ${causeLabel}; please check warehouse status and retry`;\n}\n\ntype TypegenFailure = QuerySyntaxError | QueryFatalError;\n\nfunction plural(count: number, singular: string, pluralForm = `${singular}s`) {\n return count === 1 ? singular : pluralForm;\n}\n\nfunction isQueryDegraded(schema: QuerySchema): boolean {\n return schema.degraded === true;\n}\n\nfunction hasAnyDegradedMetrics(schemas: MetricSchema[]): boolean {\n return schemas.some((s) => s.degraded === true);\n}\n\nfunction formatFailureRows(\n label: string,\n queries: TypegenFailure[],\n color: (value: string) => string,\n) {\n if (queries.length === 0) return [];\n\n // Group by message so a shared failure — e.g. a warehouse-level fatal that\n // hits every query identically — prints once instead of repeating per row.\n const byMessage = new Map<string, string[]>();\n for (const { name, message } of queries) {\n const names = byMessage.get(message);\n if (names) names.push(name);\n else byMessage.set(message, [name]);\n }\n\n const maxNameLen = Math.max(...queries.map((query) => query.name.length));\n const tag = color(label.padEnd(7));\n const rows: string[] = [];\n for (const [message, names] of byMessage) {\n if (names.length === 1) {\n rows.push(\n ` ${tag} ${pc.bold(names[0].padEnd(maxNameLen))} ${pc.dim(message)}`,\n );\n continue;\n }\n // Shared message → print it once, then list the affected query names.\n rows.push(\n ` ${tag} ${pc.dim(message)} ${pc.dim(`(${names.length} ${plural(names.length, \"query\", \"queries\")})`)}`,\n );\n rows.push(\n ` ${names.map((name) => pc.bold(name)).join(pc.dim(\", \"))}`,\n );\n }\n return rows;\n}\n\nfunction formatTypegenFailureMessage(options: {\n syntaxErrors: QuerySyntaxError[];\n fatalErrors?: QueryFatalError[];\n warehouseId?: string;\n title: string;\n causes: string[];\n nextStep: string;\n}) {\n const { syntaxErrors, fatalErrors = [], warehouseId, title } = options;\n const total = syntaxErrors.length + fatalErrors.length;\n const separator = pc.dim(\"─\".repeat(60));\n const warehouse = warehouseId\n ? ` against ${pc.dim(`warehouse ${warehouseId}`)}`\n : \"\";\n\n return [\n ` ${pc.bold(pc.red(\"Type generation failed\"))}`,\n ` ${separator}`,\n ` ${title}: ${total} ${plural(total, \"query\", \"queries\")} could not be described${warehouse}.`,\n ` AppKit wrote generated types with ${pc.bold(\"result: unknown\")} for the failed ${plural(total, \"query\", \"queries\")}.`,\n \"\",\n ...formatFailureRows(\"SQL ERR\", syntaxErrors, pc.red),\n ...(syntaxErrors.length > 0 && fatalErrors.length > 0 ? [\"\"] : []),\n ...formatFailureRows(\"FATAL\", fatalErrors, pc.red),\n \"\",\n ` ${pc.bold(\"Common causes\")}`,\n ...options.causes.map((cause) => ` - ${cause}`),\n \"\",\n ` ${pc.bold(\"Next step\")}`,\n ` ${options.nextStep}`,\n ].join(\"\\n\");\n}\n\n/**\n * Thrown when one or more queries fail `DESCRIBE QUERY` against a *reachable*\n * warehouse — i.e. genuine SQL errors (bad table, syntax, incompatible type),\n * as opposed to a connectivity failure (warehouse unreachable), which degrades\n * silently. Whether this is fatal is the caller's decision: the Vite plugin and\n * CLI fail the build in production and warn-only in development.\n */\nexport class TypegenSyntaxError extends Error {\n readonly queries: QuerySyntaxError[];\n readonly fatalQueries: QueryFatalError[];\n\n constructor(\n queries: QuerySyntaxError[],\n warehouseId?: string,\n fatalQueries: QueryFatalError[] = [],\n ) {\n super(\n formatTypegenFailureMessage({\n syntaxErrors: queries,\n fatalErrors: fatalQueries,\n warehouseId,\n title: \"DESCRIBE QUERY failed\",\n causes: [\n \"SQL syntax errors\",\n \"missing tables or views\",\n \"warehouse format incompatibilities\",\n ],\n nextStep: warehouseId\n ? `Run each SQL ERR query directly in a Databricks SQL editor against warehouse ${pc.bold(warehouseId)}.`\n : \"Run each SQL ERR query directly in a Databricks SQL editor.\",\n }),\n );\n this.name = \"TypegenSyntaxError\";\n this.queries = queries;\n this.fatalQueries = fatalQueries;\n }\n}\n\n/**\n * Thrown when DESCRIBE QUERY could not be requested because of a non-SQL fatal\n * setup/request problem, such as missing permissions, invalid warehouse IDs, or\n * malformed SDK configuration. Like TypegenSyntaxError, this is thrown only\n * after the declaration file has been written with `result: unknown` entries.\n */\nexport class TypegenFatalError extends Error {\n readonly queries: QueryFatalError[];\n\n constructor(queries: QueryFatalError[], warehouseId?: string) {\n super(\n formatTypegenFailureMessage({\n syntaxErrors: [],\n fatalErrors: queries,\n warehouseId,\n title: \"DESCRIBE QUERY could not be requested\",\n causes: [\n \"missing warehouse permissions\",\n \"invalid warehouse ID\",\n \"authentication failure\",\n \"SDK configuration errors\",\n ],\n nextStep: warehouseId\n ? `Verify access to warehouse ${pc.bold(warehouseId)} and rerun type generation.`\n : \"Verify warehouse access and rerun type generation.\",\n }),\n );\n this.name = \"TypegenFatalError\";\n this.queries = queries;\n }\n}\n\n/**\n * Generate type declarations for QueryRegistry\n * Create the d.ts file from the plugin routes and query schemas\n * @param querySchemas - the list of query schemas\n * @returns - the type declarations as a string\n */\nfunction generateTypeDeclarations(querySchemas: QuerySchema[] = []): string {\n const queryEntries = querySchemas\n .map(({ name, type }) => {\n const indentedType = type\n .split(\"\\n\")\n .map((line, i) => (i === 0 ? line : ` ${line}`))\n .join(\"\\n\");\n return ` ${name}: ${indentedType}`;\n })\n .join(\";\\n\");\n\n const querySection = queryEntries ? `\\n${queryEntries};\\n ` : \"\";\n\n return `// Auto-generated by AppKit - DO NOT EDIT\n// Generated by 'npx @databricks/appkit generate-types' or Vite plugin during build\nimport \"@databricks/appkit-ui/react\";\nimport type { SQLTypeMarker, SQLStringMarker, SQLNumberMarker, SQLBooleanMarker, SQLBinaryMarker, SQLDateMarker, SQLTimestampMarker } from \"@databricks/appkit-ui/js\";\n\ndeclare module \"@databricks/appkit-ui/react\" {\n interface QueryRegistry {${querySection}}\n}\n`;\n}\n\n/**\n * Status-only probe for the metric-view gate in {@link generateFromEntryPoint}\n *\n * Uses {@link getWarehouseState} (`warehouses.get`) —\n * a read-only GET that can never start the warehouse\n *\n * Takes the lazy client *getter* so the probe also absorbs client construction failure.\n * A connectivity blip returns `undefined`, which the gate reads as transient not-running;\n * a deterministic failure (auth, bad id) is re-thrown so the gate can classify it\n * fatal rather than silently degrading.\n */\nasync function probeWarehouseState(\n getClient: () => WorkspaceClient,\n warehouseId: string,\n): Promise<WarehouseState | undefined> {\n try {\n return await getWarehouseState(getClient(), warehouseId);\n } catch (err) {\n // Connectivity blip → undefined (gate degrades, retries next pass). A\n // deterministic failure (auth, bad warehouse id, client construction) must\n // not masquerade as not-running — re-throw so the gate pins it fatal, the\n // same split the query path's preflight makes.\n if (isConnectivityError(err)) return undefined;\n throw err;\n }\n}\n\n/**\n * Entry point for generating type declarations from all imported files\n * @param options - the options for the generation\n * @param options.entryPoint - the entry point file\n * @param options.outFile - the output file\n * @param options.noCache - skip the typegen cache entirely: every query is\n * re-described, and the metric path ignores its cached schemas (every\n * configured key becomes describe-needed) and overwrites the cache's\n * `metrics` section with this pass's results.\n * @param options.mode - preflight policy (see {@link PreflightMode}), default\n * `\"non-blocking\"`. For queries, `\"non-blocking\"` never touches the\n * warehouse. For metric views it makes one status-only probe and DESCRIBEs\n * only when the warehouse is already RUNNING, otherwise emits permissive\n * degraded types immediately. `\"blocking\"` waits for / starts the warehouse\n * first, failing the build only for a deleted/deleting one.\n * @param options.metricViewsFolder - folder that holds `definitions.json`\n * (`<root>/config/metric-views`). Optional and independent of `queryFolder`:\n * metric-view types generate whenever this folder holds a config, even if the\n * app has no `config/queries`. When omitted it defaults to a sibling\n * `metric-views` directory of `queryFolder` (so query-only callers keep\n * working); when neither is given, the metric path is skipped.\n * @param options.mvOutFile - optional output file for the MetricRegistry\n * augmentation. Defaults to a sibling `metric-views.ts` file under the same\n * directory as `outFile`. Skipped entirely if `definitions.json` is absent.\n * @param options.metricFetcher - optional DescribeFetcher used by\n * {@link syncMetrics} (tests inject a mock; production lazily builds a\n * default WorkspaceClient-backed one). An injected fetcher always runs: it\n * hits no warehouse, so it bypasses both the non-blocking gate and the\n * blocking preflight.\n */\nexport async function generateFromEntryPoint(options: {\n outFile: string;\n queryFolder?: string;\n metricViewsFolder?: string;\n warehouseId: string;\n noCache?: boolean;\n mode?: PreflightMode;\n mvOutFile?: string;\n metricFetcher?: DescribeFetcher;\n}) {\n const {\n outFile,\n queryFolder,\n warehouseId,\n noCache,\n mode = \"non-blocking\",\n mvOutFile,\n metricFetcher,\n } = options;\n\n // Metric config lives in `config/metric-views/`, a sibling of the queries\n // folder. Prefer the explicit option; otherwise derive the sibling of\n // `queryFolder` so callers that pass only `queryFolder` keep emitting metric\n // types. Undefined when neither is given → the metric path stays dormant.\n const metricViewsFolder =\n options.metricViewsFolder ??\n (queryFolder ? path.resolve(queryFolder, \"..\", \"metric-views\") : undefined);\n const resolvedMvFile =\n mvOutFile ?? path.join(path.dirname(outFile), METRIC_TYPES_FILE);\n\n const projectRoot = resolveProjectRoot(outFile);\n\n logger.debug(\"Starting type generation...\");\n\n let queryRegistry: QuerySchema[] = [];\n let syntaxErrors: QuerySyntaxError[] = [];\n // Deterministic fatal errors only (404/400).\n let fatalErrors: QueryFatalError[] = [];\n let queryHadEnvironmentalFailure = false;\n let metricsHadEnvironmentalFailure = false;\n // Track the coarse cause of the environmental failure for the warning message.\n let environmentalCause: \"auth\" | \"unreachable\" | \"unavailable\" | undefined;\n\n if (queryFolder) {\n const result = await generateQueriesFromDescribe(queryFolder, warehouseId, {\n noCache,\n mode,\n });\n queryRegistry = result.schemas;\n syntaxErrors = result.syntaxErrors ?? [];\n fatalErrors = result.fatalErrors ?? [];\n queryHadEnvironmentalFailure = result.hadEnvironmentalFailure ?? false;\n environmentalCause =\n environmentalCause ?? result.environmentalCause ?? undefined;\n }\n\n const typeDeclarations = generateTypeDeclarations(queryRegistry);\n\n // In blocking mode, never overwrite committed types with a schema explicitly\n // marked degraded. Leave the committed .d.ts as the fallback of record.\n // Non-blocking mode always writes.\n const hasAnyDegradedQuery = queryRegistry.some(isQueryDegraded);\n if (mode === \"blocking\" && hasAnyDegradedQuery) {\n // A degraded schema always participates in the committed-types gate. Keep\n // this invariant next to write suppression so a new producer cannot update\n // one decision without the other.\n queryHadEnvironmentalFailure = true;\n environmentalCause = environmentalCause ?? \"unavailable\";\n }\n const shouldWriteQueries = mode !== \"blocking\" || !hasAnyDegradedQuery;\n\n if (shouldWriteQueries) {\n await fs.mkdir(path.dirname(outFile), { recursive: true });\n await fs.writeFile(outFile, typeDeclarations, \"utf-8\");\n }\n\n // Metric-view types: emit whenever a metric-views folder is resolved (gated\n // on the metric config's own dir, NOT the queries folder — an app can declare\n // metric views without any `.sql` queries). `syncMetricViewsTypes` still\n // returns `noConfig` when the folder holds no `definitions.json`.\n if (metricViewsFolder) {\n let mvResult: SyncMetricViewsTypesResult;\n try {\n mvResult = await syncMetricViewsTypes({\n metricViewsFolder,\n warehouseId,\n metricOutFile: resolvedMvFile,\n cache: !noCache,\n metricFetcher,\n mode,\n // In blocking mode, never overwrite committed metric types with a\n // degraded result — including on runs that go on to throw, so a failing\n // build leaves the committed type file intact. Non-blocking always writes.\n suppressDegradedWrite: mode === \"blocking\",\n });\n } catch (configError) {\n // syncMetricViewsTypes only throws for a malformed definitions.json — re-throw as a message-only TypegenFatalError.\n throw new TypegenFatalError(\n [\n {\n name: \"config/metric-views/definitions.json\",\n message: getErrorDiagnostic(configError),\n },\n ],\n warehouseId,\n );\n }\n\n // Deleted/deleting-warehouse fatal preflight (blocking mode only);\n // empty (no-op) when definitions.json is absent or in non-blocking mode.\n // Only deterministic fatals are recorded in fatalErrors.\n for (const fe of mvResult.fatalErrors) {\n fatalErrors.push(fe);\n }\n\n metricsHadEnvironmentalFailure =\n (mvResult.hadEnvironmentalFailure ?? false) ||\n (mode === \"blocking\" && hasAnyDegradedMetrics(mvResult.schemas));\n environmentalCause =\n environmentalCause ?? mvResult.environmentalCause ?? undefined;\n\n // Blocking (`--wait` / prod Vite) escalates only deterministic per-key\n // DESCRIBE failures. Transient connectivity failures are already recorded\n // as environmental by syncMetricViewsTypes and fall through to the\n // committed-types gate below.\n if (mode === \"blocking\") {\n for (const failure of mvResult.failures) {\n if (failure.transient) continue;\n fatalErrors.push({\n name: failure.key,\n message: `metric view ${failure.key} (${failure.source}) could not be described: ${failure.reason}`,\n });\n }\n }\n }\n\n await removeOldGeneratedTypes(projectRoot, \"appKitTypes.d.ts\");\n await migrateProjectConfig(projectRoot);\n\n // Deterministic failures (SQL syntax errors or 404/400 HTTP) always crash regardless of mode.\n if (syntaxErrors.length > 0) {\n throw new TypegenSyntaxError(syntaxErrors, warehouseId, fatalErrors);\n }\n if (fatalErrors.length > 0) {\n throw new TypegenFatalError(fatalErrors, warehouseId);\n }\n\n if (\n mode === \"blocking\" &&\n (queryHadEnvironmentalFailure || metricsHadEnvironmentalFailure)\n ) {\n const missingCommittedTypes: string[] = [];\n if (queryHadEnvironmentalFailure && !existsSync(outFile)) {\n missingCommittedTypes.push(path.basename(outFile));\n }\n if (metricsHadEnvironmentalFailure && !existsSync(resolvedMvFile)) {\n missingCommittedTypes.push(path.basename(resolvedMvFile));\n }\n\n if (missingCommittedTypes.length === 0) {\n // Committed types present: emit loud warning and exit 0.\n const warningMessage = determineWarningMessage(\n environmentalCause ?? \"unavailable\",\n warehouseId,\n );\n logger.warn(warningMessage);\n } else {\n throw new TypegenFatalError(\n [\n {\n name: \"type-generator\",\n message: `Warehouse ${warehouseId} could not provide schemas and the required committed type ${plural(missingCommittedTypes.length, \"artifact is\", \"artifacts are\")} missing: ${missingCommittedTypes.join(\", \")}. Run 'npx @databricks/appkit generate-types --wait' locally and commit the generated type files.`,\n },\n ],\n warehouseId,\n );\n }\n }\n\n logger.debug(\"Type generation complete!\");\n}\n\n/**\n * Result of a {@link syncMetricViewsTypes} run, returned to the caller (the CLI\n * directly, or {@link generateFromEntryPoint} which delegates to it) so it can\n * report what happened and decide its exit code.\n */\nexport interface SyncMetricViewsTypesResult {\n metricOutFile?: string;\n schemas: MetricSchema[];\n failures: MetricSyncFailure[];\n /**\n * `true` when no `definitions.json` was found in the metric-views folder, so\n * nothing was synced.\n */\n noConfig: boolean;\n /**\n * Per-key fatal preflight errors (empty except in the `blocking`-mode\n * deleted/deleting-warehouse and deterministic-preflight-failure cases).\n * {@link generateFromEntryPoint} surfaces these by throwing\n * {@link TypegenFatalError}; when the run also degraded, `suppressDegradedWrite`\n * means no artifact was written and the committed types stand. A `\"describe-now\"`\n * run sets no blocking preflight, so for that mode this is always empty.\n * ONLY contains deterministic failures (404/400).\n */\n fatalErrors: Array<{ name: string; message: string }>;\n /**\n * `true` when an environmental failure occurred in blocking mode (auth, connectivity,\n * DELETED/DELETING, wait-timeout, or other unrecognized failures). Used by\n * {@link generateFromEntryPoint} to decide whether to apply the has-types gate.\n * Does not directly cause a throw — the gate decides that. Always false in\n * non-blocking or describe-now mode.\n */\n hadEnvironmentalFailure?: boolean;\n /**\n * Coarse cause label for the environmental failure, one of \"auth\" (401/403),\n * \"unreachable\" (connectivity), or \"unavailable\" (other). Only set when\n * hadEnvironmentalFailure is true; used by the warning message.\n */\n environmentalCause?: \"auth\" | \"unreachable\" | \"unavailable\";\n}\n\n/**\n * Unified metric-view type-generation pipeline behind {@link\n * generateFromEntryPoint}'s metric section (which forwards its\n * `\"non-blocking\"`/`\"blocking\"` mode). Also directly callable with the default\n * `\"describe-now\"` mode for a focused, always-converge metric refresh.\n *\n *\n * @param options.metricViewsFolder - folder that holds `definitions.json` (`<root>/config/metric-views`).\n * @param options.warehouseId - SQL warehouse used for `DESCRIBE TABLE EXTENDED`.\n * @param options.metricOutFile - output path for the MetricRegistry `.ts` (the\n * generated source carries both the `declare module` augmentation and the\n * runtime `metricViewsMetadata` const).\n * @param options.cache - cache toggle, default ON. Only `cache === false` disables it (so `undefined`/`true` keep caching).\n * @param options.metricFetcher - optional injected {@link DescribeFetcher}\n * @param options.mode - preflight/gate policy, default `\"describe-now\"`. When set to `\"blocking\"`,\n * metric-view `.ts` writes are suppressed if any metric is degraded (to preserve committed files).\n * @param options.suppressDegradedWrite - when true (only in `mode === \"blocking\"` context), skip\n * the metricOutFile write if any metric schema has `degraded === true`. Used to prevent\n * overwriting committed type files with degraded types in blocking mode.\n */\nexport async function syncMetricViewsTypes(options: {\n metricViewsFolder: string;\n warehouseId: string;\n metricOutFile: string;\n cache?: boolean;\n metricFetcher?: DescribeFetcher;\n mode?: \"describe-now\" | \"non-blocking\" | \"blocking\";\n suppressDegradedWrite?: boolean;\n}): Promise<SyncMetricViewsTypesResult> {\n const {\n metricViewsFolder,\n warehouseId,\n metricOutFile,\n cache: cacheEnabled,\n metricFetcher,\n mode = \"describe-now\",\n suppressDegradedWrite,\n } = options;\n\n // Only `cache === false` disables caching; `undefined`/`true` keep it on.\n const noCache = cacheEnabled === false;\n\n const mvConfig = await readMetricConfig(metricViewsFolder);\n if (!mvConfig) {\n // No definitions.json — additive path stays dormant. The CLI turns this\n // into a friendly \"nothing to sync\" message and exits 0;\n // generateFromEntryPoint simply ignores `noConfig`.\n return { schemas: [], failures: [], fatalErrors: [], noConfig: true };\n }\n\n const resolution = resolveMetricConfig(mvConfig);\n\n const fatalErrors: Array<{ name: string; message: string }> = [];\n\n // Load the shared typegen cache and copy its `metrics` section into a null-prototype map.\n const cache = await loadCache();\n const mvCacheSection: Record<string, MetricCacheEntry> = Object.create(null);\n if (!noCache && cache.metrics) {\n for (const key of Object.keys(cache.metrics)) {\n mvCacheSection[key] = cache.metrics[key];\n }\n }\n\n // Partition BEFORE any gate/preflight decision: a hit (a structurally valid,\n // hash-matching, NON-degraded cached entry) is served from cache no matter\n // what the warehouse is doing. The cache only ever holds successful describes\n // (a degraded outcome is never persisted — see the write block below), so the\n // `degraded !== true` guard is normally moot; it also defends against a stale\n // degraded entry left by an older writer, which re-describes instead of\n // serving. Everything else (new, edited, unrevivable, or degraded) is eligible\n // for DESCRIBE, so a fully-warm pass makes zero warehouse calls and constructs\n // zero clients. Mirrors the query path: only a good result is cache-servable.\n const hitSchemas = new Map<string, MetricSchema>();\n const describeNeeded: typeof resolution.entries = [];\n for (const entry of resolution.entries) {\n const prior = mvCacheSection[entry.key];\n if (\n prior !== undefined &&\n isRevivableMetricCacheEntry(prior) &&\n prior.hash === metricCacheHash(entry.source, entry.lane) &&\n prior.schema.degraded !== true\n ) {\n hitSchemas.set(entry.key, prior.schema);\n } else {\n describeNeeded.push(entry);\n }\n }\n\n let mvClient: WorkspaceClient | undefined;\n const getMvClient = (): WorkspaceClient => {\n mvClient ??= createWorkspaceClient();\n return mvClient;\n };\n\n // Blocking-mode preflight: ensure the warehouse is running before the MV DESCRIBE\n // batch (probe → decide → wait / start+wait; only DELETED/DELETING is fatal). Two softenings vs the query preflight: a failed probe and a timed-out wait are NOT fatal here — we fall through to syncMetrics, which classifies a still-not-ready warehouse as degraded rather than failing the build. Skipped for `describe-now`/`non-blocking` (only `mode === \"blocking\"` enters here).\n let preflightFatalMessage: string | undefined;\n let hadEnvironmentalFailure = false;\n let environmentalCause: \"auth\" | \"unreachable\" | \"unavailable\" | undefined;\n if (\n mode === \"blocking\" &&\n metricFetcher === undefined &&\n describeNeeded.length > 0\n ) {\n try {\n const state = await getWarehouseState(getMvClient(), warehouseId);\n const decision = decidePreflight(state, mode);\n if (decision === \"fatal\") {\n preflightFatalMessage = `warehouse ${warehouseId} is ${state}`;\n // State-based DELETED/DELETING is environmental, not deterministic.\n hadEnvironmentalFailure = true;\n environmentalCause = \"unavailable\";\n } else if (decision === \"startWaitProceed\") {\n // treatStoppedAsTransient rides out the stale pre-start STOPPED/STOPPING\n // reading, same as the query preflight.\n await startWarehouse(getMvClient(), warehouseId);\n const settled = await waitUntilRunning(getMvClient(), warehouseId, {\n maxMs: MV_PREFLIGHT_WAIT_MAX_MS,\n treatStoppedAsTransient: true,\n });\n if (settled !== \"RUNNING\") {\n // With treatStoppedAsTransient, a non-RUNNING resolve is exactly\n // DELETED/DELETING — the warehouse was deleted while we waited.\n preflightFatalMessage = `warehouse ${warehouseId} is ${settled}`;\n hadEnvironmentalFailure = true;\n }\n } else if (decision === \"waitThenProceed\") {\n const settled = await waitUntilRunning(getMvClient(), warehouseId, {\n maxMs: MV_PREFLIGHT_WAIT_MAX_MS,\n });\n if (settled === \"DELETED\" || settled === \"DELETING\") {\n // Deleted mid-wait: fatal. Environmental (state-based).\n preflightFatalMessage = `warehouse ${warehouseId} is ${settled}`;\n hadEnvironmentalFailure = true;\n }\n }\n } catch (err) {\n // Connectivity blip: fall through to syncMetrics, whose DESCRIBEs degrade\n // a not-ready / unreachable warehouse rather than throwing.\n if (!isConnectivityError(err)) {\n // Deterministic failures become fatal errors; environmental failures\n // degrade for the committed-types gate.\n const classification = classifyBlockingFailure(err);\n if (classification === \"deterministic\") {\n preflightFatalMessage = `warehouse ${warehouseId}: ${getErrorDiagnostic(err)}`;\n } else {\n preflightFatalMessage = `warehouse ${warehouseId}: ${getErrorDiagnostic(err)}`;\n hadEnvironmentalFailure = true;\n environmentalCause = classifyEnvironmentalCause(err);\n }\n }\n }\n }\n\n let gateState: WarehouseState | undefined;\n let describeNow =\n metricFetcher !== undefined ||\n mode !== \"non-blocking\" ||\n describeNeeded.length === 0;\n if (!describeNow) {\n try {\n gateState = await probeWarehouseState(getMvClient, warehouseId);\n } catch (err) {\n preflightFatalMessage = `warehouse ${warehouseId}: ${getErrorDiagnostic(err)}`;\n }\n describeNow = gateState === \"RUNNING\";\n }\n\n let described: MetricSchema[];\n let failures: MetricSyncFailure[] = [];\n if (preflightFatalMessage !== undefined) {\n // Environmental failures degrade for the committed-types gate; deterministic\n // failures record one fatal error per key. Degraded schemas are not cached.\n described = describeNeeded.map(emptyMetricSchema);\n if (!hadEnvironmentalFailure) {\n for (const entry of describeNeeded) {\n fatalErrors.push({ name: entry.key, message: preflightFatalMessage });\n }\n }\n } else if (describeNeeded.length === 0) {\n // Nothing left to describe — every configured key was a cache hit.\n // syncMetrics would be a no-op (and building its fetcher would construct a\n // client for nothing); artifacts regenerate from cache.\n described = [];\n } else if (describeNow) {\n const fetcher =\n metricFetcher ??\n createWorkspaceDescribeFetcher(getMvClient(), warehouseId);\n ({ schemas: described, failures } = await syncMetrics(\n { entries: describeNeeded },\n fetcher,\n ));\n\n // Surface DESCRIBE failures loudly: a misconfigured definitions.json would\n // otherwise silently ship an empty entry that the runtime fail-closed gate\n // 503s in production. syncMetrics is log-free; this caller is the single\n // owner of failure logging.\n if (failures.length > 0) {\n for (const f of failures) {\n logger.warn(\n \"metric sync failed for %s (%s): %s\",\n f.key,\n f.source,\n f.reason,\n );\n }\n }\n\n // A rejected DESCRIBE with a connectivity signal is expected to recover on\n // a later pass. In blocking mode, route it through the same committed-types\n // gate as preflight outages instead of treating it as a configuration error.\n if (mode === \"blocking\" && failures.some((failure) => failure.transient)) {\n hadEnvironmentalFailure = true;\n environmentalCause = environmentalCause ?? \"unreachable\";\n }\n\n // Degraded-but-not-failed keys: the warehouse answered with a non-terminal\n // state (stopped / cold-starting), so their schemas are unknown.\n const failedKeys = new Set(failures.map((f) => f.key));\n const degradedKeys = described\n .filter((s) => s.degraded && !failedKeys.has(s.key))\n .map((s) => s.key);\n if (degradedKeys.length > 0) {\n logger.info(\n \"Warehouse %s did not return schemas for %d metric view(s) (%s) — wrote degraded metric types (permissive); they will refresh once the warehouse is available.\",\n warehouseId,\n degradedKeys.length,\n degradedKeys.join(\", \"),\n );\n hadEnvironmentalFailure = true;\n environmentalCause = environmentalCause ?? \"unavailable\";\n }\n } else {\n // Un-probed DESCRIBEs emit degraded schemas; cache hits remain last-known-good.\n described = describeNeeded.map(emptyMetricSchema);\n logger.info(\n \"Warehouse %s is not running — wrote degraded metric types (permissive) for %d metric view(s) (%s); they will refresh once the warehouse is available.\",\n warehouseId,\n describeNeeded.length,\n describeNeeded.map((e) => e.key).join(\", \"),\n );\n hadEnvironmentalFailure = true;\n environmentalCause = environmentalCause ?? \"unavailable\";\n }\n\n // Cache only successful schema results for describe-needed keys; remove stale cache for degraded ones.\n for (let i = 0; i < describeNeeded.length; i++) {\n // syncMetrics return one schema per entry in entry order, so described[i] always belongs to describeNeeded[i].\n const entry = describeNeeded[i];\n if (described[i].degraded === true) {\n delete mvCacheSection[entry.key];\n continue;\n }\n mvCacheSection[entry.key] = {\n hash: metricCacheHash(entry.source, entry.lane),\n schema: described[i],\n // Vestigial, mirrors the query path's only cache write (always false): a\n // persisted entry is by construction a good result, so it never needs a\n // re-describe flag. Kept for on-disk shape compatibility with existing\n // version-3 caches (isRevivableMetricCacheEntry gates on a boolean).\n retry: false,\n };\n }\n\n // Prune entries whose key is no longer configured\n const configuredKeys = new Set(resolution.entries.map((e) => e.key));\n let prunedCount = 0;\n for (const key of Object.keys(mvCacheSection)) {\n if (!configuredKeys.has(key)) {\n delete mvCacheSection[key];\n prunedCount++;\n }\n }\n\n // Save when this pass produced outcomes, bypassed the cache, or pruned.\n if (describeNeeded.length > 0 || noCache || prunedCount > 0) {\n cache.metrics = mvCacheSection;\n await saveCache(cache);\n }\n\n // Merge cached hits with fresh results back into config order.\n const describedByKey = new Map<string, MetricSchema>();\n for (const schema of described) {\n describedByKey.set(schema.key, schema);\n }\n const schemas = resolution.entries.map((entry) => {\n const schema = hitSchemas.get(entry.key) ?? describedByKey.get(entry.key);\n if (schema !== undefined) return schema;\n logger.warn(\n \"no schema resolved for metric key %s — emitting degraded types (should not happen)\",\n entry.key,\n );\n return emptyMetricSchema(entry);\n });\n\n // Same anti-clobber rule as the query path: when suppressDegradedWrite is set\n // (blocking mode), skip the write if any metric degraded, preserving the\n // committed metric-views.d.ts. Non-blocking mode always writes.\n const shouldWriteMetrics =\n !suppressDegradedWrite || !hasAnyDegradedMetrics(schemas);\n\n if (shouldWriteMetrics) {\n await fs.mkdir(path.dirname(metricOutFile), { recursive: true });\n await fs.writeFile(\n metricOutFile,\n generateMetricTypeDeclarations(schemas),\n \"utf-8\",\n );\n\n const bundlePath = path.join(metricViewsFolder, METRIC_METADATA_FILE);\n await fs.writeFile(\n bundlePath,\n `${JSON.stringify(buildMetricMetadataBundle(schemas), null, 2)}\\n`,\n \"utf-8\",\n );\n logger.debug(\"Wrote metric metadata bundle to %s\", bundlePath);\n }\n // Sweep the `metric-views.ts` an interim version left behind, which would\n // otherwise duplicate the augmentation the `.d.ts` emits. Skipped unless the\n // replacement was actually written, so a degraded blocking pass leaves an\n // app's only committed metric types in place.\n if (metricOutFile.endsWith(\".d.ts\") && existsSync(metricOutFile)) {\n const staleTs = `${metricOutFile.slice(0, -\".d.ts\".length)}.ts`;\n try {\n await fs.unlink(staleTs);\n logger.debug(\"Removed stale generated types at %s\", staleTs);\n } catch {\n // No stale sibling — nothing to clean up.\n }\n }\n\n logger.debug(\n \"Wrote MetricRegistry augmentation for %d metric(s)%s\",\n schemas.length,\n failures.length > 0 ? ` (${failures.length} failure(s))` : \"\",\n );\n\n return {\n metricOutFile,\n schemas,\n failures,\n fatalErrors,\n noConfig: false,\n hadEnvironmentalFailure:\n mode === \"blocking\" ? hadEnvironmentalFailure : undefined,\n environmentalCause:\n mode === \"blocking\" && hadEnvironmentalFailure\n ? environmentalCause\n : undefined,\n };\n}\n\n// Rolldown tree-shaking only preserves \"own exports\" (locally defined) — not re-exports.\n// A local binding ensures the serving vite plugin's import keeps this in the dependency graph,\n// mirroring how generateFromEntryPoint (also defined here) is preserved via the analytics vite plugin.\nexport const generateServingTypes = generateServingTypesImpl;\n\n// Re-export the mv-registry types so consumers (CLI, the type-generator\n// .d.ts shim in `packages/shared`) can pick them up from this entry point —\n// the .d.ts shim documents these as part of the package's public surface.\nexport type {\n MetricColumnMetadata,\n MetricLane,\n MetricSchema,\n MetricSyncFailure,\n MetricSyncResult,\n};\n\nexport const TYPES_DIR = \"appkit-types\";\nexport const ANALYTICS_TYPES_FILE = \"analytics.d.ts\";\nexport const SERVING_TYPES_FILE = \"serving.d.ts\";\nexport const METRIC_TYPES_FILE = \"metric-views.d.ts\";\n"],"mappings":"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"}
@@ -1,6 +1,5 @@
1
+ import { createWorkspaceClient } from "../shared/src/workspace-client/factory.js";
1
2
  import { createLogger } from "../logging/logger.js";
2
- import { createWorkspaceClient } from "../workspace-client/factory.js";
3
- import "../workspace-client/index.js";
4
3
  import { CACHE_VERSION, hashSQL, loadCache, saveCache } from "./cache.js";
5
4
  import { classifyBlockingFailure, classifyEnvironmentalCause, getErrorDiagnostic, isConnectivityError } from "./errors.js";
6
5
  import { describeAdaptive } from "./statement-result.js";