@databricks/appkit 0.38.1 → 0.40.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 (38) hide show
  1. package/dist/appkit/package.js +1 -1
  2. package/dist/cli/commands/generate-types.js +114 -5
  3. package/dist/cli/commands/generate-types.js.map +1 -1
  4. package/dist/cli/commands/spawn-lock.js +116 -0
  5. package/dist/cli/commands/spawn-lock.js.map +1 -0
  6. package/dist/cli/index.js +1 -1
  7. package/dist/cli/index.js.map +1 -1
  8. package/dist/connectors/index.js +1 -1
  9. package/dist/connectors/sql-warehouse/client.js +168 -1
  10. package/dist/connectors/sql-warehouse/client.js.map +1 -1
  11. package/dist/connectors/sql-warehouse/index.js +1 -1
  12. package/dist/connectors/sql-warehouse/warehouse-poll-backoff.js +24 -0
  13. package/dist/connectors/sql-warehouse/warehouse-poll-backoff.js.map +1 -0
  14. package/dist/connectors/sql-warehouse/warehouse-status-emitter.js +40 -0
  15. package/dist/connectors/sql-warehouse/warehouse-status-emitter.js.map +1 -0
  16. package/dist/plugins/analytics/analytics.d.ts.map +1 -1
  17. package/dist/plugins/analytics/analytics.js +73 -8
  18. package/dist/plugins/analytics/analytics.js.map +1 -1
  19. package/dist/plugins/analytics/manifest.js +17 -5
  20. package/dist/plugins/analytics/types.d.ts +13 -0
  21. package/dist/plugins/analytics/types.d.ts.map +1 -1
  22. package/dist/plugins/analytics/types.js.map +1 -1
  23. package/dist/type-generator/index.js +115 -12
  24. package/dist/type-generator/index.js.map +1 -1
  25. package/dist/type-generator/preflight.js +24 -0
  26. package/dist/type-generator/preflight.js.map +1 -0
  27. package/dist/type-generator/query-registry.js +322 -90
  28. package/dist/type-generator/query-registry.js.map +1 -1
  29. package/dist/type-generator/types.js.map +1 -1
  30. package/dist/type-generator/vite-plugin.d.ts.map +1 -1
  31. package/dist/type-generator/vite-plugin.js +141 -7
  32. package/dist/type-generator/vite-plugin.js.map +1 -1
  33. package/dist/type-generator/warehouse-status.js +116 -0
  34. package/dist/type-generator/warehouse-status.js.map +1 -0
  35. package/docs/development/type-generation.md +13 -0
  36. package/docs/plugins/analytics.md +156 -0
  37. package/package.json +1 -1
  38. package/sbom.cdx.json +1 -1
@@ -2,6 +2,7 @@ import { createLogger } from "../logging/logger.js";
2
2
  import { migrateProjectConfig, removeOldGeneratedTypes, resolveProjectRoot } from "./migration.js";
3
3
  import { generateQueriesFromDescribe } from "./query-registry.js";
4
4
  import { generateServingTypes as generateServingTypes$1 } from "./serving/generator.js";
5
+ import pc from "picocolors";
5
6
  import fs from "node:fs/promises";
6
7
  import path from "node:path";
7
8
  import dotenv from "dotenv";
@@ -9,6 +10,106 @@ import dotenv from "dotenv";
9
10
  //#region src/type-generator/index.ts
10
11
  dotenv.config();
11
12
  const logger = createLogger("type-generator");
13
+ function plural(count, singular, pluralForm = `${singular}s`) {
14
+ return count === 1 ? singular : pluralForm;
15
+ }
16
+ function formatFailureRows(label, queries, color) {
17
+ if (queries.length === 0) return [];
18
+ const byMessage = /* @__PURE__ */ new Map();
19
+ for (const { name, message } of queries) {
20
+ const names = byMessage.get(message);
21
+ if (names) names.push(name);
22
+ else byMessage.set(message, [name]);
23
+ }
24
+ const maxNameLen = Math.max(...queries.map((query) => query.name.length));
25
+ const tag = color(label.padEnd(7));
26
+ const rows = [];
27
+ for (const [message, names] of byMessage) {
28
+ if (names.length === 1) {
29
+ rows.push(` ${tag} ${pc.bold(names[0].padEnd(maxNameLen))} ${pc.dim(message)}`);
30
+ continue;
31
+ }
32
+ rows.push(` ${tag} ${pc.dim(message)} ${pc.dim(`(${names.length} ${plural(names.length, "query", "queries")})`)}`);
33
+ rows.push(` ${names.map((name) => pc.bold(name)).join(pc.dim(", "))}`);
34
+ }
35
+ return rows;
36
+ }
37
+ function formatTypegenFailureMessage(options) {
38
+ const { syntaxErrors, fatalErrors = [], warehouseId, title } = options;
39
+ const total = syntaxErrors.length + fatalErrors.length;
40
+ const separator = pc.dim("─".repeat(60));
41
+ const warehouse = warehouseId ? ` against ${pc.dim(`warehouse ${warehouseId}`)}` : "";
42
+ return [
43
+ ` ${pc.bold(pc.red("Type generation failed"))}`,
44
+ ` ${separator}`,
45
+ ` ${title}: ${total} ${plural(total, "query", "queries")} could not be described${warehouse}.`,
46
+ ` AppKit wrote generated types with ${pc.bold("result: unknown")} for the failed ${plural(total, "query", "queries")}.`,
47
+ "",
48
+ ...formatFailureRows("SQL ERR", syntaxErrors, pc.red),
49
+ ...syntaxErrors.length > 0 && fatalErrors.length > 0 ? [""] : [],
50
+ ...formatFailureRows("FATAL", fatalErrors, pc.red),
51
+ "",
52
+ ` ${pc.bold("Common causes")}`,
53
+ ...options.causes.map((cause) => ` - ${cause}`),
54
+ "",
55
+ ` ${pc.bold("Next step")}`,
56
+ ` ${options.nextStep}`
57
+ ].join("\n");
58
+ }
59
+ /**
60
+ * Thrown when one or more queries fail `DESCRIBE QUERY` against a *reachable*
61
+ * warehouse — i.e. genuine SQL errors (bad table, syntax, incompatible type),
62
+ * as opposed to a connectivity failure (warehouse unreachable), which degrades
63
+ * silently. Whether this is fatal is the caller's decision: the Vite plugin and
64
+ * CLI fail the build in production and warn-only in development.
65
+ */
66
+ var TypegenSyntaxError = class extends Error {
67
+ queries;
68
+ fatalQueries;
69
+ constructor(queries, warehouseId, fatalQueries = []) {
70
+ super(formatTypegenFailureMessage({
71
+ syntaxErrors: queries,
72
+ fatalErrors: fatalQueries,
73
+ warehouseId,
74
+ title: "DESCRIBE QUERY failed",
75
+ causes: [
76
+ "SQL syntax errors",
77
+ "missing tables or views",
78
+ "warehouse format incompatibilities"
79
+ ],
80
+ nextStep: warehouseId ? `Run each SQL ERR query directly in a Databricks SQL editor against warehouse ${pc.bold(warehouseId)}.` : "Run each SQL ERR query directly in a Databricks SQL editor."
81
+ }));
82
+ this.name = "TypegenSyntaxError";
83
+ this.queries = queries;
84
+ this.fatalQueries = fatalQueries;
85
+ }
86
+ };
87
+ /**
88
+ * Thrown when DESCRIBE QUERY could not be requested because of a non-SQL fatal
89
+ * setup/request problem, such as missing permissions, invalid warehouse IDs, or
90
+ * malformed SDK configuration. Like TypegenSyntaxError, this is thrown only
91
+ * after the declaration file has been written with `result: unknown` entries.
92
+ */
93
+ var TypegenFatalError = class extends Error {
94
+ queries;
95
+ constructor(queries, warehouseId) {
96
+ super(formatTypegenFailureMessage({
97
+ syntaxErrors: [],
98
+ fatalErrors: queries,
99
+ warehouseId,
100
+ title: "DESCRIBE QUERY could not be requested",
101
+ causes: [
102
+ "missing warehouse permissions",
103
+ "invalid warehouse ID",
104
+ "authentication failure",
105
+ "SDK configuration errors"
106
+ ],
107
+ nextStep: warehouseId ? `Verify access to warehouse ${pc.bold(warehouseId)} and rerun type generation.` : "Verify warehouse access and rerun type generation."
108
+ }));
109
+ this.name = "TypegenFatalError";
110
+ this.queries = queries;
111
+ }
112
+ };
12
113
  /**
13
114
  * Generate type declarations for QueryRegistry
14
115
  * Create the d.ts file from the plugin routes and query schemas
@@ -37,26 +138,28 @@ declare module "@databricks/appkit-ui/react" {
37
138
  * @param options.querySchemaFile - optional path to query schema file (e.g. config/queries/schema.ts)
38
139
  */
39
140
  async function generateFromEntryPoint(options) {
40
- const { outFile, queryFolder, warehouseId, noCache } = options;
141
+ const { outFile, queryFolder, warehouseId, noCache, mode = "non-blocking" } = options;
41
142
  const projectRoot = resolveProjectRoot(outFile);
42
143
  logger.debug("Starting type generation...");
43
144
  let queryRegistry = [];
44
- if (queryFolder) queryRegistry = await generateQueriesFromDescribe(queryFolder, warehouseId, { noCache });
45
- const failedQueries = queryRegistry.filter((q) => q.type.includes("result: unknown"));
46
- if (failedQueries.length > 0) {
47
- const names = failedQueries.map((q) => q.name).join(", ");
48
- throw new Error([
49
- `Type generation failed: ${failedQueries.length} ${failedQueries.length === 1 ? "query" : "queries"} could not be described: ${names}.`,
50
- `DESCRIBE QUERY failed for these queries — see the error codes above for details.`,
51
- `Common causes: SQL syntax errors, missing tables/views, or warehouse format incompatibilities.`,
52
- `To debug: run the failing query directly in a SQL editor against warehouse ${warehouseId}.`
53
- ].join("\n"));
145
+ let syntaxErrors = [];
146
+ let fatalErrors = [];
147
+ if (queryFolder) {
148
+ const result = await generateQueriesFromDescribe(queryFolder, warehouseId, {
149
+ noCache,
150
+ mode
151
+ });
152
+ queryRegistry = result.schemas;
153
+ syntaxErrors = result.syntaxErrors ?? [];
154
+ fatalErrors = result.fatalErrors ?? [];
54
155
  }
55
156
  const typeDeclarations = generateTypeDeclarations(queryRegistry);
56
157
  await fs.mkdir(path.dirname(outFile), { recursive: true });
57
158
  await fs.writeFile(outFile, typeDeclarations, "utf-8");
58
159
  await removeOldGeneratedTypes(projectRoot, "appKitTypes.d.ts");
59
160
  await migrateProjectConfig(projectRoot);
161
+ if (syntaxErrors.length > 0) throw new TypegenSyntaxError(syntaxErrors, warehouseId, fatalErrors);
162
+ if (fatalErrors.length > 0) throw new TypegenFatalError(fatalErrors, warehouseId);
60
163
  logger.debug("Type generation complete!");
61
164
  }
62
165
  const generateServingTypes = generateServingTypes$1;
@@ -68,5 +171,5 @@ const ANALYTICS_TYPES_FILE = "analytics.d.ts";
68
171
  const SERVING_TYPES_FILE = "serving.d.ts";
69
172
 
70
173
  //#endregion
71
- export { ANALYTICS_TYPES_FILE, SERVING_TYPES_FILE, TYPES_DIR, generateFromEntryPoint, generateServingTypes };
174
+ export { ANALYTICS_TYPES_FILE, SERVING_TYPES_FILE, TYPES_DIR, TypegenFatalError, TypegenSyntaxError, generateFromEntryPoint, generateServingTypes };
72
175
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["generateServingTypesImpl"],"sources":["../../src/type-generator/index.ts"],"sourcesContent":["import fs from \"node:fs/promises\";\nimport path from \"node:path\";\nimport dotenv from \"dotenv\";\nimport { createLogger } from \"../logging/logger\";\nimport {\n migrateProjectConfig,\n removeOldGeneratedTypes,\n resolveProjectRoot,\n} from \"./migration\";\nimport { generateQueriesFromDescribe } from \"./query-registry\";\nimport { generateServingTypes as generateServingTypesImpl } from \"./serving/generator\";\nimport type { QuerySchema } from \"./types\";\n\ndotenv.config();\n\nconst logger = createLogger(\"type-generator\");\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 * 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.querySchemaFile - optional path to query schema file (e.g. config/queries/schema.ts)\n */\nexport async function generateFromEntryPoint(options: {\n outFile: string;\n queryFolder?: string;\n warehouseId: string;\n noCache?: boolean;\n}) {\n const { outFile, queryFolder, warehouseId, noCache } = options;\n const projectRoot = resolveProjectRoot(outFile);\n\n logger.debug(\"Starting type generation...\");\n\n let queryRegistry: QuerySchema[] = [];\n if (queryFolder)\n queryRegistry = await generateQueriesFromDescribe(\n queryFolder,\n warehouseId,\n {\n noCache,\n },\n );\n\n const failedQueries = queryRegistry.filter((q) =>\n q.type.includes(\"result: unknown\"),\n );\n if (failedQueries.length > 0) {\n const names = failedQueries.map((q) => q.name).join(\", \");\n throw new Error(\n [\n `Type generation failed: ${failedQueries.length} ${failedQueries.length === 1 ? \"query\" : \"queries\"} could not be described: ${names}.`,\n `DESCRIBE QUERY failed for these queries — see the error codes above for details.`,\n `Common causes: SQL syntax errors, missing tables/views, or warehouse format incompatibilities.`,\n `To debug: run the failing query directly in a SQL editor against warehouse ${warehouseId}.`,\n ].join(\"\\n\"),\n );\n }\n\n const typeDeclarations = generateTypeDeclarations(queryRegistry);\n\n await fs.mkdir(path.dirname(outFile), { recursive: true });\n await fs.writeFile(outFile, typeDeclarations, \"utf-8\");\n\n // One-time migration: remove old generated file and patch project configs\n await removeOldGeneratedTypes(projectRoot, \"appKitTypes.d.ts\");\n await migrateProjectConfig(projectRoot);\n\n logger.debug(\"Type generation complete!\");\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/** Directory name for generated AppKit type declaration files. */\nexport const TYPES_DIR = \"appkit-types\";\n/** Default filename for analytics query type declarations. */\nexport const ANALYTICS_TYPES_FILE = \"analytics.d.ts\";\n/** Default filename for serving endpoint type declarations. */\nexport const SERVING_TYPES_FILE = \"serving.d.ts\";\n"],"mappings":";;;;;;;;;AAaA,OAAO,QAAQ;AAEf,MAAM,SAAS,aAAa,iBAAiB;;;;;;;AAQ7C,SAAS,yBAAyB,eAA8B,EAAE,EAAU;CAC1E,MAAM,eAAe,aAClB,KAAK,EAAE,MAAM,WAAW;AAKvB,SAAO,OAAO,KAAK,IAJE,KAClB,MAAM,KAAK,CACX,KAAK,MAAM,MAAO,MAAM,IAAI,OAAO,OAAO,OAAQ,CAClD,KAAK,KAAK;GAEb,CACD,KAAK,MAAM;AAId,QAAO;;;;;;6BAFc,eAAe,KAAK,aAAa,SAAS,GAQvB;;;;;;;;;;;AAY1C,eAAsB,uBAAuB,SAK1C;CACD,MAAM,EAAE,SAAS,aAAa,aAAa,YAAY;CACvD,MAAM,cAAc,mBAAmB,QAAQ;AAE/C,QAAO,MAAM,8BAA8B;CAE3C,IAAI,gBAA+B,EAAE;AACrC,KAAI,YACF,iBAAgB,MAAM,4BACpB,aACA,aACA,EACE,SACD,CACF;CAEH,MAAM,gBAAgB,cAAc,QAAQ,MAC1C,EAAE,KAAK,SAAS,kBAAkB,CACnC;AACD,KAAI,cAAc,SAAS,GAAG;EAC5B,MAAM,QAAQ,cAAc,KAAK,MAAM,EAAE,KAAK,CAAC,KAAK,KAAK;AACzD,QAAM,IAAI,MACR;GACE,2BAA2B,cAAc,OAAO,GAAG,cAAc,WAAW,IAAI,UAAU,UAAU,2BAA2B,MAAM;GACrI;GACA;GACA,8EAA8E,YAAY;GAC3F,CAAC,KAAK,KAAK,CACb;;CAGH,MAAM,mBAAmB,yBAAyB,cAAc;AAEhE,OAAM,GAAG,MAAM,KAAK,QAAQ,QAAQ,EAAE,EAAE,WAAW,MAAM,CAAC;AAC1D,OAAM,GAAG,UAAU,SAAS,kBAAkB,QAAQ;AAGtD,OAAM,wBAAwB,aAAa,mBAAmB;AAC9D,OAAM,qBAAqB,YAAY;AAEvC,QAAO,MAAM,4BAA4B;;AAM3C,MAAa,uBAAuBA;;AAGpC,MAAa,YAAY;;AAEzB,MAAa,uBAAuB;;AAEpC,MAAa,qBAAqB"}
1
+ {"version":3,"file":"index.js","names":["generateServingTypesImpl"],"sources":["../../src/type-generator/index.ts"],"sourcesContent":["import fs from \"node:fs/promises\";\nimport path from \"node:path\";\nimport dotenv from \"dotenv\";\nimport pc from \"picocolors\";\nimport { createLogger } from \"../logging/logger\";\nimport {\n migrateProjectConfig,\n removeOldGeneratedTypes,\n resolveProjectRoot,\n} from \"./migration\";\nimport type { PreflightMode } from \"./preflight\";\nimport { generateQueriesFromDescribe } from \"./query-registry\";\nimport { generateServingTypes as generateServingTypesImpl } from \"./serving/generator\";\nimport type { QueryFatalError, QuerySchema, QuerySyntaxError } from \"./types\";\n\ndotenv.config();\n\nconst logger = createLogger(\"type-generator\");\n\ntype TypegenFailure = QuerySyntaxError | QueryFatalError;\n\nfunction plural(count: number, singular: string, pluralForm = `${singular}s`) {\n return count === 1 ? singular : pluralForm;\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 // Unique message → keep the compact one-line `tag name message` form.\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 * 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.querySchemaFile - optional path to query schema file (e.g. config/queries/schema.ts)\n */\nexport async function generateFromEntryPoint(options: {\n outFile: string;\n queryFolder?: string;\n warehouseId: string;\n noCache?: boolean;\n mode?: PreflightMode;\n}) {\n const {\n outFile,\n queryFolder,\n warehouseId,\n noCache,\n mode = \"non-blocking\",\n } = options;\n const projectRoot = resolveProjectRoot(outFile);\n\n logger.debug(\"Starting type generation...\");\n\n let queryRegistry: QuerySchema[] = [];\n let syntaxErrors: QuerySyntaxError[] = [];\n let fatalErrors: QueryFatalError[] = [];\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 }\n\n const typeDeclarations = generateTypeDeclarations(queryRegistry);\n\n await fs.mkdir(path.dirname(outFile), { recursive: true });\n await fs.writeFile(outFile, typeDeclarations, \"utf-8\");\n\n // One-time migration: remove old generated file and patch project configs\n await removeOldGeneratedTypes(projectRoot, \"appKitTypes.d.ts\");\n await migrateProjectConfig(projectRoot);\n\n // Types are always written above — including `result: unknown` for any query\n // that could not be described. Connectivity failures pass silently so a\n // transient warehouse outage never blocks a build; genuine SQL errors and\n // non-connectivity fatal request failures surface after the file write.\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 logger.debug(\"Type generation complete!\");\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/** Directory name for generated AppKit type declaration files. */\nexport const TYPES_DIR = \"appkit-types\";\n/** Default filename for analytics query type declarations. */\nexport const ANALYTICS_TYPES_FILE = \"analytics.d.ts\";\n/** Default filename for serving endpoint type declarations. */\nexport const SERVING_TYPES_FILE = \"serving.d.ts\";\n"],"mappings":"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"}
@@ -0,0 +1,24 @@
1
+ //#region src/type-generator/preflight.ts
2
+ /**
3
+ * Pure policy mapping a warehouse state + mode to a preflight decision.
4
+ *
5
+ * Unknown/unexpected states fall through to `proceed`: the describe loop and
6
+ * its per-query backstop already degrade gracefully, so we don't want a new
7
+ * SDK state value to turn into a spurious `fatal`.
8
+ */
9
+ function decidePreflight(state, mode) {
10
+ if (mode === "non-blocking") return "degradeAll";
11
+ switch (state) {
12
+ case "RUNNING": return "proceed";
13
+ case "STARTING": return "waitThenProceed";
14
+ case "STOPPED":
15
+ case "STOPPING": return "startWaitProceed";
16
+ case "DELETED":
17
+ case "DELETING": return "fatal";
18
+ default: return "proceed";
19
+ }
20
+ }
21
+
22
+ //#endregion
23
+ export { decidePreflight };
24
+ //# sourceMappingURL=preflight.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"preflight.js","names":[],"sources":["../../src/type-generator/preflight.ts"],"sourcesContent":["import type { WarehouseState } from \"./warehouse-status\";\n\n/**\n * How aggressively typegen should react to a not-ready warehouse.\n * - `non-blocking`: never describe and never probe the warehouse — emit\n * best-available types (cache where the SQL hash matches, else `unknown`) and\n * return at once. The default for interactive/foreground runs that can't\n * afford to block on (or fail because of) a warehouse, even a RUNNING one.\n * - `blocking`: a startable warehouse is worth waiting for, and a stopped one\n * is worth starting — only a deleted/deleting warehouse is a hard failure.\n */\nexport type PreflightMode = \"non-blocking\" | \"blocking\";\n\n/**\n * What the caller should do given a warehouse state and mode.\n * - `proceed`: run DESCRIBE now.\n * - `degradeAll`: skip DESCRIBE; emit degraded (cached/`unknown`) types.\n * - `waitThenProceed`: wait for the warehouse to start, then run DESCRIBE.\n * - `startWaitProceed`: start the stopped warehouse, wait for RUNNING, then\n * run DESCRIBE.\n * - `fatal`: stop — the warehouse can't serve this run.\n */\nexport type PreflightDecision =\n | \"proceed\"\n | \"degradeAll\"\n | \"waitThenProceed\"\n | \"startWaitProceed\"\n | \"fatal\";\n\n/**\n * Pure policy mapping a warehouse state + mode to a preflight decision.\n *\n * Unknown/unexpected states fall through to `proceed`: the describe loop and\n * its per-query backstop already degrade gracefully, so we don't want a new\n * SDK state value to turn into a spurious `fatal`.\n */\nexport function decidePreflight(\n state: WarehouseState,\n mode: PreflightMode,\n): PreflightDecision {\n // `non-blocking` never describes regardless of state: emit cached/`unknown`\n // types and return. The caller short-circuits before probing, so this is only\n // a belt-and-suspenders mapping, but it keeps the policy total and\n // self-contained.\n if (mode === \"non-blocking\") return \"degradeAll\";\n\n // `blocking`: a starting warehouse is worth waiting for, a stopped one is\n // worth starting (then waiting), and only a deleted/deleting one is fatal.\n switch (state) {\n case \"RUNNING\":\n return \"proceed\";\n case \"STARTING\":\n return \"waitThenProceed\";\n case \"STOPPED\":\n case \"STOPPING\":\n return \"startWaitProceed\";\n case \"DELETED\":\n case \"DELETING\":\n return \"fatal\";\n default:\n return \"proceed\";\n }\n}\n"],"mappings":";;;;;;;;AAoCA,SAAgB,gBACd,OACA,MACmB;AAKnB,KAAI,SAAS,eAAgB,QAAO;AAIpC,SAAQ,OAAR;EACE,KAAK,UACH,QAAO;EACT,KAAK,WACH,QAAO;EACT,KAAK;EACL,KAAK,WACH,QAAO;EACT,KAAK;EACL,KAAK,WACH,QAAO;EACT,QACE,QAAO"}