@databricks/appkit 0.20.2 → 0.21.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CLAUDE.md +5 -13
- package/NOTICE.md +3 -6
- package/dist/app/index.js.map +1 -1
- package/dist/appkit/package.js +1 -1
- package/dist/cli/commands/plugin/add-resource/add-resource.js.map +1 -1
- package/dist/connectors/files/client.js.map +1 -1
- package/dist/connectors/files/defaults.js +1 -1
- package/dist/connectors/files/defaults.js.map +1 -1
- package/dist/connectors/files/index.js +1 -1
- package/dist/connectors/genie/client.js.map +1 -1
- package/dist/connectors/genie/index.d.ts +0 -1
- package/dist/connectors/genie/index.js +0 -2
- package/dist/connectors/index.js +1 -3
- package/dist/connectors/lakebase/index.js.map +1 -1
- package/dist/connectors/sql-warehouse/client.js.map +1 -1
- package/dist/context/index.d.ts +2 -2
- package/dist/context/index.js +0 -1
- package/dist/context/index.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/logging/index.js +0 -13
- package/dist/logging/logger.js.map +1 -1
- package/dist/logging/sampling.js.map +1 -1
- package/dist/plugins/files/defaults.js +0 -2
- package/dist/plugins/files/defaults.js.map +1 -1
- package/dist/plugins/files/index.js +0 -1
- package/dist/plugins/genie/index.d.ts +1 -1
- package/dist/plugins/genie/types.d.ts +1 -1
- package/dist/plugins/genie/types.d.ts.map +1 -1
- package/dist/plugins/index.d.ts +2 -3
- package/dist/plugins/index.js +1 -2
- package/dist/plugins/lakebase/index.d.ts +1 -1
- package/dist/plugins/lakebase/index.js +1 -1
- package/dist/plugins/lakebase/lakebase.d.ts +1 -1
- package/dist/plugins/lakebase/lakebase.d.ts.map +1 -1
- package/dist/plugins/lakebase/lakebase.js +1 -1
- package/dist/plugins/lakebase/lakebase.js.map +1 -1
- package/dist/plugins/server/index.js.map +1 -1
- package/dist/plugins/server/utils.js.map +1 -1
- package/dist/registry/index.d.ts +3 -2
- package/dist/registry/manifest-loader.d.ts +4 -3
- package/dist/registry/manifest-loader.d.ts.map +1 -1
- package/dist/registry/types.d.ts +19 -57
- package/dist/registry/types.d.ts.map +1 -1
- package/dist/registry/types.generated.d.ts +1 -1
- package/dist/registry/types.js +7 -2
- package/dist/registry/types.js.map +1 -1
- package/dist/schemas/plugin-manifest.generated.d.ts +178 -0
- package/dist/schemas/plugin-manifest.generated.d.ts.map +1 -0
- package/dist/schemas/plugin-manifest.schema.json +2 -0
- package/dist/shared/src/cache.d.ts +1 -1
- package/dist/shared/src/execute.d.ts +7 -1
- package/dist/shared/src/execute.d.ts.map +1 -1
- package/dist/shared/src/index.d.ts +2 -1
- package/dist/shared/src/plugin.d.ts +19 -48
- package/dist/shared/src/plugin.d.ts.map +1 -1
- package/dist/shared/src/schemas/plugin-manifest.generated.d.ts +178 -0
- package/dist/shared/src/schemas/plugin-manifest.generated.d.ts.map +1 -0
- package/dist/stream/arrow-stream-processor.js.map +1 -1
- package/dist/stream/index.d.ts +1 -3
- package/dist/stream/index.js +0 -3
- package/dist/stream/stream-manager.js +1 -1
- package/dist/stream/types.js.map +1 -1
- package/dist/telemetry/config.js +1 -0
- package/dist/telemetry/config.js.map +1 -1
- package/dist/telemetry/index.d.ts +1 -1
- package/dist/telemetry/noop.js.map +1 -1
- package/dist/telemetry/types.d.ts +1 -1
- package/dist/type-generator/query-registry.js.map +1 -1
- package/dist/utils/path-exclusions.js.map +1 -1
- package/docs/api/appkit/Interface.CacheConfig.md +1 -1
- package/docs/api/appkit/Interface.PluginManifest.md +104 -6
- package/docs/api/appkit/Interface.ResourceEntry.md +5 -7
- package/docs/api/appkit/Interface.ResourceFieldEntry.md +2 -0
- package/docs/api/appkit/Interface.ResourceRequirement.md +63 -7
- package/docs/api/appkit/Interface.StreamExecutionSettings.md +1 -1
- package/docs/api/appkit/TypeAlias.PluginData.md +2 -0
- package/docs/api/appkit/TypeAlias.ToPlugin.md +2 -0
- package/docs/api/appkit.md +6 -6
- package/llms.txt +5 -13
- package/package.json +2 -2
- package/dist/stream/arrow-stream-processor.d.ts +0 -1
- package/dist/stream/buffers.d.ts +0 -1
- package/dist/stream/types.d.ts +0 -3
- package/docs/api/appkit-ui/data/AreaChart.md +0 -79
- package/docs/api/appkit-ui/data/BarChart.md +0 -74
- package/docs/api/appkit-ui/data/DonutChart.md +0 -72
- package/docs/api/appkit-ui/data/HeatmapChart.md +0 -91
- package/docs/api/appkit-ui/data/LineChart.md +0 -77
- package/docs/api/appkit-ui/data/PieChart.md +0 -72
- package/docs/api/appkit-ui/data/RadarChart.md +0 -74
- package/docs/api/appkit-ui/data/ScatterChart.md +0 -76
package/dist/stream/index.d.ts
CHANGED
package/dist/stream/index.js
CHANGED
|
@@ -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";
|
package/dist/stream/types.js.map
CHANGED
|
@@ -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
|
|
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"}
|
package/dist/telemetry/config.js
CHANGED
|
@@ -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":"
|
|
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,
|
|
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\
|
|
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"}
|
|
@@ -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 */\
|
|
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,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
|
-
|
|
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.
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
3
|
+
Execution settings for streaming endpoints. Extends PluginExecutionSettings with SSE stream configuration.
|
|
4
4
|
|
|
5
5
|
## Properties[](#properties "Direct link to Properties")
|
|
6
6
|
|
|
@@ -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 |
|