@databricks/appkit 0.20.2 → 0.20.3

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 (91) hide show
  1. package/CLAUDE.md +5 -13
  2. package/NOTICE.md +3 -6
  3. package/dist/app/index.js.map +1 -1
  4. package/dist/appkit/package.js +1 -1
  5. package/dist/cli/commands/plugin/add-resource/add-resource.js.map +1 -1
  6. package/dist/connectors/files/client.js.map +1 -1
  7. package/dist/connectors/files/defaults.js +1 -1
  8. package/dist/connectors/files/defaults.js.map +1 -1
  9. package/dist/connectors/files/index.js +1 -1
  10. package/dist/connectors/genie/client.js.map +1 -1
  11. package/dist/connectors/genie/index.d.ts +0 -1
  12. package/dist/connectors/genie/index.js +0 -2
  13. package/dist/connectors/index.js +1 -3
  14. package/dist/connectors/lakebase/index.js.map +1 -1
  15. package/dist/connectors/sql-warehouse/client.js.map +1 -1
  16. package/dist/context/index.d.ts +2 -2
  17. package/dist/context/index.js +0 -1
  18. package/dist/context/index.js.map +1 -1
  19. package/dist/index.d.ts +2 -1
  20. package/dist/logging/index.js +0 -13
  21. package/dist/logging/logger.js.map +1 -1
  22. package/dist/logging/sampling.js.map +1 -1
  23. package/dist/plugins/files/defaults.js +0 -2
  24. package/dist/plugins/files/defaults.js.map +1 -1
  25. package/dist/plugins/files/index.js +0 -1
  26. package/dist/plugins/genie/index.d.ts +1 -1
  27. package/dist/plugins/genie/types.d.ts +1 -1
  28. package/dist/plugins/genie/types.d.ts.map +1 -1
  29. package/dist/plugins/index.d.ts +2 -3
  30. package/dist/plugins/index.js +1 -2
  31. package/dist/plugins/lakebase/index.d.ts +1 -1
  32. package/dist/plugins/lakebase/index.js +1 -1
  33. package/dist/plugins/lakebase/lakebase.d.ts +1 -1
  34. package/dist/plugins/lakebase/lakebase.d.ts.map +1 -1
  35. package/dist/plugins/lakebase/lakebase.js +1 -1
  36. package/dist/plugins/lakebase/lakebase.js.map +1 -1
  37. package/dist/plugins/server/index.js.map +1 -1
  38. package/dist/plugins/server/utils.js.map +1 -1
  39. package/dist/registry/index.d.ts +3 -2
  40. package/dist/registry/manifest-loader.d.ts +4 -3
  41. package/dist/registry/manifest-loader.d.ts.map +1 -1
  42. package/dist/registry/types.d.ts +19 -57
  43. package/dist/registry/types.d.ts.map +1 -1
  44. package/dist/registry/types.generated.d.ts +1 -1
  45. package/dist/registry/types.js +7 -2
  46. package/dist/registry/types.js.map +1 -1
  47. package/dist/schemas/plugin-manifest.generated.d.ts +178 -0
  48. package/dist/schemas/plugin-manifest.generated.d.ts.map +1 -0
  49. package/dist/schemas/plugin-manifest.schema.json +2 -0
  50. package/dist/shared/src/cache.d.ts +1 -1
  51. package/dist/shared/src/execute.d.ts +7 -1
  52. package/dist/shared/src/execute.d.ts.map +1 -1
  53. package/dist/shared/src/index.d.ts +2 -1
  54. package/dist/shared/src/plugin.d.ts +19 -48
  55. package/dist/shared/src/plugin.d.ts.map +1 -1
  56. package/dist/shared/src/schemas/plugin-manifest.generated.d.ts +178 -0
  57. package/dist/shared/src/schemas/plugin-manifest.generated.d.ts.map +1 -0
  58. package/dist/stream/arrow-stream-processor.js.map +1 -1
  59. package/dist/stream/index.d.ts +1 -3
  60. package/dist/stream/index.js +0 -3
  61. package/dist/stream/stream-manager.js +1 -1
  62. package/dist/stream/types.js.map +1 -1
  63. package/dist/telemetry/config.js +1 -0
  64. package/dist/telemetry/config.js.map +1 -1
  65. package/dist/telemetry/index.d.ts +1 -1
  66. package/dist/telemetry/noop.js.map +1 -1
  67. package/dist/telemetry/types.d.ts +1 -1
  68. package/dist/type-generator/query-registry.js.map +1 -1
  69. package/dist/utils/path-exclusions.js.map +1 -1
  70. package/docs/api/appkit/Interface.CacheConfig.md +1 -1
  71. package/docs/api/appkit/Interface.PluginManifest.md +104 -6
  72. package/docs/api/appkit/Interface.ResourceEntry.md +5 -7
  73. package/docs/api/appkit/Interface.ResourceFieldEntry.md +2 -0
  74. package/docs/api/appkit/Interface.ResourceRequirement.md +63 -7
  75. package/docs/api/appkit/Interface.StreamExecutionSettings.md +1 -1
  76. package/docs/api/appkit/TypeAlias.PluginData.md +2 -0
  77. package/docs/api/appkit/TypeAlias.ToPlugin.md +2 -0
  78. package/docs/api/appkit.md +6 -6
  79. package/llms.txt +5 -13
  80. package/package.json +2 -2
  81. package/dist/stream/arrow-stream-processor.d.ts +0 -1
  82. package/dist/stream/buffers.d.ts +0 -1
  83. package/dist/stream/types.d.ts +0 -3
  84. package/docs/api/appkit-ui/data/AreaChart.md +0 -79
  85. package/docs/api/appkit-ui/data/BarChart.md +0 -74
  86. package/docs/api/appkit-ui/data/DonutChart.md +0 -72
  87. package/docs/api/appkit-ui/data/HeatmapChart.md +0 -91
  88. package/docs/api/appkit-ui/data/LineChart.md +0 -77
  89. package/docs/api/appkit-ui/data/PieChart.md +0 -72
  90. package/docs/api/appkit-ui/data/RadarChart.md +0 -74
  91. package/docs/api/appkit-ui/data/ScatterChart.md +0 -76
@@ -1,3 +1 @@
1
- import "./arrow-stream-processor.js";
2
- import { StreamManager } from "./stream-manager.js";
3
- import "./types.js";
1
+ import { StreamManager } from "./stream-manager.js";
@@ -1,6 +1,3 @@
1
- import { ArrowStreamProcessor } from "./arrow-stream-processor.js";
2
- import { streamDefaults } from "./defaults.js";
3
- import { SSEWarningCode } from "./types.js";
4
1
  import { StreamManager } from "./stream-manager.js";
5
2
 
6
3
  export { };
@@ -1,5 +1,5 @@
1
- import { streamDefaults } from "./defaults.js";
2
1
  import { EventRingBuffer } from "./buffers.js";
2
+ import { streamDefaults } from "./defaults.js";
3
3
  import { SSEErrorCode } from "./types.js";
4
4
  import { StreamValidator } from "./validator.js";
5
5
  import { SSEWriter } from "./sse-writer.js";
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","names":[],"sources":["../../src/stream/types.ts"],"sourcesContent":["import type { Context } from \"@opentelemetry/api\";\nimport type { IAppResponse } from \"shared\";\nimport type { EventRingBuffer } from \"./buffers\";\n\nexport const SSEWarningCode = {\n BUFFER_OVERFLOW_RESTART: \"BUFFER_OVERFLOW_RESTART\",\n} as const satisfies Record<string, string>;\n\nexport type SSEWarningCode =\n (typeof SSEWarningCode)[keyof typeof SSEWarningCode];\n\nexport const SSEErrorCode = {\n TEMPORARY_UNAVAILABLE: \"TEMPORARY_UNAVAILABLE\",\n TIMEOUT: \"TIMEOUT\",\n INTERNAL_ERROR: \"INTERNAL_ERROR\",\n INVALID_REQUEST: \"INVALID_REQUEST\",\n STREAM_ABORTED: \"STREAM_ABORTED\",\n STREAM_EVICTED: \"STREAM_EVICTED\",\n} as const satisfies Record<string, string>;\n\nexport type SSEErrorCode = (typeof SSEErrorCode)[keyof typeof SSEErrorCode];\n\nexport interface SSEError {\n error: string;\n code: SSEErrorCode;\n}\n\nexport interface BufferedEvent {\n id: string;\n type: string;\n data: string;\n timestamp: number;\n}\n\nexport interface StreamEntry {\n streamId: string;\n generator: AsyncGenerator<any, void, unknown>;\n eventBuffer: EventRingBuffer;\n clients: Set<IAppResponse>;\n isCompleted: boolean;\n lastAccess: number;\n abortController: AbortController;\n traceContext: Context;\n}\n\nexport interface BufferEntry {\n buffer: EventRingBuffer;\n lastAccess: number;\n}\n\nexport interface StreamOperation {\n controller: AbortController;\n type: \"query\" | \"stream\";\n heartbeat?: NodeJS.Timeout;\n}\n"],"mappings":";AAIA,MAAa,iBAAiB,EAC5B,yBAAyB,2BAC1B;AAKD,MAAa,eAAe;CAC1B,uBAAuB;CACvB,SAAS;CACT,gBAAgB;CAChB,iBAAiB;CACjB,gBAAgB;CAChB,gBAAgB;CACjB"}
1
+ {"version":3,"file":"types.js","names":[],"sources":["../../src/stream/types.ts"],"sourcesContent":["import type { Context } from \"@opentelemetry/api\";\nimport type { IAppResponse } from \"shared\";\nimport type { EventRingBuffer } from \"./buffers\";\n\nexport const SSEWarningCode = {\n BUFFER_OVERFLOW_RESTART: \"BUFFER_OVERFLOW_RESTART\",\n} as const satisfies Record<string, string>;\n\nexport type SSEWarningCode =\n (typeof SSEWarningCode)[keyof typeof SSEWarningCode];\n\nexport const SSEErrorCode = {\n TEMPORARY_UNAVAILABLE: \"TEMPORARY_UNAVAILABLE\",\n TIMEOUT: \"TIMEOUT\",\n INTERNAL_ERROR: \"INTERNAL_ERROR\",\n INVALID_REQUEST: \"INVALID_REQUEST\",\n STREAM_ABORTED: \"STREAM_ABORTED\",\n STREAM_EVICTED: \"STREAM_EVICTED\",\n} as const satisfies Record<string, string>;\n\nexport type SSEErrorCode = (typeof SSEErrorCode)[keyof typeof SSEErrorCode];\n\nexport interface SSEError {\n error: string;\n code: SSEErrorCode;\n}\n\nexport interface BufferedEvent {\n id: string;\n type: string;\n data: string;\n timestamp: number;\n}\n\nexport interface StreamEntry {\n streamId: string;\n generator: AsyncGenerator<any, void, unknown>;\n eventBuffer: EventRingBuffer;\n clients: Set<IAppResponse>;\n isCompleted: boolean;\n lastAccess: number;\n abortController: AbortController;\n traceContext: Context;\n}\n\nexport interface StreamOperation {\n controller: AbortController;\n type: \"query\" | \"stream\";\n heartbeat?: NodeJS.Timeout;\n}\n"],"mappings":";AAIA,MAAa,iBAAiB,EAC5B,yBAAyB,2BAC1B;AAKD,MAAa,eAAe;CAC1B,uBAAuB;CACvB,SAAS;CACT,gBAAgB;CAChB,iBAAiB;CACjB,gBAAgB;CAChB,gBAAgB;CACjB"}
@@ -1,4 +1,5 @@
1
1
  //#region src/telemetry/config.ts
2
+ /** Converts a TelemetryOptions value (boolean, object, or undefined) into a fully resolved config with explicit traces/metrics/logs flags. Defaults to all enabled. */
2
3
  function normalizeTelemetryOptions(config) {
3
4
  if (typeof config === "undefined" || typeof config === "boolean") {
4
5
  const value = config ?? true;
@@ -1 +1 @@
1
- {"version":3,"file":"config.js","names":[],"sources":["../../src/telemetry/config.ts"],"sourcesContent":["import type { TelemetryOptions } from \"shared\";\n\nexport interface TelemetryProviderConfig {\n traces: boolean;\n metrics: boolean;\n logs: boolean;\n}\n\nexport function normalizeTelemetryOptions(\n config?: TelemetryOptions,\n): TelemetryProviderConfig {\n if (typeof config === \"undefined\" || typeof config === \"boolean\") {\n const value = config ?? true;\n return {\n traces: value,\n metrics: value,\n logs: value,\n };\n }\n\n return {\n traces: config?.traces ?? true,\n metrics: config?.metrics ?? true,\n logs: config?.logs ?? true,\n };\n}\n"],"mappings":";AAQA,SAAgB,0BACd,QACyB;AACzB,KAAI,OAAO,WAAW,eAAe,OAAO,WAAW,WAAW;EAChE,MAAM,QAAQ,UAAU;AACxB,SAAO;GACL,QAAQ;GACR,SAAS;GACT,MAAM;GACP;;AAGH,QAAO;EACL,QAAQ,QAAQ,UAAU;EAC1B,SAAS,QAAQ,WAAW;EAC5B,MAAM,QAAQ,QAAQ;EACvB"}
1
+ {"version":3,"file":"config.js","names":[],"sources":["../../src/telemetry/config.ts"],"sourcesContent":["import type { TelemetryOptions } from \"shared\";\n\nexport interface TelemetryProviderConfig {\n traces: boolean;\n metrics: boolean;\n logs: boolean;\n}\n\n/** Converts a TelemetryOptions value (boolean, object, or undefined) into a fully resolved config with explicit traces/metrics/logs flags. Defaults to all enabled. */\nexport function normalizeTelemetryOptions(\n config?: TelemetryOptions,\n): TelemetryProviderConfig {\n if (typeof config === \"undefined\" || typeof config === \"boolean\") {\n const value = config ?? true;\n return {\n traces: value,\n metrics: value,\n logs: value,\n };\n }\n\n return {\n traces: config?.traces ?? true,\n metrics: config?.metrics ?? true,\n logs: config?.logs ?? true,\n };\n}\n"],"mappings":";;AASA,SAAgB,0BACd,QACyB;AACzB,KAAI,OAAO,WAAW,eAAe,OAAO,WAAW,WAAW;EAChE,MAAM,QAAQ,UAAU;AACxB,SAAO;GACL,QAAQ;GACR,SAAS;GACT,MAAM;GACP;;AAGH,QAAO;EACL,QAAQ,QAAQ,UAAU;EAC1B,SAAS,QAAQ,WAAW;EAC5B,MAAM,QAAQ,QAAQ;EACvB"}
@@ -1,6 +1,6 @@
1
1
  import "./config.js";
2
2
  import "./instrumentations.js";
3
- import { ITelemetry, InstrumentConfig, TelemetryConfig } from "./types.js";
3
+ import { ITelemetry, TelemetryConfig } from "./types.js";
4
4
  import "./telemetry-provider.js";
5
5
  import "./telemetry-manager.js";
6
6
  import { Counter, Histogram, Span as Span$1, SpanStatusCode } from "@opentelemetry/api";
@@ -1 +1 @@
1
- {"version":3,"file":"noop.js","names":[],"sources":["../../src/telemetry/noop.ts"],"sourcesContent":["// Our own noop tracer implementation.\n// Why?\n// Unfortunately, noop tracer is not exported from the api package, unlike noop meter and noop logger.\n// Read more: https://github.com/open-telemetry/opentelemetry-js/issues/3455\n// and https://github.com/open-telemetry/opentelemetry-js/issues/4518\n//\n// The original implementation is here: https://github.com/open-telemetry/opentelemetry-js/blob/a7acd9355cd0c1da63d285dfb960efeacc3cbc15/api/src/trace/NoopTracer.ts#L32\n// licensed under the Apache License 2.0.\n// Our own implementation is much simpler but will do the job for our needs.\n\nimport type {\n Context,\n Span,\n SpanContext,\n SpanOptions,\n Tracer,\n} from \"@opentelemetry/api\";\nimport {\n createNoopMeter,\n INVALID_SPAN_CONTEXT,\n type SpanStatusCode,\n} from \"@opentelemetry/api\";\n\nclass NonRecordingSpan implements Span {\n private readonly _spanContext: SpanContext;\n\n constructor(spanContext: SpanContext = INVALID_SPAN_CONTEXT) {\n this._spanContext = spanContext;\n }\n\n spanContext(): SpanContext {\n return this._spanContext;\n }\n\n setAttribute(_key: string, _value: any): this {\n return this;\n }\n\n setAttributes(_attributes: any): this {\n return this;\n }\n\n addEvent(\n _name: string,\n _attributesOrStartTime?: any,\n _startTime?: any,\n ): this {\n return this;\n }\n\n addLink(_link: any): this {\n return this;\n }\n\n addLinks(_links: any[]): this {\n return this;\n }\n\n setStatus(_status: { code: SpanStatusCode; message?: string }): this {\n return this;\n }\n\n updateName(_name: string): this {\n return this;\n }\n\n end(_endTime?: number): void {}\n\n isRecording(): boolean {\n return false;\n }\n\n recordException(_exception: any, _time?: number): void {}\n}\n\nexport class NoopTracer implements Tracer {\n startSpan(_name: string, _options?: SpanOptions, _context?: Context): Span {\n return new NonRecordingSpan(INVALID_SPAN_CONTEXT);\n }\n\n startActiveSpan<F extends (span: Span) => any>(\n _name: string,\n ...args: [F] | [SpanOptions, F] | [SpanOptions, Context, F]\n ): ReturnType<F> | undefined {\n const fn = args[args.length - 1] as F;\n\n if (typeof fn !== \"function\") {\n return undefined as ReturnType<F>;\n }\n\n return fn(new NonRecordingSpan(INVALID_SPAN_CONTEXT));\n }\n}\n\nexport const NOOP_TRACER = new NoopTracer();\nexport const NOOP_METER = createNoopMeter();\nexport { NOOP_LOGGER } from \"@opentelemetry/api-logs\";\n"],"mappings":";;;;AAuBA,IAAM,mBAAN,MAAuC;CACrC,AAAiB;CAEjB,YAAY,cAA2B,sBAAsB;AAC3D,OAAK,eAAe;;CAGtB,cAA2B;AACzB,SAAO,KAAK;;CAGd,aAAa,MAAc,QAAmB;AAC5C,SAAO;;CAGT,cAAc,aAAwB;AACpC,SAAO;;CAGT,SACE,OACA,wBACA,YACM;AACN,SAAO;;CAGT,QAAQ,OAAkB;AACxB,SAAO;;CAGT,SAAS,QAAqB;AAC5B,SAAO;;CAGT,UAAU,SAA2D;AACnE,SAAO;;CAGT,WAAW,OAAqB;AAC9B,SAAO;;CAGT,IAAI,UAAyB;CAE7B,cAAuB;AACrB,SAAO;;CAGT,gBAAgB,YAAiB,OAAsB;;AAGzD,IAAa,aAAb,MAA0C;CACxC,UAAU,OAAe,UAAwB,UAA0B;AACzE,SAAO,IAAI,iBAAiB,qBAAqB;;CAGnD,gBACE,OACA,GAAG,MACwB;EAC3B,MAAM,KAAK,KAAK,KAAK,SAAS;AAE9B,MAAI,OAAO,OAAO,WAChB;AAGF,SAAO,GAAG,IAAI,iBAAiB,qBAAqB,CAAC;;;AAIzD,MAAa,cAAc,IAAI,YAAY;AAC3C,MAAa,aAAa,iBAAiB"}
1
+ {"version":3,"file":"noop.js","names":[],"sources":["../../src/telemetry/noop.ts"],"sourcesContent":["// Our own noop tracer implementation.\n// Why?\n// Unfortunately, noop tracer is not exported from the api package, unlike noop meter and noop logger.\n// Read more: https://github.com/open-telemetry/opentelemetry-js/issues/3455\n// and https://github.com/open-telemetry/opentelemetry-js/issues/4518\n//\n// The original implementation is here: https://github.com/open-telemetry/opentelemetry-js/blob/a7acd9355cd0c1da63d285dfb960efeacc3cbc15/api/src/trace/NoopTracer.ts#L32\n// licensed under the Apache License 2.0.\n// Our own implementation is much simpler but will do the job for our needs.\n\nimport type {\n Context,\n Span,\n SpanContext,\n SpanOptions,\n Tracer,\n} from \"@opentelemetry/api\";\nimport {\n createNoopMeter,\n INVALID_SPAN_CONTEXT,\n type SpanStatusCode,\n} from \"@opentelemetry/api\";\n\nclass NonRecordingSpan implements Span {\n private readonly _spanContext: SpanContext;\n\n constructor(spanContext: SpanContext = INVALID_SPAN_CONTEXT) {\n this._spanContext = spanContext;\n }\n\n spanContext(): SpanContext {\n return this._spanContext;\n }\n\n setAttribute(_key: string, _value: any): this {\n return this;\n }\n\n setAttributes(_attributes: any): this {\n return this;\n }\n\n addEvent(\n _name: string,\n _attributesOrStartTime?: any,\n _startTime?: any,\n ): this {\n return this;\n }\n\n addLink(_link: any): this {\n return this;\n }\n\n addLinks(_links: any[]): this {\n return this;\n }\n\n setStatus(_status: { code: SpanStatusCode; message?: string }): this {\n return this;\n }\n\n updateName(_name: string): this {\n return this;\n }\n\n end(_endTime?: number): void {}\n\n isRecording(): boolean {\n return false;\n }\n\n recordException(_exception: any, _time?: number): void {}\n}\n\nclass NoopTracer implements Tracer {\n startSpan(_name: string, _options?: SpanOptions, _context?: Context): Span {\n return new NonRecordingSpan(INVALID_SPAN_CONTEXT);\n }\n\n startActiveSpan<F extends (span: Span) => any>(\n _name: string,\n ...args: [F] | [SpanOptions, F] | [SpanOptions, Context, F]\n ): ReturnType<F> | undefined {\n const fn = args[args.length - 1] as F;\n\n if (typeof fn !== \"function\") {\n return undefined as ReturnType<F>;\n }\n\n return fn(new NonRecordingSpan(INVALID_SPAN_CONTEXT));\n }\n}\n\nexport const NOOP_TRACER = new NoopTracer();\nexport const NOOP_METER = createNoopMeter();\nexport { NOOP_LOGGER } from \"@opentelemetry/api-logs\";\n"],"mappings":";;;;AAuBA,IAAM,mBAAN,MAAuC;CACrC,AAAiB;CAEjB,YAAY,cAA2B,sBAAsB;AAC3D,OAAK,eAAe;;CAGtB,cAA2B;AACzB,SAAO,KAAK;;CAGd,aAAa,MAAc,QAAmB;AAC5C,SAAO;;CAGT,cAAc,aAAwB;AACpC,SAAO;;CAGT,SACE,OACA,wBACA,YACM;AACN,SAAO;;CAGT,QAAQ,OAAkB;AACxB,SAAO;;CAGT,SAAS,QAAqB;AAC5B,SAAO;;CAGT,UAAU,SAA2D;AACnE,SAAO;;CAGT,WAAW,OAAqB;AAC9B,SAAO;;CAGT,IAAI,UAAyB;CAE7B,cAAuB;AACrB,SAAO;;CAGT,gBAAgB,YAAiB,OAAsB;;AAGzD,IAAM,aAAN,MAAmC;CACjC,UAAU,OAAe,UAAwB,UAA0B;AACzE,SAAO,IAAI,iBAAiB,qBAAqB;;CAGnD,gBACE,OACA,GAAG,MACwB;EAC3B,MAAM,KAAK,KAAK,KAAK,SAAS;AAE9B,MAAI,OAAO,OAAO,WAChB;AAGF,SAAO,GAAG,IAAI,iBAAiB,qBAAqB,CAAC;;;AAIzD,MAAa,cAAc,IAAI,YAAY;AAC3C,MAAa,aAAa,iBAAiB"}
@@ -71,5 +71,5 @@ interface ITelemetry {
71
71
  registerInstrumentations(instrumentations: Instrumentation[]): void;
72
72
  }
73
73
  //#endregion
74
- export { ITelemetry, InstrumentConfig, TelemetryConfig };
74
+ export { ITelemetry, TelemetryConfig };
75
75
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"query-registry.js","names":[],"sources":["../../src/type-generator/query-registry.ts"],"sourcesContent":["import fs from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { WorkspaceClient } from \"@databricks/sdk-experimental\";\nimport pc from \"picocolors\";\nimport { createLogger } from \"../logging/logger\";\nimport { CACHE_VERSION, hashSQL, loadCache, saveCache } from \"./cache\";\nimport { Spinner } from \"./spinner\";\nimport {\n type DatabricksStatementExecutionResponse,\n type QuerySchema,\n sqlTypeToHelper,\n sqlTypeToMarker,\n} from \"./types\";\n\nconst logger = createLogger(\"type-generator:query-registry\");\n\n/**\n * Parse a raw API/SDK error into a structured code + message.\n * Handles Databricks-style JSON bodies embedded in the message string,\n * e.g. `Response from server (Bad Request) {\"error_code\":\"...\",\"message\":\"...\"}`.\n */\nfunction parseError(raw: string): { code?: string; message: string } {\n const jsonMatch = raw.match(/\\{[\\s\\S]*\\}/);\n if (jsonMatch) {\n try {\n const parsed = JSON.parse(jsonMatch[0]);\n if (parsed.error_code || parsed.message) {\n return {\n code: parsed.error_code,\n message: parsed.message || raw,\n };\n }\n } catch {\n // not valid JSON, fall through\n }\n }\n return { message: raw };\n}\n\n/**\n * Extract parameters from a SQL query\n * @param sql - the SQL query to extract parameters from\n * @returns an array of parameter names\n */\nexport function extractParameters(sql: string): string[] {\n const matches = sql.matchAll(/:([a-zA-Z_]\\w*)/g);\n const params = new Set<string>();\n for (const match of matches) {\n params.add(match[1]);\n }\n return Array.from(params);\n}\n\n// parameters that are injected by the server\nexport const SERVER_INJECTED_PARAMS = [\"workspaceId\"];\n\n/**\n * Generates the TypeScript type literal for query parameters from SQL.\n * Shared by both the success and failure paths.\n */\nfunction formatParametersType(sql: string): string {\n const params = extractParameters(sql).filter(\n (p) => !SERVER_INJECTED_PARAMS.includes(p),\n );\n const paramTypes = extractParameterTypes(sql);\n\n return params.length > 0\n ? `{\\n ${params\n .map((p) => {\n const sqlType = paramTypes[p];\n const markerType = sqlType\n ? sqlTypeToMarker[sqlType]\n : \"SQLTypeMarker\";\n const helper = sqlType ? sqlTypeToHelper[sqlType] : \"sql.*()\";\n return `/** ${sqlType || \"any\"} - use ${helper} */\\n ${p}: ${markerType}`;\n })\n .join(\";\\n \")};\\n }`\n : \"Record<string, never>\";\n}\n\nexport function convertToQueryType(\n result: DatabricksStatementExecutionResponse,\n sql: string,\n queryName: string,\n): { type: string; hasResults: boolean } {\n const dataRows = result.result?.data_array || [];\n const columns = dataRows.map((row) => ({\n name: row[0] || \"\",\n type_name: row[1]?.toUpperCase() || \"STRING\",\n comment: row[2] || undefined,\n }));\n\n const paramsType = formatParametersType(sql);\n\n // generate result fields with JSDoc\n const resultFields = columns.map((column) => {\n const normalizedType = normalizeTypeName(column.type_name);\n const mappedType = typeMap[normalizedType] || \"unknown\";\n // validate column name is a valid identifier\n const name = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(column.name)\n ? column.name\n : `\"${column.name}\"`;\n\n // generate comment for column\n const comment = column.comment\n ? `/** ${column.comment} */\\n `\n : `/** @sqlType ${column.type_name} */\\n `;\n\n return `${comment}${name}: ${mappedType}`;\n });\n\n const hasResults = resultFields.length > 0;\n\n const type = `{\n name: \"${queryName}\";\n parameters: ${paramsType};\n result: ${\n hasResults\n ? `Array<{\n ${resultFields.join(\";\\n \")};\n }>`\n : \"unknown\"\n };\n }`;\n\n return { type, hasResults };\n}\n\n/**\n * Used when DESCRIBE QUERY fails so the query still appears in QueryRegistry.\n * Generates a type with unknown result from SQL alone (no warehouse call).\n */\nfunction generateUnknownResultQuery(sql: string, queryName: string): string {\n const paramsType = formatParametersType(sql);\n\n return `{\n name: \"${queryName}\";\n parameters: ${paramsType};\n result: unknown;\n }`;\n}\n\nexport function extractParameterTypes(sql: string): Record<string, string> {\n const paramTypes: Record<string, string> = {};\n const regex =\n /--\\s*@param\\s+(\\w+)\\s+(STRING|NUMERIC|BOOLEAN|DATE|TIMESTAMP|BINARY)/gi;\n const matches = sql.matchAll(regex);\n for (const match of matches) {\n const [, paramName, paramType] = match;\n paramTypes[paramName] = paramType.toUpperCase();\n }\n\n return paramTypes;\n}\n\n/**\n * Generate query schemas from a folder of SQL files\n * It uses DESCRIBE QUERY to get the schema without executing the query\n * @param queryFolder - the folder containing the SQL files\n * @param warehouseId - the warehouse id to use for schema analysis\n * @param options - options for the query generation\n * @param options.noCache - if true, skip the cache and regenerate all types\n * @returns an array of query schemas\n */\nexport async function generateQueriesFromDescribe(\n queryFolder: string,\n warehouseId: string,\n options: { noCache?: boolean; concurrency?: number } = {},\n): Promise<QuerySchema[]> {\n const { noCache = false, concurrency: rawConcurrency = 10 } = options;\n const concurrency =\n typeof rawConcurrency === \"number\" && Number.isFinite(rawConcurrency)\n ? Math.max(1, Math.floor(rawConcurrency))\n : 10;\n\n // read all query files and cache in parallel\n const [allFiles, cache] = await Promise.all([\n fs.readdir(queryFolder),\n noCache\n ? ({ version: CACHE_VERSION, queries: {} } as Awaited<\n ReturnType<typeof loadCache>\n >)\n : loadCache(),\n ]);\n\n const queryFiles = allFiles.filter((file) => file.endsWith(\".sql\"));\n logger.debug(\"Found %d SQL queries\", queryFiles.length);\n\n const client = new WorkspaceClient({});\n const spinner = new Spinner();\n\n // Read all SQL files in parallel\n const sqlContents = await Promise.all(\n queryFiles.map((file) => fs.readFile(path.join(queryFolder, file), \"utf8\")),\n );\n\n const startTime = performance.now();\n\n // Phase 1: Check cache, separate cached vs uncached\n const cachedResults: Array<{ index: number; schema: QuerySchema }> = [];\n const uncachedQueries: Array<{\n index: number;\n queryName: string;\n sql: string;\n sqlHash: string;\n cleanedSql: string;\n }> = [];\n const logEntries: Array<{\n queryName: string;\n status: \"HIT\" | \"MISS\";\n failed?: boolean;\n error?: { code?: string; message: string };\n }> = [];\n\n for (let i = 0; i < queryFiles.length; i++) {\n const file = queryFiles[i];\n const rawName = path.basename(file, \".sql\");\n const queryName = normalizeQueryName(rawName);\n\n const sql = sqlContents[i];\n const sqlHash = hashSQL(sql);\n\n const cached = cache.queries[queryName];\n if (cached && cached.hash === sqlHash && !cached.retry) {\n cachedResults.push({\n index: i,\n schema: { name: queryName, type: cached.type },\n });\n logEntries.push({ queryName, status: \"HIT\" });\n } else {\n const sqlWithDefaults = sql.replace(/:([a-zA-Z_]\\w*)/g, \"''\");\n const cleanedSql = sqlWithDefaults.trim().replace(/;\\s*$/, \"\");\n uncachedQueries.push({ index: i, queryName, sql, sqlHash, cleanedSql });\n }\n }\n\n // Phase 2: Execute all uncached DESCRIBE calls in parallel\n type DescribeResult =\n | {\n status: \"ok\";\n index: number;\n schema: QuerySchema;\n cacheEntry: { hash: string; type: string; retry: boolean };\n }\n | {\n status: \"fail\";\n index: number;\n schema: QuerySchema;\n cacheEntry: { hash: string; type: string; retry: boolean };\n error: { code?: string; message: string };\n };\n\n const freshResults: Array<{ index: number; schema: QuerySchema }> = [];\n\n if (uncachedQueries.length > 0) {\n let completed = 0;\n const total = uncachedQueries.length;\n spinner.start(\n `Describing ${total} ${total === 1 ? \"query\" : \"queries\"} (0/${total})`,\n );\n\n const describeOne = async ({\n index,\n queryName,\n sql,\n sqlHash,\n cleanedSql,\n }: (typeof uncachedQueries)[number]): Promise<DescribeResult> => {\n const result = (await client.statementExecution.executeStatement({\n statement: `DESCRIBE QUERY ${cleanedSql}`,\n warehouse_id: warehouseId,\n })) as DatabricksStatementExecutionResponse;\n\n completed++;\n spinner.update(\n `Describing ${total} ${total === 1 ? \"query\" : \"queries\"} (${completed}/${total})`,\n );\n\n logger.debug(\n \"DESCRIBE result for %s: state=%s, rows=%d\",\n queryName,\n result.status.state,\n result.result?.data_array?.length ?? 0,\n );\n\n if (result.status.state === \"FAILED\") {\n const sqlError =\n result.status.error?.message || \"Query execution failed\";\n logger.warn(\"DESCRIBE failed for %s: %s\", queryName, sqlError);\n const type = generateUnknownResultQuery(sql, queryName);\n return {\n status: \"fail\",\n index,\n schema: { name: queryName, type },\n cacheEntry: { hash: sqlHash, type, retry: true },\n error: parseError(sqlError),\n };\n }\n\n const { type, hasResults } = convertToQueryType(result, sql, queryName);\n return {\n status: \"ok\",\n index,\n schema: { name: queryName, type },\n cacheEntry: { hash: sqlHash, type, retry: !hasResults },\n };\n };\n\n // Process in chunks, saving cache after each chunk\n const processBatchResults = (\n settled: PromiseSettledResult<DescribeResult>[],\n batchOffset: number,\n ) => {\n for (let i = 0; i < settled.length; i++) {\n const entry = settled[i];\n const { queryName } = uncachedQueries[batchOffset + i];\n\n if (entry.status === \"fulfilled\") {\n const res = entry.value;\n freshResults.push({ index: res.index, schema: res.schema });\n cache.queries[queryName] = res.cacheEntry;\n logEntries.push({\n queryName,\n status: \"MISS\",\n failed: res.status === \"fail\",\n error: res.status === \"fail\" ? res.error : undefined,\n });\n } else {\n const { sql, sqlHash, index } = uncachedQueries[batchOffset + i];\n const reason =\n entry.reason instanceof Error\n ? entry.reason.message\n : String(entry.reason);\n logger.warn(\"DESCRIBE rejected for %s: %s\", queryName, reason);\n const type = generateUnknownResultQuery(sql, queryName);\n freshResults.push({ index, schema: { name: queryName, type } });\n cache.queries[queryName] = { hash: sqlHash, type, retry: true };\n logEntries.push({\n queryName,\n status: \"MISS\",\n failed: true,\n error: parseError(reason),\n });\n }\n }\n };\n\n if (uncachedQueries.length > concurrency) {\n for (let b = 0; b < uncachedQueries.length; b += concurrency) {\n const batch = uncachedQueries.slice(b, b + concurrency);\n const batchResults = await Promise.allSettled(batch.map(describeOne));\n processBatchResults(batchResults, b);\n await saveCache(cache);\n }\n } else {\n const settled = await Promise.allSettled(\n uncachedQueries.map(describeOne),\n );\n processBatchResults(settled, 0);\n await saveCache(cache);\n }\n\n spinner.stop(\"\");\n }\n\n const elapsed = ((performance.now() - startTime) / 1000).toFixed(2);\n\n // Print formatted table\n if (logEntries.length > 0) {\n const maxNameLen = Math.max(...logEntries.map((e) => e.queryName.length));\n const separator = pc.dim(\"─\".repeat(50));\n console.log(\"\");\n console.log(\n ` ${pc.bold(\"Typegen Queries\")} ${pc.dim(`(${logEntries.length})`)}`,\n );\n console.log(` ${separator}`);\n for (const entry of logEntries) {\n const tag = entry.failed\n ? pc.bold(pc.red(\"ERROR\"))\n : entry.status === \"HIT\"\n ? `cache ${pc.bold(pc.green(\"HIT \"))}`\n : `cache ${pc.bold(pc.yellow(\"MISS \"))}`;\n const rawName = entry.queryName.padEnd(maxNameLen);\n const name = entry.failed ? pc.dim(pc.strikethrough(rawName)) : rawName;\n const errorCode = entry.error?.message.match(/\\[([^\\]]+)\\]/)?.[1];\n const reason = errorCode ? ` ${pc.dim(errorCode)}` : \"\";\n console.log(` ${tag} ${name}${reason}`);\n }\n const newCount = logEntries.filter(\n (e) => e.status === \"MISS\" && !e.failed,\n ).length;\n const cacheCount = logEntries.filter(\n (e) => e.status === \"HIT\" && !e.failed,\n ).length;\n const errorCount = logEntries.filter((e) => e.failed).length;\n console.log(` ${separator}`);\n const parts = [`${newCount} new`, `${cacheCount} from cache`];\n if (errorCount > 0)\n parts.push(`${errorCount} ${errorCount === 1 ? \"error\" : \"errors\"}`);\n console.log(` ${parts.join(\", \")}. ${pc.dim(`${elapsed}s`)}`);\n console.log(\"\");\n }\n\n // Merge and sort by original file index for deterministic output\n return [...cachedResults, ...freshResults]\n .sort((a, b) => a.index - b.index)\n .map((r) => r.schema);\n}\n\n/**\n * Normalize query name by removing the .obo extension\n * @param queryName - the query name to normalize\n * @returns the normalized query name\n */\nexport function normalizeQueryName(fileName: string): string {\n return fileName.replace(/\\.obo$/, \"\");\n}\n\n/**\n * Normalize SQL type name by removing parameters/generics\n * Examples:\n * DECIMAL(38,6) -> DECIMAL\n * ARRAY<STRING> -> ARRAY\n * MAP<STRING,INT> -> MAP\n * STRUCT<name:STRING> -> STRUCT\n * INTERVAL DAY TO SECOND -> INTERVAL\n * GEOGRAPHY(4326) -> GEOGRAPHY\n */\nexport function normalizeTypeName(typeName: string): string {\n return typeName\n .replace(/\\(.*\\)$/, \"\") // remove (p, s) eg: DECIMAL(38,6) -> DECIMAL\n .replace(/<.*>$/, \"\") // remove <T> eg: ARRAY<STRING> -> ARRAY\n .split(\" \")[0]; // take first word eg: INTERVAL DAY TO SECOND -> INTERVAL\n}\n\n/** Type Map for Databricks data types to JavaScript types */\nconst typeMap: Record<string, string> = {\n // string types\n STRING: \"string\",\n BINARY: \"string\",\n // boolean\n BOOLEAN: \"boolean\",\n // numeric types\n TINYINT: \"number\",\n SMALLINT: \"number\",\n INT: \"number\",\n BIGINT: \"number\",\n FLOAT: \"number\",\n DOUBLE: \"number\",\n DECIMAL: \"number\",\n // date/time types\n DATE: \"string\",\n TIMESTAMP: \"string\",\n TIMESTAMP_NTZ: \"string\",\n INTERVAL: \"string\",\n // complex types\n ARRAY: \"unknown[]\",\n MAP: \"Record<string, unknown>\",\n STRUCT: \"Record<string, unknown>\",\n OBJECT: \"Record<string, unknown>\",\n VARIANT: \"unknown\",\n // spatial types\n GEOGRAPHY: \"unknown\",\n GEOMETRY: \"unknown\",\n // null type\n VOID: \"null\",\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"query-registry.js","names":[],"sources":["../../src/type-generator/query-registry.ts"],"sourcesContent":["import fs from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { WorkspaceClient } from \"@databricks/sdk-experimental\";\nimport pc from \"picocolors\";\nimport { createLogger } from \"../logging/logger\";\nimport { CACHE_VERSION, hashSQL, loadCache, saveCache } from \"./cache\";\nimport { Spinner } from \"./spinner\";\nimport {\n type DatabricksStatementExecutionResponse,\n type QuerySchema,\n sqlTypeToHelper,\n sqlTypeToMarker,\n} from \"./types\";\n\nconst logger = createLogger(\"type-generator:query-registry\");\n\n/**\n * Parse a raw API/SDK error into a structured code + message.\n * Handles Databricks-style JSON bodies embedded in the message string,\n * e.g. `Response from server (Bad Request) {\"error_code\":\"...\",\"message\":\"...\"}`.\n */\nfunction parseError(raw: string): { code?: string; message: string } {\n const jsonMatch = raw.match(/\\{[\\s\\S]*\\}/);\n if (jsonMatch) {\n try {\n const parsed = JSON.parse(jsonMatch[0]);\n if (parsed.error_code || parsed.message) {\n return {\n code: parsed.error_code,\n message: parsed.message || raw,\n };\n }\n } catch {\n // not valid JSON, fall through\n }\n }\n return { message: raw };\n}\n\n/**\n * Extract parameters from a SQL query\n * @param sql - the SQL query to extract parameters from\n * @returns an array of parameter names\n */\nexport function extractParameters(sql: string): string[] {\n const matches = sql.matchAll(/:([a-zA-Z_]\\w*)/g);\n const params = new Set<string>();\n for (const match of matches) {\n params.add(match[1]);\n }\n return Array.from(params);\n}\n\n// parameters that are injected by the server\nexport const SERVER_INJECTED_PARAMS = [\"workspaceId\"];\n\n/**\n * Generates the TypeScript type literal for query parameters from SQL.\n * Shared by both the success and failure paths.\n */\nfunction formatParametersType(sql: string): string {\n const params = extractParameters(sql).filter(\n (p) => !SERVER_INJECTED_PARAMS.includes(p),\n );\n const paramTypes = extractParameterTypes(sql);\n\n return params.length > 0\n ? `{\\n ${params\n .map((p) => {\n const sqlType = paramTypes[p];\n const markerType = sqlType\n ? sqlTypeToMarker[sqlType]\n : \"SQLTypeMarker\";\n const helper = sqlType ? sqlTypeToHelper[sqlType] : \"sql.*()\";\n return `/** ${sqlType || \"any\"} - use ${helper} */\\n ${p}: ${markerType}`;\n })\n .join(\";\\n \")};\\n }`\n : \"Record<string, never>\";\n}\n\nexport function convertToQueryType(\n result: DatabricksStatementExecutionResponse,\n sql: string,\n queryName: string,\n): { type: string; hasResults: boolean } {\n const dataRows = result.result?.data_array || [];\n const columns = dataRows.map((row) => ({\n name: row[0] || \"\",\n type_name: row[1]?.toUpperCase() || \"STRING\",\n comment: row[2] || undefined,\n }));\n\n const paramsType = formatParametersType(sql);\n\n // generate result fields with JSDoc\n const resultFields = columns.map((column) => {\n const normalizedType = normalizeTypeName(column.type_name);\n const mappedType = typeMap[normalizedType] || \"unknown\";\n // validate column name is a valid identifier\n const name = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(column.name)\n ? column.name\n : `\"${column.name}\"`;\n\n // generate comment for column\n const comment = column.comment\n ? `/** ${column.comment} */\\n `\n : `/** @sqlType ${column.type_name} */\\n `;\n\n return `${comment}${name}: ${mappedType}`;\n });\n\n const hasResults = resultFields.length > 0;\n\n const type = `{\n name: \"${queryName}\";\n parameters: ${paramsType};\n result: ${\n hasResults\n ? `Array<{\n ${resultFields.join(\";\\n \")};\n }>`\n : \"unknown\"\n };\n }`;\n\n return { type, hasResults };\n}\n\n/**\n * Used when DESCRIBE QUERY fails so the query still appears in QueryRegistry.\n * Generates a type with unknown result from SQL alone (no warehouse call).\n */\nfunction generateUnknownResultQuery(sql: string, queryName: string): string {\n const paramsType = formatParametersType(sql);\n\n return `{\n name: \"${queryName}\";\n parameters: ${paramsType};\n result: unknown;\n }`;\n}\n\nexport function extractParameterTypes(sql: string): Record<string, string> {\n const paramTypes: Record<string, string> = {};\n const regex =\n /--\\s*@param\\s+(\\w+)\\s+(STRING|NUMERIC|BOOLEAN|DATE|TIMESTAMP|BINARY)/gi;\n const matches = sql.matchAll(regex);\n for (const match of matches) {\n const [, paramName, paramType] = match;\n paramTypes[paramName] = paramType.toUpperCase();\n }\n\n return paramTypes;\n}\n\n/**\n * Generate query schemas from a folder of SQL files\n * It uses DESCRIBE QUERY to get the schema without executing the query\n * @param queryFolder - the folder containing the SQL files\n * @param warehouseId - the warehouse id to use for schema analysis\n * @param options - options for the query generation\n * @param options.noCache - if true, skip the cache and regenerate all types\n * @returns an array of query schemas\n */\nexport async function generateQueriesFromDescribe(\n queryFolder: string,\n warehouseId: string,\n options: { noCache?: boolean; concurrency?: number } = {},\n): Promise<QuerySchema[]> {\n const { noCache = false, concurrency: rawConcurrency = 10 } = options;\n const concurrency =\n typeof rawConcurrency === \"number\" && Number.isFinite(rawConcurrency)\n ? Math.max(1, Math.floor(rawConcurrency))\n : 10;\n\n // read all query files and cache in parallel\n const [allFiles, cache] = await Promise.all([\n fs.readdir(queryFolder),\n noCache\n ? ({ version: CACHE_VERSION, queries: {} } as Awaited<\n ReturnType<typeof loadCache>\n >)\n : loadCache(),\n ]);\n\n const queryFiles = allFiles.filter((file) => file.endsWith(\".sql\"));\n logger.debug(\"Found %d SQL queries\", queryFiles.length);\n\n const client = new WorkspaceClient({});\n const spinner = new Spinner();\n\n // Read all SQL files in parallel\n const sqlContents = await Promise.all(\n queryFiles.map((file) => fs.readFile(path.join(queryFolder, file), \"utf8\")),\n );\n\n const startTime = performance.now();\n\n // Phase 1: Check cache, separate cached vs uncached\n const cachedResults: Array<{ index: number; schema: QuerySchema }> = [];\n const uncachedQueries: Array<{\n index: number;\n queryName: string;\n sql: string;\n sqlHash: string;\n cleanedSql: string;\n }> = [];\n const logEntries: Array<{\n queryName: string;\n status: \"HIT\" | \"MISS\";\n failed?: boolean;\n error?: { code?: string; message: string };\n }> = [];\n\n for (let i = 0; i < queryFiles.length; i++) {\n const file = queryFiles[i];\n const rawName = path.basename(file, \".sql\");\n const queryName = normalizeQueryName(rawName);\n\n const sql = sqlContents[i];\n const sqlHash = hashSQL(sql);\n\n const cached = cache.queries[queryName];\n if (cached && cached.hash === sqlHash && !cached.retry) {\n cachedResults.push({\n index: i,\n schema: { name: queryName, type: cached.type },\n });\n logEntries.push({ queryName, status: \"HIT\" });\n } else {\n const sqlWithDefaults = sql.replace(/:([a-zA-Z_]\\w*)/g, \"''\");\n const cleanedSql = sqlWithDefaults.trim().replace(/;\\s*$/, \"\");\n uncachedQueries.push({ index: i, queryName, sql, sqlHash, cleanedSql });\n }\n }\n\n // Phase 2: Execute all uncached DESCRIBE calls in parallel\n type DescribeResult =\n | {\n status: \"ok\";\n index: number;\n schema: QuerySchema;\n cacheEntry: { hash: string; type: string; retry: boolean };\n }\n | {\n status: \"fail\";\n index: number;\n schema: QuerySchema;\n cacheEntry: { hash: string; type: string; retry: boolean };\n error: { code?: string; message: string };\n };\n\n const freshResults: Array<{ index: number; schema: QuerySchema }> = [];\n\n if (uncachedQueries.length > 0) {\n let completed = 0;\n const total = uncachedQueries.length;\n spinner.start(\n `Describing ${total} ${total === 1 ? \"query\" : \"queries\"} (0/${total})`,\n );\n\n const describeOne = async ({\n index,\n queryName,\n sql,\n sqlHash,\n cleanedSql,\n }: (typeof uncachedQueries)[number]): Promise<DescribeResult> => {\n const result = (await client.statementExecution.executeStatement({\n statement: `DESCRIBE QUERY ${cleanedSql}`,\n warehouse_id: warehouseId,\n })) as DatabricksStatementExecutionResponse;\n\n completed++;\n spinner.update(\n `Describing ${total} ${total === 1 ? \"query\" : \"queries\"} (${completed}/${total})`,\n );\n\n logger.debug(\n \"DESCRIBE result for %s: state=%s, rows=%d\",\n queryName,\n result.status.state,\n result.result?.data_array?.length ?? 0,\n );\n\n if (result.status.state === \"FAILED\") {\n const sqlError =\n result.status.error?.message || \"Query execution failed\";\n logger.warn(\"DESCRIBE failed for %s: %s\", queryName, sqlError);\n const type = generateUnknownResultQuery(sql, queryName);\n return {\n status: \"fail\",\n index,\n schema: { name: queryName, type },\n cacheEntry: { hash: sqlHash, type, retry: true },\n error: parseError(sqlError),\n };\n }\n\n const { type, hasResults } = convertToQueryType(result, sql, queryName);\n return {\n status: \"ok\",\n index,\n schema: { name: queryName, type },\n cacheEntry: { hash: sqlHash, type, retry: !hasResults },\n };\n };\n\n // Process in chunks, saving cache after each chunk\n const processBatchResults = (\n settled: PromiseSettledResult<DescribeResult>[],\n batchOffset: number,\n ) => {\n for (let i = 0; i < settled.length; i++) {\n const entry = settled[i];\n const { queryName } = uncachedQueries[batchOffset + i];\n\n if (entry.status === \"fulfilled\") {\n const res = entry.value;\n freshResults.push({ index: res.index, schema: res.schema });\n cache.queries[queryName] = res.cacheEntry;\n logEntries.push({\n queryName,\n status: \"MISS\",\n failed: res.status === \"fail\",\n error: res.status === \"fail\" ? res.error : undefined,\n });\n } else {\n const { sql, sqlHash, index } = uncachedQueries[batchOffset + i];\n const reason =\n entry.reason instanceof Error\n ? entry.reason.message\n : String(entry.reason);\n logger.warn(\"DESCRIBE rejected for %s: %s\", queryName, reason);\n const type = generateUnknownResultQuery(sql, queryName);\n freshResults.push({ index, schema: { name: queryName, type } });\n cache.queries[queryName] = { hash: sqlHash, type, retry: true };\n logEntries.push({\n queryName,\n status: \"MISS\",\n failed: true,\n error: parseError(reason),\n });\n }\n }\n };\n\n if (uncachedQueries.length > concurrency) {\n for (let b = 0; b < uncachedQueries.length; b += concurrency) {\n const batch = uncachedQueries.slice(b, b + concurrency);\n const batchResults = await Promise.allSettled(batch.map(describeOne));\n processBatchResults(batchResults, b);\n await saveCache(cache);\n }\n } else {\n const settled = await Promise.allSettled(\n uncachedQueries.map(describeOne),\n );\n processBatchResults(settled, 0);\n await saveCache(cache);\n }\n\n spinner.stop(\"\");\n }\n\n const elapsed = ((performance.now() - startTime) / 1000).toFixed(2);\n\n // Print formatted table\n if (logEntries.length > 0) {\n const maxNameLen = Math.max(...logEntries.map((e) => e.queryName.length));\n const separator = pc.dim(\"─\".repeat(50));\n console.log(\"\");\n console.log(\n ` ${pc.bold(\"Typegen Queries\")} ${pc.dim(`(${logEntries.length})`)}`,\n );\n console.log(` ${separator}`);\n for (const entry of logEntries) {\n const tag = entry.failed\n ? pc.bold(pc.red(\"ERROR\"))\n : entry.status === \"HIT\"\n ? `cache ${pc.bold(pc.green(\"HIT \"))}`\n : `cache ${pc.bold(pc.yellow(\"MISS \"))}`;\n const rawName = entry.queryName.padEnd(maxNameLen);\n const name = entry.failed ? pc.dim(pc.strikethrough(rawName)) : rawName;\n const errorCode = entry.error?.message.match(/\\[([^\\]]+)\\]/)?.[1];\n const reason = errorCode ? ` ${pc.dim(errorCode)}` : \"\";\n console.log(` ${tag} ${name}${reason}`);\n }\n const newCount = logEntries.filter(\n (e) => e.status === \"MISS\" && !e.failed,\n ).length;\n const cacheCount = logEntries.filter(\n (e) => e.status === \"HIT\" && !e.failed,\n ).length;\n const errorCount = logEntries.filter((e) => e.failed).length;\n console.log(` ${separator}`);\n const parts = [`${newCount} new`, `${cacheCount} from cache`];\n if (errorCount > 0)\n parts.push(`${errorCount} ${errorCount === 1 ? \"error\" : \"errors\"}`);\n console.log(` ${parts.join(\", \")}. ${pc.dim(`${elapsed}s`)}`);\n console.log(\"\");\n }\n\n // Merge and sort by original file index for deterministic output\n return [...cachedResults, ...freshResults]\n .sort((a, b) => a.index - b.index)\n .map((r) => r.schema);\n}\n\n/**\n * Normalize query name by removing the .obo extension\n * @param queryName - the query name to normalize\n * @returns the normalized query name\n */\nfunction normalizeQueryName(fileName: string): string {\n return fileName.replace(/\\.obo$/, \"\");\n}\n\n/**\n * Normalize SQL type name by removing parameters/generics\n * Examples:\n * DECIMAL(38,6) -> DECIMAL\n * ARRAY<STRING> -> ARRAY\n * MAP<STRING,INT> -> MAP\n * STRUCT<name:STRING> -> STRUCT\n * INTERVAL DAY TO SECOND -> INTERVAL\n * GEOGRAPHY(4326) -> GEOGRAPHY\n */\nexport function normalizeTypeName(typeName: string): string {\n return typeName\n .replace(/\\(.*\\)$/, \"\") // remove (p, s) eg: DECIMAL(38,6) -> DECIMAL\n .replace(/<.*>$/, \"\") // remove <T> eg: ARRAY<STRING> -> ARRAY\n .split(\" \")[0]; // take first word eg: INTERVAL DAY TO SECOND -> INTERVAL\n}\n\n/** Type Map for Databricks data types to JavaScript types */\nconst typeMap: Record<string, string> = {\n // string types\n STRING: \"string\",\n BINARY: \"string\",\n // boolean\n BOOLEAN: \"boolean\",\n // numeric types\n TINYINT: \"number\",\n SMALLINT: \"number\",\n INT: \"number\",\n BIGINT: \"number\",\n FLOAT: \"number\",\n DOUBLE: \"number\",\n DECIMAL: \"number\",\n // date/time types\n DATE: \"string\",\n TIMESTAMP: \"string\",\n TIMESTAMP_NTZ: \"string\",\n INTERVAL: \"string\",\n // complex types\n ARRAY: \"unknown[]\",\n MAP: \"Record<string, unknown>\",\n STRUCT: \"Record<string, unknown>\",\n OBJECT: \"Record<string, unknown>\",\n VARIANT: \"unknown\",\n // spatial types\n GEOGRAPHY: \"unknown\",\n GEOMETRY: \"unknown\",\n // null type\n VOID: \"null\",\n};\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"path-exclusions.js","names":[],"sources":["../../src/utils/path-exclusions.ts"],"sourcesContent":["import type { IncomingMessage } from \"node:http\";\n\n/**\n * Paths and patterns to exclude from tracing and logging.\n * Requests matching these will not create spans or WideEvents.\n */\nexport const EXCLUDED_PATH_PREFIXES = [\n // Vite dev server internals\n \"/@fs/\",\n \"/@vite/\",\n \"/@id/\",\n \"/@react-refresh\",\n \"/src/\", // Vite HMR source files\n \"/node_modules/\",\n\n // Static assets and common paths\n \"/favicon.ico\",\n \"/_next/\",\n \"/static/\",\n\n // Health checks\n \"/health\",\n \"/metrics\",\n];\n\n/**\n * File extensions to exclude from tracing.\n * These are typically static assets that don't need tracing.\n */\nexport const EXCLUDED_EXTENSIONS = [\n \".svg\",\n \".png\",\n \".jpg\",\n \".jpeg\",\n \".gif\",\n \".webp\",\n \".ico\",\n \".css\",\n \".woff\",\n \".woff2\",\n \".ttf\",\n \".eot\",\n \".map\", // Source maps\n \".js\", // Static JS files (not API endpoints)\n];\n\n/**\n * Check if a request should be ignored for tracing.\n * This is the primary filter used by HttpInstrumentation.\n */\nexport function shouldIgnoreRequest(request: IncomingMessage): boolean {\n const url = request.url;\n if (!url) return false;\n\n // Remove query string for path matching\n const path = url.split(\"?\")[0];\n\n return shouldExcludePath(path);\n}\n\n/**\n * Check if a path should be excluded from tracing/logging.\n * Returns true if path should be excluded, false otherwise.\n */\nexport function shouldExcludePath(path: string | undefined): boolean {\n if (typeof path !== \"string\") return false;\n\n // Remove query string\n const cleanPath = path.split(\"?\")[0];\n const lowerPath = cleanPath.toLowerCase();\n\n // Check path prefixes\n for (const prefix of EXCLUDED_PATH_PREFIXES) {\n if (cleanPath.includes(prefix)) {\n return true;\n }\n }\n\n // Check file extensions (but not for /api/ routes)\n if (!cleanPath.startsWith(\"/api/\")) {\n for (const ext of EXCLUDED_EXTENSIONS) {\n if (lowerPath.endsWith(ext)) {\n return true;\n }\n }\n }\n\n return false;\n}\n"],"mappings":";;;;;AAMA,MAAa,yBAAyB;CAEpC;CACA;CACA;CACA;CACA;CACA;CAGA;CACA;CACA;CAGA;CACA;CACD;;;;;AAMD,MAAa,sBAAsB;CACjC;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACD;;;;;AAMD,SAAgB,oBAAoB,SAAmC;CACrE,MAAM,MAAM,QAAQ;AACpB,KAAI,CAAC,IAAK,QAAO;CAGjB,MAAM,OAAO,IAAI,MAAM,IAAI,CAAC;AAE5B,QAAO,kBAAkB,KAAK;;;;;;AAOhC,SAAgB,kBAAkB,MAAmC;AACnE,KAAI,OAAO,SAAS,SAAU,QAAO;CAGrC,MAAM,YAAY,KAAK,MAAM,IAAI,CAAC;CAClC,MAAM,YAAY,UAAU,aAAa;AAGzC,MAAK,MAAM,UAAU,uBACnB,KAAI,UAAU,SAAS,OAAO,CAC5B,QAAO;AAKX,KAAI,CAAC,UAAU,WAAW,QAAQ,EAChC;OAAK,MAAM,OAAO,oBAChB,KAAI,UAAU,SAAS,IAAI,CACzB,QAAO;;AAKb,QAAO"}
1
+ {"version":3,"file":"path-exclusions.js","names":[],"sources":["../../src/utils/path-exclusions.ts"],"sourcesContent":["import type { IncomingMessage } from \"node:http\";\n\n/**\n * Paths and patterns to exclude from tracing and logging.\n * Requests matching these will not create spans or WideEvents.\n */\nconst EXCLUDED_PATH_PREFIXES = [\n // Vite dev server internals\n \"/@fs/\",\n \"/@vite/\",\n \"/@id/\",\n \"/@react-refresh\",\n \"/src/\", // Vite HMR source files\n \"/node_modules/\",\n\n // Static assets and common paths\n \"/favicon.ico\",\n \"/_next/\",\n \"/static/\",\n\n // Health checks\n \"/health\",\n \"/metrics\",\n];\n\n/**\n * File extensions to exclude from tracing.\n * These are typically static assets that don't need tracing.\n */\nconst EXCLUDED_EXTENSIONS = [\n \".svg\",\n \".png\",\n \".jpg\",\n \".jpeg\",\n \".gif\",\n \".webp\",\n \".ico\",\n \".css\",\n \".woff\",\n \".woff2\",\n \".ttf\",\n \".eot\",\n \".map\", // Source maps\n \".js\", // Static JS files (not API endpoints)\n];\n\n/**\n * Check if a request should be ignored for tracing.\n * This is the primary filter used by HttpInstrumentation.\n */\nexport function shouldIgnoreRequest(request: IncomingMessage): boolean {\n const url = request.url;\n if (!url) return false;\n\n // Remove query string for path matching\n const path = url.split(\"?\")[0];\n\n return shouldExcludePath(path);\n}\n\n/**\n * Check if a path should be excluded from tracing/logging.\n * Returns true if path should be excluded, false otherwise.\n */\nexport function shouldExcludePath(path: string | undefined): boolean {\n if (typeof path !== \"string\") return false;\n\n // Remove query string\n const cleanPath = path.split(\"?\")[0];\n const lowerPath = cleanPath.toLowerCase();\n\n // Check path prefixes\n for (const prefix of EXCLUDED_PATH_PREFIXES) {\n if (cleanPath.includes(prefix)) {\n return true;\n }\n }\n\n // Check file extensions (but not for /api/ routes)\n if (!cleanPath.startsWith(\"/api/\")) {\n for (const ext of EXCLUDED_EXTENSIONS) {\n if (lowerPath.endsWith(ext)) {\n return true;\n }\n }\n }\n\n return false;\n}\n"],"mappings":";;;;;AAMA,MAAM,yBAAyB;CAE7B;CACA;CACA;CACA;CACA;CACA;CAGA;CACA;CACA;CAGA;CACA;CACD;;;;;AAMD,MAAM,sBAAsB;CAC1B;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACD;;;;;AAMD,SAAgB,oBAAoB,SAAmC;CACrE,MAAM,MAAM,QAAQ;AACpB,KAAI,CAAC,IAAK,QAAO;CAGjB,MAAM,OAAO,IAAI,MAAM,IAAI,CAAC;AAE5B,QAAO,kBAAkB,KAAK;;;;;;AAOhC,SAAgB,kBAAkB,MAAmC;AACnE,KAAI,OAAO,SAAS,SAAU,QAAO;CAGrC,MAAM,YAAY,KAAK,MAAM,IAAI,CAAC;CAClC,MAAM,YAAY,UAAU,aAAa;AAGzC,MAAK,MAAM,UAAU,uBACnB,KAAI,UAAU,SAAS,OAAO,CAC5B,QAAO;AAKX,KAAI,CAAC,UAAU,WAAW,QAAQ,EAChC;OAAK,MAAM,OAAO,oBAChB,KAAI,UAAU,SAAS,IAAI,CACzB,QAAO;;AAKb,QAAO"}
@@ -1,6 +1,6 @@
1
1
  # Interface: CacheConfig
2
2
 
3
- Configuration for caching
3
+ Configuration for the CacheInterceptor. Controls TTL, size limits, storage backend, and probabilistic cleanup.
4
4
 
5
5
  ## Indexable[​](#indexable "Direct link to Indexable")
6
6
 
@@ -1,6 +1,15 @@
1
1
  # Interface: PluginManifest\<TName>
2
2
 
3
- Plugin manifest that declares metadata and resource requirements. Attached to plugin classes as a static property.
3
+ Plugin manifest that declares metadata and resource requirements. Attached to plugin classes as a static property. Extends the shared PluginManifest with strict resource types.
4
+
5
+ ## See[​](#see "Direct link to See")
6
+
7
+ * `packages/shared/src/schemas/plugin-manifest.generated.ts` `PluginManifest` — generated base
8
+ * SharedPluginManifest — shared re-export with JSONSchema7 config
9
+
10
+ ## Extends[​](#extends "Direct link to Extends")
11
+
12
+ * `Omit`<`SharedPluginManifest`, `"resources"` | `"config"`>
4
13
 
5
14
  ## Type Parameters[​](#type-parameters "Direct link to Type Parameters")
6
15
 
@@ -17,7 +26,14 @@ optional author: string;
17
26
 
18
27
  ```
19
28
 
20
- Optional metadata for community plugins
29
+ Author name or organization
30
+
31
+ #### Inherited from[​](#inherited-from "Direct link to Inherited from")
32
+
33
+ ```ts
34
+ Omit.author
35
+
36
+ ```
21
37
 
22
38
  ***
23
39
 
@@ -30,7 +46,7 @@ optional config: {
30
46
 
31
47
  ```
32
48
 
33
- Configuration schema for the plugin. Defines the shape and validation rules for plugin config.
49
+ Configuration schema for the plugin. Uses JSONSchema7 instead of the generated ConfigSchema (which is too restrictive).
34
50
 
35
51
  #### schema[​](#schema "Direct link to schema")
36
52
 
@@ -50,6 +66,13 @@ description: string;
50
66
 
51
67
  Brief description of what the plugin does
52
68
 
69
+ #### Inherited from[​](#inherited-from-1 "Direct link to Inherited from")
70
+
71
+ ```ts
72
+ Omit.description
73
+
74
+ ```
75
+
53
76
  ***
54
77
 
55
78
  ### displayName[​](#displayname "Direct link to displayName")
@@ -59,7 +82,14 @@ displayName: string;
59
82
 
60
83
  ```
61
84
 
62
- Human-readable display name for UI/CLI
85
+ Human-readable display name for UI and CLI
86
+
87
+ #### Inherited from[​](#inherited-from-2 "Direct link to Inherited from")
88
+
89
+ ```ts
90
+ Omit.displayName
91
+
92
+ ```
63
93
 
64
94
  ***
65
95
 
@@ -70,7 +100,14 @@ optional hidden: boolean;
70
100
 
71
101
  ```
72
102
 
73
- When true, excluded from the template plugins manifest during sync.
103
+ When true, this plugin is excluded from the template plugins manifest (appkit.plugins.json) during sync.
104
+
105
+ #### Inherited from[​](#inherited-from-3 "Direct link to Inherited from")
106
+
107
+ ```ts
108
+ Omit.hidden
109
+
110
+ ```
74
111
 
75
112
  ***
76
113
 
@@ -81,6 +118,15 @@ optional keywords: string[];
81
118
 
82
119
  ```
83
120
 
121
+ Keywords for plugin discovery
122
+
123
+ #### Inherited from[​](#inherited-from-4 "Direct link to Inherited from")
124
+
125
+ ```ts
126
+ Omit.keywords
127
+
128
+ ```
129
+
84
130
  ***
85
131
 
86
132
  ### license?[​](#license "Direct link to license?")
@@ -90,6 +136,15 @@ optional license: string;
90
136
 
91
137
  ```
92
138
 
139
+ SPDX license identifier
140
+
141
+ #### Inherited from[​](#inherited-from-5 "Direct link to Inherited from")
142
+
143
+ ```ts
144
+ Omit.license
145
+
146
+ ```
147
+
93
148
  ***
94
149
 
95
150
  ### name[​](#name "Direct link to name")
@@ -101,6 +156,31 @@ name: TName;
101
156
 
102
157
  Plugin identifier — the single source of truth for the plugin's name
103
158
 
159
+ #### Overrides[​](#overrides "Direct link to Overrides")
160
+
161
+ ```ts
162
+ Omit.name
163
+
164
+ ```
165
+
166
+ ***
167
+
168
+ ### onSetupMessage?[​](#onsetupmessage "Direct link to onSetupMessage?")
169
+
170
+ ```ts
171
+ optional onSetupMessage: string;
172
+
173
+ ```
174
+
175
+ Message displayed to the user after project initialization. Use this to inform about manual setup steps (e.g. environment variables, resource provisioning).
176
+
177
+ #### Inherited from[​](#inherited-from-6 "Direct link to Inherited from")
178
+
179
+ ```ts
180
+ Omit.onSetupMessage
181
+
182
+ ```
183
+
104
184
  ***
105
185
 
106
186
  ### repository?[​](#repository "Direct link to repository?")
@@ -110,6 +190,15 @@ optional repository: string;
110
190
 
111
191
  ```
112
192
 
193
+ URL to the plugin's source repository
194
+
195
+ #### Inherited from[​](#inherited-from-7 "Direct link to Inherited from")
196
+
197
+ ```ts
198
+ Omit.repository
199
+
200
+ ```
201
+
113
202
  ***
114
203
 
115
204
  ### resources[​](#resources "Direct link to resources")
@@ -122,7 +211,7 @@ resources: {
122
211
 
123
212
  ```
124
213
 
125
- Resource requirements declaration
214
+ Resource requirements declaration (with strict ResourceRequirement types)
126
215
 
127
216
  #### optional[​](#optional "Direct link to optional")
128
217
 
@@ -150,3 +239,12 @@ Resources that must be available for the plugin to function
150
239
  optional version: string;
151
240
 
152
241
  ```
242
+
243
+ Plugin version (semver format)
244
+
245
+ #### Inherited from[​](#inherited-from-8 "Direct link to Inherited from")
246
+
247
+ ```ts
248
+ Omit.version
249
+
250
+ ```
@@ -15,7 +15,7 @@ alias: string;
15
15
 
16
16
  ```
17
17
 
18
- Unique alias for this resource within the plugin (e.g., 'warehouse', 'secrets'). Used for UI/display.
18
+ Human-readable label for UI/display only. Deduplication uses resourceKey, not alias.
19
19
 
20
20
  #### Inherited from[​](#inherited-from "Direct link to Inherited from")
21
21
 
@@ -45,7 +45,7 @@ fields: Record<string, ResourceFieldEntry>;
45
45
 
46
46
  ```
47
47
 
48
- Map of field name to env and optional description. Single-value types use one key (e.g. id); multi-value (database, secret) use multiple keys.
48
+ Map of field name to env and optional description. Single-value types use one key (e.g. id); multi-value (database, secret) use multiple (e.g. instance\_name, database\_name or scope, key).
49
49
 
50
50
  #### Inherited from[​](#inherited-from-2 "Direct link to Inherited from")
51
51
 
@@ -60,7 +60,7 @@ permission: ResourcePermission;
60
60
 
61
61
  ```
62
62
 
63
- Required permission level for the resource
63
+ Required permission level for the resource (narrowed to union)
64
64
 
65
65
  #### Inherited from[​](#inherited-from-3 "Direct link to Inherited from")
66
66
 
@@ -97,8 +97,6 @@ required: boolean;
97
97
 
98
98
  ```
99
99
 
100
- Whether this resource is required (true) or optional (false)
101
-
102
100
  #### Inherited from[​](#inherited-from-4 "Direct link to Inherited from")
103
101
 
104
102
  [`ResourceRequirement`](./docs/api/appkit/Interface.ResourceRequirement.md).[`required`](./docs/api/appkit/Interface.ResourceRequirement.md#required)
@@ -123,7 +121,7 @@ resourceKey: string;
123
121
 
124
122
  ```
125
123
 
126
- Stable key for machine use (env naming, composite keys, app.yaml). Required.
124
+ Stable key for machine use: deduplication, env naming, composite keys, app.yaml. Required for registry lookup.
127
125
 
128
126
  #### Inherited from[​](#inherited-from-5 "Direct link to Inherited from")
129
127
 
@@ -138,7 +136,7 @@ type: ResourceType;
138
136
 
139
137
  ```
140
138
 
141
- Type of Databricks resource required
139
+ Type of Databricks resource required (narrowed to enum)
142
140
 
143
141
  #### Inherited from[​](#inherited-from-6 "Direct link to Inherited from")
144
142
 
@@ -2,6 +2,8 @@
2
2
 
3
3
  Defines a single field for a resource. Each field has its own environment variable and optional description. Single-value types use one key (e.g. id); multi-value types (database, secret) use multiple (e.g. instance\_name, database\_name or scope, key).
4
4
 
5
+ This interface was referenced by `PluginManifest`'s JSON-Schema via the `definition` "resourceFieldEntry".
6
+
5
7
  ## Properties[​](#properties "Direct link to Properties")
6
8
 
7
9
  ### bundleIgnore?[​](#bundleignore "Direct link to bundleIgnore?")
@@ -1,6 +1,15 @@
1
1
  # Interface: ResourceRequirement
2
2
 
3
- Declares a resource requirement for a plugin. Can be defined statically in a manifest or dynamically via getResourceRequirements().
3
+ Declares a resource requirement for a plugin. Can be defined statically in a manifest or dynamically via getResourceRequirements(). Narrows the generated base: type → ResourceType enum, permission → ResourcePermission union.
4
+
5
+ ## See[​](#see "Direct link to See")
6
+
7
+ * `packages/shared/src/schemas/plugin-manifest.generated.ts` `ResourceRequirement` — generated base
8
+ * SharedResourceRequirement — shared re-export with runtime `fields` and `required`
9
+
10
+ ## Extends[​](#extends "Direct link to Extends")
11
+
12
+ * `ResourceRequirement`
4
13
 
5
14
  ## Extended by[​](#extended-by "Direct link to Extended by")
6
15
 
@@ -15,7 +24,14 @@ alias: string;
15
24
 
16
25
  ```
17
26
 
18
- Unique alias for this resource within the plugin (e.g., 'warehouse', 'secrets'). Used for UI/display.
27
+ Human-readable label for UI/display only. Deduplication uses resourceKey, not alias.
28
+
29
+ #### Inherited from[​](#inherited-from "Direct link to Inherited from")
30
+
31
+ ```ts
32
+ SharedResourceRequirement.alias
33
+
34
+ ```
19
35
 
20
36
  ***
21
37
 
@@ -28,6 +44,13 @@ description: string;
28
44
 
29
45
  Human-readable description of why this resource is needed
30
46
 
47
+ #### Inherited from[​](#inherited-from-1 "Direct link to Inherited from")
48
+
49
+ ```ts
50
+ SharedResourceRequirement.description
51
+
52
+ ```
53
+
31
54
  ***
32
55
 
33
56
  ### fields[​](#fields "Direct link to fields")
@@ -37,7 +60,14 @@ fields: Record<string, ResourceFieldEntry>;
37
60
 
38
61
  ```
39
62
 
40
- Map of field name to env and optional description. Single-value types use one key (e.g. id); multi-value (database, secret) use multiple keys.
63
+ Map of field name to env and optional description. Single-value types use one key (e.g. id); multi-value (database, secret) use multiple (e.g. instance\_name, database\_name or scope, key).
64
+
65
+ #### Inherited from[​](#inherited-from-2 "Direct link to Inherited from")
66
+
67
+ ```ts
68
+ SharedResourceRequirement.fields
69
+
70
+ ```
41
71
 
42
72
  ***
43
73
 
@@ -48,7 +78,14 @@ permission: ResourcePermission;
48
78
 
49
79
  ```
50
80
 
51
- Required permission level for the resource
81
+ Required permission level for the resource (narrowed to union)
82
+
83
+ #### Overrides[​](#overrides "Direct link to Overrides")
84
+
85
+ ```ts
86
+ SharedResourceRequirement.permission
87
+
88
+ ```
52
89
 
53
90
  ***
54
91
 
@@ -59,7 +96,12 @@ required: boolean;
59
96
 
60
97
  ```
61
98
 
62
- Whether this resource is required (true) or optional (false)
99
+ #### Inherited from[​](#inherited-from-3 "Direct link to Inherited from")
100
+
101
+ ```ts
102
+ SharedResourceRequirement.required
103
+
104
+ ```
63
105
 
64
106
  ***
65
107
 
@@ -70,7 +112,14 @@ resourceKey: string;
70
112
 
71
113
  ```
72
114
 
73
- Stable key for machine use (env naming, composite keys, app.yaml). Required.
115
+ Stable key for machine use: deduplication, env naming, composite keys, app.yaml. Required for registry lookup.
116
+
117
+ #### Inherited from[​](#inherited-from-4 "Direct link to Inherited from")
118
+
119
+ ```ts
120
+ SharedResourceRequirement.resourceKey
121
+
122
+ ```
74
123
 
75
124
  ***
76
125
 
@@ -81,4 +130,11 @@ type: ResourceType;
81
130
 
82
131
  ```
83
132
 
84
- Type of Databricks resource required
133
+ Type of Databricks resource required (narrowed to enum)
134
+
135
+ #### Overrides[​](#overrides-1 "Direct link to Overrides")
136
+
137
+ ```ts
138
+ SharedResourceRequirement.type
139
+
140
+ ```
@@ -1,6 +1,6 @@
1
1
  # Interface: StreamExecutionSettings
2
2
 
3
- Configuration for streaming execution with default and user-scoped settings
3
+ Execution settings for streaming endpoints. Extends PluginExecutionSettings with SSE stream configuration.
4
4
 
5
5
  ## Properties[​](#properties "Direct link to Properties")
6
6
 
@@ -9,6 +9,8 @@ type PluginData<T, U, N> = {
9
9
 
10
10
  ```
11
11
 
12
+ Tuple of plugin class, config, and name. Created by `toPlugin()` and passed to `createApp()`.
13
+
12
14
  ## Type Parameters[​](#type-parameters "Direct link to Type Parameters")
13
15
 
14
16
  | Type Parameter |
@@ -5,6 +5,8 @@ type ToPlugin<T, U, N> = (config?: U) => PluginData<T, U, N>;
5
5
 
6
6
  ```
7
7
 
8
+ Factory function type returned by `toPlugin()`. Accepts optional config and returns a PluginData tuple.
9
+
8
10
  ## Type Parameters[​](#type-parameters "Direct link to Type Parameters")
9
11
 
10
12
  | Type Parameter |