@querypanel/node-sdk 1.0.32 → 1.0.34
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/dist/index.cjs +14 -4
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +14 -4
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -1018,10 +1018,11 @@ var import_node_crypto2 = require("crypto");
|
|
|
1018
1018
|
async function syncSchema(client, queryEngine, databaseName, options, signal) {
|
|
1019
1019
|
const tenantId = resolveTenantId3(client, options.tenantId);
|
|
1020
1020
|
const adapter = queryEngine.getDatabase(databaseName);
|
|
1021
|
+
const metadata = queryEngine.getDatabaseMetadata(databaseName);
|
|
1021
1022
|
const introspection = await adapter.introspect(
|
|
1022
1023
|
options.tables ? { tables: options.tables } : void 0
|
|
1023
1024
|
);
|
|
1024
|
-
const payload = buildSchemaRequest(databaseName, adapter, introspection);
|
|
1025
|
+
const payload = buildSchemaRequest(databaseName, adapter, introspection, metadata);
|
|
1025
1026
|
if (options.forceReindex) {
|
|
1026
1027
|
payload.force_reindex = true;
|
|
1027
1028
|
}
|
|
@@ -1046,7 +1047,7 @@ function resolveTenantId3(client, tenantId) {
|
|
|
1046
1047
|
}
|
|
1047
1048
|
return resolved;
|
|
1048
1049
|
}
|
|
1049
|
-
function buildSchemaRequest(databaseName, adapter, introspection) {
|
|
1050
|
+
function buildSchemaRequest(databaseName, adapter, introspection, metadata) {
|
|
1050
1051
|
const dialect = adapter.getDialect();
|
|
1051
1052
|
const tables = introspection.tables.map((table) => ({
|
|
1052
1053
|
table_name: table.name,
|
|
@@ -1058,11 +1059,19 @@ function buildSchemaRequest(databaseName, adapter, introspection) {
|
|
|
1058
1059
|
description: column.comment ?? ""
|
|
1059
1060
|
}))
|
|
1060
1061
|
}));
|
|
1061
|
-
|
|
1062
|
+
const request = {
|
|
1062
1063
|
database: databaseName,
|
|
1063
1064
|
dialect,
|
|
1064
1065
|
tables
|
|
1065
1066
|
};
|
|
1067
|
+
if (metadata?.tenantFieldName && metadata?.tenantFieldType && metadata?.enforceTenantIsolation !== void 0) {
|
|
1068
|
+
request.tenant_settings = {
|
|
1069
|
+
tenantFieldName: metadata.tenantFieldName,
|
|
1070
|
+
tenantFieldType: metadata.tenantFieldType,
|
|
1071
|
+
enforceTenantIsolation: metadata.enforceTenantIsolation
|
|
1072
|
+
};
|
|
1073
|
+
}
|
|
1074
|
+
return request;
|
|
1066
1075
|
}
|
|
1067
1076
|
|
|
1068
1077
|
// src/routes/query.ts
|
|
@@ -1147,7 +1156,8 @@ async function ask(client, queryEngine, question, options, signal) {
|
|
|
1147
1156
|
fields: execution.fields,
|
|
1148
1157
|
chart,
|
|
1149
1158
|
context: queryResponse.context,
|
|
1150
|
-
attempts: attempt + 1
|
|
1159
|
+
attempts: attempt + 1,
|
|
1160
|
+
target_db: databaseName
|
|
1151
1161
|
};
|
|
1152
1162
|
} catch (error) {
|
|
1153
1163
|
attempt++;
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/utils/clickhouse.ts","../src/adapters/clickhouse.ts","../src/adapters/postgres.ts","../src/core/client.ts","../src/core/query-engine.ts","../src/routes/charts.ts","../src/routes/active-charts.ts","../src/routes/ingest.ts","../src/routes/query.ts"],"sourcesContent":["import {\n\tClickHouseAdapter,\n\ttype ClickHouseAdapterOptions,\n\ttype ClickHouseClientFn,\n} from \"./adapters/clickhouse\";\nimport {\n\tPostgresAdapter,\n\ttype PostgresAdapterOptions,\n\ttype PostgresClientFn,\n} from \"./adapters/postgres\";\nimport type { DatabaseAdapter, DatabaseDialect } from \"./adapters/types\";\nimport { ApiClient } from \"./core/client\";\nimport { type DatabaseMetadata, QueryEngine } from \"./core/query-engine\";\nimport * as activeChartsRoute from \"./routes/active-charts\";\nimport * as chartsRoute from \"./routes/charts\";\nimport * as ingestRoute from \"./routes/ingest\";\nimport * as queryRoute from \"./routes/query\";\nimport type { SchemaIntrospection } from \"./schema/types\";\n\n// Re-export all public types\nexport { ClickHouseAdapter, PostgresAdapter };\n\nexport type {\n\tClickHouseAdapterOptions,\n\tClickHouseClientFn,\n\tDatabaseAdapter,\n\tDatabaseDialect,\n\tPostgresAdapterOptions,\n\tPostgresClientFn,\n\tSchemaIntrospection,\n};\n\n// Re-export from query-engine\nexport type { ParamRecord, ParamValue } from \"./core/query-engine\";\nexport type {\n\tActiveChartCreateInput,\n\tActiveChartListOptions,\n\tActiveChartUpdateInput,\n\tSdkActiveChart,\n} from \"./routes/active-charts\";\n\nexport type {\n\tChartCreateInput,\n\tChartListOptions,\n\tChartUpdateInput,\n\tPaginatedResponse,\n\tPaginationInfo,\n\tPaginationQuery,\n\tSdkChart,\n} from \"./routes/charts\";\n// Re-export route types\nexport type {\n\tIngestResponse,\n\tSchemaSyncOptions,\n} from \"./routes/ingest\";\nexport type {\n\tAskOptions,\n\tAskResponse,\n\tChartEnvelope,\n\tContextDocument,\n} from \"./routes/query\";\n\n// Re-export anonymizeResults utility\nexport { anonymizeResults } from \"./routes/query\";\n\n/**\n * Main SDK class - Thin orchestrator\n * Delegates to deep modules (ApiClient, QueryEngine, route modules)\n * Following Ousterhout's principle: \"Simple interface hiding complexity\"\n */\nexport class QueryPanelSdkAPI {\n\tprivate readonly client: ApiClient;\n\tprivate readonly queryEngine: QueryEngine;\n\n\tconstructor(\n\t\tbaseUrl: string,\n\t\tprivateKey: string,\n\t\torganizationId: string,\n\t\toptions?: {\n\t\t\tdefaultTenantId?: string;\n\t\t\tadditionalHeaders?: Record<string, string>;\n\t\t\tfetch?: typeof fetch;\n\t\t},\n\t) {\n\t\tthis.client = new ApiClient(baseUrl, privateKey, organizationId, options);\n\t\tthis.queryEngine = new QueryEngine();\n\t}\n\n\t// Database attachment methods\n\n\tattachClickhouse(\n\t\tname: string,\n\t\tclientFn: ClickHouseClientFn,\n\t\toptions?: ClickHouseAdapterOptions & {\n\t\t\tdescription?: string;\n\t\t\ttags?: string[];\n\t\t\ttenantFieldName?: string;\n\t\t\ttenantFieldType?: string;\n\t\t\tenforceTenantIsolation?: boolean;\n\t\t},\n\t): void {\n\t\tconst adapter = new ClickHouseAdapter(clientFn, options);\n\n\t\tconst metadata: DatabaseMetadata = {\n\t\t\tname,\n\t\t\tdialect: \"clickhouse\",\n\t\t\tdescription: options?.description,\n\t\t\ttags: options?.tags,\n\t\t\ttenantFieldName: options?.tenantFieldName,\n\t\t\ttenantFieldType: options?.tenantFieldType ?? \"String\",\n\t\t\tenforceTenantIsolation: options?.tenantFieldName\n\t\t\t\t? (options?.enforceTenantIsolation ?? true)\n\t\t\t\t: undefined,\n\t\t};\n\n\t\tthis.queryEngine.attachDatabase(name, adapter, metadata);\n\t}\n\n\tattachPostgres(\n\t\tname: string,\n\t\tclientFn: PostgresClientFn,\n\t\toptions?: PostgresAdapterOptions & {\n\t\t\tdescription?: string;\n\t\t\ttags?: string[];\n\t\t\ttenantFieldName?: string;\n\t\t\tenforceTenantIsolation?: boolean;\n\t\t},\n\t): void {\n\t\tconst adapter = new PostgresAdapter(clientFn, options);\n\n\t\tconst metadata: DatabaseMetadata = {\n\t\t\tname,\n\t\t\tdialect: \"postgres\",\n\t\t\tdescription: options?.description,\n\t\t\ttags: options?.tags,\n\t\t\ttenantFieldName: options?.tenantFieldName,\n\t\t\tenforceTenantIsolation: options?.tenantFieldName\n\t\t\t\t? (options?.enforceTenantIsolation ?? true)\n\t\t\t\t: undefined,\n\t\t};\n\n\t\tthis.queryEngine.attachDatabase(name, adapter, metadata);\n\t}\n\n\tattachDatabase(name: string, adapter: DatabaseAdapter): void {\n\t\tconst metadata: DatabaseMetadata = {\n\t\t\tname,\n\t\t\tdialect: adapter.getDialect(),\n\t\t};\n\t\tthis.queryEngine.attachDatabase(name, adapter, metadata);\n\t}\n\n\t// Schema introspection and sync\n\n\tasync introspect(\n\t\tdatabaseName: string,\n\t\ttables?: string[],\n\t): Promise<SchemaIntrospection> {\n\t\tconst adapter = this.queryEngine.getDatabase(databaseName);\n\t\treturn await adapter.introspect(tables ? { tables } : undefined);\n\t}\n\n\tasync syncSchema(\n\t\tdatabaseName: string,\n\t\toptions: ingestRoute.SchemaSyncOptions,\n\t\tsignal?: AbortSignal,\n\t): Promise<ingestRoute.IngestResponse> {\n\t\treturn await ingestRoute.syncSchema(\n\t\t\tthis.client,\n\t\t\tthis.queryEngine,\n\t\t\tdatabaseName,\n\t\t\toptions,\n\t\t\tsignal,\n\t\t);\n\t}\n\n\t// Natural language query\n\n\tasync ask(\n\t\tquestion: string,\n\t\toptions: queryRoute.AskOptions,\n\t\tsignal?: AbortSignal,\n\t): Promise<queryRoute.AskResponse> {\n\t\treturn await queryRoute.ask(\n\t\t\tthis.client,\n\t\t\tthis.queryEngine,\n\t\t\tquestion,\n\t\t\toptions,\n\t\t\tsignal,\n\t\t);\n\t}\n\n\t// Chart CRUD operations\n\n\tasync createChart(\n\t\tbody: chartsRoute.ChartCreateInput,\n\t\toptions?: { tenantId?: string; userId?: string; scopes?: string[] },\n\t\tsignal?: AbortSignal,\n\t): Promise<chartsRoute.SdkChart> {\n\t\treturn await chartsRoute.createChart(this.client, body, options, signal);\n\t}\n\n\tasync listCharts(\n\t\toptions?: chartsRoute.ChartListOptions,\n\t\tsignal?: AbortSignal,\n\t): Promise<chartsRoute.PaginatedResponse<chartsRoute.SdkChart>> {\n\t\treturn await chartsRoute.listCharts(\n\t\t\tthis.client,\n\t\t\tthis.queryEngine,\n\t\t\toptions,\n\t\t\tsignal,\n\t\t);\n\t}\n\n\tasync getChart(\n\t\tid: string,\n\t\toptions?: { tenantId?: string; userId?: string; scopes?: string[] },\n\t\tsignal?: AbortSignal,\n\t): Promise<chartsRoute.SdkChart> {\n\t\treturn await chartsRoute.getChart(\n\t\t\tthis.client,\n\t\t\tthis.queryEngine,\n\t\t\tid,\n\t\t\toptions,\n\t\t\tsignal,\n\t\t);\n\t}\n\n\tasync updateChart(\n\t\tid: string,\n\t\tbody: chartsRoute.ChartUpdateInput,\n\t\toptions?: { tenantId?: string; userId?: string; scopes?: string[] },\n\t\tsignal?: AbortSignal,\n\t): Promise<chartsRoute.SdkChart> {\n\t\treturn await chartsRoute.updateChart(\n\t\t\tthis.client,\n\t\t\tid,\n\t\t\tbody,\n\t\t\toptions,\n\t\t\tsignal,\n\t\t);\n\t}\n\n\tasync deleteChart(\n\t\tid: string,\n\t\toptions?: { tenantId?: string; userId?: string; scopes?: string[] },\n\t\tsignal?: AbortSignal,\n\t): Promise<void> {\n\t\tawait chartsRoute.deleteChart(this.client, id, options, signal);\n\t}\n\n\t// Active Chart CRUD operations\n\n\tasync createActiveChart(\n\t\tbody: activeChartsRoute.ActiveChartCreateInput,\n\t\toptions?: { tenantId?: string; userId?: string; scopes?: string[] },\n\t\tsignal?: AbortSignal,\n\t): Promise<activeChartsRoute.SdkActiveChart> {\n\t\treturn await activeChartsRoute.createActiveChart(\n\t\t\tthis.client,\n\t\t\tbody,\n\t\t\toptions,\n\t\t\tsignal,\n\t\t);\n\t}\n\n\tasync listActiveCharts(\n\t\toptions?: activeChartsRoute.ActiveChartListOptions,\n\t\tsignal?: AbortSignal,\n\t): Promise<chartsRoute.PaginatedResponse<activeChartsRoute.SdkActiveChart>> {\n\t\treturn await activeChartsRoute.listActiveCharts(\n\t\t\tthis.client,\n\t\t\tthis.queryEngine,\n\t\t\toptions,\n\t\t\tsignal,\n\t\t);\n\t}\n\n\tasync getActiveChart(\n\t\tid: string,\n\t\toptions?: activeChartsRoute.ActiveChartListOptions,\n\t\tsignal?: AbortSignal,\n\t): Promise<activeChartsRoute.SdkActiveChart> {\n\t\treturn await activeChartsRoute.getActiveChart(\n\t\t\tthis.client,\n\t\t\tthis.queryEngine,\n\t\t\tid,\n\t\t\toptions,\n\t\t\tsignal,\n\t\t);\n\t}\n\n\tasync updateActiveChart(\n\t\tid: string,\n\t\tbody: activeChartsRoute.ActiveChartUpdateInput,\n\t\toptions?: { tenantId?: string; userId?: string; scopes?: string[] },\n\t\tsignal?: AbortSignal,\n\t): Promise<activeChartsRoute.SdkActiveChart> {\n\t\treturn await activeChartsRoute.updateActiveChart(\n\t\t\tthis.client,\n\t\t\tid,\n\t\t\tbody,\n\t\t\toptions,\n\t\t\tsignal,\n\t\t);\n\t}\n\n\tasync deleteActiveChart(\n\t\tid: string,\n\t\toptions?: { tenantId?: string; userId?: string; scopes?: string[] },\n\t\tsignal?: AbortSignal,\n\t): Promise<void> {\n\t\tawait activeChartsRoute.deleteActiveChart(this.client, id, options, signal);\n\t}\n}\n","const WRAPPER_REGEX =\n /^(Nullable|LowCardinality|SimpleAggregateFunction)\\((.+)\\)$/i;\n\nexport function isNullableType(type: string): boolean {\n return /Nullable\\s*\\(/i.test(type);\n}\n\nexport function unwrapTypeModifiers(type: string): string {\n let current = type.trim();\n let match = WRAPPER_REGEX.exec(current);\n while (match) {\n const inner = match[2];\n if (!inner) {\n break;\n }\n current = inner.trim();\n match = WRAPPER_REGEX.exec(current);\n }\n return current;\n}\n\nexport function extractPrecisionScale(type: string): {\n precision?: number;\n scale?: number;\n} {\n const unwrapped = unwrapTypeModifiers(type);\n const decimalMatch = unwrapped.match(/Decimal(?:\\d+)?\\((\\d+)\\s*,\\s*(\\d+)\\)/i);\n if (!decimalMatch) return {};\n const precision = decimalMatch[1];\n const scale = decimalMatch[2];\n if (!precision || !scale) return {};\n return {\n precision: Number.parseInt(precision, 10),\n scale: Number.parseInt(scale, 10),\n };\n}\n\nexport function extractFixedStringLength(type: string): number | undefined {\n const unwrapped = unwrapTypeModifiers(type);\n const match = unwrapped.match(/^(?:FixedString|StringFixed)\\((\\d+)\\)$/i);\n if (!match) return undefined;\n const length = match[1];\n if (!length) return undefined;\n return Number.parseInt(length, 10);\n}\n\nexport function parseKeyExpression(expression?: string | null): string[] {\n if (!expression) return [];\n let value = expression.trim();\n if (!value) return [];\n if (/^tuple\\s*\\(/i.test(value) && value.endsWith(\")\")) {\n value = value.replace(/^tuple\\s*\\(/i, \"\").replace(/\\)$/, \"\");\n }\n\n const columns: string[] = [];\n let depth = 0;\n let token = \"\";\n for (const ch of value) {\n if (ch === \"(\") {\n depth += 1;\n token += ch;\n continue;\n }\n if (ch === \")\") {\n depth = Math.max(0, depth - 1);\n token += ch;\n continue;\n }\n if (ch === \",\" && depth === 0) {\n const col = token.trim();\n if (col) columns.push(stripWrapper(col));\n token = \"\";\n continue;\n }\n token += ch;\n }\n const last = token.trim();\n if (last) columns.push(stripWrapper(last));\n return columns.filter(Boolean);\n}\n\nfunction stripWrapper(value: string): string {\n const noQuotes = stripQuotes(value);\n const withoutTicks = noQuotes.replace(/`/g, \"\").trim();\n const parts = withoutTicks.split(\".\");\n return parts[parts.length - 1]?.trim() ?? \"\";\n}\n\nfunction stripQuotes(value: string): string {\n if (\n (value.startsWith('\"') && value.endsWith('\"')) ||\n (value.startsWith(\"'\") && value.endsWith(\"'\"))\n ) {\n return value.slice(1, -1);\n }\n return value;\n}\n","import type {\n\tClickHouseSettings,\n\tDataFormat,\n\tQueryParams,\n} from \"@clickhouse/client\";\nimport type {\n\tColumnSchema,\n\tIntrospectOptions,\n\tSchemaIntrospection,\n\tTableSchema,\n} from \"../schema/types\";\nimport { parseKeyExpression, unwrapTypeModifiers } from \"../utils/clickhouse\";\nimport type { DatabaseAdapter, DatabaseExecutionResult } from \"./types\";\n\nexport interface ClickHouseAdapterOptions {\n\t/** Optional logical database name used in introspection metadata. */\n\tdatabase?: string;\n\t/** Override the default response format used for query execution. */\n\tdefaultFormat?: DataFormat;\n\t/**\n\t * Optional database kind label. Defaults to \"clickhouse\" but allows\n\t * sub-classing/custom branding if needed.\n\t */\n\tkind?: SchemaIntrospection[\"db\"][\"kind\"];\n\t/**\n\t * Optional allow-list of table names.\n\t * When specified, introspection and queries are restricted to these tables only.\n\t * ClickHouse tables are not schema-qualified, so just provide table names.\n\t */\n\tallowedTables?: string[];\n}\n\nexport type ClickHouseQueryResult = { json: () => Promise<unknown> };\n\nexport type ClickHouseClientFn = (\n\tparams: QueryParams,\n) => Promise<\n\t| ClickHouseQueryResult\n\t| Array<Record<string, unknown>>\n\t| Record<string, unknown>[]\n>;\n\ninterface QueryOptions {\n\tparams?: Record<string, unknown>;\n\tformat?: DataFormat;\n\tsettings?: ClickHouseSettings;\n}\n\ntype TableRow = {\n\tname: string;\n\tengine: string;\n\tcomment: string | null;\n\tprimary_key: string | null;\n};\n\ntype ColumnRow = {\n\ttable: string;\n\tname: string;\n\ttype: string;\n\tposition: number;\n\tcomment: string | null;\n\tis_in_primary_key: string | number | null;\n};\n\n/**\n * Simplified ClickHouse adapter following IngestRequest format\n * Removed: indexes, constraints, statistics\n * Kept only: tables, columns (name, type, isPrimaryKey, comment)\n */\nexport class ClickHouseAdapter implements DatabaseAdapter {\n\tprivate readonly databaseName: string;\n\tprivate readonly defaultFormat: QueryParams[\"format\"];\n\tprivate readonly kind: SchemaIntrospection[\"db\"][\"kind\"];\n\tprivate readonly allowedTables?: string[];\n\n\tconstructor(\n\t\tprivate readonly clientFn: ClickHouseClientFn,\n\t\toptions: ClickHouseAdapterOptions = {},\n\t) {\n\t\tthis.databaseName = options.database ?? \"default\";\n\t\tthis.defaultFormat = options.defaultFormat ?? \"JSONEachRow\";\n\t\tthis.kind = options.kind ?? \"clickhouse\";\n\t\tif (options.allowedTables) {\n\t\t\tthis.allowedTables = normalizeTableFilter(options.allowedTables);\n\t\t}\n\t}\n\n\tasync execute(\n\t\tsql: string,\n\t\tparams?: Record<string, string | number | boolean | string[] | number[]>,\n\t): Promise<DatabaseExecutionResult> {\n\t\t// Validate query against allowed tables if restrictions are in place\n\t\tif (this.allowedTables) {\n\t\t\tthis.validateQueryTables(sql);\n\t\t}\n\n\t\tconst queryOptions: QueryOptions = {\n\t\t\tformat: this.defaultFormat,\n\t\t};\n\t\tif (params) {\n\t\t\tqueryOptions.params = params;\n\t\t}\n\n\t\tconst rows = await this.query<Record<string, unknown>>(sql, queryOptions);\n\t\tconst fields = rows.length > 0 ? Object.keys(rows[0] ?? {}) : [];\n\t\treturn { fields, rows };\n\t}\n\n\tasync validate(\n\t\tsql: string,\n\t\tparams?: Record<string, string | number | boolean | string[] | number[]>,\n\t): Promise<void> {\n\t\tconst queryOptions: QueryOptions = {\n\t\t\tformat: this.defaultFormat,\n\t\t};\n\t\tif (params) {\n\t\t\tqueryOptions.params = params;\n\t\t}\n\n\t\tawait this.query(`EXPLAIN ${sql}`, queryOptions);\n\t}\n\n\tgetDialect() {\n\t\treturn \"clickhouse\" as const;\n\t}\n\n\t/**\n\t * Simplified introspection: only collect table/column metadata for IngestRequest\n\t * No indexes, constraints, or statistics\n\t */\n\tasync introspect(options?: IntrospectOptions): Promise<SchemaIntrospection> {\n\t\t// Use adapter-level allowedTables if no specific tables provided in options\n\t\tconst tablesToIntrospect = options?.tables\n\t\t\t? normalizeTableFilter(options.tables)\n\t\t\t: this.allowedTables;\n\t\tconst allowTables = tablesToIntrospect ?? [];\n\t\tconst hasFilter = allowTables.length > 0;\n\t\tconst queryParams: Record<string, unknown> = {\n\t\t\tdb: this.databaseName,\n\t\t};\n\t\tif (hasFilter) {\n\t\t\tqueryParams.tables = allowTables;\n\t\t}\n\n\t\tconst filterClause = hasFilter ? \" AND name IN {tables:Array(String)}\" : \"\";\n\t\tconst tables = await this.query<TableRow>(\n\t\t\t`SELECT name, engine, comment, primary_key\n FROM system.tables\n WHERE database = {db:String}${filterClause}\n ORDER BY name`,\n\t\t\t{ params: queryParams },\n\t\t);\n\n\t\tconst columnFilterClause = hasFilter\n\t\t\t? \" AND table IN {tables:Array(String)}\"\n\t\t\t: \"\";\n\t\tconst columns = await this.query<ColumnRow>(\n\t\t\t`SELECT table, name, type, position, comment, is_in_primary_key\n FROM system.columns\n WHERE database = {db:String}${columnFilterClause}\n ORDER BY table, position`,\n\t\t\t{ params: queryParams },\n\t\t);\n\n\t\tconst columnsByTable = new Map<string, ColumnSchema[]>();\n\t\tfor (const rawColumn of columns) {\n\t\t\tconst list = columnsByTable.get(rawColumn.table) ?? [];\n\t\t\tlist.push(transformColumnRow(rawColumn));\n\t\t\tcolumnsByTable.set(rawColumn.table, list);\n\t\t}\n\n\t\tconst tableSchemas: TableSchema[] = tables.map((table) => {\n\t\t\tconst tableColumns = columnsByTable.get(table.name) ?? [];\n\t\t\tconst primaryKeyColumns = parseKeyExpression(table.primary_key);\n\n\t\t\t// Mark columns as primary key\n\t\t\tfor (const column of tableColumns) {\n\t\t\t\tcolumn.isPrimaryKey =\n\t\t\t\t\tcolumn.isPrimaryKey || primaryKeyColumns.includes(column.name);\n\t\t\t}\n\n\t\t\tconst base: TableSchema = {\n\t\t\t\tname: table.name,\n\t\t\t\tschema: this.databaseName,\n\t\t\t\ttype: asTableType(table.engine),\n\t\t\t\tcolumns: tableColumns,\n\t\t\t};\n\n\t\t\tconst comment = sanitize(table.comment);\n\t\t\tif (comment !== undefined) {\n\t\t\t\tbase.comment = comment;\n\t\t\t}\n\n\t\t\treturn base;\n\t\t});\n\n\t\treturn {\n\t\t\tdb: {\n\t\t\t\tkind: this.kind,\n\t\t\t\tname: this.databaseName,\n\t\t\t},\n\t\t\ttables: tableSchemas,\n\t\t\tintrospectedAt: new Date().toISOString(),\n\t\t};\n\t}\n\n\tprivate validateQueryTables(sql: string): void {\n\t\tif (!this.allowedTables || this.allowedTables.length === 0) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst allowedSet = new Set(this.allowedTables);\n\n\t\t// Extract potential table references from SQL\n\t\tconst tablePattern =\n\t\t\t/(?:FROM|JOIN)\\s+(?:FINAL\\s+)?(?:(?:[a-zA-Z_][a-zA-Z0-9_]*)\\.)?([\"'`]?[a-zA-Z_][a-zA-Z0-9_]*[\"'`]?)/gi;\n\t\tconst matches = sql.matchAll(tablePattern);\n\n\t\tfor (const match of matches) {\n\t\t\tconst table = match[1]?.replace(/[\"'`]/g, \"\");\n\t\t\tif (table) {\n\t\t\t\tif (!allowedSet.has(table)) {\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t`Query references table \"${table}\" which is not in the allowed tables list`,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tasync close(): Promise<void> {\n\t\t// No-op: lifecycle of the underlying client is controlled by the caller.\n\t}\n\n\tprivate async query<T>(sql: string, options?: QueryOptions): Promise<T[]> {\n\t\tconst params: QueryParams = {\n\t\t\tquery: sql,\n\t\t};\n\n\t\tconst format = options?.format ?? this.defaultFormat;\n\t\tif (format !== undefined) {\n\t\t\tparams.format = format;\n\t\t}\n\n\t\tif (options?.params) {\n\t\t\tparams.query_params = options.params;\n\t\t}\n\n\t\tif (options?.settings) {\n\t\t\tparams.clickhouse_settings = options.settings;\n\t\t}\n\n\t\tconst result = await this.clientFn(params);\n\t\treturn this.extractRows<T>(result);\n\t}\n\n\tprivate async extractRows<T>(\n\t\tresult:\n\t\t\t| ClickHouseQueryResult\n\t\t\t| Array<Record<string, unknown>>\n\t\t\t| Record<string, unknown>[],\n\t): Promise<T[]> {\n\t\tif (Array.isArray(result)) {\n\t\t\treturn result as T[];\n\t\t}\n\n\t\tif (\n\t\t\tresult &&\n\t\t\ttypeof (result as ClickHouseQueryResult).json === \"function\"\n\t\t) {\n\t\t\tconst payload = await (result as ClickHouseQueryResult).json();\n\t\t\treturn normalizePayload<T>(payload);\n\t\t}\n\n\t\treturn [];\n\t}\n}\n\nfunction normalizePayload<T>(payload: unknown): T[] {\n\tif (Array.isArray(payload)) {\n\t\treturn payload as T[];\n\t}\n\tif (payload && typeof payload === \"object\") {\n\t\tconst maybeData = (payload as { data?: unknown }).data;\n\t\tif (Array.isArray(maybeData)) {\n\t\t\treturn maybeData as T[];\n\t\t}\n\t}\n\treturn [];\n}\n\nfunction normalizeTableFilter(tables?: string[] | null): string[] {\n\tif (!tables?.length) return [];\n\tconst seen = new Set<string>();\n\tconst normalized: string[] = [];\n\tfor (const table of tables) {\n\t\tif (!table) continue;\n\t\tconst trimmed = table.trim();\n\t\tif (!trimmed) continue;\n\t\tconst parts = trimmed.split(\".\");\n\t\tconst tableName = parts[parts.length - 1];\n\t\tif (!tableName || seen.has(tableName)) continue;\n\t\tseen.add(tableName);\n\t\tnormalized.push(tableName);\n\t}\n\treturn normalized;\n}\n\nfunction transformColumnRow(row: ColumnRow): ColumnSchema {\n\tconst unwrappedType = unwrapTypeModifiers(row.type);\n\n\tconst column: ColumnSchema = {\n\t\tname: row.name,\n\t\ttype: unwrappedType,\n\t\trawType: row.type,\n\t\tisPrimaryKey: Boolean(toNumber(row.is_in_primary_key)),\n\t};\n\n\tconst comment = sanitize(row.comment);\n\tif (comment !== undefined) column.comment = comment;\n\n\treturn column;\n}\n\nfunction asTableType(engine: unknown): TableSchema[\"type\"] {\n\tif (typeof engine === \"string\") {\n\t\tconst normalized = engine.toLowerCase();\n\t\t// ClickHouse view engines: View, MaterializedView, LiveView\n\t\tif (normalized.includes(\"view\")) {\n\t\t\treturn \"view\";\n\t\t}\n\t}\n\treturn \"table\";\n}\n\nfunction sanitize(value: unknown): string | undefined {\n\tif (value === null || value === undefined) return undefined;\n\tconst trimmed = String(value).trim();\n\treturn trimmed.length ? trimmed : undefined;\n}\n\nfunction toNumber(value: unknown): number | undefined {\n\tif (value === null || value === undefined) return undefined;\n\tif (typeof value === \"number\") return value;\n\tconst parsed = Number.parseFloat(String(value));\n\treturn Number.isNaN(parsed) ? undefined : parsed;\n}\n","import type {\n\tColumnSchema,\n\tIntrospectOptions,\n\tSchemaIntrospection,\n\tTableSchema,\n} from \"../schema/types\";\nimport type { DatabaseAdapter, DatabaseExecutionResult } from \"./types\";\n\nexport interface PostgresQueryResult {\n\trows: Array<Record<string, unknown>>;\n\tfields: Array<{ name: string }>;\n}\n\nexport type PostgresClientFn = (\n\tsql: string,\n\tparams?: unknown[],\n) => Promise<PostgresQueryResult>;\n\nexport interface PostgresAdapterOptions {\n\t/** Logical database name used in introspection metadata. */\n\tdatabase?: string;\n\t/** Schema to assume when a table is provided without qualification. */\n\tdefaultSchema?: string;\n\t/** Optional database kind label. Defaults to \"postgres\". */\n\tkind?: SchemaIntrospection[\"db\"][\"kind\"];\n\t/**\n\t * Optional allow-list of table names (schema-qualified or bare).\n\t * When specified, introspection and queries are restricted to these tables only.\n\t */\n\tallowedTables?: string[];\n}\n\ntype TableRow = {\n\ttable_name: string;\n\tschema_name: string;\n\ttable_type: string;\n\tcomment: string | null;\n};\n\ntype ColumnRow = {\n\ttable_name: string;\n\ttable_schema: string;\n\tcolumn_name: string;\n\tdata_type: string;\n\tudt_name: string | null;\n\tis_primary_key: boolean;\n\tdescription: string | null;\n};\n\ninterface NormalizedTable {\n\tschema: string;\n\ttable: string;\n}\n\n/**\n * Simplified PostgreSQL adapter following IngestRequest format\n * Removed: indexes, constraints, foreign keys, statistics\n * Kept only: tables, columns (name, type, isPrimaryKey, comment)\n */\nexport class PostgresAdapter implements DatabaseAdapter {\n\tprivate readonly databaseName: string;\n\tprivate readonly defaultSchema: string;\n\tprivate readonly kind: SchemaIntrospection[\"db\"][\"kind\"];\n\tprivate readonly allowedTables?: NormalizedTable[];\n\n\tconstructor(\n\t\tprivate readonly clientFn: PostgresClientFn,\n\t\toptions: PostgresAdapterOptions = {},\n\t) {\n\t\tthis.databaseName = options.database ?? \"postgres\";\n\t\tthis.defaultSchema = options.defaultSchema ?? \"public\";\n\t\tthis.kind = options.kind ?? \"postgres\";\n\t\tif (options.allowedTables) {\n\t\t\tthis.allowedTables = normalizeTableFilter(\n\t\t\t\toptions.allowedTables,\n\t\t\t\tthis.defaultSchema,\n\t\t\t);\n\t\t}\n\t}\n\n\tasync execute(\n\t\tsql: string,\n\t\tparams?: Record<string, string | number | boolean | string[] | number[]>,\n\t): Promise<DatabaseExecutionResult> {\n\t\t// Validate query against allowed tables if restrictions are in place\n\t\tif (this.allowedTables) {\n\t\t\tthis.validateQueryTables(sql);\n\t\t}\n\n\t\t// Convert named params to positional array for PostgreSQL\n\t\tlet paramArray: unknown[] | undefined;\n\t\tif (params) {\n\t\t\tparamArray = this.convertNamedToPositionalParams(params);\n\t\t}\n\n\t\tconst result = await this.clientFn(sql, paramArray);\n\t\tconst fields = result.fields.map((f) => f.name);\n\t\treturn { fields, rows: result.rows };\n\t}\n\n\tprivate validateQueryTables(sql: string): void {\n\t\tif (!this.allowedTables || this.allowedTables.length === 0) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst allowedSet = new Set(\n\t\t\tthis.allowedTables.map((t) => tableKey(t.schema, t.table)),\n\t\t);\n\n\t\t// Extract potential table references from SQL\n\t\tconst tablePattern =\n\t\t\t/(?:FROM|JOIN)\\s+(?:ONLY\\s+)?(?:([a-zA-Z_][a-zA-Z0-9_]*)\\.)?([\"']?[a-zA-Z_][a-zA-Z0-9_]*[\"']?)/gi;\n\t\tconst matches = sql.matchAll(tablePattern);\n\n\t\tfor (const match of matches) {\n\t\t\tconst schema = match[1] ?? this.defaultSchema;\n\t\t\tconst table = match[2]?.replace(/['\"]/g, \"\");\n\t\t\tif (table) {\n\t\t\t\tconst key = tableKey(schema, table);\n\t\t\t\tif (!allowedSet.has(key)) {\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t`Query references table \"${schema}.${table}\" which is not in the allowed tables list`,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Convert named params to positional array for PostgreSQL\n\t * PostgreSQL expects $1, $2, $3 in SQL and an array of values [val1, val2, val3]\n\t */\n\tprivate convertNamedToPositionalParams(\n\t\tparams: Record<string, string | number | boolean | string[] | number[]>,\n\t): unknown[] {\n\t\t// Separate numeric and named keys\n\t\tconst numericKeys = Object.keys(params)\n\t\t\t.filter((k) => /^\\d+$/.test(k))\n\t\t\t.map((k) => Number.parseInt(k, 10))\n\t\t\t.sort((a, b) => a - b);\n\n\t\tconst namedKeys = Object.keys(params)\n\t\t\t.filter((k) => !/^\\d+$/.test(k))\n\t\t\t.sort(); // Alphabetical order for consistency\n\n\t\t// Build positional array\n\t\tconst positionalParams: unknown[] = [];\n\n\t\t// First, add values from numeric keys (in sorted order)\n\t\tfor (const key of numericKeys) {\n\t\t\tlet val: unknown = params[String(key)];\n\t\t\tif (typeof val === \"string\") {\n\t\t\t\t// Resolve placeholder tokens like `<tenant_id>` to their named values\n\t\t\t\tconst match = val.match(/^<([a-zA-Z0-9_]+)>$/);\n\t\t\t\tconst namedKey = match?.[1];\n\t\t\t\tif (namedKey && namedKey in params) {\n\t\t\t\t\tval = params[namedKey as keyof typeof params];\n\t\t\t\t}\n\t\t\t}\n\t\t\tpositionalParams.push(val);\n\t\t}\n\n\t\t// Then, add values from named keys (in alphabetical order)\n\t\tfor (const key of namedKeys) {\n\t\t\tconst val = params[key];\n\t\t\tpositionalParams.push(val);\n\t\t}\n\n\t\treturn positionalParams;\n\t}\n\n\tasync validate(\n\t\tsql: string,\n\t\tparams?: Record<string, string | number | boolean | string[] | number[]>,\n\t): Promise<void> {\n\t\tlet paramArray: unknown[] | undefined;\n\t\tif (params) {\n\t\t\tparamArray = this.convertNamedToPositionalParams(params);\n\t\t}\n\n\t\tawait this.clientFn(`EXPLAIN ${sql}`, paramArray);\n\t}\n\n\tgetDialect() {\n\t\treturn \"postgres\" as const;\n\t}\n\n\t/**\n\t * Simplified introspection: only collect table/column metadata for IngestRequest\n\t * No indexes, constraints, or statistics\n\t */\n\tasync introspect(options?: IntrospectOptions): Promise<SchemaIntrospection> {\n\t\t// Use adapter-level allowedTables if no specific tables provided in options\n\t\tconst tablesToIntrospect = options?.tables\n\t\t\t? normalizeTableFilter(options.tables, this.defaultSchema)\n\t\t\t: this.allowedTables;\n\t\tconst normalizedTables = tablesToIntrospect ?? [];\n\n\t\tconst tablesResult = await this.clientFn(\n\t\t\tbuildTablesQuery(normalizedTables),\n\t\t);\n\t\tconst tableRows = tablesResult.rows as TableRow[];\n\n\t\tconst columnsResult = await this.clientFn(\n\t\t\tbuildColumnsQuery(normalizedTables),\n\t\t);\n\t\tconst columnRows = columnsResult.rows as ColumnRow[];\n\n\t\tconst tablesByKey = new Map<string, TableSchema>();\n\n\t\t// Build tables\n\t\tfor (const row of tableRows) {\n\t\t\tconst key = tableKey(row.schema_name, row.table_name);\n\t\t\tconst table: TableSchema = {\n\t\t\t\tname: row.table_name,\n\t\t\t\tschema: row.schema_name,\n\t\t\t\ttype: asTableType(row.table_type),\n\t\t\t\tcolumns: [],\n\t\t\t};\n\n\t\t\tconst comment = sanitize(row.comment);\n\t\t\tif (comment !== undefined) {\n\t\t\t\ttable.comment = comment;\n\t\t\t}\n\n\t\t\ttablesByKey.set(key, table);\n\t\t}\n\n\t\t// Build columns\n\t\tfor (const row of columnRows) {\n\t\t\tconst key = tableKey(row.table_schema, row.table_name);\n\t\t\tconst table = tablesByKey.get(key);\n\t\t\tif (!table) continue;\n\n\t\t\tconst column: ColumnSchema = {\n\t\t\t\tname: row.column_name,\n\t\t\t\ttype: row.data_type,\n\t\t\t\tisPrimaryKey: row.is_primary_key,\n\t\t\t};\n\n\t\t\tconst rawType = row.udt_name ?? undefined;\n\t\t\tif (rawType !== undefined) column.rawType = rawType;\n\n\t\t\tconst comment = sanitize(row.description);\n\t\t\tif (comment !== undefined) column.comment = comment;\n\n\t\t\ttable.columns.push(column);\n\t\t}\n\n\t\tconst tables = Array.from(tablesByKey.values()).sort((a, b) => {\n\t\t\tif (a.schema === b.schema) {\n\t\t\t\treturn a.name.localeCompare(b.name);\n\t\t\t}\n\t\t\treturn a.schema.localeCompare(b.schema);\n\t\t});\n\n\t\treturn {\n\t\t\tdb: {\n\t\t\t\tkind: this.kind,\n\t\t\t\tname: this.databaseName,\n\t\t\t},\n\t\t\ttables,\n\t\t\tintrospectedAt: new Date().toISOString(),\n\t\t};\n\t}\n}\n\nfunction normalizeTableFilter(\n\ttables: string[] | undefined,\n\tdefaultSchema: string,\n): NormalizedTable[] {\n\tif (!tables?.length) return [];\n\tconst normalized: NormalizedTable[] = [];\n\tconst seen = new Set<string>();\n\n\tfor (const raw of tables) {\n\t\tif (!raw) continue;\n\t\tconst trimmed = raw.trim();\n\t\tif (!trimmed) continue;\n\t\tconst parts = trimmed.split(\".\");\n\t\tconst table = parts.pop() ?? \"\";\n\t\tconst schema = parts.pop() ?? defaultSchema;\n\t\tif (!isSafeIdentifier(schema) || !isSafeIdentifier(table)) {\n\t\t\tcontinue;\n\t\t}\n\t\tconst key = tableKey(schema, table);\n\t\tif (seen.has(key)) continue;\n\t\tseen.add(key);\n\t\tnormalized.push({ schema, table });\n\t}\n\n\treturn normalized;\n}\n\nfunction buildTablesQuery(tables: NormalizedTable[]): string {\n\tconst filter = buildFilterClause(tables, \"n.nspname\", \"c.relname\");\n\treturn `SELECT\n c.relname AS table_name,\n n.nspname AS schema_name,\n CASE c.relkind\n WHEN 'r' THEN 'table'\n WHEN 'v' THEN 'view'\n WHEN 'm' THEN 'materialized_view'\n ELSE c.relkind::text\n END AS table_type,\n obj_description(c.oid) AS comment\n FROM pg_class c\n JOIN pg_namespace n ON n.oid = c.relnamespace\n WHERE n.nspname NOT IN ('pg_catalog', 'information_schema')\n AND c.relkind IN ('r', 'v', 'm')\n ${filter}\n ORDER BY n.nspname, c.relname;`;\n}\n\nfunction buildColumnsQuery(tables: NormalizedTable[]): string {\n\tconst filter = buildFilterClause(\n\t\ttables,\n\t\t\"cols.table_schema\",\n\t\t\"cols.table_name\",\n\t);\n\treturn `SELECT\n cols.table_name,\n cols.table_schema,\n cols.column_name,\n cols.data_type,\n cols.udt_name,\n pgd.description,\n EXISTS(\n SELECT 1\n FROM information_schema.table_constraints tc\n JOIN information_schema.key_column_usage kcu\n ON tc.constraint_name = kcu.constraint_name\n AND tc.table_schema = kcu.table_schema\n WHERE tc.constraint_type = 'PRIMARY KEY'\n AND tc.table_schema = cols.table_schema\n AND tc.table_name = cols.table_name\n AND kcu.column_name = cols.column_name\n ) AS is_primary_key\n FROM information_schema.columns cols\n LEFT JOIN pg_catalog.pg_class c\n ON c.relname = cols.table_name\n AND c.relkind IN ('r', 'v', 'm')\n LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace\n LEFT JOIN pg_catalog.pg_attribute attr\n ON attr.attrelid = c.oid\n AND attr.attname = cols.column_name\n LEFT JOIN pg_catalog.pg_description pgd\n ON pgd.objoid = attr.attrelid AND pgd.objsubid = attr.attnum\n WHERE cols.table_schema NOT IN ('pg_catalog', 'information_schema')\n ${filter}\n ORDER BY cols.table_schema, cols.table_name, cols.ordinal_position;`;\n}\n\nfunction buildFilterClause(\n\ttables: NormalizedTable[],\n\tschemaExpr: string,\n\ttableExpr: string,\n): string {\n\tif (!tables.length) return \"\";\n\tconst clauses = tables.map(({ schema, table }) => {\n\t\treturn `(${schemaExpr} = '${schema}' AND ${tableExpr} = '${table}')`;\n\t});\n\treturn `AND (${clauses.join(\" OR \")})`;\n}\n\nfunction tableKey(schema: string, table: string): string {\n\treturn `${schema}.${table}`;\n}\n\nfunction isSafeIdentifier(value: string): boolean {\n\treturn /^[A-Za-z_][A-Za-z0-9_]*$/.test(value);\n}\n\nfunction asTableType(value: string): TableSchema[\"type\"] {\n\tconst normalized = value.toLowerCase();\n\tif (normalized.includes(\"view\")) {\n\t\treturn normalized.includes(\"materialized\") ? \"materialized_view\" : \"view\";\n\t}\n\treturn \"table\";\n}\n\nfunction sanitize(value: unknown): string | undefined {\n\tif (value === null || value === undefined) return undefined;\n\tconst trimmed = String(value).trim();\n\treturn trimmed.length ? trimmed : undefined;\n}\n","import { createSign } from \"node:crypto\";\n\n/**\n * Deep module: Hides JWT signing and HTTP complexity behind simple interface\n * Following Ousterhout's principle: \"Pull complexity downward\"\n */\nexport class ApiClient {\n\tprivate readonly baseUrl: string;\n\tprivate readonly privateKey: string;\n\tprivate readonly organizationId: string;\n\tprivate readonly defaultTenantId?: string;\n\tprivate readonly additionalHeaders?: Record<string, string>;\n\tprivate readonly fetchImpl: typeof fetch;\n\n\tconstructor(\n\t\tbaseUrl: string,\n\t\tprivateKey: string,\n\t\torganizationId: string,\n\t\toptions?: {\n\t\t\tdefaultTenantId?: string;\n\t\t\tadditionalHeaders?: Record<string, string>;\n\t\t\tfetch?: typeof fetch;\n\t\t},\n\t) {\n\t\tif (!baseUrl) {\n\t\t\tthrow new Error(\"Base URL is required\");\n\t\t}\n\t\tif (!privateKey) {\n\t\t\tthrow new Error(\"Private key is required\");\n\t\t}\n\t\tif (!organizationId) {\n\t\t\tthrow new Error(\"Organization ID is required\");\n\t\t}\n\n\t\tthis.baseUrl = baseUrl.replace(/\\/+$/, \"\");\n\t\tthis.privateKey = privateKey;\n\t\tthis.organizationId = organizationId;\n\t\tthis.defaultTenantId = options?.defaultTenantId;\n\t\tthis.additionalHeaders = options?.additionalHeaders;\n\t\tthis.fetchImpl = options?.fetch ?? globalThis.fetch;\n\n\t\tif (!this.fetchImpl) {\n\t\t\tthrow new Error(\n\t\t\t\t\"Fetch implementation not found. Provide options.fetch or use Node 18+.\",\n\t\t\t);\n\t\t}\n\t}\n\n\tgetDefaultTenantId(): string | undefined {\n\t\treturn this.defaultTenantId;\n\t}\n\n\tasync get<T>(\n\t\tpath: string,\n\t\ttenantId: string,\n\t\tuserId?: string,\n\t\tscopes?: string[],\n\t\tsignal?: AbortSignal,\n\t\tsessionId?: string,\n\t): Promise<T> {\n\t\treturn await this.request<T>(path, {\n\t\t\tmethod: \"GET\",\n\t\t\theaders: await this.buildHeaders(\n\t\t\t\ttenantId,\n\t\t\t\tuserId,\n\t\t\t\tscopes,\n\t\t\t\tfalse,\n\t\t\t\tsessionId,\n\t\t\t),\n\t\t\tsignal,\n\t\t});\n\t}\n\n\tasync post<T>(\n\t\tpath: string,\n\t\tbody: unknown,\n\t\ttenantId: string,\n\t\tuserId?: string,\n\t\tscopes?: string[],\n\t\tsignal?: AbortSignal,\n\t\tsessionId?: string,\n\t): Promise<T> {\n\t\treturn await this.request<T>(path, {\n\t\t\tmethod: \"POST\",\n\t\t\theaders: await this.buildHeaders(\n\t\t\t\ttenantId,\n\t\t\t\tuserId,\n\t\t\t\tscopes,\n\t\t\t\ttrue,\n\t\t\t\tsessionId,\n\t\t\t),\n\t\t\tbody: JSON.stringify(body ?? {}),\n\t\t\tsignal,\n\t\t});\n\t}\n\n\tasync put<T>(\n\t\tpath: string,\n\t\tbody: unknown,\n\t\ttenantId: string,\n\t\tuserId?: string,\n\t\tscopes?: string[],\n\t\tsignal?: AbortSignal,\n\t\tsessionId?: string,\n\t): Promise<T> {\n\t\treturn await this.request<T>(path, {\n\t\t\tmethod: \"PUT\",\n\t\t\theaders: await this.buildHeaders(\n\t\t\t\ttenantId,\n\t\t\t\tuserId,\n\t\t\t\tscopes,\n\t\t\t\ttrue,\n\t\t\t\tsessionId,\n\t\t\t),\n\t\t\tbody: JSON.stringify(body ?? {}),\n\t\t\tsignal,\n\t\t});\n\t}\n\n\tasync delete<T = void>(\n\t\tpath: string,\n\t\ttenantId: string,\n\t\tuserId?: string,\n\t\tscopes?: string[],\n\t\tsignal?: AbortSignal,\n\t\tsessionId?: string,\n\t): Promise<T> {\n\t\treturn await this.request<T>(path, {\n\t\t\tmethod: \"DELETE\",\n\t\t\theaders: await this.buildHeaders(\n\t\t\t\ttenantId,\n\t\t\t\tuserId,\n\t\t\t\tscopes,\n\t\t\t\tfalse,\n\t\t\t\tsessionId,\n\t\t\t),\n\t\t\tsignal,\n\t\t});\n\t}\n\n\tprivate async request<T>(path: string, init: RequestInit): Promise<T> {\n\t\tconst response = await this.fetchImpl(`${this.baseUrl}${path}`, init);\n\t\tconst text = await response.text();\n\t\tlet json: any;\n\t\ttry {\n\t\t\tjson = text ? JSON.parse(text) : undefined;\n\t\t} catch {\n\t\t\tjson = undefined;\n\t\t}\n\n\t\tif (!response.ok) {\n\t\t\tconst error = new Error(\n\t\t\t\tjson?.error || response.statusText || \"Request failed\",\n\t\t\t);\n\t\t\t(error as any).status = response.status;\n\t\t\tif (json?.details) (error as any).details = json.details;\n\t\t\tthrow error;\n\t\t}\n\n\t\treturn json as T;\n\t}\n\n\tprivate async buildHeaders(\n\t\ttenantId: string,\n\t\tuserId?: string,\n\t\tscopes?: string[],\n\t\tincludeJson: boolean = true,\n\t\tsessionId?: string,\n\t): Promise<Record<string, string>> {\n\t\tconst token = await this.generateJWT(tenantId, userId, scopes);\n\t\tconst headers: Record<string, string> = {\n\t\t\tAuthorization: `Bearer ${token}`,\n\t\t\tAccept: \"application/json\",\n\t\t};\n\t\tif (includeJson) {\n\t\t\theaders[\"Content-Type\"] = \"application/json\";\n\t\t}\n\t\tif (sessionId) {\n\t\t\theaders[\"x-session-id\"] = sessionId;\n\t\t}\n\t\tif (this.additionalHeaders) {\n\t\t\tObject.assign(headers, this.additionalHeaders);\n\t\t}\n\t\treturn headers;\n\t}\n\n\tprivate async generateJWT(\n\t\ttenantId: string,\n\t\tuserId?: string,\n\t\tscopes?: string[],\n\t): Promise<string> {\n\t\tconst header = {\n\t\t\talg: \"RS256\",\n\t\t\ttyp: \"JWT\",\n\t\t};\n\n\t\tconst payload: Record<string, unknown> = {\n\t\t\torganizationId: this.organizationId,\n\t\t\ttenantId,\n\t\t};\n\n\t\tif (userId) payload.userId = userId;\n\t\tif (scopes?.length) payload.scopes = scopes;\n\n\t\tconst encodeJson = (obj: unknown): string => {\n\t\t\tconst json = JSON.stringify(obj);\n\t\t\tconst base64 = Buffer.from(json).toString(\"base64\");\n\t\t\t// base64url encoding: replace non-url chars and strip padding\n\t\t\treturn base64.replace(/\\+/g, \"-\").replace(/\\//g, \"_\").replace(/=+$/g, \"\");\n\t\t};\n\n\t\tconst encodedHeader = encodeJson(header);\n\t\tconst encodedPayload = encodeJson(payload);\n\t\tconst data = `${encodedHeader}.${encodedPayload}`;\n\n\t\tconst signer = createSign(\"RSA-SHA256\");\n\t\tsigner.update(data);\n\t\tsigner.end();\n\n\t\tconst signature = signer.sign(this.privateKey);\n\t\tconst encodedSignature = signature\n\t\t\t.toString(\"base64\")\n\t\t\t.replace(/\\+/g, \"-\")\n\t\t\t.replace(/\\//g, \"_\")\n\t\t\t.replace(/=+$/g, \"\");\n\n\t\treturn `${data}.${encodedSignature}`;\n\t}\n}\n","import type { DatabaseAdapter, DatabaseDialect } from \"../adapters/types\";\n\nexport type ParamValue = string | number | boolean | string[] | number[];\nexport type ParamRecord = Record<string, ParamValue>;\n\nexport interface DatabaseMetadata {\n\tname: string;\n\tdialect: DatabaseDialect;\n\tdescription?: string;\n\ttags?: string[];\n\ttenantFieldName?: string;\n\ttenantFieldType?: string;\n\tenforceTenantIsolation?: boolean;\n}\n\nexport interface DatabaseExecutionResult {\n\trows: Array<Record<string, unknown>>;\n\tfields: string[];\n}\n\n/**\n * Deep module: Hides SQL execution complexity and tenant isolation logic\n * Following Ousterhout's principle: \"Information hiding\"\n */\nexport class QueryEngine {\n\tprivate databases = new Map<string, DatabaseAdapter>();\n\tprivate databaseMetadata = new Map<string, DatabaseMetadata>();\n\tprivate defaultDatabase?: string;\n\n\tattachDatabase(name: string, adapter: DatabaseAdapter, metadata: DatabaseMetadata): void {\n\t\tthis.databases.set(name, adapter);\n\t\tthis.databaseMetadata.set(name, metadata);\n\t\tif (!this.defaultDatabase) {\n\t\t\tthis.defaultDatabase = name;\n\t\t}\n\t}\n\n\tgetDatabase(name?: string): DatabaseAdapter {\n\t\tconst dbName = name ?? this.defaultDatabase;\n\t\tif (!dbName) {\n\t\t\tthrow new Error(\"No database attached.\");\n\t\t}\n\t\tconst adapter = this.databases.get(dbName);\n\t\tif (!adapter) {\n\t\t\tthrow new Error(\n\t\t\t\t`Database '${dbName}' not found. Attached: ${Array.from(\n\t\t\t\t\tthis.databases.keys(),\n\t\t\t\t).join(\", \")}`,\n\t\t\t);\n\t\t}\n\t\treturn adapter;\n\t}\n\n\tgetDatabaseMetadata(name?: string): DatabaseMetadata | undefined {\n\t\tconst dbName = name ?? this.defaultDatabase;\n\t\tif (!dbName) return undefined;\n\t\treturn this.databaseMetadata.get(dbName);\n\t}\n\n\tgetDefaultDatabase(): string | undefined {\n\t\treturn this.defaultDatabase;\n\t}\n\n\tasync validateAndExecute(\n\t\tsql: string,\n\t\tparams: ParamRecord,\n\t\tdatabaseName: string,\n\t\ttenantId: string,\n\t): Promise<DatabaseExecutionResult> {\n\t\tconst adapter = this.getDatabase(databaseName);\n\t\tconst metadata = this.getDatabaseMetadata(databaseName);\n\n\t\t// Apply tenant isolation if configured\n\t\tlet finalSql = sql;\n\t\tif (metadata) {\n\t\t\tfinalSql = this.ensureTenantIsolation(sql, params, metadata, tenantId);\n\t\t}\n\n\t\t// Validate SQL\n\t\tawait adapter.validate(finalSql, params);\n\n\t\t// Execute\n\t\tconst result = await adapter.execute(finalSql, params);\n\t\treturn {\n\t\t\trows: result.rows,\n\t\t\tfields: result.fields,\n\t\t};\n\t}\n\n\tasync execute(\n\t\tsql: string,\n\t\tparams: ParamRecord | undefined,\n\t\tdatabaseName?: string,\n\t): Promise<Array<Record<string, unknown>>> {\n\t\ttry {\n\t\t\tconst adapter = this.getDatabase(databaseName);\n\t\t\tconst result = await adapter.execute(sql, params);\n\t\t\treturn result.rows;\n\t\t} catch (error) {\n\t\t\tconsole.warn(\n\t\t\t\t`Failed to execute SQL locally for database '${databaseName}':`,\n\t\t\t\terror,\n\t\t\t);\n\t\t\treturn [];\n\t\t}\n\t}\n\n\tmapGeneratedParams(params: Array<Record<string, unknown>>): ParamRecord {\n\t\tconst record: ParamRecord = {};\n\n\t\tparams.forEach((param, index) => {\n\t\t\tconst value = param.value as ParamValue | undefined;\n\t\t\tif (value === undefined) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst nameCandidate =\n\t\t\t\t(typeof param.name === \"string\" && param.name.trim()) ||\n\t\t\t\t(typeof param.placeholder === \"string\" && param.placeholder.trim()) ||\n\t\t\t\t(typeof param.position === \"number\" && String(param.position)) ||\n\t\t\t\tString(index + 1);\n\t\t\tconst key = nameCandidate.replace(/[{}:$]/g, \"\").trim();\n\t\t\trecord[key] = value;\n\t\t});\n\n\t\treturn record;\n\t}\n\n\tprivate ensureTenantIsolation(\n\t\tsql: string,\n\t\tparams: ParamRecord,\n\t\tmetadata: DatabaseMetadata,\n\t\ttenantId: string,\n\t): string {\n\t\tif (\n\t\t\t!metadata.tenantFieldName ||\n\t\t\tmetadata.enforceTenantIsolation === false\n\t\t) {\n\t\t\treturn sql;\n\t\t}\n\n\t\tconst tenantField = metadata.tenantFieldName;\n\t\tconst paramKey = tenantField;\n\t\tparams[paramKey] = tenantId;\n\n\t\tconst normalizedSql = sql.toLowerCase();\n\t\tif (normalizedSql.includes(tenantField.toLowerCase())) {\n\t\t\treturn sql;\n\t\t}\n\n\t\tconst tenantPredicate =\n\t\t\tmetadata.dialect === \"clickhouse\"\n\t\t\t\t? `${tenantField} = {${tenantField}:${metadata.tenantFieldType ?? \"String\"}}`\n\t\t\t\t: `${tenantField} = '${tenantId}'`;\n\n\t\tif (/\\bwhere\\b/i.test(sql)) {\n\t\t\treturn sql.replace(\n\t\t\t\t/\\bwhere\\b/i,\n\t\t\t\t(match) => `${match} ${tenantPredicate} AND `,\n\t\t\t);\n\t\t}\n\n\t\treturn `${sql} WHERE ${tenantPredicate}`;\n\t}\n}\n","import type { ApiClient } from \"../core/client\";\nimport type { ParamRecord, QueryEngine } from \"../core/query-engine\";\n\nexport interface SdkChart {\n\tid: string;\n\ttitle: string;\n\tdescription: string | null;\n\tsql: string;\n\tsql_params: Record<string, unknown> | null;\n\tvega_lite_spec: Record<string, unknown>;\n\tquery_id: string | null;\n\torganization_id: string | null;\n\ttenant_id: string | null;\n\tuser_id: string | null;\n\tcreated_at: string | null;\n\tupdated_at: string | null;\n\tactive?: boolean;\n\ttarget_db?: string | null;\n}\n\nexport interface ChartCreateInput {\n\ttitle: string;\n\tdescription?: string;\n\tsql: string;\n\tsql_params?: Record<string, unknown>;\n\tvega_lite_spec: Record<string, unknown>;\n\tquery_id?: string;\n\ttarget_db?: string;\n}\n\nexport interface ChartUpdateInput {\n\ttitle?: string;\n\tdescription?: string;\n\tsql?: string;\n\tsql_params?: Record<string, unknown>;\n\tvega_lite_spec?: Record<string, unknown>;\n\ttarget_db?: string;\n}\n\nexport interface PaginationQuery {\n\tpage?: number;\n\tlimit?: number;\n}\n\nexport interface PaginationInfo {\n\tpage: number;\n\tlimit: number;\n\ttotal: number;\n\ttotalPages: number;\n\thasNext: boolean;\n\thasPrev: boolean;\n}\n\nexport interface PaginatedResponse<T> {\n\tdata: T[];\n\tpagination: PaginationInfo;\n}\n\nexport interface ChartListOptions {\n\ttenantId?: string;\n\tuserId?: string;\n\tscopes?: string[];\n\tpagination?: PaginationQuery;\n\tsortBy?: \"title\" | \"user_id\" | \"created_at\" | \"updated_at\";\n\tsortDir?: \"asc\" | \"desc\";\n\ttitle?: string;\n\tuserFilter?: string;\n\tcreatedFrom?: string;\n\tcreatedTo?: string;\n\tupdatedFrom?: string;\n\tupdatedTo?: string;\n\tincludeData?: boolean;\n}\n\ninterface RequestOptions {\n\ttenantId?: string;\n\tuserId?: string;\n\tscopes?: string[];\n}\n\n/**\n * Route module for Chart CRUD operations\n * Simple pass-through to backend with optional data hydration\n */\nexport async function createChart(\n\tclient: ApiClient,\n\tbody: ChartCreateInput,\n\toptions?: RequestOptions,\n\tsignal?: AbortSignal,\n): Promise<SdkChart> {\n\tconst tenantId = resolveTenantId(client, options?.tenantId);\n\treturn await client.post<SdkChart>(\n\t\t\"/charts\",\n\t\tbody,\n\t\ttenantId,\n\t\toptions?.userId,\n\t\toptions?.scopes,\n\t\tsignal,\n\t);\n}\n\nexport async function listCharts(\n\tclient: ApiClient,\n\tqueryEngine: QueryEngine,\n\toptions?: ChartListOptions,\n\tsignal?: AbortSignal,\n): Promise<PaginatedResponse<SdkChart>> {\n\tconst tenantId = resolveTenantId(client, options?.tenantId);\n\tconst params = new URLSearchParams();\n\tif (options?.pagination?.page)\n\t\tparams.set(\"page\", `${options.pagination.page}`);\n\tif (options?.pagination?.limit)\n\t\tparams.set(\"limit\", `${options.pagination.limit}`);\n\tif (options?.sortBy) params.set(\"sort_by\", options.sortBy);\n\tif (options?.sortDir) params.set(\"sort_dir\", options.sortDir);\n\tif (options?.title) params.set(\"title\", options.title);\n\tif (options?.userFilter) params.set(\"user_id\", options.userFilter);\n\tif (options?.createdFrom) params.set(\"created_from\", options.createdFrom);\n\tif (options?.createdTo) params.set(\"created_to\", options.createdTo);\n\tif (options?.updatedFrom) params.set(\"updated_from\", options.updatedFrom);\n\tif (options?.updatedTo) params.set(\"updated_to\", options.updatedTo);\n\n\tconst response = await client.get<PaginatedResponse<SdkChart>>(\n\t\t`/charts${params.toString() ? `?${params.toString()}` : \"\"}`,\n\t\ttenantId,\n\t\toptions?.userId,\n\t\toptions?.scopes,\n\t\tsignal,\n\t);\n\n\tif (options?.includeData) {\n\t\tresponse.data = await Promise.all(\n\t\t\tresponse.data.map(async (chart) => ({\n\t\t\t\t...chart,\n\t\t\t\tvega_lite_spec: {\n\t\t\t\t\t...chart.vega_lite_spec,\n\t\t\t\t\tdata: {\n\t\t\t\t\t\tvalues: await queryEngine.execute(\n\t\t\t\t\t\t\tchart.sql,\n\t\t\t\t\t\t\t(chart.sql_params as ParamRecord | null) ?? undefined,\n\t\t\t\t\t\t\tchart.target_db ?? undefined,\n\t\t\t\t\t\t),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t})),\n\t\t);\n\t}\n\n\treturn response;\n}\n\nexport async function getChart(\n\tclient: ApiClient,\n\tqueryEngine: QueryEngine,\n\tid: string,\n\toptions?: RequestOptions,\n\tsignal?: AbortSignal,\n): Promise<SdkChart> {\n\tconst tenantId = resolveTenantId(client, options?.tenantId);\n\tconst chart = await client.get<SdkChart>(\n\t\t`/charts/${encodeURIComponent(id)}`,\n\t\ttenantId,\n\t\toptions?.userId,\n\t\toptions?.scopes,\n\t\tsignal,\n\t);\n\n\treturn {\n\t\t...chart,\n\t\tvega_lite_spec: {\n\t\t\t...chart.vega_lite_spec,\n\t\t\tdata: {\n\t\t\t\tvalues: await queryEngine.execute(\n\t\t\t\t\tchart.sql,\n\t\t\t\t\t(chart.sql_params as ParamRecord | null) ?? undefined,\n\t\t\t\t\tchart.target_db ?? undefined,\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t};\n}\n\nexport async function updateChart(\n\tclient: ApiClient,\n\tid: string,\n\tbody: ChartUpdateInput,\n\toptions?: RequestOptions,\n\tsignal?: AbortSignal,\n): Promise<SdkChart> {\n\tconst tenantId = resolveTenantId(client, options?.tenantId);\n\treturn await client.put<SdkChart>(\n\t\t`/charts/${encodeURIComponent(id)}`,\n\t\tbody,\n\t\ttenantId,\n\t\toptions?.userId,\n\t\toptions?.scopes,\n\t\tsignal,\n\t);\n}\n\nexport async function deleteChart(\n\tclient: ApiClient,\n\tid: string,\n\toptions?: RequestOptions,\n\tsignal?: AbortSignal,\n): Promise<void> {\n\tconst tenantId = resolveTenantId(client, options?.tenantId);\n\tawait client.delete(\n\t\t`/charts/${encodeURIComponent(id)}`,\n\t\ttenantId,\n\t\toptions?.userId,\n\t\toptions?.scopes,\n\t\tsignal,\n\t);\n}\n\nfunction resolveTenantId(client: ApiClient, tenantId?: string): string {\n\tconst resolved = tenantId ?? client.getDefaultTenantId();\n\tif (!resolved) {\n\t\tthrow new Error(\n\t\t\t\"tenantId is required. Provide it per request or via defaultTenantId option.\",\n\t\t);\n\t}\n\treturn resolved;\n}\n","import type { ApiClient } from \"../core/client\";\nimport type { QueryEngine } from \"../core/query-engine\";\nimport * as charts from \"./charts\";\n\nexport interface SdkActiveChart {\n\tid: string;\n\tchart_id: string;\n\torder: number | null;\n\tmeta: Record<string, unknown> | null;\n\torganization_id: string | null;\n\ttenant_id: string | null;\n\tuser_id: string | null;\n\tcreated_at: string | null;\n\tupdated_at: string | null;\n\tchart?: charts.SdkChart | null;\n}\n\nexport interface ActiveChartCreateInput {\n\tchart_id: string;\n\torder?: number;\n\tmeta?: Record<string, unknown>;\n}\n\nexport interface ActiveChartUpdateInput {\n\tchart_id?: string;\n\torder?: number;\n\tmeta?: Record<string, unknown>;\n}\n\nexport interface ActiveChartListOptions extends charts.ChartListOptions {\n\twithData?: boolean;\n}\n\ninterface RequestOptions {\n\ttenantId?: string;\n\tuserId?: string;\n\tscopes?: string[];\n}\n\n/**\n * Route module for Active Chart CRUD operations\n * Simple pass-through to backend with optional chart data hydration\n */\nexport async function createActiveChart(\n\tclient: ApiClient,\n\tbody: ActiveChartCreateInput,\n\toptions?: RequestOptions,\n\tsignal?: AbortSignal,\n): Promise<SdkActiveChart> {\n\tconst tenantId = resolveTenantId(client, options?.tenantId);\n\treturn await client.post<SdkActiveChart>(\n\t\t\"/active-charts\",\n\t\tbody,\n\t\ttenantId,\n\t\toptions?.userId,\n\t\toptions?.scopes,\n\t\tsignal,\n\t);\n}\n\nexport async function listActiveCharts(\n\tclient: ApiClient,\n\tqueryEngine: QueryEngine,\n\toptions?: ActiveChartListOptions,\n\tsignal?: AbortSignal,\n): Promise<charts.PaginatedResponse<SdkActiveChart>> {\n\tconst tenantId = resolveTenantId(client, options?.tenantId);\n\tconst params = new URLSearchParams();\n\tif (options?.pagination?.page)\n\t\tparams.set(\"page\", `${options.pagination.page}`);\n\tif (options?.pagination?.limit)\n\t\tparams.set(\"limit\", `${options.pagination.limit}`);\n\tif (options?.sortBy) params.set(\"sort_by\", options.sortBy);\n\tif (options?.sortDir) params.set(\"sort_dir\", options.sortDir);\n\tif (options?.title) params.set(\"name\", options.title);\n\tif (options?.userFilter) params.set(\"user_id\", options.userFilter);\n\tif (options?.createdFrom) params.set(\"created_from\", options.createdFrom);\n\tif (options?.createdTo) params.set(\"created_to\", options.createdTo);\n\tif (options?.updatedFrom) params.set(\"updated_from\", options.updatedFrom);\n\tif (options?.updatedTo) params.set(\"updated_to\", options.updatedTo);\n\n\tconst response = await client.get<\n\t\tcharts.PaginatedResponse<SdkActiveChart>\n\t>(\n\t\t`/active-charts${params.toString() ? `?${params.toString()}` : \"\"}`,\n\t\ttenantId,\n\t\toptions?.userId,\n\t\toptions?.scopes,\n\t\tsignal,\n\t);\n\n\tif (options?.withData) {\n\t\tresponse.data = await Promise.all(\n\t\t\tresponse.data.map(async (active) => ({\n\t\t\t\t...active,\n\t\t\t\tchart: active.chart\n\t\t\t\t\t? await charts.getChart(\n\t\t\t\t\t\t\tclient,\n\t\t\t\t\t\t\tqueryEngine,\n\t\t\t\t\t\t\tactive.chart_id,\n\t\t\t\t\t\t\toptions,\n\t\t\t\t\t\t\tsignal,\n\t\t\t\t\t\t)\n\t\t\t\t\t: null,\n\t\t\t})),\n\t\t);\n\t}\n\n\treturn response;\n}\n\nexport async function getActiveChart(\n\tclient: ApiClient,\n\tqueryEngine: QueryEngine,\n\tid: string,\n\toptions?: ActiveChartListOptions,\n\tsignal?: AbortSignal,\n): Promise<SdkActiveChart> {\n\tconst tenantId = resolveTenantId(client, options?.tenantId);\n\tconst active = await client.get<SdkActiveChart>(\n\t\t`/active-charts/${encodeURIComponent(id)}`,\n\t\ttenantId,\n\t\toptions?.userId,\n\t\toptions?.scopes,\n\t\tsignal,\n\t);\n\n\tif (options?.withData && active.chart_id) {\n\t\treturn {\n\t\t\t...active,\n\t\t\tchart: await charts.getChart(\n\t\t\t\tclient,\n\t\t\t\tqueryEngine,\n\t\t\t\tactive.chart_id,\n\t\t\t\toptions,\n\t\t\t\tsignal,\n\t\t\t),\n\t\t};\n\t}\n\n\treturn active;\n}\n\nexport async function updateActiveChart(\n\tclient: ApiClient,\n\tid: string,\n\tbody: ActiveChartUpdateInput,\n\toptions?: RequestOptions,\n\tsignal?: AbortSignal,\n): Promise<SdkActiveChart> {\n\tconst tenantId = resolveTenantId(client, options?.tenantId);\n\treturn await client.put<SdkActiveChart>(\n\t\t`/active-charts/${encodeURIComponent(id)}`,\n\t\tbody,\n\t\ttenantId,\n\t\toptions?.userId,\n\t\toptions?.scopes,\n\t\tsignal,\n\t);\n}\n\nexport async function deleteActiveChart(\n\tclient: ApiClient,\n\tid: string,\n\toptions?: RequestOptions,\n\tsignal?: AbortSignal,\n): Promise<void> {\n\tconst tenantId = resolveTenantId(client, options?.tenantId);\n\tawait client.delete(\n\t\t`/active-charts/${encodeURIComponent(id)}`,\n\t\ttenantId,\n\t\toptions?.userId,\n\t\toptions?.scopes,\n\t\tsignal,\n\t);\n}\n\nfunction resolveTenantId(client: ApiClient, tenantId?: string): string {\n\tconst resolved = tenantId ?? client.getDefaultTenantId();\n\tif (!resolved) {\n\t\tthrow new Error(\n\t\t\t\"tenantId is required. Provide it per request or via defaultTenantId option.\",\n\t\t);\n\t}\n\treturn resolved;\n}\n","import { randomUUID } from \"node:crypto\";\nimport type { ApiClient } from \"../core/client\";\nimport type { QueryEngine } from \"../core/query-engine\";\nimport type { SchemaIntrospection } from \"../schema/types\";\n\nexport interface IngestResponse {\n\tsuccess: boolean;\n\tmessage: string;\n\tchunks: number;\n\tchunks_with_annotations: number;\n\tschema_id?: string;\n\tschema_hash?: string;\n\tdrift_detected?: boolean;\n\tskipped?: boolean;\n}\n\nexport interface SchemaSyncOptions {\n\ttenantId?: string;\n\tuserId?: string;\n\tscopes?: string[];\n\ttables?: string[];\n\tforceReindex?: boolean;\n}\n\ninterface SchemaIngestColumn {\n\tname: string;\n\tdata_type: string;\n\tis_primary_key: boolean;\n\tdescription: string;\n}\n\ninterface SchemaIngestTable {\n\ttable_name: string;\n\tdescription: string;\n\tcolumns: SchemaIngestColumn[];\n}\n\ninterface SchemaIngestRequest {\n\tdatabase: string;\n\tdialect: string;\n\ttables: SchemaIngestTable[];\n\tforce_reindex?: boolean;\n}\n\n/**\n * Route module for schema ingestion\n * Handles introspection and sync to backend\n */\nexport async function syncSchema(\n\tclient: ApiClient,\n\tqueryEngine: QueryEngine,\n\tdatabaseName: string,\n\toptions: SchemaSyncOptions,\n\tsignal?: AbortSignal,\n): Promise<IngestResponse> {\n\tconst tenantId = resolveTenantId(client, options.tenantId);\n\tconst adapter = queryEngine.getDatabase(databaseName);\n\n\tconst introspection = await adapter.introspect(\n\t\toptions.tables ? { tables: options.tables } : undefined,\n\t);\n\n\tconst payload = buildSchemaRequest(databaseName, adapter, introspection);\n\tif (options.forceReindex) {\n\t\tpayload.force_reindex = true;\n\t}\n\n\t// Generate a session id so backend telemetry can correlate all work for this sync\n\tconst sessionId = randomUUID();\n\n\tconst response = await client.post<IngestResponse>(\n\t\t\"/ingest\",\n\t\tpayload,\n\t\ttenantId,\n\t\toptions.userId,\n\t\toptions.scopes,\n\t\tsignal,\n\t\tsessionId,\n\t);\n\n\treturn response;\n}\n\nfunction resolveTenantId(client: ApiClient, tenantId?: string): string {\n\tconst resolved = tenantId ?? client.getDefaultTenantId();\n\tif (!resolved) {\n\t\tthrow new Error(\n\t\t\t\"tenantId is required. Provide it per request or via defaultTenantId option.\",\n\t\t);\n\t}\n\treturn resolved;\n}\n\nfunction buildSchemaRequest(\n\tdatabaseName: string,\n\tadapter: { getDialect: () => string },\n\tintrospection: SchemaIntrospection,\n): SchemaIngestRequest {\n\tconst dialect = adapter.getDialect();\n\tconst tables: SchemaIngestTable[] = introspection.tables.map((table) => ({\n\t\ttable_name: table.name,\n\t\tdescription: table.comment ?? `Table ${table.name}`,\n\t\tcolumns: table.columns.map((column) => ({\n\t\t\tname: column.name,\n\t\t\tdata_type: column.rawType ?? column.type,\n\t\t\tis_primary_key: Boolean(column.isPrimaryKey),\n\t\t\tdescription: column.comment ?? \"\",\n\t\t})),\n\t}));\n\n\treturn {\n\t\tdatabase: databaseName,\n\t\tdialect,\n\t\ttables,\n\t};\n}\n","import { randomUUID } from \"node:crypto\";\nimport type { ApiClient } from \"../core/client\";\nimport type { ParamRecord, QueryEngine } from \"../core/query-engine\";\n\nexport interface ContextDocument {\n\tsource?: string;\n\tpageContent: string;\n\tmetadata?: Record<string, unknown>;\n\tscore?: number;\n}\n\nexport interface ChartEnvelope {\n\tvegaLiteSpec: Record<string, unknown> | null;\n\tnotes: string | null;\n}\n\nexport interface AskOptions {\n\ttenantId?: string;\n\tuserId?: string;\n\tscopes?: string[];\n\tdatabase?: string;\n\tlastError?: string;\n\tpreviousSql?: string;\n\tmaxRetry?: number;\n\tchartMaxRetries?: number;\n}\n\nexport interface AskResponse {\n\tsql: string;\n\tparams: ParamRecord;\n\tparamMetadata: Array<Record<string, unknown>>;\n\trationale?: string;\n\tdialect: string;\n\tqueryId?: string;\n\trows: Array<Record<string, unknown>>;\n\tfields: string[];\n\tchart: ChartEnvelope;\n\tcontext?: ContextDocument[];\n\tattempts?: number;\n}\n\ninterface ServerQueryResponse {\n\tsuccess: boolean;\n\tsql: string;\n\tparams?: Array<Record<string, unknown>>;\n\tdialect: string;\n\tdatabase?: string;\n\ttable?: string;\n\trationale?: string;\n\tqueryId?: string;\n\tcontext?: ContextDocument[];\n}\n\ninterface ServerChartResponse {\n\tchart: Record<string, unknown> | null;\n\tnotes: string | null;\n}\n\n/**\n * Route module for natural language query generation\n * Simple orchestration following Ousterhout's principle\n */\nexport async function ask(\n\tclient: ApiClient,\n\tqueryEngine: QueryEngine,\n\tquestion: string,\n\toptions: AskOptions,\n\tsignal?: AbortSignal,\n): Promise<AskResponse> {\n\tconst tenantId = resolveTenantId(client, options.tenantId);\n\tconst sessionId = randomUUID();\n\tconst maxRetry = options.maxRetry ?? 0;\n\tlet attempt = 0;\n\tlet lastError: string | undefined = options.lastError;\n\tlet previousSql: string | undefined = options.previousSql;\n\n\twhile (attempt <= maxRetry) {\n\t\t// Step 1: Get SQL from backend\n\t\tconsole.log({ lastError, previousSql });\n\t\tconst queryResponse = await client.post<ServerQueryResponse>(\n\t\t\t\"/query\",\n\t\t\t{\n\t\t\t\tquestion,\n\t\t\t\t...(lastError ? { last_error: lastError } : {}),\n\t\t\t\t...(previousSql ? { previous_sql: previousSql } : {}),\n\t\t\t\t...(options.maxRetry ? { max_retry: options.maxRetry } : {}),\n\t\t\t},\n\t\t\ttenantId,\n\t\t\toptions.userId,\n\t\t\toptions.scopes,\n\t\t\tsignal,\n\t\t\tsessionId,\n\t\t);\n\n\t\tconst databaseName =\n\t\t\tqueryResponse.database ??\n\t\t\toptions.database ??\n\t\t\tqueryEngine.getDefaultDatabase();\n\t\tif (!databaseName) {\n\t\t\tthrow new Error(\n\t\t\t\t\"No database attached. Call attachPostgres/attachClickhouse first.\",\n\t\t\t);\n\t\t}\n\n\t\t// Step 2: Map and validate parameters\n\t\tconst paramMetadata = Array.isArray(queryResponse.params)\n\t\t\t? queryResponse.params\n\t\t\t: [];\n\t\tconst paramValues = queryEngine.mapGeneratedParams(paramMetadata);\n\n\t\t// Step 3: Execute SQL with tenant isolation\n\t\ttry {\n\t\t\tconst execution = await queryEngine.validateAndExecute(\n\t\t\t\tqueryResponse.sql,\n\t\t\t\tparamValues,\n\t\t\t\tdatabaseName,\n\t\t\t\ttenantId,\n\t\t\t);\n\t\t\tconst rows = execution.rows ?? [];\n\n\t\t\t// Step 4: Generate chart if we have data\n\t\t\tlet chart: ChartEnvelope = {\n\t\t\t\tvegaLiteSpec: null,\n\t\t\t\tnotes: rows.length === 0 ? \"Query returned no rows.\" : null,\n\t\t\t};\n\n\t\t\tif (rows.length > 0) {\n\t\t\t\tconst chartResponse = await client.post<ServerChartResponse>(\n\t\t\t\t\t\"/chart\",\n\t\t\t\t\t{\n\t\t\t\t\t\tquestion,\n\t\t\t\t\t\tsql: queryResponse.sql,\n\t\t\t\t\t\trationale: queryResponse.rationale,\n\t\t\t\t\t\tfields: execution.fields,\n\t\t\t\t\t\trows: anonymizeResults(rows),\n\t\t\t\t\t\tmax_retries: options.chartMaxRetries ?? 3,\n\t\t\t\t\t\tquery_id: queryResponse.queryId,\n\t\t\t\t\t},\n\t\t\t\t\ttenantId,\n\t\t\t\t\toptions.userId,\n\t\t\t\t\toptions.scopes,\n\t\t\t\t\tsignal,\n\t\t\t\t\tsessionId,\n\t\t\t\t);\n\n\t\t\t\tchart = {\n\t\t\t\t\tvegaLiteSpec: chartResponse.chart\n\t\t\t\t\t\t? {\n\t\t\t\t\t\t\t\t...chartResponse.chart,\n\t\t\t\t\t\t\t\tdata: { values: rows },\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t: null,\n\t\t\t\t\tnotes: chartResponse.notes,\n\t\t\t\t};\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\tsql: queryResponse.sql,\n\t\t\t\tparams: paramValues,\n\t\t\t\tparamMetadata,\n\t\t\t\trationale: queryResponse.rationale,\n\t\t\t\tdialect: queryResponse.dialect,\n\t\t\t\tqueryId: queryResponse.queryId,\n\t\t\t\trows,\n\t\t\t\tfields: execution.fields,\n\t\t\t\tchart,\n\t\t\t\tcontext: queryResponse.context,\n\t\t\t\tattempts: attempt + 1,\n\t\t\t};\n\t\t} catch (error) {\n\t\t\tattempt++;\n\n\t\t\t// If we've exhausted all retries, throw the error\n\t\t\tif (attempt > maxRetry) {\n\t\t\t\tthrow error;\n\t\t\t}\n\n\t\t\t// Save error and SQL for next retry\n\t\t\tlastError = error instanceof Error ? error.message : String(error);\n\t\t\tpreviousSql = queryResponse.sql;\n\n\t\t\t// Log retry attempt\n\t\t\tconsole.warn(\n\t\t\t\t`SQL execution failed (attempt ${attempt}/${maxRetry + 1}): ${lastError}. Retrying...`,\n\t\t\t);\n\t\t}\n\t}\n\n\t// This should never be reached, but TypeScript needs it\n\tthrow new Error(\"Unexpected error in ask retry loop\");\n}\n\nfunction resolveTenantId(client: ApiClient, tenantId?: string): string {\n\tconst resolved = tenantId ?? client.getDefaultTenantId();\n\tif (!resolved) {\n\t\tthrow new Error(\n\t\t\t\"tenantId is required. Provide it per request or via defaultTenantId option.\",\n\t\t);\n\t}\n\treturn resolved;\n}\n\nexport function anonymizeResults(\n\trows: Array<Record<string, unknown>>,\n): Array<Record<string, string>> {\n\tif (!rows?.length) return [];\n\treturn rows.map((row) => {\n\t\tconst masked: Record<string, string> = {};\n\t\tObject.entries(row).forEach(([key, value]) => {\n\t\t\tif (value === null) masked[key] = \"null\";\n\t\t\telse if (Array.isArray(value)) masked[key] = \"array\";\n\t\t\telse masked[key] = typeof value;\n\t\t});\n\t\treturn masked;\n\t});\n}\n"],"mappings":"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","names":["normalizeTableFilter","asTableType","sanitize","resolveTenantId","import_node_crypto","resolveTenantId","import_node_crypto","resolveTenantId"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/utils/clickhouse.ts","../src/adapters/clickhouse.ts","../src/adapters/postgres.ts","../src/core/client.ts","../src/core/query-engine.ts","../src/routes/charts.ts","../src/routes/active-charts.ts","../src/routes/ingest.ts","../src/routes/query.ts"],"sourcesContent":["import {\n\tClickHouseAdapter,\n\ttype ClickHouseAdapterOptions,\n\ttype ClickHouseClientFn,\n} from \"./adapters/clickhouse\";\nimport {\n\tPostgresAdapter,\n\ttype PostgresAdapterOptions,\n\ttype PostgresClientFn,\n} from \"./adapters/postgres\";\nimport type { DatabaseAdapter, DatabaseDialect } from \"./adapters/types\";\nimport { ApiClient } from \"./core/client\";\nimport { type DatabaseMetadata, QueryEngine } from \"./core/query-engine\";\nimport * as activeChartsRoute from \"./routes/active-charts\";\nimport * as chartsRoute from \"./routes/charts\";\nimport * as ingestRoute from \"./routes/ingest\";\nimport * as queryRoute from \"./routes/query\";\nimport type { SchemaIntrospection } from \"./schema/types\";\n\n// Re-export all public types\nexport { ClickHouseAdapter, PostgresAdapter };\n\nexport type {\n\tClickHouseAdapterOptions,\n\tClickHouseClientFn,\n\tDatabaseAdapter,\n\tDatabaseDialect,\n\tPostgresAdapterOptions,\n\tPostgresClientFn,\n\tSchemaIntrospection,\n};\n\n// Re-export from query-engine\nexport type { ParamRecord, ParamValue } from \"./core/query-engine\";\nexport type {\n\tActiveChartCreateInput,\n\tActiveChartListOptions,\n\tActiveChartUpdateInput,\n\tSdkActiveChart,\n} from \"./routes/active-charts\";\n\nexport type {\n\tChartCreateInput,\n\tChartListOptions,\n\tChartUpdateInput,\n\tPaginatedResponse,\n\tPaginationInfo,\n\tPaginationQuery,\n\tSdkChart,\n} from \"./routes/charts\";\n// Re-export route types\nexport type {\n\tIngestResponse,\n\tSchemaSyncOptions,\n} from \"./routes/ingest\";\nexport type {\n\tAskOptions,\n\tAskResponse,\n\tChartEnvelope,\n\tContextDocument,\n} from \"./routes/query\";\n\n// Re-export anonymizeResults utility\nexport { anonymizeResults } from \"./routes/query\";\n\n/**\n * Main SDK class - Thin orchestrator\n * Delegates to deep modules (ApiClient, QueryEngine, route modules)\n * Following Ousterhout's principle: \"Simple interface hiding complexity\"\n */\nexport class QueryPanelSdkAPI {\n\tprivate readonly client: ApiClient;\n\tprivate readonly queryEngine: QueryEngine;\n\n\tconstructor(\n\t\tbaseUrl: string,\n\t\tprivateKey: string,\n\t\torganizationId: string,\n\t\toptions?: {\n\t\t\tdefaultTenantId?: string;\n\t\t\tadditionalHeaders?: Record<string, string>;\n\t\t\tfetch?: typeof fetch;\n\t\t},\n\t) {\n\t\tthis.client = new ApiClient(baseUrl, privateKey, organizationId, options);\n\t\tthis.queryEngine = new QueryEngine();\n\t}\n\n\t// Database attachment methods\n\n\tattachClickhouse(\n\t\tname: string,\n\t\tclientFn: ClickHouseClientFn,\n\t\toptions?: ClickHouseAdapterOptions & {\n\t\t\tdescription?: string;\n\t\t\ttags?: string[];\n\t\t\ttenantFieldName?: string;\n\t\t\ttenantFieldType?: string;\n\t\t\tenforceTenantIsolation?: boolean;\n\t\t},\n\t): void {\n\t\tconst adapter = new ClickHouseAdapter(clientFn, options);\n\n\t\tconst metadata: DatabaseMetadata = {\n\t\t\tname,\n\t\t\tdialect: \"clickhouse\",\n\t\t\tdescription: options?.description,\n\t\t\ttags: options?.tags,\n\t\t\ttenantFieldName: options?.tenantFieldName,\n\t\t\ttenantFieldType: options?.tenantFieldType ?? \"String\",\n\t\t\tenforceTenantIsolation: options?.tenantFieldName\n\t\t\t\t? (options?.enforceTenantIsolation ?? true)\n\t\t\t\t: undefined,\n\t\t};\n\n\t\tthis.queryEngine.attachDatabase(name, adapter, metadata);\n\t}\n\n\tattachPostgres(\n\t\tname: string,\n\t\tclientFn: PostgresClientFn,\n\t\toptions?: PostgresAdapterOptions & {\n\t\t\tdescription?: string;\n\t\t\ttags?: string[];\n\t\t\ttenantFieldName?: string;\n\t\t\tenforceTenantIsolation?: boolean;\n\t\t},\n\t): void {\n\t\tconst adapter = new PostgresAdapter(clientFn, options);\n\n\t\tconst metadata: DatabaseMetadata = {\n\t\t\tname,\n\t\t\tdialect: \"postgres\",\n\t\t\tdescription: options?.description,\n\t\t\ttags: options?.tags,\n\t\t\ttenantFieldName: options?.tenantFieldName,\n\t\t\tenforceTenantIsolation: options?.tenantFieldName\n\t\t\t\t? (options?.enforceTenantIsolation ?? true)\n\t\t\t\t: undefined,\n\t\t};\n\n\t\tthis.queryEngine.attachDatabase(name, adapter, metadata);\n\t}\n\n\tattachDatabase(name: string, adapter: DatabaseAdapter): void {\n\t\tconst metadata: DatabaseMetadata = {\n\t\t\tname,\n\t\t\tdialect: adapter.getDialect(),\n\t\t};\n\t\tthis.queryEngine.attachDatabase(name, adapter, metadata);\n\t}\n\n\t// Schema introspection and sync\n\n\tasync introspect(\n\t\tdatabaseName: string,\n\t\ttables?: string[],\n\t): Promise<SchemaIntrospection> {\n\t\tconst adapter = this.queryEngine.getDatabase(databaseName);\n\t\treturn await adapter.introspect(tables ? { tables } : undefined);\n\t}\n\n\tasync syncSchema(\n\t\tdatabaseName: string,\n\t\toptions: ingestRoute.SchemaSyncOptions,\n\t\tsignal?: AbortSignal,\n\t): Promise<ingestRoute.IngestResponse> {\n\t\treturn await ingestRoute.syncSchema(\n\t\t\tthis.client,\n\t\t\tthis.queryEngine,\n\t\t\tdatabaseName,\n\t\t\toptions,\n\t\t\tsignal,\n\t\t);\n\t}\n\n\t// Natural language query\n\n\tasync ask(\n\t\tquestion: string,\n\t\toptions: queryRoute.AskOptions,\n\t\tsignal?: AbortSignal,\n\t): Promise<queryRoute.AskResponse> {\n\t\treturn await queryRoute.ask(\n\t\t\tthis.client,\n\t\t\tthis.queryEngine,\n\t\t\tquestion,\n\t\t\toptions,\n\t\t\tsignal,\n\t\t);\n\t}\n\n\t// Chart CRUD operations\n\n\tasync createChart(\n\t\tbody: chartsRoute.ChartCreateInput,\n\t\toptions?: { tenantId?: string; userId?: string; scopes?: string[] },\n\t\tsignal?: AbortSignal,\n\t): Promise<chartsRoute.SdkChart> {\n\t\treturn await chartsRoute.createChart(this.client, body, options, signal);\n\t}\n\n\tasync listCharts(\n\t\toptions?: chartsRoute.ChartListOptions,\n\t\tsignal?: AbortSignal,\n\t): Promise<chartsRoute.PaginatedResponse<chartsRoute.SdkChart>> {\n\t\treturn await chartsRoute.listCharts(\n\t\t\tthis.client,\n\t\t\tthis.queryEngine,\n\t\t\toptions,\n\t\t\tsignal,\n\t\t);\n\t}\n\n\tasync getChart(\n\t\tid: string,\n\t\toptions?: { tenantId?: string; userId?: string; scopes?: string[] },\n\t\tsignal?: AbortSignal,\n\t): Promise<chartsRoute.SdkChart> {\n\t\treturn await chartsRoute.getChart(\n\t\t\tthis.client,\n\t\t\tthis.queryEngine,\n\t\t\tid,\n\t\t\toptions,\n\t\t\tsignal,\n\t\t);\n\t}\n\n\tasync updateChart(\n\t\tid: string,\n\t\tbody: chartsRoute.ChartUpdateInput,\n\t\toptions?: { tenantId?: string; userId?: string; scopes?: string[] },\n\t\tsignal?: AbortSignal,\n\t): Promise<chartsRoute.SdkChart> {\n\t\treturn await chartsRoute.updateChart(\n\t\t\tthis.client,\n\t\t\tid,\n\t\t\tbody,\n\t\t\toptions,\n\t\t\tsignal,\n\t\t);\n\t}\n\n\tasync deleteChart(\n\t\tid: string,\n\t\toptions?: { tenantId?: string; userId?: string; scopes?: string[] },\n\t\tsignal?: AbortSignal,\n\t): Promise<void> {\n\t\tawait chartsRoute.deleteChart(this.client, id, options, signal);\n\t}\n\n\t// Active Chart CRUD operations\n\n\tasync createActiveChart(\n\t\tbody: activeChartsRoute.ActiveChartCreateInput,\n\t\toptions?: { tenantId?: string; userId?: string; scopes?: string[] },\n\t\tsignal?: AbortSignal,\n\t): Promise<activeChartsRoute.SdkActiveChart> {\n\t\treturn await activeChartsRoute.createActiveChart(\n\t\t\tthis.client,\n\t\t\tbody,\n\t\t\toptions,\n\t\t\tsignal,\n\t\t);\n\t}\n\n\tasync listActiveCharts(\n\t\toptions?: activeChartsRoute.ActiveChartListOptions,\n\t\tsignal?: AbortSignal,\n\t): Promise<chartsRoute.PaginatedResponse<activeChartsRoute.SdkActiveChart>> {\n\t\treturn await activeChartsRoute.listActiveCharts(\n\t\t\tthis.client,\n\t\t\tthis.queryEngine,\n\t\t\toptions,\n\t\t\tsignal,\n\t\t);\n\t}\n\n\tasync getActiveChart(\n\t\tid: string,\n\t\toptions?: activeChartsRoute.ActiveChartListOptions,\n\t\tsignal?: AbortSignal,\n\t): Promise<activeChartsRoute.SdkActiveChart> {\n\t\treturn await activeChartsRoute.getActiveChart(\n\t\t\tthis.client,\n\t\t\tthis.queryEngine,\n\t\t\tid,\n\t\t\toptions,\n\t\t\tsignal,\n\t\t);\n\t}\n\n\tasync updateActiveChart(\n\t\tid: string,\n\t\tbody: activeChartsRoute.ActiveChartUpdateInput,\n\t\toptions?: { tenantId?: string; userId?: string; scopes?: string[] },\n\t\tsignal?: AbortSignal,\n\t): Promise<activeChartsRoute.SdkActiveChart> {\n\t\treturn await activeChartsRoute.updateActiveChart(\n\t\t\tthis.client,\n\t\t\tid,\n\t\t\tbody,\n\t\t\toptions,\n\t\t\tsignal,\n\t\t);\n\t}\n\n\tasync deleteActiveChart(\n\t\tid: string,\n\t\toptions?: { tenantId?: string; userId?: string; scopes?: string[] },\n\t\tsignal?: AbortSignal,\n\t): Promise<void> {\n\t\tawait activeChartsRoute.deleteActiveChart(this.client, id, options, signal);\n\t}\n}\n","const WRAPPER_REGEX =\n /^(Nullable|LowCardinality|SimpleAggregateFunction)\\((.+)\\)$/i;\n\nexport function isNullableType(type: string): boolean {\n return /Nullable\\s*\\(/i.test(type);\n}\n\nexport function unwrapTypeModifiers(type: string): string {\n let current = type.trim();\n let match = WRAPPER_REGEX.exec(current);\n while (match) {\n const inner = match[2];\n if (!inner) {\n break;\n }\n current = inner.trim();\n match = WRAPPER_REGEX.exec(current);\n }\n return current;\n}\n\nexport function extractPrecisionScale(type: string): {\n precision?: number;\n scale?: number;\n} {\n const unwrapped = unwrapTypeModifiers(type);\n const decimalMatch = unwrapped.match(/Decimal(?:\\d+)?\\((\\d+)\\s*,\\s*(\\d+)\\)/i);\n if (!decimalMatch) return {};\n const precision = decimalMatch[1];\n const scale = decimalMatch[2];\n if (!precision || !scale) return {};\n return {\n precision: Number.parseInt(precision, 10),\n scale: Number.parseInt(scale, 10),\n };\n}\n\nexport function extractFixedStringLength(type: string): number | undefined {\n const unwrapped = unwrapTypeModifiers(type);\n const match = unwrapped.match(/^(?:FixedString|StringFixed)\\((\\d+)\\)$/i);\n if (!match) return undefined;\n const length = match[1];\n if (!length) return undefined;\n return Number.parseInt(length, 10);\n}\n\nexport function parseKeyExpression(expression?: string | null): string[] {\n if (!expression) return [];\n let value = expression.trim();\n if (!value) return [];\n if (/^tuple\\s*\\(/i.test(value) && value.endsWith(\")\")) {\n value = value.replace(/^tuple\\s*\\(/i, \"\").replace(/\\)$/, \"\");\n }\n\n const columns: string[] = [];\n let depth = 0;\n let token = \"\";\n for (const ch of value) {\n if (ch === \"(\") {\n depth += 1;\n token += ch;\n continue;\n }\n if (ch === \")\") {\n depth = Math.max(0, depth - 1);\n token += ch;\n continue;\n }\n if (ch === \",\" && depth === 0) {\n const col = token.trim();\n if (col) columns.push(stripWrapper(col));\n token = \"\";\n continue;\n }\n token += ch;\n }\n const last = token.trim();\n if (last) columns.push(stripWrapper(last));\n return columns.filter(Boolean);\n}\n\nfunction stripWrapper(value: string): string {\n const noQuotes = stripQuotes(value);\n const withoutTicks = noQuotes.replace(/`/g, \"\").trim();\n const parts = withoutTicks.split(\".\");\n return parts[parts.length - 1]?.trim() ?? \"\";\n}\n\nfunction stripQuotes(value: string): string {\n if (\n (value.startsWith('\"') && value.endsWith('\"')) ||\n (value.startsWith(\"'\") && value.endsWith(\"'\"))\n ) {\n return value.slice(1, -1);\n }\n return value;\n}\n","import type {\n\tClickHouseSettings,\n\tDataFormat,\n\tQueryParams,\n} from \"@clickhouse/client\";\nimport type {\n\tColumnSchema,\n\tIntrospectOptions,\n\tSchemaIntrospection,\n\tTableSchema,\n} from \"../schema/types\";\nimport { parseKeyExpression, unwrapTypeModifiers } from \"../utils/clickhouse\";\nimport type { DatabaseAdapter, DatabaseExecutionResult } from \"./types\";\n\nexport interface ClickHouseAdapterOptions {\n\t/** Optional logical database name used in introspection metadata. */\n\tdatabase?: string;\n\t/** Override the default response format used for query execution. */\n\tdefaultFormat?: DataFormat;\n\t/**\n\t * Optional database kind label. Defaults to \"clickhouse\" but allows\n\t * sub-classing/custom branding if needed.\n\t */\n\tkind?: SchemaIntrospection[\"db\"][\"kind\"];\n\t/**\n\t * Optional allow-list of table names.\n\t * When specified, introspection and queries are restricted to these tables only.\n\t * ClickHouse tables are not schema-qualified, so just provide table names.\n\t */\n\tallowedTables?: string[];\n}\n\nexport type ClickHouseQueryResult = { json: () => Promise<unknown> };\n\nexport type ClickHouseClientFn = (\n\tparams: QueryParams,\n) => Promise<\n\t| ClickHouseQueryResult\n\t| Array<Record<string, unknown>>\n\t| Record<string, unknown>[]\n>;\n\ninterface QueryOptions {\n\tparams?: Record<string, unknown>;\n\tformat?: DataFormat;\n\tsettings?: ClickHouseSettings;\n}\n\ntype TableRow = {\n\tname: string;\n\tengine: string;\n\tcomment: string | null;\n\tprimary_key: string | null;\n};\n\ntype ColumnRow = {\n\ttable: string;\n\tname: string;\n\ttype: string;\n\tposition: number;\n\tcomment: string | null;\n\tis_in_primary_key: string | number | null;\n};\n\n/**\n * Simplified ClickHouse adapter following IngestRequest format\n * Removed: indexes, constraints, statistics\n * Kept only: tables, columns (name, type, isPrimaryKey, comment)\n */\nexport class ClickHouseAdapter implements DatabaseAdapter {\n\tprivate readonly databaseName: string;\n\tprivate readonly defaultFormat: QueryParams[\"format\"];\n\tprivate readonly kind: SchemaIntrospection[\"db\"][\"kind\"];\n\tprivate readonly allowedTables?: string[];\n\n\tconstructor(\n\t\tprivate readonly clientFn: ClickHouseClientFn,\n\t\toptions: ClickHouseAdapterOptions = {},\n\t) {\n\t\tthis.databaseName = options.database ?? \"default\";\n\t\tthis.defaultFormat = options.defaultFormat ?? \"JSONEachRow\";\n\t\tthis.kind = options.kind ?? \"clickhouse\";\n\t\tif (options.allowedTables) {\n\t\t\tthis.allowedTables = normalizeTableFilter(options.allowedTables);\n\t\t}\n\t}\n\n\tasync execute(\n\t\tsql: string,\n\t\tparams?: Record<string, string | number | boolean | string[] | number[]>,\n\t): Promise<DatabaseExecutionResult> {\n\t\t// Validate query against allowed tables if restrictions are in place\n\t\tif (this.allowedTables) {\n\t\t\tthis.validateQueryTables(sql);\n\t\t}\n\n\t\tconst queryOptions: QueryOptions = {\n\t\t\tformat: this.defaultFormat,\n\t\t};\n\t\tif (params) {\n\t\t\tqueryOptions.params = params;\n\t\t}\n\n\t\tconst rows = await this.query<Record<string, unknown>>(sql, queryOptions);\n\t\tconst fields = rows.length > 0 ? Object.keys(rows[0] ?? {}) : [];\n\t\treturn { fields, rows };\n\t}\n\n\tasync validate(\n\t\tsql: string,\n\t\tparams?: Record<string, string | number | boolean | string[] | number[]>,\n\t): Promise<void> {\n\t\tconst queryOptions: QueryOptions = {\n\t\t\tformat: this.defaultFormat,\n\t\t};\n\t\tif (params) {\n\t\t\tqueryOptions.params = params;\n\t\t}\n\n\t\tawait this.query(`EXPLAIN ${sql}`, queryOptions);\n\t}\n\n\tgetDialect() {\n\t\treturn \"clickhouse\" as const;\n\t}\n\n\t/**\n\t * Simplified introspection: only collect table/column metadata for IngestRequest\n\t * No indexes, constraints, or statistics\n\t */\n\tasync introspect(options?: IntrospectOptions): Promise<SchemaIntrospection> {\n\t\t// Use adapter-level allowedTables if no specific tables provided in options\n\t\tconst tablesToIntrospect = options?.tables\n\t\t\t? normalizeTableFilter(options.tables)\n\t\t\t: this.allowedTables;\n\t\tconst allowTables = tablesToIntrospect ?? [];\n\t\tconst hasFilter = allowTables.length > 0;\n\t\tconst queryParams: Record<string, unknown> = {\n\t\t\tdb: this.databaseName,\n\t\t};\n\t\tif (hasFilter) {\n\t\t\tqueryParams.tables = allowTables;\n\t\t}\n\n\t\tconst filterClause = hasFilter ? \" AND name IN {tables:Array(String)}\" : \"\";\n\t\tconst tables = await this.query<TableRow>(\n\t\t\t`SELECT name, engine, comment, primary_key\n FROM system.tables\n WHERE database = {db:String}${filterClause}\n ORDER BY name`,\n\t\t\t{ params: queryParams },\n\t\t);\n\n\t\tconst columnFilterClause = hasFilter\n\t\t\t? \" AND table IN {tables:Array(String)}\"\n\t\t\t: \"\";\n\t\tconst columns = await this.query<ColumnRow>(\n\t\t\t`SELECT table, name, type, position, comment, is_in_primary_key\n FROM system.columns\n WHERE database = {db:String}${columnFilterClause}\n ORDER BY table, position`,\n\t\t\t{ params: queryParams },\n\t\t);\n\n\t\tconst columnsByTable = new Map<string, ColumnSchema[]>();\n\t\tfor (const rawColumn of columns) {\n\t\t\tconst list = columnsByTable.get(rawColumn.table) ?? [];\n\t\t\tlist.push(transformColumnRow(rawColumn));\n\t\t\tcolumnsByTable.set(rawColumn.table, list);\n\t\t}\n\n\t\tconst tableSchemas: TableSchema[] = tables.map((table) => {\n\t\t\tconst tableColumns = columnsByTable.get(table.name) ?? [];\n\t\t\tconst primaryKeyColumns = parseKeyExpression(table.primary_key);\n\n\t\t\t// Mark columns as primary key\n\t\t\tfor (const column of tableColumns) {\n\t\t\t\tcolumn.isPrimaryKey =\n\t\t\t\t\tcolumn.isPrimaryKey || primaryKeyColumns.includes(column.name);\n\t\t\t}\n\n\t\t\tconst base: TableSchema = {\n\t\t\t\tname: table.name,\n\t\t\t\tschema: this.databaseName,\n\t\t\t\ttype: asTableType(table.engine),\n\t\t\t\tcolumns: tableColumns,\n\t\t\t};\n\n\t\t\tconst comment = sanitize(table.comment);\n\t\t\tif (comment !== undefined) {\n\t\t\t\tbase.comment = comment;\n\t\t\t}\n\n\t\t\treturn base;\n\t\t});\n\n\t\treturn {\n\t\t\tdb: {\n\t\t\t\tkind: this.kind,\n\t\t\t\tname: this.databaseName,\n\t\t\t},\n\t\t\ttables: tableSchemas,\n\t\t\tintrospectedAt: new Date().toISOString(),\n\t\t};\n\t}\n\n\tprivate validateQueryTables(sql: string): void {\n\t\tif (!this.allowedTables || this.allowedTables.length === 0) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst allowedSet = new Set(this.allowedTables);\n\n\t\t// Extract potential table references from SQL\n\t\tconst tablePattern =\n\t\t\t/(?:FROM|JOIN)\\s+(?:FINAL\\s+)?(?:(?:[a-zA-Z_][a-zA-Z0-9_]*)\\.)?([\"'`]?[a-zA-Z_][a-zA-Z0-9_]*[\"'`]?)/gi;\n\t\tconst matches = sql.matchAll(tablePattern);\n\n\t\tfor (const match of matches) {\n\t\t\tconst table = match[1]?.replace(/[\"'`]/g, \"\");\n\t\t\tif (table) {\n\t\t\t\tif (!allowedSet.has(table)) {\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t`Query references table \"${table}\" which is not in the allowed tables list`,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tasync close(): Promise<void> {\n\t\t// No-op: lifecycle of the underlying client is controlled by the caller.\n\t}\n\n\tprivate async query<T>(sql: string, options?: QueryOptions): Promise<T[]> {\n\t\tconst params: QueryParams = {\n\t\t\tquery: sql,\n\t\t};\n\n\t\tconst format = options?.format ?? this.defaultFormat;\n\t\tif (format !== undefined) {\n\t\t\tparams.format = format;\n\t\t}\n\n\t\tif (options?.params) {\n\t\t\tparams.query_params = options.params;\n\t\t}\n\n\t\tif (options?.settings) {\n\t\t\tparams.clickhouse_settings = options.settings;\n\t\t}\n\n\t\tconst result = await this.clientFn(params);\n\t\treturn this.extractRows<T>(result);\n\t}\n\n\tprivate async extractRows<T>(\n\t\tresult:\n\t\t\t| ClickHouseQueryResult\n\t\t\t| Array<Record<string, unknown>>\n\t\t\t| Record<string, unknown>[],\n\t): Promise<T[]> {\n\t\tif (Array.isArray(result)) {\n\t\t\treturn result as T[];\n\t\t}\n\n\t\tif (\n\t\t\tresult &&\n\t\t\ttypeof (result as ClickHouseQueryResult).json === \"function\"\n\t\t) {\n\t\t\tconst payload = await (result as ClickHouseQueryResult).json();\n\t\t\treturn normalizePayload<T>(payload);\n\t\t}\n\n\t\treturn [];\n\t}\n}\n\nfunction normalizePayload<T>(payload: unknown): T[] {\n\tif (Array.isArray(payload)) {\n\t\treturn payload as T[];\n\t}\n\tif (payload && typeof payload === \"object\") {\n\t\tconst maybeData = (payload as { data?: unknown }).data;\n\t\tif (Array.isArray(maybeData)) {\n\t\t\treturn maybeData as T[];\n\t\t}\n\t}\n\treturn [];\n}\n\nfunction normalizeTableFilter(tables?: string[] | null): string[] {\n\tif (!tables?.length) return [];\n\tconst seen = new Set<string>();\n\tconst normalized: string[] = [];\n\tfor (const table of tables) {\n\t\tif (!table) continue;\n\t\tconst trimmed = table.trim();\n\t\tif (!trimmed) continue;\n\t\tconst parts = trimmed.split(\".\");\n\t\tconst tableName = parts[parts.length - 1];\n\t\tif (!tableName || seen.has(tableName)) continue;\n\t\tseen.add(tableName);\n\t\tnormalized.push(tableName);\n\t}\n\treturn normalized;\n}\n\nfunction transformColumnRow(row: ColumnRow): ColumnSchema {\n\tconst unwrappedType = unwrapTypeModifiers(row.type);\n\n\tconst column: ColumnSchema = {\n\t\tname: row.name,\n\t\ttype: unwrappedType,\n\t\trawType: row.type,\n\t\tisPrimaryKey: Boolean(toNumber(row.is_in_primary_key)),\n\t};\n\n\tconst comment = sanitize(row.comment);\n\tif (comment !== undefined) column.comment = comment;\n\n\treturn column;\n}\n\nfunction asTableType(engine: unknown): TableSchema[\"type\"] {\n\tif (typeof engine === \"string\") {\n\t\tconst normalized = engine.toLowerCase();\n\t\t// ClickHouse view engines: View, MaterializedView, LiveView\n\t\tif (normalized.includes(\"view\")) {\n\t\t\treturn \"view\";\n\t\t}\n\t}\n\treturn \"table\";\n}\n\nfunction sanitize(value: unknown): string | undefined {\n\tif (value === null || value === undefined) return undefined;\n\tconst trimmed = String(value).trim();\n\treturn trimmed.length ? trimmed : undefined;\n}\n\nfunction toNumber(value: unknown): number | undefined {\n\tif (value === null || value === undefined) return undefined;\n\tif (typeof value === \"number\") return value;\n\tconst parsed = Number.parseFloat(String(value));\n\treturn Number.isNaN(parsed) ? undefined : parsed;\n}\n","import type {\n\tColumnSchema,\n\tIntrospectOptions,\n\tSchemaIntrospection,\n\tTableSchema,\n} from \"../schema/types\";\nimport type { DatabaseAdapter, DatabaseExecutionResult } from \"./types\";\n\nexport interface PostgresQueryResult {\n\trows: Array<Record<string, unknown>>;\n\tfields: Array<{ name: string }>;\n}\n\nexport type PostgresClientFn = (\n\tsql: string,\n\tparams?: unknown[],\n) => Promise<PostgresQueryResult>;\n\nexport interface PostgresAdapterOptions {\n\t/** Logical database name used in introspection metadata. */\n\tdatabase?: string;\n\t/** Schema to assume when a table is provided without qualification. */\n\tdefaultSchema?: string;\n\t/** Optional database kind label. Defaults to \"postgres\". */\n\tkind?: SchemaIntrospection[\"db\"][\"kind\"];\n\t/**\n\t * Optional allow-list of table names (schema-qualified or bare).\n\t * When specified, introspection and queries are restricted to these tables only.\n\t */\n\tallowedTables?: string[];\n}\n\ntype TableRow = {\n\ttable_name: string;\n\tschema_name: string;\n\ttable_type: string;\n\tcomment: string | null;\n};\n\ntype ColumnRow = {\n\ttable_name: string;\n\ttable_schema: string;\n\tcolumn_name: string;\n\tdata_type: string;\n\tudt_name: string | null;\n\tis_primary_key: boolean;\n\tdescription: string | null;\n};\n\ninterface NormalizedTable {\n\tschema: string;\n\ttable: string;\n}\n\n/**\n * Simplified PostgreSQL adapter following IngestRequest format\n * Removed: indexes, constraints, foreign keys, statistics\n * Kept only: tables, columns (name, type, isPrimaryKey, comment)\n */\nexport class PostgresAdapter implements DatabaseAdapter {\n\tprivate readonly databaseName: string;\n\tprivate readonly defaultSchema: string;\n\tprivate readonly kind: SchemaIntrospection[\"db\"][\"kind\"];\n\tprivate readonly allowedTables?: NormalizedTable[];\n\n\tconstructor(\n\t\tprivate readonly clientFn: PostgresClientFn,\n\t\toptions: PostgresAdapterOptions = {},\n\t) {\n\t\tthis.databaseName = options.database ?? \"postgres\";\n\t\tthis.defaultSchema = options.defaultSchema ?? \"public\";\n\t\tthis.kind = options.kind ?? \"postgres\";\n\t\tif (options.allowedTables) {\n\t\t\tthis.allowedTables = normalizeTableFilter(\n\t\t\t\toptions.allowedTables,\n\t\t\t\tthis.defaultSchema,\n\t\t\t);\n\t\t}\n\t}\n\n\tasync execute(\n\t\tsql: string,\n\t\tparams?: Record<string, string | number | boolean | string[] | number[]>,\n\t): Promise<DatabaseExecutionResult> {\n\t\t// Validate query against allowed tables if restrictions are in place\n\t\tif (this.allowedTables) {\n\t\t\tthis.validateQueryTables(sql);\n\t\t}\n\n\t\t// Convert named params to positional array for PostgreSQL\n\t\tlet paramArray: unknown[] | undefined;\n\t\tif (params) {\n\t\t\tparamArray = this.convertNamedToPositionalParams(params);\n\t\t}\n\n\t\tconst result = await this.clientFn(sql, paramArray);\n\t\tconst fields = result.fields.map((f) => f.name);\n\t\treturn { fields, rows: result.rows };\n\t}\n\n\tprivate validateQueryTables(sql: string): void {\n\t\tif (!this.allowedTables || this.allowedTables.length === 0) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst allowedSet = new Set(\n\t\t\tthis.allowedTables.map((t) => tableKey(t.schema, t.table)),\n\t\t);\n\n\t\t// Extract potential table references from SQL\n\t\tconst tablePattern =\n\t\t\t/(?:FROM|JOIN)\\s+(?:ONLY\\s+)?(?:([a-zA-Z_][a-zA-Z0-9_]*)\\.)?([\"']?[a-zA-Z_][a-zA-Z0-9_]*[\"']?)/gi;\n\t\tconst matches = sql.matchAll(tablePattern);\n\n\t\tfor (const match of matches) {\n\t\t\tconst schema = match[1] ?? this.defaultSchema;\n\t\t\tconst table = match[2]?.replace(/['\"]/g, \"\");\n\t\t\tif (table) {\n\t\t\t\tconst key = tableKey(schema, table);\n\t\t\t\tif (!allowedSet.has(key)) {\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t`Query references table \"${schema}.${table}\" which is not in the allowed tables list`,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Convert named params to positional array for PostgreSQL\n\t * PostgreSQL expects $1, $2, $3 in SQL and an array of values [val1, val2, val3]\n\t */\n\tprivate convertNamedToPositionalParams(\n\t\tparams: Record<string, string | number | boolean | string[] | number[]>,\n\t): unknown[] {\n\t\t// Separate numeric and named keys\n\t\tconst numericKeys = Object.keys(params)\n\t\t\t.filter((k) => /^\\d+$/.test(k))\n\t\t\t.map((k) => Number.parseInt(k, 10))\n\t\t\t.sort((a, b) => a - b);\n\n\t\tconst namedKeys = Object.keys(params)\n\t\t\t.filter((k) => !/^\\d+$/.test(k))\n\t\t\t.sort(); // Alphabetical order for consistency\n\n\t\t// Build positional array\n\t\tconst positionalParams: unknown[] = [];\n\n\t\t// First, add values from numeric keys (in sorted order)\n\t\tfor (const key of numericKeys) {\n\t\t\tlet val: unknown = params[String(key)];\n\t\t\tif (typeof val === \"string\") {\n\t\t\t\t// Resolve placeholder tokens like `<tenant_id>` to their named values\n\t\t\t\tconst match = val.match(/^<([a-zA-Z0-9_]+)>$/);\n\t\t\t\tconst namedKey = match?.[1];\n\t\t\t\tif (namedKey && namedKey in params) {\n\t\t\t\t\tval = params[namedKey as keyof typeof params];\n\t\t\t\t}\n\t\t\t}\n\t\t\tpositionalParams.push(val);\n\t\t}\n\n\t\t// Then, add values from named keys (in alphabetical order)\n\t\tfor (const key of namedKeys) {\n\t\t\tconst val = params[key];\n\t\t\tpositionalParams.push(val);\n\t\t}\n\n\t\treturn positionalParams;\n\t}\n\n\tasync validate(\n\t\tsql: string,\n\t\tparams?: Record<string, string | number | boolean | string[] | number[]>,\n\t): Promise<void> {\n\t\tlet paramArray: unknown[] | undefined;\n\t\tif (params) {\n\t\t\tparamArray = this.convertNamedToPositionalParams(params);\n\t\t}\n\n\t\tawait this.clientFn(`EXPLAIN ${sql}`, paramArray);\n\t}\n\n\tgetDialect() {\n\t\treturn \"postgres\" as const;\n\t}\n\n\t/**\n\t * Simplified introspection: only collect table/column metadata for IngestRequest\n\t * No indexes, constraints, or statistics\n\t */\n\tasync introspect(options?: IntrospectOptions): Promise<SchemaIntrospection> {\n\t\t// Use adapter-level allowedTables if no specific tables provided in options\n\t\tconst tablesToIntrospect = options?.tables\n\t\t\t? normalizeTableFilter(options.tables, this.defaultSchema)\n\t\t\t: this.allowedTables;\n\t\tconst normalizedTables = tablesToIntrospect ?? [];\n\n\t\tconst tablesResult = await this.clientFn(\n\t\t\tbuildTablesQuery(normalizedTables),\n\t\t);\n\t\tconst tableRows = tablesResult.rows as TableRow[];\n\n\t\tconst columnsResult = await this.clientFn(\n\t\t\tbuildColumnsQuery(normalizedTables),\n\t\t);\n\t\tconst columnRows = columnsResult.rows as ColumnRow[];\n\n\t\tconst tablesByKey = new Map<string, TableSchema>();\n\n\t\t// Build tables\n\t\tfor (const row of tableRows) {\n\t\t\tconst key = tableKey(row.schema_name, row.table_name);\n\t\t\tconst table: TableSchema = {\n\t\t\t\tname: row.table_name,\n\t\t\t\tschema: row.schema_name,\n\t\t\t\ttype: asTableType(row.table_type),\n\t\t\t\tcolumns: [],\n\t\t\t};\n\n\t\t\tconst comment = sanitize(row.comment);\n\t\t\tif (comment !== undefined) {\n\t\t\t\ttable.comment = comment;\n\t\t\t}\n\n\t\t\ttablesByKey.set(key, table);\n\t\t}\n\n\t\t// Build columns\n\t\tfor (const row of columnRows) {\n\t\t\tconst key = tableKey(row.table_schema, row.table_name);\n\t\t\tconst table = tablesByKey.get(key);\n\t\t\tif (!table) continue;\n\n\t\t\tconst column: ColumnSchema = {\n\t\t\t\tname: row.column_name,\n\t\t\t\ttype: row.data_type,\n\t\t\t\tisPrimaryKey: row.is_primary_key,\n\t\t\t};\n\n\t\t\tconst rawType = row.udt_name ?? undefined;\n\t\t\tif (rawType !== undefined) column.rawType = rawType;\n\n\t\t\tconst comment = sanitize(row.description);\n\t\t\tif (comment !== undefined) column.comment = comment;\n\n\t\t\ttable.columns.push(column);\n\t\t}\n\n\t\tconst tables = Array.from(tablesByKey.values()).sort((a, b) => {\n\t\t\tif (a.schema === b.schema) {\n\t\t\t\treturn a.name.localeCompare(b.name);\n\t\t\t}\n\t\t\treturn a.schema.localeCompare(b.schema);\n\t\t});\n\n\t\treturn {\n\t\t\tdb: {\n\t\t\t\tkind: this.kind,\n\t\t\t\tname: this.databaseName,\n\t\t\t},\n\t\t\ttables,\n\t\t\tintrospectedAt: new Date().toISOString(),\n\t\t};\n\t}\n}\n\nfunction normalizeTableFilter(\n\ttables: string[] | undefined,\n\tdefaultSchema: string,\n): NormalizedTable[] {\n\tif (!tables?.length) return [];\n\tconst normalized: NormalizedTable[] = [];\n\tconst seen = new Set<string>();\n\n\tfor (const raw of tables) {\n\t\tif (!raw) continue;\n\t\tconst trimmed = raw.trim();\n\t\tif (!trimmed) continue;\n\t\tconst parts = trimmed.split(\".\");\n\t\tconst table = parts.pop() ?? \"\";\n\t\tconst schema = parts.pop() ?? defaultSchema;\n\t\tif (!isSafeIdentifier(schema) || !isSafeIdentifier(table)) {\n\t\t\tcontinue;\n\t\t}\n\t\tconst key = tableKey(schema, table);\n\t\tif (seen.has(key)) continue;\n\t\tseen.add(key);\n\t\tnormalized.push({ schema, table });\n\t}\n\n\treturn normalized;\n}\n\nfunction buildTablesQuery(tables: NormalizedTable[]): string {\n\tconst filter = buildFilterClause(tables, \"n.nspname\", \"c.relname\");\n\treturn `SELECT\n c.relname AS table_name,\n n.nspname AS schema_name,\n CASE c.relkind\n WHEN 'r' THEN 'table'\n WHEN 'v' THEN 'view'\n WHEN 'm' THEN 'materialized_view'\n ELSE c.relkind::text\n END AS table_type,\n obj_description(c.oid) AS comment\n FROM pg_class c\n JOIN pg_namespace n ON n.oid = c.relnamespace\n WHERE n.nspname NOT IN ('pg_catalog', 'information_schema')\n AND c.relkind IN ('r', 'v', 'm')\n ${filter}\n ORDER BY n.nspname, c.relname;`;\n}\n\nfunction buildColumnsQuery(tables: NormalizedTable[]): string {\n\tconst filter = buildFilterClause(\n\t\ttables,\n\t\t\"cols.table_schema\",\n\t\t\"cols.table_name\",\n\t);\n\treturn `SELECT\n cols.table_name,\n cols.table_schema,\n cols.column_name,\n cols.data_type,\n cols.udt_name,\n pgd.description,\n EXISTS(\n SELECT 1\n FROM information_schema.table_constraints tc\n JOIN information_schema.key_column_usage kcu\n ON tc.constraint_name = kcu.constraint_name\n AND tc.table_schema = kcu.table_schema\n WHERE tc.constraint_type = 'PRIMARY KEY'\n AND tc.table_schema = cols.table_schema\n AND tc.table_name = cols.table_name\n AND kcu.column_name = cols.column_name\n ) AS is_primary_key\n FROM information_schema.columns cols\n LEFT JOIN pg_catalog.pg_class c\n ON c.relname = cols.table_name\n AND c.relkind IN ('r', 'v', 'm')\n LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace\n LEFT JOIN pg_catalog.pg_attribute attr\n ON attr.attrelid = c.oid\n AND attr.attname = cols.column_name\n LEFT JOIN pg_catalog.pg_description pgd\n ON pgd.objoid = attr.attrelid AND pgd.objsubid = attr.attnum\n WHERE cols.table_schema NOT IN ('pg_catalog', 'information_schema')\n ${filter}\n ORDER BY cols.table_schema, cols.table_name, cols.ordinal_position;`;\n}\n\nfunction buildFilterClause(\n\ttables: NormalizedTable[],\n\tschemaExpr: string,\n\ttableExpr: string,\n): string {\n\tif (!tables.length) return \"\";\n\tconst clauses = tables.map(({ schema, table }) => {\n\t\treturn `(${schemaExpr} = '${schema}' AND ${tableExpr} = '${table}')`;\n\t});\n\treturn `AND (${clauses.join(\" OR \")})`;\n}\n\nfunction tableKey(schema: string, table: string): string {\n\treturn `${schema}.${table}`;\n}\n\nfunction isSafeIdentifier(value: string): boolean {\n\treturn /^[A-Za-z_][A-Za-z0-9_]*$/.test(value);\n}\n\nfunction asTableType(value: string): TableSchema[\"type\"] {\n\tconst normalized = value.toLowerCase();\n\tif (normalized.includes(\"view\")) {\n\t\treturn normalized.includes(\"materialized\") ? \"materialized_view\" : \"view\";\n\t}\n\treturn \"table\";\n}\n\nfunction sanitize(value: unknown): string | undefined {\n\tif (value === null || value === undefined) return undefined;\n\tconst trimmed = String(value).trim();\n\treturn trimmed.length ? trimmed : undefined;\n}\n","import { createSign } from \"node:crypto\";\n\n/**\n * Deep module: Hides JWT signing and HTTP complexity behind simple interface\n * Following Ousterhout's principle: \"Pull complexity downward\"\n */\nexport class ApiClient {\n\tprivate readonly baseUrl: string;\n\tprivate readonly privateKey: string;\n\tprivate readonly organizationId: string;\n\tprivate readonly defaultTenantId?: string;\n\tprivate readonly additionalHeaders?: Record<string, string>;\n\tprivate readonly fetchImpl: typeof fetch;\n\n\tconstructor(\n\t\tbaseUrl: string,\n\t\tprivateKey: string,\n\t\torganizationId: string,\n\t\toptions?: {\n\t\t\tdefaultTenantId?: string;\n\t\t\tadditionalHeaders?: Record<string, string>;\n\t\t\tfetch?: typeof fetch;\n\t\t},\n\t) {\n\t\tif (!baseUrl) {\n\t\t\tthrow new Error(\"Base URL is required\");\n\t\t}\n\t\tif (!privateKey) {\n\t\t\tthrow new Error(\"Private key is required\");\n\t\t}\n\t\tif (!organizationId) {\n\t\t\tthrow new Error(\"Organization ID is required\");\n\t\t}\n\n\t\tthis.baseUrl = baseUrl.replace(/\\/+$/, \"\");\n\t\tthis.privateKey = privateKey;\n\t\tthis.organizationId = organizationId;\n\t\tthis.defaultTenantId = options?.defaultTenantId;\n\t\tthis.additionalHeaders = options?.additionalHeaders;\n\t\tthis.fetchImpl = options?.fetch ?? globalThis.fetch;\n\n\t\tif (!this.fetchImpl) {\n\t\t\tthrow new Error(\n\t\t\t\t\"Fetch implementation not found. Provide options.fetch or use Node 18+.\",\n\t\t\t);\n\t\t}\n\t}\n\n\tgetDefaultTenantId(): string | undefined {\n\t\treturn this.defaultTenantId;\n\t}\n\n\tasync get<T>(\n\t\tpath: string,\n\t\ttenantId: string,\n\t\tuserId?: string,\n\t\tscopes?: string[],\n\t\tsignal?: AbortSignal,\n\t\tsessionId?: string,\n\t): Promise<T> {\n\t\treturn await this.request<T>(path, {\n\t\t\tmethod: \"GET\",\n\t\t\theaders: await this.buildHeaders(\n\t\t\t\ttenantId,\n\t\t\t\tuserId,\n\t\t\t\tscopes,\n\t\t\t\tfalse,\n\t\t\t\tsessionId,\n\t\t\t),\n\t\t\tsignal,\n\t\t});\n\t}\n\n\tasync post<T>(\n\t\tpath: string,\n\t\tbody: unknown,\n\t\ttenantId: string,\n\t\tuserId?: string,\n\t\tscopes?: string[],\n\t\tsignal?: AbortSignal,\n\t\tsessionId?: string,\n\t): Promise<T> {\n\t\treturn await this.request<T>(path, {\n\t\t\tmethod: \"POST\",\n\t\t\theaders: await this.buildHeaders(\n\t\t\t\ttenantId,\n\t\t\t\tuserId,\n\t\t\t\tscopes,\n\t\t\t\ttrue,\n\t\t\t\tsessionId,\n\t\t\t),\n\t\t\tbody: JSON.stringify(body ?? {}),\n\t\t\tsignal,\n\t\t});\n\t}\n\n\tasync put<T>(\n\t\tpath: string,\n\t\tbody: unknown,\n\t\ttenantId: string,\n\t\tuserId?: string,\n\t\tscopes?: string[],\n\t\tsignal?: AbortSignal,\n\t\tsessionId?: string,\n\t): Promise<T> {\n\t\treturn await this.request<T>(path, {\n\t\t\tmethod: \"PUT\",\n\t\t\theaders: await this.buildHeaders(\n\t\t\t\ttenantId,\n\t\t\t\tuserId,\n\t\t\t\tscopes,\n\t\t\t\ttrue,\n\t\t\t\tsessionId,\n\t\t\t),\n\t\t\tbody: JSON.stringify(body ?? {}),\n\t\t\tsignal,\n\t\t});\n\t}\n\n\tasync delete<T = void>(\n\t\tpath: string,\n\t\ttenantId: string,\n\t\tuserId?: string,\n\t\tscopes?: string[],\n\t\tsignal?: AbortSignal,\n\t\tsessionId?: string,\n\t): Promise<T> {\n\t\treturn await this.request<T>(path, {\n\t\t\tmethod: \"DELETE\",\n\t\t\theaders: await this.buildHeaders(\n\t\t\t\ttenantId,\n\t\t\t\tuserId,\n\t\t\t\tscopes,\n\t\t\t\tfalse,\n\t\t\t\tsessionId,\n\t\t\t),\n\t\t\tsignal,\n\t\t});\n\t}\n\n\tprivate async request<T>(path: string, init: RequestInit): Promise<T> {\n\t\tconst response = await this.fetchImpl(`${this.baseUrl}${path}`, init);\n\t\tconst text = await response.text();\n\t\tlet json: any;\n\t\ttry {\n\t\t\tjson = text ? JSON.parse(text) : undefined;\n\t\t} catch {\n\t\t\tjson = undefined;\n\t\t}\n\n\t\tif (!response.ok) {\n\t\t\tconst error = new Error(\n\t\t\t\tjson?.error || response.statusText || \"Request failed\",\n\t\t\t);\n\t\t\t(error as any).status = response.status;\n\t\t\tif (json?.details) (error as any).details = json.details;\n\t\t\tthrow error;\n\t\t}\n\n\t\treturn json as T;\n\t}\n\n\tprivate async buildHeaders(\n\t\ttenantId: string,\n\t\tuserId?: string,\n\t\tscopes?: string[],\n\t\tincludeJson: boolean = true,\n\t\tsessionId?: string,\n\t): Promise<Record<string, string>> {\n\t\tconst token = await this.generateJWT(tenantId, userId, scopes);\n\t\tconst headers: Record<string, string> = {\n\t\t\tAuthorization: `Bearer ${token}`,\n\t\t\tAccept: \"application/json\",\n\t\t};\n\t\tif (includeJson) {\n\t\t\theaders[\"Content-Type\"] = \"application/json\";\n\t\t}\n\t\tif (sessionId) {\n\t\t\theaders[\"x-session-id\"] = sessionId;\n\t\t}\n\t\tif (this.additionalHeaders) {\n\t\t\tObject.assign(headers, this.additionalHeaders);\n\t\t}\n\t\treturn headers;\n\t}\n\n\tprivate async generateJWT(\n\t\ttenantId: string,\n\t\tuserId?: string,\n\t\tscopes?: string[],\n\t): Promise<string> {\n\t\tconst header = {\n\t\t\talg: \"RS256\",\n\t\t\ttyp: \"JWT\",\n\t\t};\n\n\t\tconst payload: Record<string, unknown> = {\n\t\t\torganizationId: this.organizationId,\n\t\t\ttenantId,\n\t\t};\n\n\t\tif (userId) payload.userId = userId;\n\t\tif (scopes?.length) payload.scopes = scopes;\n\n\t\tconst encodeJson = (obj: unknown): string => {\n\t\t\tconst json = JSON.stringify(obj);\n\t\t\tconst base64 = Buffer.from(json).toString(\"base64\");\n\t\t\t// base64url encoding: replace non-url chars and strip padding\n\t\t\treturn base64.replace(/\\+/g, \"-\").replace(/\\//g, \"_\").replace(/=+$/g, \"\");\n\t\t};\n\n\t\tconst encodedHeader = encodeJson(header);\n\t\tconst encodedPayload = encodeJson(payload);\n\t\tconst data = `${encodedHeader}.${encodedPayload}`;\n\n\t\tconst signer = createSign(\"RSA-SHA256\");\n\t\tsigner.update(data);\n\t\tsigner.end();\n\n\t\tconst signature = signer.sign(this.privateKey);\n\t\tconst encodedSignature = signature\n\t\t\t.toString(\"base64\")\n\t\t\t.replace(/\\+/g, \"-\")\n\t\t\t.replace(/\\//g, \"_\")\n\t\t\t.replace(/=+$/g, \"\");\n\n\t\treturn `${data}.${encodedSignature}`;\n\t}\n}\n","import type { DatabaseAdapter, DatabaseDialect } from \"../adapters/types\";\n\nexport type ParamValue = string | number | boolean | string[] | number[];\nexport type ParamRecord = Record<string, ParamValue>;\n\nexport interface DatabaseMetadata {\n\tname: string;\n\tdialect: DatabaseDialect;\n\tdescription?: string;\n\ttags?: string[];\n\ttenantFieldName?: string;\n\ttenantFieldType?: string;\n\tenforceTenantIsolation?: boolean;\n}\n\nexport interface DatabaseExecutionResult {\n\trows: Array<Record<string, unknown>>;\n\tfields: string[];\n}\n\n/**\n * Deep module: Hides SQL execution complexity and tenant isolation logic\n * Following Ousterhout's principle: \"Information hiding\"\n */\nexport class QueryEngine {\n\tprivate databases = new Map<string, DatabaseAdapter>();\n\tprivate databaseMetadata = new Map<string, DatabaseMetadata>();\n\tprivate defaultDatabase?: string;\n\n\tattachDatabase(name: string, adapter: DatabaseAdapter, metadata: DatabaseMetadata): void {\n\t\tthis.databases.set(name, adapter);\n\t\tthis.databaseMetadata.set(name, metadata);\n\t\tif (!this.defaultDatabase) {\n\t\t\tthis.defaultDatabase = name;\n\t\t}\n\t}\n\n\tgetDatabase(name?: string): DatabaseAdapter {\n\t\tconst dbName = name ?? this.defaultDatabase;\n\t\tif (!dbName) {\n\t\t\tthrow new Error(\"No database attached.\");\n\t\t}\n\t\tconst adapter = this.databases.get(dbName);\n\t\tif (!adapter) {\n\t\t\tthrow new Error(\n\t\t\t\t`Database '${dbName}' not found. Attached: ${Array.from(\n\t\t\t\t\tthis.databases.keys(),\n\t\t\t\t).join(\", \")}`,\n\t\t\t);\n\t\t}\n\t\treturn adapter;\n\t}\n\n\tgetDatabaseMetadata(name?: string): DatabaseMetadata | undefined {\n\t\tconst dbName = name ?? this.defaultDatabase;\n\t\tif (!dbName) return undefined;\n\t\treturn this.databaseMetadata.get(dbName);\n\t}\n\n\tgetDefaultDatabase(): string | undefined {\n\t\treturn this.defaultDatabase;\n\t}\n\n\tasync validateAndExecute(\n\t\tsql: string,\n\t\tparams: ParamRecord,\n\t\tdatabaseName: string,\n\t\ttenantId: string,\n\t): Promise<DatabaseExecutionResult> {\n\t\tconst adapter = this.getDatabase(databaseName);\n\t\tconst metadata = this.getDatabaseMetadata(databaseName);\n\n\t\t// Apply tenant isolation if configured\n\t\tlet finalSql = sql;\n\t\tif (metadata) {\n\t\t\tfinalSql = this.ensureTenantIsolation(sql, params, metadata, tenantId);\n\t\t}\n\n\t\t// Validate SQL\n\t\tawait adapter.validate(finalSql, params);\n\n\t\t// Execute\n\t\tconst result = await adapter.execute(finalSql, params);\n\t\treturn {\n\t\t\trows: result.rows,\n\t\t\tfields: result.fields,\n\t\t};\n\t}\n\n\tasync execute(\n\t\tsql: string,\n\t\tparams: ParamRecord | undefined,\n\t\tdatabaseName?: string,\n\t): Promise<Array<Record<string, unknown>>> {\n\t\ttry {\n\t\t\tconst adapter = this.getDatabase(databaseName);\n\t\t\tconst result = await adapter.execute(sql, params);\n\t\t\treturn result.rows;\n\t\t} catch (error) {\n\t\t\tconsole.warn(\n\t\t\t\t`Failed to execute SQL locally for database '${databaseName}':`,\n\t\t\t\terror,\n\t\t\t);\n\t\t\treturn [];\n\t\t}\n\t}\n\n\tmapGeneratedParams(params: Array<Record<string, unknown>>): ParamRecord {\n\t\tconst record: ParamRecord = {};\n\n\t\tparams.forEach((param, index) => {\n\t\t\tconst value = param.value as ParamValue | undefined;\n\t\t\tif (value === undefined) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst nameCandidate =\n\t\t\t\t(typeof param.name === \"string\" && param.name.trim()) ||\n\t\t\t\t(typeof param.placeholder === \"string\" && param.placeholder.trim()) ||\n\t\t\t\t(typeof param.position === \"number\" && String(param.position)) ||\n\t\t\t\tString(index + 1);\n\t\t\tconst key = nameCandidate.replace(/[{}:$]/g, \"\").trim();\n\t\t\trecord[key] = value;\n\t\t});\n\n\t\treturn record;\n\t}\n\n\tprivate ensureTenantIsolation(\n\t\tsql: string,\n\t\tparams: ParamRecord,\n\t\tmetadata: DatabaseMetadata,\n\t\ttenantId: string,\n\t): string {\n\t\tif (\n\t\t\t!metadata.tenantFieldName ||\n\t\t\tmetadata.enforceTenantIsolation === false\n\t\t) {\n\t\t\treturn sql;\n\t\t}\n\n\t\tconst tenantField = metadata.tenantFieldName;\n\t\tconst paramKey = tenantField;\n\t\tparams[paramKey] = tenantId;\n\n\t\tconst normalizedSql = sql.toLowerCase();\n\t\tif (normalizedSql.includes(tenantField.toLowerCase())) {\n\t\t\treturn sql;\n\t\t}\n\n\t\tconst tenantPredicate =\n\t\t\tmetadata.dialect === \"clickhouse\"\n\t\t\t\t? `${tenantField} = {${tenantField}:${metadata.tenantFieldType ?? \"String\"}}`\n\t\t\t\t: `${tenantField} = '${tenantId}'`;\n\n\t\tif (/\\bwhere\\b/i.test(sql)) {\n\t\t\treturn sql.replace(\n\t\t\t\t/\\bwhere\\b/i,\n\t\t\t\t(match) => `${match} ${tenantPredicate} AND `,\n\t\t\t);\n\t\t}\n\n\t\treturn `${sql} WHERE ${tenantPredicate}`;\n\t}\n}\n","import type { ApiClient } from \"../core/client\";\nimport type { ParamRecord, QueryEngine } from \"../core/query-engine\";\n\nexport interface SdkChart {\n\tid: string;\n\ttitle: string;\n\tdescription: string | null;\n\tsql: string;\n\tsql_params: Record<string, unknown> | null;\n\tvega_lite_spec: Record<string, unknown>;\n\tquery_id: string | null;\n\torganization_id: string | null;\n\ttenant_id: string | null;\n\tuser_id: string | null;\n\tcreated_at: string | null;\n\tupdated_at: string | null;\n\tactive?: boolean;\n\ttarget_db?: string | null;\n}\n\nexport interface ChartCreateInput {\n\ttitle: string;\n\tdescription?: string;\n\tsql: string;\n\tsql_params?: Record<string, unknown>;\n\tvega_lite_spec: Record<string, unknown>;\n\tquery_id?: string;\n\ttarget_db?: string;\n}\n\nexport interface ChartUpdateInput {\n\ttitle?: string;\n\tdescription?: string;\n\tsql?: string;\n\tsql_params?: Record<string, unknown>;\n\tvega_lite_spec?: Record<string, unknown>;\n\ttarget_db?: string;\n}\n\nexport interface PaginationQuery {\n\tpage?: number;\n\tlimit?: number;\n}\n\nexport interface PaginationInfo {\n\tpage: number;\n\tlimit: number;\n\ttotal: number;\n\ttotalPages: number;\n\thasNext: boolean;\n\thasPrev: boolean;\n}\n\nexport interface PaginatedResponse<T> {\n\tdata: T[];\n\tpagination: PaginationInfo;\n}\n\nexport interface ChartListOptions {\n\ttenantId?: string;\n\tuserId?: string;\n\tscopes?: string[];\n\tpagination?: PaginationQuery;\n\tsortBy?: \"title\" | \"user_id\" | \"created_at\" | \"updated_at\";\n\tsortDir?: \"asc\" | \"desc\";\n\ttitle?: string;\n\tuserFilter?: string;\n\tcreatedFrom?: string;\n\tcreatedTo?: string;\n\tupdatedFrom?: string;\n\tupdatedTo?: string;\n\tincludeData?: boolean;\n}\n\ninterface RequestOptions {\n\ttenantId?: string;\n\tuserId?: string;\n\tscopes?: string[];\n}\n\n/**\n * Route module for Chart CRUD operations\n * Simple pass-through to backend with optional data hydration\n */\nexport async function createChart(\n\tclient: ApiClient,\n\tbody: ChartCreateInput,\n\toptions?: RequestOptions,\n\tsignal?: AbortSignal,\n): Promise<SdkChart> {\n\tconst tenantId = resolveTenantId(client, options?.tenantId);\n\treturn await client.post<SdkChart>(\n\t\t\"/charts\",\n\t\tbody,\n\t\ttenantId,\n\t\toptions?.userId,\n\t\toptions?.scopes,\n\t\tsignal,\n\t);\n}\n\nexport async function listCharts(\n\tclient: ApiClient,\n\tqueryEngine: QueryEngine,\n\toptions?: ChartListOptions,\n\tsignal?: AbortSignal,\n): Promise<PaginatedResponse<SdkChart>> {\n\tconst tenantId = resolveTenantId(client, options?.tenantId);\n\tconst params = new URLSearchParams();\n\tif (options?.pagination?.page)\n\t\tparams.set(\"page\", `${options.pagination.page}`);\n\tif (options?.pagination?.limit)\n\t\tparams.set(\"limit\", `${options.pagination.limit}`);\n\tif (options?.sortBy) params.set(\"sort_by\", options.sortBy);\n\tif (options?.sortDir) params.set(\"sort_dir\", options.sortDir);\n\tif (options?.title) params.set(\"title\", options.title);\n\tif (options?.userFilter) params.set(\"user_id\", options.userFilter);\n\tif (options?.createdFrom) params.set(\"created_from\", options.createdFrom);\n\tif (options?.createdTo) params.set(\"created_to\", options.createdTo);\n\tif (options?.updatedFrom) params.set(\"updated_from\", options.updatedFrom);\n\tif (options?.updatedTo) params.set(\"updated_to\", options.updatedTo);\n\n\tconst response = await client.get<PaginatedResponse<SdkChart>>(\n\t\t`/charts${params.toString() ? `?${params.toString()}` : \"\"}`,\n\t\ttenantId,\n\t\toptions?.userId,\n\t\toptions?.scopes,\n\t\tsignal,\n\t);\n\n\tif (options?.includeData) {\n\t\tresponse.data = await Promise.all(\n\t\t\tresponse.data.map(async (chart) => ({\n\t\t\t\t...chart,\n\t\t\t\tvega_lite_spec: {\n\t\t\t\t\t...chart.vega_lite_spec,\n\t\t\t\t\tdata: {\n\t\t\t\t\t\tvalues: await queryEngine.execute(\n\t\t\t\t\t\t\tchart.sql,\n\t\t\t\t\t\t\t(chart.sql_params as ParamRecord | null) ?? undefined,\n\t\t\t\t\t\t\tchart.target_db ?? undefined,\n\t\t\t\t\t\t),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t})),\n\t\t);\n\t}\n\n\treturn response;\n}\n\nexport async function getChart(\n\tclient: ApiClient,\n\tqueryEngine: QueryEngine,\n\tid: string,\n\toptions?: RequestOptions,\n\tsignal?: AbortSignal,\n): Promise<SdkChart> {\n\tconst tenantId = resolveTenantId(client, options?.tenantId);\n\tconst chart = await client.get<SdkChart>(\n\t\t`/charts/${encodeURIComponent(id)}`,\n\t\ttenantId,\n\t\toptions?.userId,\n\t\toptions?.scopes,\n\t\tsignal,\n\t);\n\n\treturn {\n\t\t...chart,\n\t\tvega_lite_spec: {\n\t\t\t...chart.vega_lite_spec,\n\t\t\tdata: {\n\t\t\t\tvalues: await queryEngine.execute(\n\t\t\t\t\tchart.sql,\n\t\t\t\t\t(chart.sql_params as ParamRecord | null) ?? undefined,\n\t\t\t\t\tchart.target_db ?? undefined,\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t};\n}\n\nexport async function updateChart(\n\tclient: ApiClient,\n\tid: string,\n\tbody: ChartUpdateInput,\n\toptions?: RequestOptions,\n\tsignal?: AbortSignal,\n): Promise<SdkChart> {\n\tconst tenantId = resolveTenantId(client, options?.tenantId);\n\treturn await client.put<SdkChart>(\n\t\t`/charts/${encodeURIComponent(id)}`,\n\t\tbody,\n\t\ttenantId,\n\t\toptions?.userId,\n\t\toptions?.scopes,\n\t\tsignal,\n\t);\n}\n\nexport async function deleteChart(\n\tclient: ApiClient,\n\tid: string,\n\toptions?: RequestOptions,\n\tsignal?: AbortSignal,\n): Promise<void> {\n\tconst tenantId = resolveTenantId(client, options?.tenantId);\n\tawait client.delete(\n\t\t`/charts/${encodeURIComponent(id)}`,\n\t\ttenantId,\n\t\toptions?.userId,\n\t\toptions?.scopes,\n\t\tsignal,\n\t);\n}\n\nfunction resolveTenantId(client: ApiClient, tenantId?: string): string {\n\tconst resolved = tenantId ?? client.getDefaultTenantId();\n\tif (!resolved) {\n\t\tthrow new Error(\n\t\t\t\"tenantId is required. Provide it per request or via defaultTenantId option.\",\n\t\t);\n\t}\n\treturn resolved;\n}\n","import type { ApiClient } from \"../core/client\";\nimport type { QueryEngine } from \"../core/query-engine\";\nimport * as charts from \"./charts\";\n\nexport interface SdkActiveChart {\n\tid: string;\n\tchart_id: string;\n\torder: number | null;\n\tmeta: Record<string, unknown> | null;\n\torganization_id: string | null;\n\ttenant_id: string | null;\n\tuser_id: string | null;\n\tcreated_at: string | null;\n\tupdated_at: string | null;\n\tchart?: charts.SdkChart | null;\n}\n\nexport interface ActiveChartCreateInput {\n\tchart_id: string;\n\torder?: number;\n\tmeta?: Record<string, unknown>;\n}\n\nexport interface ActiveChartUpdateInput {\n\tchart_id?: string;\n\torder?: number;\n\tmeta?: Record<string, unknown>;\n}\n\nexport interface ActiveChartListOptions extends charts.ChartListOptions {\n\twithData?: boolean;\n}\n\ninterface RequestOptions {\n\ttenantId?: string;\n\tuserId?: string;\n\tscopes?: string[];\n}\n\n/**\n * Route module for Active Chart CRUD operations\n * Simple pass-through to backend with optional chart data hydration\n */\nexport async function createActiveChart(\n\tclient: ApiClient,\n\tbody: ActiveChartCreateInput,\n\toptions?: RequestOptions,\n\tsignal?: AbortSignal,\n): Promise<SdkActiveChart> {\n\tconst tenantId = resolveTenantId(client, options?.tenantId);\n\treturn await client.post<SdkActiveChart>(\n\t\t\"/active-charts\",\n\t\tbody,\n\t\ttenantId,\n\t\toptions?.userId,\n\t\toptions?.scopes,\n\t\tsignal,\n\t);\n}\n\nexport async function listActiveCharts(\n\tclient: ApiClient,\n\tqueryEngine: QueryEngine,\n\toptions?: ActiveChartListOptions,\n\tsignal?: AbortSignal,\n): Promise<charts.PaginatedResponse<SdkActiveChart>> {\n\tconst tenantId = resolveTenantId(client, options?.tenantId);\n\tconst params = new URLSearchParams();\n\tif (options?.pagination?.page)\n\t\tparams.set(\"page\", `${options.pagination.page}`);\n\tif (options?.pagination?.limit)\n\t\tparams.set(\"limit\", `${options.pagination.limit}`);\n\tif (options?.sortBy) params.set(\"sort_by\", options.sortBy);\n\tif (options?.sortDir) params.set(\"sort_dir\", options.sortDir);\n\tif (options?.title) params.set(\"name\", options.title);\n\tif (options?.userFilter) params.set(\"user_id\", options.userFilter);\n\tif (options?.createdFrom) params.set(\"created_from\", options.createdFrom);\n\tif (options?.createdTo) params.set(\"created_to\", options.createdTo);\n\tif (options?.updatedFrom) params.set(\"updated_from\", options.updatedFrom);\n\tif (options?.updatedTo) params.set(\"updated_to\", options.updatedTo);\n\n\tconst response = await client.get<\n\t\tcharts.PaginatedResponse<SdkActiveChart>\n\t>(\n\t\t`/active-charts${params.toString() ? `?${params.toString()}` : \"\"}`,\n\t\ttenantId,\n\t\toptions?.userId,\n\t\toptions?.scopes,\n\t\tsignal,\n\t);\n\n\tif (options?.withData) {\n\t\tresponse.data = await Promise.all(\n\t\t\tresponse.data.map(async (active) => ({\n\t\t\t\t...active,\n\t\t\t\tchart: active.chart\n\t\t\t\t\t? await charts.getChart(\n\t\t\t\t\t\t\tclient,\n\t\t\t\t\t\t\tqueryEngine,\n\t\t\t\t\t\t\tactive.chart_id,\n\t\t\t\t\t\t\toptions,\n\t\t\t\t\t\t\tsignal,\n\t\t\t\t\t\t)\n\t\t\t\t\t: null,\n\t\t\t})),\n\t\t);\n\t}\n\n\treturn response;\n}\n\nexport async function getActiveChart(\n\tclient: ApiClient,\n\tqueryEngine: QueryEngine,\n\tid: string,\n\toptions?: ActiveChartListOptions,\n\tsignal?: AbortSignal,\n): Promise<SdkActiveChart> {\n\tconst tenantId = resolveTenantId(client, options?.tenantId);\n\tconst active = await client.get<SdkActiveChart>(\n\t\t`/active-charts/${encodeURIComponent(id)}`,\n\t\ttenantId,\n\t\toptions?.userId,\n\t\toptions?.scopes,\n\t\tsignal,\n\t);\n\n\tif (options?.withData && active.chart_id) {\n\t\treturn {\n\t\t\t...active,\n\t\t\tchart: await charts.getChart(\n\t\t\t\tclient,\n\t\t\t\tqueryEngine,\n\t\t\t\tactive.chart_id,\n\t\t\t\toptions,\n\t\t\t\tsignal,\n\t\t\t),\n\t\t};\n\t}\n\n\treturn active;\n}\n\nexport async function updateActiveChart(\n\tclient: ApiClient,\n\tid: string,\n\tbody: ActiveChartUpdateInput,\n\toptions?: RequestOptions,\n\tsignal?: AbortSignal,\n): Promise<SdkActiveChart> {\n\tconst tenantId = resolveTenantId(client, options?.tenantId);\n\treturn await client.put<SdkActiveChart>(\n\t\t`/active-charts/${encodeURIComponent(id)}`,\n\t\tbody,\n\t\ttenantId,\n\t\toptions?.userId,\n\t\toptions?.scopes,\n\t\tsignal,\n\t);\n}\n\nexport async function deleteActiveChart(\n\tclient: ApiClient,\n\tid: string,\n\toptions?: RequestOptions,\n\tsignal?: AbortSignal,\n): Promise<void> {\n\tconst tenantId = resolveTenantId(client, options?.tenantId);\n\tawait client.delete(\n\t\t`/active-charts/${encodeURIComponent(id)}`,\n\t\ttenantId,\n\t\toptions?.userId,\n\t\toptions?.scopes,\n\t\tsignal,\n\t);\n}\n\nfunction resolveTenantId(client: ApiClient, tenantId?: string): string {\n\tconst resolved = tenantId ?? client.getDefaultTenantId();\n\tif (!resolved) {\n\t\tthrow new Error(\n\t\t\t\"tenantId is required. Provide it per request or via defaultTenantId option.\",\n\t\t);\n\t}\n\treturn resolved;\n}\n","import { randomUUID } from \"node:crypto\";\nimport type { ApiClient } from \"../core/client\";\nimport type { QueryEngine } from \"../core/query-engine\";\nimport type { SchemaIntrospection } from \"../schema/types\";\n\nexport interface IngestResponse {\n\tsuccess: boolean;\n\tmessage: string;\n\tchunks: number;\n\tchunks_with_annotations: number;\n\tschema_id?: string;\n\tschema_hash?: string;\n\tdrift_detected?: boolean;\n\tskipped?: boolean;\n}\n\nexport interface SchemaSyncOptions {\n\ttenantId?: string;\n\tuserId?: string;\n\tscopes?: string[];\n\ttables?: string[];\n\tforceReindex?: boolean;\n}\n\ninterface SchemaIngestColumn {\n\tname: string;\n\tdata_type: string;\n\tis_primary_key: boolean;\n\tdescription: string;\n}\n\ninterface SchemaIngestTable {\n\ttable_name: string;\n\tdescription: string;\n\tcolumns: SchemaIngestColumn[];\n}\n\ninterface SchemaIngestRequest {\n\tdatabase: string;\n\tdialect: string;\n\ttables: SchemaIngestTable[];\n\tforce_reindex?: boolean;\n\ttenant_settings?: {\n\t\ttenantFieldName: string;\n\t\ttenantFieldType: string;\n\t\tenforceTenantIsolation: boolean;\n\t};\n}\n\n/**\n * Route module for schema ingestion\n * Handles introspection and sync to backend\n */\nexport async function syncSchema(\n\tclient: ApiClient,\n\tqueryEngine: QueryEngine,\n\tdatabaseName: string,\n\toptions: SchemaSyncOptions,\n\tsignal?: AbortSignal,\n): Promise<IngestResponse> {\n\tconst tenantId = resolveTenantId(client, options.tenantId);\n\tconst adapter = queryEngine.getDatabase(databaseName);\n\tconst metadata = queryEngine.getDatabaseMetadata(databaseName);\n\n\tconst introspection = await adapter.introspect(\n\t\toptions.tables ? { tables: options.tables } : undefined,\n\t);\n\n\tconst payload = buildSchemaRequest(databaseName, adapter, introspection, metadata);\n\tif (options.forceReindex) {\n\t\tpayload.force_reindex = true;\n\t}\n\n\t// Generate a session id so backend telemetry can correlate all work for this sync\n\tconst sessionId = randomUUID();\n\n\tconst response = await client.post<IngestResponse>(\n\t\t\"/ingest\",\n\t\tpayload,\n\t\ttenantId,\n\t\toptions.userId,\n\t\toptions.scopes,\n\t\tsignal,\n\t\tsessionId,\n\t);\n\n\treturn response;\n}\n\nfunction resolveTenantId(client: ApiClient, tenantId?: string): string {\n\tconst resolved = tenantId ?? client.getDefaultTenantId();\n\tif (!resolved) {\n\t\tthrow new Error(\n\t\t\t\"tenantId is required. Provide it per request or via defaultTenantId option.\",\n\t\t);\n\t}\n\treturn resolved;\n}\n\nfunction buildSchemaRequest(\n\tdatabaseName: string,\n\tadapter: { getDialect: () => string },\n\tintrospection: SchemaIntrospection,\n\tmetadata?: {\n\t\ttenantFieldName?: string;\n\t\ttenantFieldType?: string;\n\t\tenforceTenantIsolation?: boolean;\n\t},\n): SchemaIngestRequest {\n\tconst dialect = adapter.getDialect();\n\tconst tables: SchemaIngestTable[] = introspection.tables.map((table) => ({\n\t\ttable_name: table.name,\n\t\tdescription: table.comment ?? `Table ${table.name}`,\n\t\tcolumns: table.columns.map((column) => ({\n\t\t\tname: column.name,\n\t\t\tdata_type: column.rawType ?? column.type,\n\t\t\tis_primary_key: Boolean(column.isPrimaryKey),\n\t\t\tdescription: column.comment ?? \"\",\n\t\t})),\n\t}));\n\n\tconst request: SchemaIngestRequest = {\n\t\tdatabase: databaseName,\n\t\tdialect,\n\t\ttables,\n\t};\n\n\t// Include tenant_settings if configured in the database metadata\n\tif (\n\t\tmetadata?.tenantFieldName &&\n\t\tmetadata?.tenantFieldType &&\n\t\tmetadata?.enforceTenantIsolation !== undefined\n\t) {\n\t\trequest.tenant_settings = {\n\t\t\ttenantFieldName: metadata.tenantFieldName,\n\t\t\ttenantFieldType: metadata.tenantFieldType,\n\t\t\tenforceTenantIsolation: metadata.enforceTenantIsolation,\n\t\t};\n\t}\n\n\treturn request;\n}\n","import { randomUUID } from \"node:crypto\";\nimport type { ApiClient } from \"../core/client\";\nimport type { ParamRecord, QueryEngine } from \"../core/query-engine\";\n\nexport interface ContextDocument {\n\tsource?: string;\n\tpageContent: string;\n\tmetadata?: Record<string, unknown>;\n\tscore?: number;\n}\n\nexport interface ChartEnvelope {\n\tvegaLiteSpec: Record<string, unknown> | null;\n\tnotes: string | null;\n}\n\nexport interface AskOptions {\n\ttenantId?: string;\n\tuserId?: string;\n\tscopes?: string[];\n\tdatabase?: string;\n\tlastError?: string;\n\tpreviousSql?: string;\n\tmaxRetry?: number;\n\tchartMaxRetries?: number;\n}\n\nexport interface AskResponse {\n\tsql: string;\n\tparams: ParamRecord;\n\tparamMetadata: Array<Record<string, unknown>>;\n\trationale?: string;\n\tdialect: string;\n\tqueryId?: string;\n\trows: Array<Record<string, unknown>>;\n\tfields: string[];\n\tchart: ChartEnvelope;\n\tcontext?: ContextDocument[];\n\tattempts?: number;\n\ttarget_db?: string;\n}\n\ninterface ServerQueryResponse {\n\tsuccess: boolean;\n\tsql: string;\n\tparams?: Array<Record<string, unknown>>;\n\tdialect: string;\n\tdatabase?: string;\n\ttable?: string;\n\trationale?: string;\n\tqueryId?: string;\n\tcontext?: ContextDocument[];\n}\n\ninterface ServerChartResponse {\n\tchart: Record<string, unknown> | null;\n\tnotes: string | null;\n}\n\n/**\n * Route module for natural language query generation\n * Simple orchestration following Ousterhout's principle\n */\nexport async function ask(\n\tclient: ApiClient,\n\tqueryEngine: QueryEngine,\n\tquestion: string,\n\toptions: AskOptions,\n\tsignal?: AbortSignal,\n): Promise<AskResponse> {\n\tconst tenantId = resolveTenantId(client, options.tenantId);\n\tconst sessionId = randomUUID();\n\tconst maxRetry = options.maxRetry ?? 0;\n\tlet attempt = 0;\n\tlet lastError: string | undefined = options.lastError;\n\tlet previousSql: string | undefined = options.previousSql;\n\n\twhile (attempt <= maxRetry) {\n\t\t// Step 1: Get SQL from backend\n\t\tconsole.log({ lastError, previousSql });\n\t\tconst queryResponse = await client.post<ServerQueryResponse>(\n\t\t\t\"/query\",\n\t\t\t{\n\t\t\t\tquestion,\n\t\t\t\t...(lastError ? { last_error: lastError } : {}),\n\t\t\t\t...(previousSql ? { previous_sql: previousSql } : {}),\n\t\t\t\t...(options.maxRetry ? { max_retry: options.maxRetry } : {}),\n\t\t\t},\n\t\t\ttenantId,\n\t\t\toptions.userId,\n\t\t\toptions.scopes,\n\t\t\tsignal,\n\t\t\tsessionId,\n\t\t);\n\n\t\tconst databaseName =\n\t\t\tqueryResponse.database ??\n\t\t\toptions.database ??\n\t\t\tqueryEngine.getDefaultDatabase();\n\t\tif (!databaseName) {\n\t\t\tthrow new Error(\n\t\t\t\t\"No database attached. Call attachPostgres/attachClickhouse first.\",\n\t\t\t);\n\t\t}\n\n\t\t// Step 2: Map and validate parameters\n\t\tconst paramMetadata = Array.isArray(queryResponse.params)\n\t\t\t? queryResponse.params\n\t\t\t: [];\n\t\tconst paramValues = queryEngine.mapGeneratedParams(paramMetadata);\n\n\t\t// Step 3: Execute SQL with tenant isolation\n\t\ttry {\n\t\t\tconst execution = await queryEngine.validateAndExecute(\n\t\t\t\tqueryResponse.sql,\n\t\t\t\tparamValues,\n\t\t\t\tdatabaseName,\n\t\t\t\ttenantId,\n\t\t\t);\n\t\t\tconst rows = execution.rows ?? [];\n\n\t\t\t// Step 4: Generate chart if we have data\n\t\t\tlet chart: ChartEnvelope = {\n\t\t\t\tvegaLiteSpec: null,\n\t\t\t\tnotes: rows.length === 0 ? \"Query returned no rows.\" : null,\n\t\t\t};\n\n\t\t\tif (rows.length > 0) {\n\t\t\t\tconst chartResponse = await client.post<ServerChartResponse>(\n\t\t\t\t\t\"/chart\",\n\t\t\t\t\t{\n\t\t\t\t\t\tquestion,\n\t\t\t\t\t\tsql: queryResponse.sql,\n\t\t\t\t\t\trationale: queryResponse.rationale,\n\t\t\t\t\t\tfields: execution.fields,\n\t\t\t\t\t\trows: anonymizeResults(rows),\n\t\t\t\t\t\tmax_retries: options.chartMaxRetries ?? 3,\n\t\t\t\t\t\tquery_id: queryResponse.queryId,\n\t\t\t\t\t},\n\t\t\t\t\ttenantId,\n\t\t\t\t\toptions.userId,\n\t\t\t\t\toptions.scopes,\n\t\t\t\t\tsignal,\n\t\t\t\t\tsessionId,\n\t\t\t\t);\n\n\t\t\t\tchart = {\n\t\t\t\t\tvegaLiteSpec: chartResponse.chart\n\t\t\t\t\t\t? {\n\t\t\t\t\t\t\t\t...chartResponse.chart,\n\t\t\t\t\t\t\t\tdata: { values: rows },\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t: null,\n\t\t\t\t\tnotes: chartResponse.notes,\n\t\t\t\t};\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\tsql: queryResponse.sql,\n\t\t\t\tparams: paramValues,\n\t\t\t\tparamMetadata,\n\t\t\t\trationale: queryResponse.rationale,\n\t\t\t\tdialect: queryResponse.dialect,\n\t\t\t\tqueryId: queryResponse.queryId,\n\t\t\t\trows,\n\t\t\t\tfields: execution.fields,\n\t\t\t\tchart,\n\t\t\t\tcontext: queryResponse.context,\n\t\t\t\tattempts: attempt + 1,\n\t\t\t\ttarget_db: databaseName,\n\t\t\t};\n\t\t} catch (error) {\n\t\t\tattempt++;\n\n\t\t\t// If we've exhausted all retries, throw the error\n\t\t\tif (attempt > maxRetry) {\n\t\t\t\tthrow error;\n\t\t\t}\n\n\t\t\t// Save error and SQL for next retry\n\t\t\tlastError = error instanceof Error ? error.message : String(error);\n\t\t\tpreviousSql = queryResponse.sql;\n\n\t\t\t// Log retry attempt\n\t\t\tconsole.warn(\n\t\t\t\t`SQL execution failed (attempt ${attempt}/${maxRetry + 1}): ${lastError}. Retrying...`,\n\t\t\t);\n\t\t}\n\t}\n\n\t// This should never be reached, but TypeScript needs it\n\tthrow new Error(\"Unexpected error in ask retry loop\");\n}\n\nfunction resolveTenantId(client: ApiClient, tenantId?: string): string {\n\tconst resolved = tenantId ?? client.getDefaultTenantId();\n\tif (!resolved) {\n\t\tthrow new Error(\n\t\t\t\"tenantId is required. Provide it per request or via defaultTenantId option.\",\n\t\t);\n\t}\n\treturn resolved;\n}\n\nexport function anonymizeResults(\n\trows: Array<Record<string, unknown>>,\n): Array<Record<string, string>> {\n\tif (!rows?.length) return [];\n\treturn rows.map((row) => {\n\t\tconst masked: Record<string, string> = {};\n\t\tObject.entries(row).forEach(([key, value]) => {\n\t\t\tif (value === null) masked[key] = \"null\";\n\t\t\telse if (Array.isArray(value)) masked[key] = \"array\";\n\t\t\telse masked[key] = typeof value;\n\t\t});\n\t\treturn masked;\n\t});\n}\n"],"mappings":"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","names":["normalizeTableFilter","asTableType","sanitize","resolveTenantId","import_node_crypto","resolveTenantId","import_node_crypto","resolveTenantId"]}
|
package/dist/index.d.cts
CHANGED
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -989,10 +989,11 @@ import { randomUUID } from "crypto";
|
|
|
989
989
|
async function syncSchema(client, queryEngine, databaseName, options, signal) {
|
|
990
990
|
const tenantId = resolveTenantId3(client, options.tenantId);
|
|
991
991
|
const adapter = queryEngine.getDatabase(databaseName);
|
|
992
|
+
const metadata = queryEngine.getDatabaseMetadata(databaseName);
|
|
992
993
|
const introspection = await adapter.introspect(
|
|
993
994
|
options.tables ? { tables: options.tables } : void 0
|
|
994
995
|
);
|
|
995
|
-
const payload = buildSchemaRequest(databaseName, adapter, introspection);
|
|
996
|
+
const payload = buildSchemaRequest(databaseName, adapter, introspection, metadata);
|
|
996
997
|
if (options.forceReindex) {
|
|
997
998
|
payload.force_reindex = true;
|
|
998
999
|
}
|
|
@@ -1017,7 +1018,7 @@ function resolveTenantId3(client, tenantId) {
|
|
|
1017
1018
|
}
|
|
1018
1019
|
return resolved;
|
|
1019
1020
|
}
|
|
1020
|
-
function buildSchemaRequest(databaseName, adapter, introspection) {
|
|
1021
|
+
function buildSchemaRequest(databaseName, adapter, introspection, metadata) {
|
|
1021
1022
|
const dialect = adapter.getDialect();
|
|
1022
1023
|
const tables = introspection.tables.map((table) => ({
|
|
1023
1024
|
table_name: table.name,
|
|
@@ -1029,11 +1030,19 @@ function buildSchemaRequest(databaseName, adapter, introspection) {
|
|
|
1029
1030
|
description: column.comment ?? ""
|
|
1030
1031
|
}))
|
|
1031
1032
|
}));
|
|
1032
|
-
|
|
1033
|
+
const request = {
|
|
1033
1034
|
database: databaseName,
|
|
1034
1035
|
dialect,
|
|
1035
1036
|
tables
|
|
1036
1037
|
};
|
|
1038
|
+
if (metadata?.tenantFieldName && metadata?.tenantFieldType && metadata?.enforceTenantIsolation !== void 0) {
|
|
1039
|
+
request.tenant_settings = {
|
|
1040
|
+
tenantFieldName: metadata.tenantFieldName,
|
|
1041
|
+
tenantFieldType: metadata.tenantFieldType,
|
|
1042
|
+
enforceTenantIsolation: metadata.enforceTenantIsolation
|
|
1043
|
+
};
|
|
1044
|
+
}
|
|
1045
|
+
return request;
|
|
1037
1046
|
}
|
|
1038
1047
|
|
|
1039
1048
|
// src/routes/query.ts
|
|
@@ -1118,7 +1127,8 @@ async function ask(client, queryEngine, question, options, signal) {
|
|
|
1118
1127
|
fields: execution.fields,
|
|
1119
1128
|
chart,
|
|
1120
1129
|
context: queryResponse.context,
|
|
1121
|
-
attempts: attempt + 1
|
|
1130
|
+
attempts: attempt + 1,
|
|
1131
|
+
target_db: databaseName
|
|
1122
1132
|
};
|
|
1123
1133
|
} catch (error) {
|
|
1124
1134
|
attempt++;
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/utils/clickhouse.ts","../src/adapters/clickhouse.ts","../src/adapters/postgres.ts","../src/core/client.ts","../src/core/query-engine.ts","../src/routes/charts.ts","../src/routes/active-charts.ts","../src/routes/ingest.ts","../src/routes/query.ts","../src/index.ts"],"sourcesContent":["const WRAPPER_REGEX =\n /^(Nullable|LowCardinality|SimpleAggregateFunction)\\((.+)\\)$/i;\n\nexport function isNullableType(type: string): boolean {\n return /Nullable\\s*\\(/i.test(type);\n}\n\nexport function unwrapTypeModifiers(type: string): string {\n let current = type.trim();\n let match = WRAPPER_REGEX.exec(current);\n while (match) {\n const inner = match[2];\n if (!inner) {\n break;\n }\n current = inner.trim();\n match = WRAPPER_REGEX.exec(current);\n }\n return current;\n}\n\nexport function extractPrecisionScale(type: string): {\n precision?: number;\n scale?: number;\n} {\n const unwrapped = unwrapTypeModifiers(type);\n const decimalMatch = unwrapped.match(/Decimal(?:\\d+)?\\((\\d+)\\s*,\\s*(\\d+)\\)/i);\n if (!decimalMatch) return {};\n const precision = decimalMatch[1];\n const scale = decimalMatch[2];\n if (!precision || !scale) return {};\n return {\n precision: Number.parseInt(precision, 10),\n scale: Number.parseInt(scale, 10),\n };\n}\n\nexport function extractFixedStringLength(type: string): number | undefined {\n const unwrapped = unwrapTypeModifiers(type);\n const match = unwrapped.match(/^(?:FixedString|StringFixed)\\((\\d+)\\)$/i);\n if (!match) return undefined;\n const length = match[1];\n if (!length) return undefined;\n return Number.parseInt(length, 10);\n}\n\nexport function parseKeyExpression(expression?: string | null): string[] {\n if (!expression) return [];\n let value = expression.trim();\n if (!value) return [];\n if (/^tuple\\s*\\(/i.test(value) && value.endsWith(\")\")) {\n value = value.replace(/^tuple\\s*\\(/i, \"\").replace(/\\)$/, \"\");\n }\n\n const columns: string[] = [];\n let depth = 0;\n let token = \"\";\n for (const ch of value) {\n if (ch === \"(\") {\n depth += 1;\n token += ch;\n continue;\n }\n if (ch === \")\") {\n depth = Math.max(0, depth - 1);\n token += ch;\n continue;\n }\n if (ch === \",\" && depth === 0) {\n const col = token.trim();\n if (col) columns.push(stripWrapper(col));\n token = \"\";\n continue;\n }\n token += ch;\n }\n const last = token.trim();\n if (last) columns.push(stripWrapper(last));\n return columns.filter(Boolean);\n}\n\nfunction stripWrapper(value: string): string {\n const noQuotes = stripQuotes(value);\n const withoutTicks = noQuotes.replace(/`/g, \"\").trim();\n const parts = withoutTicks.split(\".\");\n return parts[parts.length - 1]?.trim() ?? \"\";\n}\n\nfunction stripQuotes(value: string): string {\n if (\n (value.startsWith('\"') && value.endsWith('\"')) ||\n (value.startsWith(\"'\") && value.endsWith(\"'\"))\n ) {\n return value.slice(1, -1);\n }\n return value;\n}\n","import type {\n\tClickHouseSettings,\n\tDataFormat,\n\tQueryParams,\n} from \"@clickhouse/client\";\nimport type {\n\tColumnSchema,\n\tIntrospectOptions,\n\tSchemaIntrospection,\n\tTableSchema,\n} from \"../schema/types\";\nimport { parseKeyExpression, unwrapTypeModifiers } from \"../utils/clickhouse\";\nimport type { DatabaseAdapter, DatabaseExecutionResult } from \"./types\";\n\nexport interface ClickHouseAdapterOptions {\n\t/** Optional logical database name used in introspection metadata. */\n\tdatabase?: string;\n\t/** Override the default response format used for query execution. */\n\tdefaultFormat?: DataFormat;\n\t/**\n\t * Optional database kind label. Defaults to \"clickhouse\" but allows\n\t * sub-classing/custom branding if needed.\n\t */\n\tkind?: SchemaIntrospection[\"db\"][\"kind\"];\n\t/**\n\t * Optional allow-list of table names.\n\t * When specified, introspection and queries are restricted to these tables only.\n\t * ClickHouse tables are not schema-qualified, so just provide table names.\n\t */\n\tallowedTables?: string[];\n}\n\nexport type ClickHouseQueryResult = { json: () => Promise<unknown> };\n\nexport type ClickHouseClientFn = (\n\tparams: QueryParams,\n) => Promise<\n\t| ClickHouseQueryResult\n\t| Array<Record<string, unknown>>\n\t| Record<string, unknown>[]\n>;\n\ninterface QueryOptions {\n\tparams?: Record<string, unknown>;\n\tformat?: DataFormat;\n\tsettings?: ClickHouseSettings;\n}\n\ntype TableRow = {\n\tname: string;\n\tengine: string;\n\tcomment: string | null;\n\tprimary_key: string | null;\n};\n\ntype ColumnRow = {\n\ttable: string;\n\tname: string;\n\ttype: string;\n\tposition: number;\n\tcomment: string | null;\n\tis_in_primary_key: string | number | null;\n};\n\n/**\n * Simplified ClickHouse adapter following IngestRequest format\n * Removed: indexes, constraints, statistics\n * Kept only: tables, columns (name, type, isPrimaryKey, comment)\n */\nexport class ClickHouseAdapter implements DatabaseAdapter {\n\tprivate readonly databaseName: string;\n\tprivate readonly defaultFormat: QueryParams[\"format\"];\n\tprivate readonly kind: SchemaIntrospection[\"db\"][\"kind\"];\n\tprivate readonly allowedTables?: string[];\n\n\tconstructor(\n\t\tprivate readonly clientFn: ClickHouseClientFn,\n\t\toptions: ClickHouseAdapterOptions = {},\n\t) {\n\t\tthis.databaseName = options.database ?? \"default\";\n\t\tthis.defaultFormat = options.defaultFormat ?? \"JSONEachRow\";\n\t\tthis.kind = options.kind ?? \"clickhouse\";\n\t\tif (options.allowedTables) {\n\t\t\tthis.allowedTables = normalizeTableFilter(options.allowedTables);\n\t\t}\n\t}\n\n\tasync execute(\n\t\tsql: string,\n\t\tparams?: Record<string, string | number | boolean | string[] | number[]>,\n\t): Promise<DatabaseExecutionResult> {\n\t\t// Validate query against allowed tables if restrictions are in place\n\t\tif (this.allowedTables) {\n\t\t\tthis.validateQueryTables(sql);\n\t\t}\n\n\t\tconst queryOptions: QueryOptions = {\n\t\t\tformat: this.defaultFormat,\n\t\t};\n\t\tif (params) {\n\t\t\tqueryOptions.params = params;\n\t\t}\n\n\t\tconst rows = await this.query<Record<string, unknown>>(sql, queryOptions);\n\t\tconst fields = rows.length > 0 ? Object.keys(rows[0] ?? {}) : [];\n\t\treturn { fields, rows };\n\t}\n\n\tasync validate(\n\t\tsql: string,\n\t\tparams?: Record<string, string | number | boolean | string[] | number[]>,\n\t): Promise<void> {\n\t\tconst queryOptions: QueryOptions = {\n\t\t\tformat: this.defaultFormat,\n\t\t};\n\t\tif (params) {\n\t\t\tqueryOptions.params = params;\n\t\t}\n\n\t\tawait this.query(`EXPLAIN ${sql}`, queryOptions);\n\t}\n\n\tgetDialect() {\n\t\treturn \"clickhouse\" as const;\n\t}\n\n\t/**\n\t * Simplified introspection: only collect table/column metadata for IngestRequest\n\t * No indexes, constraints, or statistics\n\t */\n\tasync introspect(options?: IntrospectOptions): Promise<SchemaIntrospection> {\n\t\t// Use adapter-level allowedTables if no specific tables provided in options\n\t\tconst tablesToIntrospect = options?.tables\n\t\t\t? normalizeTableFilter(options.tables)\n\t\t\t: this.allowedTables;\n\t\tconst allowTables = tablesToIntrospect ?? [];\n\t\tconst hasFilter = allowTables.length > 0;\n\t\tconst queryParams: Record<string, unknown> = {\n\t\t\tdb: this.databaseName,\n\t\t};\n\t\tif (hasFilter) {\n\t\t\tqueryParams.tables = allowTables;\n\t\t}\n\n\t\tconst filterClause = hasFilter ? \" AND name IN {tables:Array(String)}\" : \"\";\n\t\tconst tables = await this.query<TableRow>(\n\t\t\t`SELECT name, engine, comment, primary_key\n FROM system.tables\n WHERE database = {db:String}${filterClause}\n ORDER BY name`,\n\t\t\t{ params: queryParams },\n\t\t);\n\n\t\tconst columnFilterClause = hasFilter\n\t\t\t? \" AND table IN {tables:Array(String)}\"\n\t\t\t: \"\";\n\t\tconst columns = await this.query<ColumnRow>(\n\t\t\t`SELECT table, name, type, position, comment, is_in_primary_key\n FROM system.columns\n WHERE database = {db:String}${columnFilterClause}\n ORDER BY table, position`,\n\t\t\t{ params: queryParams },\n\t\t);\n\n\t\tconst columnsByTable = new Map<string, ColumnSchema[]>();\n\t\tfor (const rawColumn of columns) {\n\t\t\tconst list = columnsByTable.get(rawColumn.table) ?? [];\n\t\t\tlist.push(transformColumnRow(rawColumn));\n\t\t\tcolumnsByTable.set(rawColumn.table, list);\n\t\t}\n\n\t\tconst tableSchemas: TableSchema[] = tables.map((table) => {\n\t\t\tconst tableColumns = columnsByTable.get(table.name) ?? [];\n\t\t\tconst primaryKeyColumns = parseKeyExpression(table.primary_key);\n\n\t\t\t// Mark columns as primary key\n\t\t\tfor (const column of tableColumns) {\n\t\t\t\tcolumn.isPrimaryKey =\n\t\t\t\t\tcolumn.isPrimaryKey || primaryKeyColumns.includes(column.name);\n\t\t\t}\n\n\t\t\tconst base: TableSchema = {\n\t\t\t\tname: table.name,\n\t\t\t\tschema: this.databaseName,\n\t\t\t\ttype: asTableType(table.engine),\n\t\t\t\tcolumns: tableColumns,\n\t\t\t};\n\n\t\t\tconst comment = sanitize(table.comment);\n\t\t\tif (comment !== undefined) {\n\t\t\t\tbase.comment = comment;\n\t\t\t}\n\n\t\t\treturn base;\n\t\t});\n\n\t\treturn {\n\t\t\tdb: {\n\t\t\t\tkind: this.kind,\n\t\t\t\tname: this.databaseName,\n\t\t\t},\n\t\t\ttables: tableSchemas,\n\t\t\tintrospectedAt: new Date().toISOString(),\n\t\t};\n\t}\n\n\tprivate validateQueryTables(sql: string): void {\n\t\tif (!this.allowedTables || this.allowedTables.length === 0) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst allowedSet = new Set(this.allowedTables);\n\n\t\t// Extract potential table references from SQL\n\t\tconst tablePattern =\n\t\t\t/(?:FROM|JOIN)\\s+(?:FINAL\\s+)?(?:(?:[a-zA-Z_][a-zA-Z0-9_]*)\\.)?([\"'`]?[a-zA-Z_][a-zA-Z0-9_]*[\"'`]?)/gi;\n\t\tconst matches = sql.matchAll(tablePattern);\n\n\t\tfor (const match of matches) {\n\t\t\tconst table = match[1]?.replace(/[\"'`]/g, \"\");\n\t\t\tif (table) {\n\t\t\t\tif (!allowedSet.has(table)) {\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t`Query references table \"${table}\" which is not in the allowed tables list`,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tasync close(): Promise<void> {\n\t\t// No-op: lifecycle of the underlying client is controlled by the caller.\n\t}\n\n\tprivate async query<T>(sql: string, options?: QueryOptions): Promise<T[]> {\n\t\tconst params: QueryParams = {\n\t\t\tquery: sql,\n\t\t};\n\n\t\tconst format = options?.format ?? this.defaultFormat;\n\t\tif (format !== undefined) {\n\t\t\tparams.format = format;\n\t\t}\n\n\t\tif (options?.params) {\n\t\t\tparams.query_params = options.params;\n\t\t}\n\n\t\tif (options?.settings) {\n\t\t\tparams.clickhouse_settings = options.settings;\n\t\t}\n\n\t\tconst result = await this.clientFn(params);\n\t\treturn this.extractRows<T>(result);\n\t}\n\n\tprivate async extractRows<T>(\n\t\tresult:\n\t\t\t| ClickHouseQueryResult\n\t\t\t| Array<Record<string, unknown>>\n\t\t\t| Record<string, unknown>[],\n\t): Promise<T[]> {\n\t\tif (Array.isArray(result)) {\n\t\t\treturn result as T[];\n\t\t}\n\n\t\tif (\n\t\t\tresult &&\n\t\t\ttypeof (result as ClickHouseQueryResult).json === \"function\"\n\t\t) {\n\t\t\tconst payload = await (result as ClickHouseQueryResult).json();\n\t\t\treturn normalizePayload<T>(payload);\n\t\t}\n\n\t\treturn [];\n\t}\n}\n\nfunction normalizePayload<T>(payload: unknown): T[] {\n\tif (Array.isArray(payload)) {\n\t\treturn payload as T[];\n\t}\n\tif (payload && typeof payload === \"object\") {\n\t\tconst maybeData = (payload as { data?: unknown }).data;\n\t\tif (Array.isArray(maybeData)) {\n\t\t\treturn maybeData as T[];\n\t\t}\n\t}\n\treturn [];\n}\n\nfunction normalizeTableFilter(tables?: string[] | null): string[] {\n\tif (!tables?.length) return [];\n\tconst seen = new Set<string>();\n\tconst normalized: string[] = [];\n\tfor (const table of tables) {\n\t\tif (!table) continue;\n\t\tconst trimmed = table.trim();\n\t\tif (!trimmed) continue;\n\t\tconst parts = trimmed.split(\".\");\n\t\tconst tableName = parts[parts.length - 1];\n\t\tif (!tableName || seen.has(tableName)) continue;\n\t\tseen.add(tableName);\n\t\tnormalized.push(tableName);\n\t}\n\treturn normalized;\n}\n\nfunction transformColumnRow(row: ColumnRow): ColumnSchema {\n\tconst unwrappedType = unwrapTypeModifiers(row.type);\n\n\tconst column: ColumnSchema = {\n\t\tname: row.name,\n\t\ttype: unwrappedType,\n\t\trawType: row.type,\n\t\tisPrimaryKey: Boolean(toNumber(row.is_in_primary_key)),\n\t};\n\n\tconst comment = sanitize(row.comment);\n\tif (comment !== undefined) column.comment = comment;\n\n\treturn column;\n}\n\nfunction asTableType(engine: unknown): TableSchema[\"type\"] {\n\tif (typeof engine === \"string\") {\n\t\tconst normalized = engine.toLowerCase();\n\t\t// ClickHouse view engines: View, MaterializedView, LiveView\n\t\tif (normalized.includes(\"view\")) {\n\t\t\treturn \"view\";\n\t\t}\n\t}\n\treturn \"table\";\n}\n\nfunction sanitize(value: unknown): string | undefined {\n\tif (value === null || value === undefined) return undefined;\n\tconst trimmed = String(value).trim();\n\treturn trimmed.length ? trimmed : undefined;\n}\n\nfunction toNumber(value: unknown): number | undefined {\n\tif (value === null || value === undefined) return undefined;\n\tif (typeof value === \"number\") return value;\n\tconst parsed = Number.parseFloat(String(value));\n\treturn Number.isNaN(parsed) ? undefined : parsed;\n}\n","import type {\n\tColumnSchema,\n\tIntrospectOptions,\n\tSchemaIntrospection,\n\tTableSchema,\n} from \"../schema/types\";\nimport type { DatabaseAdapter, DatabaseExecutionResult } from \"./types\";\n\nexport interface PostgresQueryResult {\n\trows: Array<Record<string, unknown>>;\n\tfields: Array<{ name: string }>;\n}\n\nexport type PostgresClientFn = (\n\tsql: string,\n\tparams?: unknown[],\n) => Promise<PostgresQueryResult>;\n\nexport interface PostgresAdapterOptions {\n\t/** Logical database name used in introspection metadata. */\n\tdatabase?: string;\n\t/** Schema to assume when a table is provided without qualification. */\n\tdefaultSchema?: string;\n\t/** Optional database kind label. Defaults to \"postgres\". */\n\tkind?: SchemaIntrospection[\"db\"][\"kind\"];\n\t/**\n\t * Optional allow-list of table names (schema-qualified or bare).\n\t * When specified, introspection and queries are restricted to these tables only.\n\t */\n\tallowedTables?: string[];\n}\n\ntype TableRow = {\n\ttable_name: string;\n\tschema_name: string;\n\ttable_type: string;\n\tcomment: string | null;\n};\n\ntype ColumnRow = {\n\ttable_name: string;\n\ttable_schema: string;\n\tcolumn_name: string;\n\tdata_type: string;\n\tudt_name: string | null;\n\tis_primary_key: boolean;\n\tdescription: string | null;\n};\n\ninterface NormalizedTable {\n\tschema: string;\n\ttable: string;\n}\n\n/**\n * Simplified PostgreSQL adapter following IngestRequest format\n * Removed: indexes, constraints, foreign keys, statistics\n * Kept only: tables, columns (name, type, isPrimaryKey, comment)\n */\nexport class PostgresAdapter implements DatabaseAdapter {\n\tprivate readonly databaseName: string;\n\tprivate readonly defaultSchema: string;\n\tprivate readonly kind: SchemaIntrospection[\"db\"][\"kind\"];\n\tprivate readonly allowedTables?: NormalizedTable[];\n\n\tconstructor(\n\t\tprivate readonly clientFn: PostgresClientFn,\n\t\toptions: PostgresAdapterOptions = {},\n\t) {\n\t\tthis.databaseName = options.database ?? \"postgres\";\n\t\tthis.defaultSchema = options.defaultSchema ?? \"public\";\n\t\tthis.kind = options.kind ?? \"postgres\";\n\t\tif (options.allowedTables) {\n\t\t\tthis.allowedTables = normalizeTableFilter(\n\t\t\t\toptions.allowedTables,\n\t\t\t\tthis.defaultSchema,\n\t\t\t);\n\t\t}\n\t}\n\n\tasync execute(\n\t\tsql: string,\n\t\tparams?: Record<string, string | number | boolean | string[] | number[]>,\n\t): Promise<DatabaseExecutionResult> {\n\t\t// Validate query against allowed tables if restrictions are in place\n\t\tif (this.allowedTables) {\n\t\t\tthis.validateQueryTables(sql);\n\t\t}\n\n\t\t// Convert named params to positional array for PostgreSQL\n\t\tlet paramArray: unknown[] | undefined;\n\t\tif (params) {\n\t\t\tparamArray = this.convertNamedToPositionalParams(params);\n\t\t}\n\n\t\tconst result = await this.clientFn(sql, paramArray);\n\t\tconst fields = result.fields.map((f) => f.name);\n\t\treturn { fields, rows: result.rows };\n\t}\n\n\tprivate validateQueryTables(sql: string): void {\n\t\tif (!this.allowedTables || this.allowedTables.length === 0) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst allowedSet = new Set(\n\t\t\tthis.allowedTables.map((t) => tableKey(t.schema, t.table)),\n\t\t);\n\n\t\t// Extract potential table references from SQL\n\t\tconst tablePattern =\n\t\t\t/(?:FROM|JOIN)\\s+(?:ONLY\\s+)?(?:([a-zA-Z_][a-zA-Z0-9_]*)\\.)?([\"']?[a-zA-Z_][a-zA-Z0-9_]*[\"']?)/gi;\n\t\tconst matches = sql.matchAll(tablePattern);\n\n\t\tfor (const match of matches) {\n\t\t\tconst schema = match[1] ?? this.defaultSchema;\n\t\t\tconst table = match[2]?.replace(/['\"]/g, \"\");\n\t\t\tif (table) {\n\t\t\t\tconst key = tableKey(schema, table);\n\t\t\t\tif (!allowedSet.has(key)) {\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t`Query references table \"${schema}.${table}\" which is not in the allowed tables list`,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Convert named params to positional array for PostgreSQL\n\t * PostgreSQL expects $1, $2, $3 in SQL and an array of values [val1, val2, val3]\n\t */\n\tprivate convertNamedToPositionalParams(\n\t\tparams: Record<string, string | number | boolean | string[] | number[]>,\n\t): unknown[] {\n\t\t// Separate numeric and named keys\n\t\tconst numericKeys = Object.keys(params)\n\t\t\t.filter((k) => /^\\d+$/.test(k))\n\t\t\t.map((k) => Number.parseInt(k, 10))\n\t\t\t.sort((a, b) => a - b);\n\n\t\tconst namedKeys = Object.keys(params)\n\t\t\t.filter((k) => !/^\\d+$/.test(k))\n\t\t\t.sort(); // Alphabetical order for consistency\n\n\t\t// Build positional array\n\t\tconst positionalParams: unknown[] = [];\n\n\t\t// First, add values from numeric keys (in sorted order)\n\t\tfor (const key of numericKeys) {\n\t\t\tlet val: unknown = params[String(key)];\n\t\t\tif (typeof val === \"string\") {\n\t\t\t\t// Resolve placeholder tokens like `<tenant_id>` to their named values\n\t\t\t\tconst match = val.match(/^<([a-zA-Z0-9_]+)>$/);\n\t\t\t\tconst namedKey = match?.[1];\n\t\t\t\tif (namedKey && namedKey in params) {\n\t\t\t\t\tval = params[namedKey as keyof typeof params];\n\t\t\t\t}\n\t\t\t}\n\t\t\tpositionalParams.push(val);\n\t\t}\n\n\t\t// Then, add values from named keys (in alphabetical order)\n\t\tfor (const key of namedKeys) {\n\t\t\tconst val = params[key];\n\t\t\tpositionalParams.push(val);\n\t\t}\n\n\t\treturn positionalParams;\n\t}\n\n\tasync validate(\n\t\tsql: string,\n\t\tparams?: Record<string, string | number | boolean | string[] | number[]>,\n\t): Promise<void> {\n\t\tlet paramArray: unknown[] | undefined;\n\t\tif (params) {\n\t\t\tparamArray = this.convertNamedToPositionalParams(params);\n\t\t}\n\n\t\tawait this.clientFn(`EXPLAIN ${sql}`, paramArray);\n\t}\n\n\tgetDialect() {\n\t\treturn \"postgres\" as const;\n\t}\n\n\t/**\n\t * Simplified introspection: only collect table/column metadata for IngestRequest\n\t * No indexes, constraints, or statistics\n\t */\n\tasync introspect(options?: IntrospectOptions): Promise<SchemaIntrospection> {\n\t\t// Use adapter-level allowedTables if no specific tables provided in options\n\t\tconst tablesToIntrospect = options?.tables\n\t\t\t? normalizeTableFilter(options.tables, this.defaultSchema)\n\t\t\t: this.allowedTables;\n\t\tconst normalizedTables = tablesToIntrospect ?? [];\n\n\t\tconst tablesResult = await this.clientFn(\n\t\t\tbuildTablesQuery(normalizedTables),\n\t\t);\n\t\tconst tableRows = tablesResult.rows as TableRow[];\n\n\t\tconst columnsResult = await this.clientFn(\n\t\t\tbuildColumnsQuery(normalizedTables),\n\t\t);\n\t\tconst columnRows = columnsResult.rows as ColumnRow[];\n\n\t\tconst tablesByKey = new Map<string, TableSchema>();\n\n\t\t// Build tables\n\t\tfor (const row of tableRows) {\n\t\t\tconst key = tableKey(row.schema_name, row.table_name);\n\t\t\tconst table: TableSchema = {\n\t\t\t\tname: row.table_name,\n\t\t\t\tschema: row.schema_name,\n\t\t\t\ttype: asTableType(row.table_type),\n\t\t\t\tcolumns: [],\n\t\t\t};\n\n\t\t\tconst comment = sanitize(row.comment);\n\t\t\tif (comment !== undefined) {\n\t\t\t\ttable.comment = comment;\n\t\t\t}\n\n\t\t\ttablesByKey.set(key, table);\n\t\t}\n\n\t\t// Build columns\n\t\tfor (const row of columnRows) {\n\t\t\tconst key = tableKey(row.table_schema, row.table_name);\n\t\t\tconst table = tablesByKey.get(key);\n\t\t\tif (!table) continue;\n\n\t\t\tconst column: ColumnSchema = {\n\t\t\t\tname: row.column_name,\n\t\t\t\ttype: row.data_type,\n\t\t\t\tisPrimaryKey: row.is_primary_key,\n\t\t\t};\n\n\t\t\tconst rawType = row.udt_name ?? undefined;\n\t\t\tif (rawType !== undefined) column.rawType = rawType;\n\n\t\t\tconst comment = sanitize(row.description);\n\t\t\tif (comment !== undefined) column.comment = comment;\n\n\t\t\ttable.columns.push(column);\n\t\t}\n\n\t\tconst tables = Array.from(tablesByKey.values()).sort((a, b) => {\n\t\t\tif (a.schema === b.schema) {\n\t\t\t\treturn a.name.localeCompare(b.name);\n\t\t\t}\n\t\t\treturn a.schema.localeCompare(b.schema);\n\t\t});\n\n\t\treturn {\n\t\t\tdb: {\n\t\t\t\tkind: this.kind,\n\t\t\t\tname: this.databaseName,\n\t\t\t},\n\t\t\ttables,\n\t\t\tintrospectedAt: new Date().toISOString(),\n\t\t};\n\t}\n}\n\nfunction normalizeTableFilter(\n\ttables: string[] | undefined,\n\tdefaultSchema: string,\n): NormalizedTable[] {\n\tif (!tables?.length) return [];\n\tconst normalized: NormalizedTable[] = [];\n\tconst seen = new Set<string>();\n\n\tfor (const raw of tables) {\n\t\tif (!raw) continue;\n\t\tconst trimmed = raw.trim();\n\t\tif (!trimmed) continue;\n\t\tconst parts = trimmed.split(\".\");\n\t\tconst table = parts.pop() ?? \"\";\n\t\tconst schema = parts.pop() ?? defaultSchema;\n\t\tif (!isSafeIdentifier(schema) || !isSafeIdentifier(table)) {\n\t\t\tcontinue;\n\t\t}\n\t\tconst key = tableKey(schema, table);\n\t\tif (seen.has(key)) continue;\n\t\tseen.add(key);\n\t\tnormalized.push({ schema, table });\n\t}\n\n\treturn normalized;\n}\n\nfunction buildTablesQuery(tables: NormalizedTable[]): string {\n\tconst filter = buildFilterClause(tables, \"n.nspname\", \"c.relname\");\n\treturn `SELECT\n c.relname AS table_name,\n n.nspname AS schema_name,\n CASE c.relkind\n WHEN 'r' THEN 'table'\n WHEN 'v' THEN 'view'\n WHEN 'm' THEN 'materialized_view'\n ELSE c.relkind::text\n END AS table_type,\n obj_description(c.oid) AS comment\n FROM pg_class c\n JOIN pg_namespace n ON n.oid = c.relnamespace\n WHERE n.nspname NOT IN ('pg_catalog', 'information_schema')\n AND c.relkind IN ('r', 'v', 'm')\n ${filter}\n ORDER BY n.nspname, c.relname;`;\n}\n\nfunction buildColumnsQuery(tables: NormalizedTable[]): string {\n\tconst filter = buildFilterClause(\n\t\ttables,\n\t\t\"cols.table_schema\",\n\t\t\"cols.table_name\",\n\t);\n\treturn `SELECT\n cols.table_name,\n cols.table_schema,\n cols.column_name,\n cols.data_type,\n cols.udt_name,\n pgd.description,\n EXISTS(\n SELECT 1\n FROM information_schema.table_constraints tc\n JOIN information_schema.key_column_usage kcu\n ON tc.constraint_name = kcu.constraint_name\n AND tc.table_schema = kcu.table_schema\n WHERE tc.constraint_type = 'PRIMARY KEY'\n AND tc.table_schema = cols.table_schema\n AND tc.table_name = cols.table_name\n AND kcu.column_name = cols.column_name\n ) AS is_primary_key\n FROM information_schema.columns cols\n LEFT JOIN pg_catalog.pg_class c\n ON c.relname = cols.table_name\n AND c.relkind IN ('r', 'v', 'm')\n LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace\n LEFT JOIN pg_catalog.pg_attribute attr\n ON attr.attrelid = c.oid\n AND attr.attname = cols.column_name\n LEFT JOIN pg_catalog.pg_description pgd\n ON pgd.objoid = attr.attrelid AND pgd.objsubid = attr.attnum\n WHERE cols.table_schema NOT IN ('pg_catalog', 'information_schema')\n ${filter}\n ORDER BY cols.table_schema, cols.table_name, cols.ordinal_position;`;\n}\n\nfunction buildFilterClause(\n\ttables: NormalizedTable[],\n\tschemaExpr: string,\n\ttableExpr: string,\n): string {\n\tif (!tables.length) return \"\";\n\tconst clauses = tables.map(({ schema, table }) => {\n\t\treturn `(${schemaExpr} = '${schema}' AND ${tableExpr} = '${table}')`;\n\t});\n\treturn `AND (${clauses.join(\" OR \")})`;\n}\n\nfunction tableKey(schema: string, table: string): string {\n\treturn `${schema}.${table}`;\n}\n\nfunction isSafeIdentifier(value: string): boolean {\n\treturn /^[A-Za-z_][A-Za-z0-9_]*$/.test(value);\n}\n\nfunction asTableType(value: string): TableSchema[\"type\"] {\n\tconst normalized = value.toLowerCase();\n\tif (normalized.includes(\"view\")) {\n\t\treturn normalized.includes(\"materialized\") ? \"materialized_view\" : \"view\";\n\t}\n\treturn \"table\";\n}\n\nfunction sanitize(value: unknown): string | undefined {\n\tif (value === null || value === undefined) return undefined;\n\tconst trimmed = String(value).trim();\n\treturn trimmed.length ? trimmed : undefined;\n}\n","import { createSign } from \"node:crypto\";\n\n/**\n * Deep module: Hides JWT signing and HTTP complexity behind simple interface\n * Following Ousterhout's principle: \"Pull complexity downward\"\n */\nexport class ApiClient {\n\tprivate readonly baseUrl: string;\n\tprivate readonly privateKey: string;\n\tprivate readonly organizationId: string;\n\tprivate readonly defaultTenantId?: string;\n\tprivate readonly additionalHeaders?: Record<string, string>;\n\tprivate readonly fetchImpl: typeof fetch;\n\n\tconstructor(\n\t\tbaseUrl: string,\n\t\tprivateKey: string,\n\t\torganizationId: string,\n\t\toptions?: {\n\t\t\tdefaultTenantId?: string;\n\t\t\tadditionalHeaders?: Record<string, string>;\n\t\t\tfetch?: typeof fetch;\n\t\t},\n\t) {\n\t\tif (!baseUrl) {\n\t\t\tthrow new Error(\"Base URL is required\");\n\t\t}\n\t\tif (!privateKey) {\n\t\t\tthrow new Error(\"Private key is required\");\n\t\t}\n\t\tif (!organizationId) {\n\t\t\tthrow new Error(\"Organization ID is required\");\n\t\t}\n\n\t\tthis.baseUrl = baseUrl.replace(/\\/+$/, \"\");\n\t\tthis.privateKey = privateKey;\n\t\tthis.organizationId = organizationId;\n\t\tthis.defaultTenantId = options?.defaultTenantId;\n\t\tthis.additionalHeaders = options?.additionalHeaders;\n\t\tthis.fetchImpl = options?.fetch ?? globalThis.fetch;\n\n\t\tif (!this.fetchImpl) {\n\t\t\tthrow new Error(\n\t\t\t\t\"Fetch implementation not found. Provide options.fetch or use Node 18+.\",\n\t\t\t);\n\t\t}\n\t}\n\n\tgetDefaultTenantId(): string | undefined {\n\t\treturn this.defaultTenantId;\n\t}\n\n\tasync get<T>(\n\t\tpath: string,\n\t\ttenantId: string,\n\t\tuserId?: string,\n\t\tscopes?: string[],\n\t\tsignal?: AbortSignal,\n\t\tsessionId?: string,\n\t): Promise<T> {\n\t\treturn await this.request<T>(path, {\n\t\t\tmethod: \"GET\",\n\t\t\theaders: await this.buildHeaders(\n\t\t\t\ttenantId,\n\t\t\t\tuserId,\n\t\t\t\tscopes,\n\t\t\t\tfalse,\n\t\t\t\tsessionId,\n\t\t\t),\n\t\t\tsignal,\n\t\t});\n\t}\n\n\tasync post<T>(\n\t\tpath: string,\n\t\tbody: unknown,\n\t\ttenantId: string,\n\t\tuserId?: string,\n\t\tscopes?: string[],\n\t\tsignal?: AbortSignal,\n\t\tsessionId?: string,\n\t): Promise<T> {\n\t\treturn await this.request<T>(path, {\n\t\t\tmethod: \"POST\",\n\t\t\theaders: await this.buildHeaders(\n\t\t\t\ttenantId,\n\t\t\t\tuserId,\n\t\t\t\tscopes,\n\t\t\t\ttrue,\n\t\t\t\tsessionId,\n\t\t\t),\n\t\t\tbody: JSON.stringify(body ?? {}),\n\t\t\tsignal,\n\t\t});\n\t}\n\n\tasync put<T>(\n\t\tpath: string,\n\t\tbody: unknown,\n\t\ttenantId: string,\n\t\tuserId?: string,\n\t\tscopes?: string[],\n\t\tsignal?: AbortSignal,\n\t\tsessionId?: string,\n\t): Promise<T> {\n\t\treturn await this.request<T>(path, {\n\t\t\tmethod: \"PUT\",\n\t\t\theaders: await this.buildHeaders(\n\t\t\t\ttenantId,\n\t\t\t\tuserId,\n\t\t\t\tscopes,\n\t\t\t\ttrue,\n\t\t\t\tsessionId,\n\t\t\t),\n\t\t\tbody: JSON.stringify(body ?? {}),\n\t\t\tsignal,\n\t\t});\n\t}\n\n\tasync delete<T = void>(\n\t\tpath: string,\n\t\ttenantId: string,\n\t\tuserId?: string,\n\t\tscopes?: string[],\n\t\tsignal?: AbortSignal,\n\t\tsessionId?: string,\n\t): Promise<T> {\n\t\treturn await this.request<T>(path, {\n\t\t\tmethod: \"DELETE\",\n\t\t\theaders: await this.buildHeaders(\n\t\t\t\ttenantId,\n\t\t\t\tuserId,\n\t\t\t\tscopes,\n\t\t\t\tfalse,\n\t\t\t\tsessionId,\n\t\t\t),\n\t\t\tsignal,\n\t\t});\n\t}\n\n\tprivate async request<T>(path: string, init: RequestInit): Promise<T> {\n\t\tconst response = await this.fetchImpl(`${this.baseUrl}${path}`, init);\n\t\tconst text = await response.text();\n\t\tlet json: any;\n\t\ttry {\n\t\t\tjson = text ? JSON.parse(text) : undefined;\n\t\t} catch {\n\t\t\tjson = undefined;\n\t\t}\n\n\t\tif (!response.ok) {\n\t\t\tconst error = new Error(\n\t\t\t\tjson?.error || response.statusText || \"Request failed\",\n\t\t\t);\n\t\t\t(error as any).status = response.status;\n\t\t\tif (json?.details) (error as any).details = json.details;\n\t\t\tthrow error;\n\t\t}\n\n\t\treturn json as T;\n\t}\n\n\tprivate async buildHeaders(\n\t\ttenantId: string,\n\t\tuserId?: string,\n\t\tscopes?: string[],\n\t\tincludeJson: boolean = true,\n\t\tsessionId?: string,\n\t): Promise<Record<string, string>> {\n\t\tconst token = await this.generateJWT(tenantId, userId, scopes);\n\t\tconst headers: Record<string, string> = {\n\t\t\tAuthorization: `Bearer ${token}`,\n\t\t\tAccept: \"application/json\",\n\t\t};\n\t\tif (includeJson) {\n\t\t\theaders[\"Content-Type\"] = \"application/json\";\n\t\t}\n\t\tif (sessionId) {\n\t\t\theaders[\"x-session-id\"] = sessionId;\n\t\t}\n\t\tif (this.additionalHeaders) {\n\t\t\tObject.assign(headers, this.additionalHeaders);\n\t\t}\n\t\treturn headers;\n\t}\n\n\tprivate async generateJWT(\n\t\ttenantId: string,\n\t\tuserId?: string,\n\t\tscopes?: string[],\n\t): Promise<string> {\n\t\tconst header = {\n\t\t\talg: \"RS256\",\n\t\t\ttyp: \"JWT\",\n\t\t};\n\n\t\tconst payload: Record<string, unknown> = {\n\t\t\torganizationId: this.organizationId,\n\t\t\ttenantId,\n\t\t};\n\n\t\tif (userId) payload.userId = userId;\n\t\tif (scopes?.length) payload.scopes = scopes;\n\n\t\tconst encodeJson = (obj: unknown): string => {\n\t\t\tconst json = JSON.stringify(obj);\n\t\t\tconst base64 = Buffer.from(json).toString(\"base64\");\n\t\t\t// base64url encoding: replace non-url chars and strip padding\n\t\t\treturn base64.replace(/\\+/g, \"-\").replace(/\\//g, \"_\").replace(/=+$/g, \"\");\n\t\t};\n\n\t\tconst encodedHeader = encodeJson(header);\n\t\tconst encodedPayload = encodeJson(payload);\n\t\tconst data = `${encodedHeader}.${encodedPayload}`;\n\n\t\tconst signer = createSign(\"RSA-SHA256\");\n\t\tsigner.update(data);\n\t\tsigner.end();\n\n\t\tconst signature = signer.sign(this.privateKey);\n\t\tconst encodedSignature = signature\n\t\t\t.toString(\"base64\")\n\t\t\t.replace(/\\+/g, \"-\")\n\t\t\t.replace(/\\//g, \"_\")\n\t\t\t.replace(/=+$/g, \"\");\n\n\t\treturn `${data}.${encodedSignature}`;\n\t}\n}\n","import type { DatabaseAdapter, DatabaseDialect } from \"../adapters/types\";\n\nexport type ParamValue = string | number | boolean | string[] | number[];\nexport type ParamRecord = Record<string, ParamValue>;\n\nexport interface DatabaseMetadata {\n\tname: string;\n\tdialect: DatabaseDialect;\n\tdescription?: string;\n\ttags?: string[];\n\ttenantFieldName?: string;\n\ttenantFieldType?: string;\n\tenforceTenantIsolation?: boolean;\n}\n\nexport interface DatabaseExecutionResult {\n\trows: Array<Record<string, unknown>>;\n\tfields: string[];\n}\n\n/**\n * Deep module: Hides SQL execution complexity and tenant isolation logic\n * Following Ousterhout's principle: \"Information hiding\"\n */\nexport class QueryEngine {\n\tprivate databases = new Map<string, DatabaseAdapter>();\n\tprivate databaseMetadata = new Map<string, DatabaseMetadata>();\n\tprivate defaultDatabase?: string;\n\n\tattachDatabase(name: string, adapter: DatabaseAdapter, metadata: DatabaseMetadata): void {\n\t\tthis.databases.set(name, adapter);\n\t\tthis.databaseMetadata.set(name, metadata);\n\t\tif (!this.defaultDatabase) {\n\t\t\tthis.defaultDatabase = name;\n\t\t}\n\t}\n\n\tgetDatabase(name?: string): DatabaseAdapter {\n\t\tconst dbName = name ?? this.defaultDatabase;\n\t\tif (!dbName) {\n\t\t\tthrow new Error(\"No database attached.\");\n\t\t}\n\t\tconst adapter = this.databases.get(dbName);\n\t\tif (!adapter) {\n\t\t\tthrow new Error(\n\t\t\t\t`Database '${dbName}' not found. Attached: ${Array.from(\n\t\t\t\t\tthis.databases.keys(),\n\t\t\t\t).join(\", \")}`,\n\t\t\t);\n\t\t}\n\t\treturn adapter;\n\t}\n\n\tgetDatabaseMetadata(name?: string): DatabaseMetadata | undefined {\n\t\tconst dbName = name ?? this.defaultDatabase;\n\t\tif (!dbName) return undefined;\n\t\treturn this.databaseMetadata.get(dbName);\n\t}\n\n\tgetDefaultDatabase(): string | undefined {\n\t\treturn this.defaultDatabase;\n\t}\n\n\tasync validateAndExecute(\n\t\tsql: string,\n\t\tparams: ParamRecord,\n\t\tdatabaseName: string,\n\t\ttenantId: string,\n\t): Promise<DatabaseExecutionResult> {\n\t\tconst adapter = this.getDatabase(databaseName);\n\t\tconst metadata = this.getDatabaseMetadata(databaseName);\n\n\t\t// Apply tenant isolation if configured\n\t\tlet finalSql = sql;\n\t\tif (metadata) {\n\t\t\tfinalSql = this.ensureTenantIsolation(sql, params, metadata, tenantId);\n\t\t}\n\n\t\t// Validate SQL\n\t\tawait adapter.validate(finalSql, params);\n\n\t\t// Execute\n\t\tconst result = await adapter.execute(finalSql, params);\n\t\treturn {\n\t\t\trows: result.rows,\n\t\t\tfields: result.fields,\n\t\t};\n\t}\n\n\tasync execute(\n\t\tsql: string,\n\t\tparams: ParamRecord | undefined,\n\t\tdatabaseName?: string,\n\t): Promise<Array<Record<string, unknown>>> {\n\t\ttry {\n\t\t\tconst adapter = this.getDatabase(databaseName);\n\t\t\tconst result = await adapter.execute(sql, params);\n\t\t\treturn result.rows;\n\t\t} catch (error) {\n\t\t\tconsole.warn(\n\t\t\t\t`Failed to execute SQL locally for database '${databaseName}':`,\n\t\t\t\terror,\n\t\t\t);\n\t\t\treturn [];\n\t\t}\n\t}\n\n\tmapGeneratedParams(params: Array<Record<string, unknown>>): ParamRecord {\n\t\tconst record: ParamRecord = {};\n\n\t\tparams.forEach((param, index) => {\n\t\t\tconst value = param.value as ParamValue | undefined;\n\t\t\tif (value === undefined) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst nameCandidate =\n\t\t\t\t(typeof param.name === \"string\" && param.name.trim()) ||\n\t\t\t\t(typeof param.placeholder === \"string\" && param.placeholder.trim()) ||\n\t\t\t\t(typeof param.position === \"number\" && String(param.position)) ||\n\t\t\t\tString(index + 1);\n\t\t\tconst key = nameCandidate.replace(/[{}:$]/g, \"\").trim();\n\t\t\trecord[key] = value;\n\t\t});\n\n\t\treturn record;\n\t}\n\n\tprivate ensureTenantIsolation(\n\t\tsql: string,\n\t\tparams: ParamRecord,\n\t\tmetadata: DatabaseMetadata,\n\t\ttenantId: string,\n\t): string {\n\t\tif (\n\t\t\t!metadata.tenantFieldName ||\n\t\t\tmetadata.enforceTenantIsolation === false\n\t\t) {\n\t\t\treturn sql;\n\t\t}\n\n\t\tconst tenantField = metadata.tenantFieldName;\n\t\tconst paramKey = tenantField;\n\t\tparams[paramKey] = tenantId;\n\n\t\tconst normalizedSql = sql.toLowerCase();\n\t\tif (normalizedSql.includes(tenantField.toLowerCase())) {\n\t\t\treturn sql;\n\t\t}\n\n\t\tconst tenantPredicate =\n\t\t\tmetadata.dialect === \"clickhouse\"\n\t\t\t\t? `${tenantField} = {${tenantField}:${metadata.tenantFieldType ?? \"String\"}}`\n\t\t\t\t: `${tenantField} = '${tenantId}'`;\n\n\t\tif (/\\bwhere\\b/i.test(sql)) {\n\t\t\treturn sql.replace(\n\t\t\t\t/\\bwhere\\b/i,\n\t\t\t\t(match) => `${match} ${tenantPredicate} AND `,\n\t\t\t);\n\t\t}\n\n\t\treturn `${sql} WHERE ${tenantPredicate}`;\n\t}\n}\n","import type { ApiClient } from \"../core/client\";\nimport type { ParamRecord, QueryEngine } from \"../core/query-engine\";\n\nexport interface SdkChart {\n\tid: string;\n\ttitle: string;\n\tdescription: string | null;\n\tsql: string;\n\tsql_params: Record<string, unknown> | null;\n\tvega_lite_spec: Record<string, unknown>;\n\tquery_id: string | null;\n\torganization_id: string | null;\n\ttenant_id: string | null;\n\tuser_id: string | null;\n\tcreated_at: string | null;\n\tupdated_at: string | null;\n\tactive?: boolean;\n\ttarget_db?: string | null;\n}\n\nexport interface ChartCreateInput {\n\ttitle: string;\n\tdescription?: string;\n\tsql: string;\n\tsql_params?: Record<string, unknown>;\n\tvega_lite_spec: Record<string, unknown>;\n\tquery_id?: string;\n\ttarget_db?: string;\n}\n\nexport interface ChartUpdateInput {\n\ttitle?: string;\n\tdescription?: string;\n\tsql?: string;\n\tsql_params?: Record<string, unknown>;\n\tvega_lite_spec?: Record<string, unknown>;\n\ttarget_db?: string;\n}\n\nexport interface PaginationQuery {\n\tpage?: number;\n\tlimit?: number;\n}\n\nexport interface PaginationInfo {\n\tpage: number;\n\tlimit: number;\n\ttotal: number;\n\ttotalPages: number;\n\thasNext: boolean;\n\thasPrev: boolean;\n}\n\nexport interface PaginatedResponse<T> {\n\tdata: T[];\n\tpagination: PaginationInfo;\n}\n\nexport interface ChartListOptions {\n\ttenantId?: string;\n\tuserId?: string;\n\tscopes?: string[];\n\tpagination?: PaginationQuery;\n\tsortBy?: \"title\" | \"user_id\" | \"created_at\" | \"updated_at\";\n\tsortDir?: \"asc\" | \"desc\";\n\ttitle?: string;\n\tuserFilter?: string;\n\tcreatedFrom?: string;\n\tcreatedTo?: string;\n\tupdatedFrom?: string;\n\tupdatedTo?: string;\n\tincludeData?: boolean;\n}\n\ninterface RequestOptions {\n\ttenantId?: string;\n\tuserId?: string;\n\tscopes?: string[];\n}\n\n/**\n * Route module for Chart CRUD operations\n * Simple pass-through to backend with optional data hydration\n */\nexport async function createChart(\n\tclient: ApiClient,\n\tbody: ChartCreateInput,\n\toptions?: RequestOptions,\n\tsignal?: AbortSignal,\n): Promise<SdkChart> {\n\tconst tenantId = resolveTenantId(client, options?.tenantId);\n\treturn await client.post<SdkChart>(\n\t\t\"/charts\",\n\t\tbody,\n\t\ttenantId,\n\t\toptions?.userId,\n\t\toptions?.scopes,\n\t\tsignal,\n\t);\n}\n\nexport async function listCharts(\n\tclient: ApiClient,\n\tqueryEngine: QueryEngine,\n\toptions?: ChartListOptions,\n\tsignal?: AbortSignal,\n): Promise<PaginatedResponse<SdkChart>> {\n\tconst tenantId = resolveTenantId(client, options?.tenantId);\n\tconst params = new URLSearchParams();\n\tif (options?.pagination?.page)\n\t\tparams.set(\"page\", `${options.pagination.page}`);\n\tif (options?.pagination?.limit)\n\t\tparams.set(\"limit\", `${options.pagination.limit}`);\n\tif (options?.sortBy) params.set(\"sort_by\", options.sortBy);\n\tif (options?.sortDir) params.set(\"sort_dir\", options.sortDir);\n\tif (options?.title) params.set(\"title\", options.title);\n\tif (options?.userFilter) params.set(\"user_id\", options.userFilter);\n\tif (options?.createdFrom) params.set(\"created_from\", options.createdFrom);\n\tif (options?.createdTo) params.set(\"created_to\", options.createdTo);\n\tif (options?.updatedFrom) params.set(\"updated_from\", options.updatedFrom);\n\tif (options?.updatedTo) params.set(\"updated_to\", options.updatedTo);\n\n\tconst response = await client.get<PaginatedResponse<SdkChart>>(\n\t\t`/charts${params.toString() ? `?${params.toString()}` : \"\"}`,\n\t\ttenantId,\n\t\toptions?.userId,\n\t\toptions?.scopes,\n\t\tsignal,\n\t);\n\n\tif (options?.includeData) {\n\t\tresponse.data = await Promise.all(\n\t\t\tresponse.data.map(async (chart) => ({\n\t\t\t\t...chart,\n\t\t\t\tvega_lite_spec: {\n\t\t\t\t\t...chart.vega_lite_spec,\n\t\t\t\t\tdata: {\n\t\t\t\t\t\tvalues: await queryEngine.execute(\n\t\t\t\t\t\t\tchart.sql,\n\t\t\t\t\t\t\t(chart.sql_params as ParamRecord | null) ?? undefined,\n\t\t\t\t\t\t\tchart.target_db ?? undefined,\n\t\t\t\t\t\t),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t})),\n\t\t);\n\t}\n\n\treturn response;\n}\n\nexport async function getChart(\n\tclient: ApiClient,\n\tqueryEngine: QueryEngine,\n\tid: string,\n\toptions?: RequestOptions,\n\tsignal?: AbortSignal,\n): Promise<SdkChart> {\n\tconst tenantId = resolveTenantId(client, options?.tenantId);\n\tconst chart = await client.get<SdkChart>(\n\t\t`/charts/${encodeURIComponent(id)}`,\n\t\ttenantId,\n\t\toptions?.userId,\n\t\toptions?.scopes,\n\t\tsignal,\n\t);\n\n\treturn {\n\t\t...chart,\n\t\tvega_lite_spec: {\n\t\t\t...chart.vega_lite_spec,\n\t\t\tdata: {\n\t\t\t\tvalues: await queryEngine.execute(\n\t\t\t\t\tchart.sql,\n\t\t\t\t\t(chart.sql_params as ParamRecord | null) ?? undefined,\n\t\t\t\t\tchart.target_db ?? undefined,\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t};\n}\n\nexport async function updateChart(\n\tclient: ApiClient,\n\tid: string,\n\tbody: ChartUpdateInput,\n\toptions?: RequestOptions,\n\tsignal?: AbortSignal,\n): Promise<SdkChart> {\n\tconst tenantId = resolveTenantId(client, options?.tenantId);\n\treturn await client.put<SdkChart>(\n\t\t`/charts/${encodeURIComponent(id)}`,\n\t\tbody,\n\t\ttenantId,\n\t\toptions?.userId,\n\t\toptions?.scopes,\n\t\tsignal,\n\t);\n}\n\nexport async function deleteChart(\n\tclient: ApiClient,\n\tid: string,\n\toptions?: RequestOptions,\n\tsignal?: AbortSignal,\n): Promise<void> {\n\tconst tenantId = resolveTenantId(client, options?.tenantId);\n\tawait client.delete(\n\t\t`/charts/${encodeURIComponent(id)}`,\n\t\ttenantId,\n\t\toptions?.userId,\n\t\toptions?.scopes,\n\t\tsignal,\n\t);\n}\n\nfunction resolveTenantId(client: ApiClient, tenantId?: string): string {\n\tconst resolved = tenantId ?? client.getDefaultTenantId();\n\tif (!resolved) {\n\t\tthrow new Error(\n\t\t\t\"tenantId is required. Provide it per request or via defaultTenantId option.\",\n\t\t);\n\t}\n\treturn resolved;\n}\n","import type { ApiClient } from \"../core/client\";\nimport type { QueryEngine } from \"../core/query-engine\";\nimport * as charts from \"./charts\";\n\nexport interface SdkActiveChart {\n\tid: string;\n\tchart_id: string;\n\torder: number | null;\n\tmeta: Record<string, unknown> | null;\n\torganization_id: string | null;\n\ttenant_id: string | null;\n\tuser_id: string | null;\n\tcreated_at: string | null;\n\tupdated_at: string | null;\n\tchart?: charts.SdkChart | null;\n}\n\nexport interface ActiveChartCreateInput {\n\tchart_id: string;\n\torder?: number;\n\tmeta?: Record<string, unknown>;\n}\n\nexport interface ActiveChartUpdateInput {\n\tchart_id?: string;\n\torder?: number;\n\tmeta?: Record<string, unknown>;\n}\n\nexport interface ActiveChartListOptions extends charts.ChartListOptions {\n\twithData?: boolean;\n}\n\ninterface RequestOptions {\n\ttenantId?: string;\n\tuserId?: string;\n\tscopes?: string[];\n}\n\n/**\n * Route module for Active Chart CRUD operations\n * Simple pass-through to backend with optional chart data hydration\n */\nexport async function createActiveChart(\n\tclient: ApiClient,\n\tbody: ActiveChartCreateInput,\n\toptions?: RequestOptions,\n\tsignal?: AbortSignal,\n): Promise<SdkActiveChart> {\n\tconst tenantId = resolveTenantId(client, options?.tenantId);\n\treturn await client.post<SdkActiveChart>(\n\t\t\"/active-charts\",\n\t\tbody,\n\t\ttenantId,\n\t\toptions?.userId,\n\t\toptions?.scopes,\n\t\tsignal,\n\t);\n}\n\nexport async function listActiveCharts(\n\tclient: ApiClient,\n\tqueryEngine: QueryEngine,\n\toptions?: ActiveChartListOptions,\n\tsignal?: AbortSignal,\n): Promise<charts.PaginatedResponse<SdkActiveChart>> {\n\tconst tenantId = resolveTenantId(client, options?.tenantId);\n\tconst params = new URLSearchParams();\n\tif (options?.pagination?.page)\n\t\tparams.set(\"page\", `${options.pagination.page}`);\n\tif (options?.pagination?.limit)\n\t\tparams.set(\"limit\", `${options.pagination.limit}`);\n\tif (options?.sortBy) params.set(\"sort_by\", options.sortBy);\n\tif (options?.sortDir) params.set(\"sort_dir\", options.sortDir);\n\tif (options?.title) params.set(\"name\", options.title);\n\tif (options?.userFilter) params.set(\"user_id\", options.userFilter);\n\tif (options?.createdFrom) params.set(\"created_from\", options.createdFrom);\n\tif (options?.createdTo) params.set(\"created_to\", options.createdTo);\n\tif (options?.updatedFrom) params.set(\"updated_from\", options.updatedFrom);\n\tif (options?.updatedTo) params.set(\"updated_to\", options.updatedTo);\n\n\tconst response = await client.get<\n\t\tcharts.PaginatedResponse<SdkActiveChart>\n\t>(\n\t\t`/active-charts${params.toString() ? `?${params.toString()}` : \"\"}`,\n\t\ttenantId,\n\t\toptions?.userId,\n\t\toptions?.scopes,\n\t\tsignal,\n\t);\n\n\tif (options?.withData) {\n\t\tresponse.data = await Promise.all(\n\t\t\tresponse.data.map(async (active) => ({\n\t\t\t\t...active,\n\t\t\t\tchart: active.chart\n\t\t\t\t\t? await charts.getChart(\n\t\t\t\t\t\t\tclient,\n\t\t\t\t\t\t\tqueryEngine,\n\t\t\t\t\t\t\tactive.chart_id,\n\t\t\t\t\t\t\toptions,\n\t\t\t\t\t\t\tsignal,\n\t\t\t\t\t\t)\n\t\t\t\t\t: null,\n\t\t\t})),\n\t\t);\n\t}\n\n\treturn response;\n}\n\nexport async function getActiveChart(\n\tclient: ApiClient,\n\tqueryEngine: QueryEngine,\n\tid: string,\n\toptions?: ActiveChartListOptions,\n\tsignal?: AbortSignal,\n): Promise<SdkActiveChart> {\n\tconst tenantId = resolveTenantId(client, options?.tenantId);\n\tconst active = await client.get<SdkActiveChart>(\n\t\t`/active-charts/${encodeURIComponent(id)}`,\n\t\ttenantId,\n\t\toptions?.userId,\n\t\toptions?.scopes,\n\t\tsignal,\n\t);\n\n\tif (options?.withData && active.chart_id) {\n\t\treturn {\n\t\t\t...active,\n\t\t\tchart: await charts.getChart(\n\t\t\t\tclient,\n\t\t\t\tqueryEngine,\n\t\t\t\tactive.chart_id,\n\t\t\t\toptions,\n\t\t\t\tsignal,\n\t\t\t),\n\t\t};\n\t}\n\n\treturn active;\n}\n\nexport async function updateActiveChart(\n\tclient: ApiClient,\n\tid: string,\n\tbody: ActiveChartUpdateInput,\n\toptions?: RequestOptions,\n\tsignal?: AbortSignal,\n): Promise<SdkActiveChart> {\n\tconst tenantId = resolveTenantId(client, options?.tenantId);\n\treturn await client.put<SdkActiveChart>(\n\t\t`/active-charts/${encodeURIComponent(id)}`,\n\t\tbody,\n\t\ttenantId,\n\t\toptions?.userId,\n\t\toptions?.scopes,\n\t\tsignal,\n\t);\n}\n\nexport async function deleteActiveChart(\n\tclient: ApiClient,\n\tid: string,\n\toptions?: RequestOptions,\n\tsignal?: AbortSignal,\n): Promise<void> {\n\tconst tenantId = resolveTenantId(client, options?.tenantId);\n\tawait client.delete(\n\t\t`/active-charts/${encodeURIComponent(id)}`,\n\t\ttenantId,\n\t\toptions?.userId,\n\t\toptions?.scopes,\n\t\tsignal,\n\t);\n}\n\nfunction resolveTenantId(client: ApiClient, tenantId?: string): string {\n\tconst resolved = tenantId ?? client.getDefaultTenantId();\n\tif (!resolved) {\n\t\tthrow new Error(\n\t\t\t\"tenantId is required. Provide it per request or via defaultTenantId option.\",\n\t\t);\n\t}\n\treturn resolved;\n}\n","import { randomUUID } from \"node:crypto\";\nimport type { ApiClient } from \"../core/client\";\nimport type { QueryEngine } from \"../core/query-engine\";\nimport type { SchemaIntrospection } from \"../schema/types\";\n\nexport interface IngestResponse {\n\tsuccess: boolean;\n\tmessage: string;\n\tchunks: number;\n\tchunks_with_annotations: number;\n\tschema_id?: string;\n\tschema_hash?: string;\n\tdrift_detected?: boolean;\n\tskipped?: boolean;\n}\n\nexport interface SchemaSyncOptions {\n\ttenantId?: string;\n\tuserId?: string;\n\tscopes?: string[];\n\ttables?: string[];\n\tforceReindex?: boolean;\n}\n\ninterface SchemaIngestColumn {\n\tname: string;\n\tdata_type: string;\n\tis_primary_key: boolean;\n\tdescription: string;\n}\n\ninterface SchemaIngestTable {\n\ttable_name: string;\n\tdescription: string;\n\tcolumns: SchemaIngestColumn[];\n}\n\ninterface SchemaIngestRequest {\n\tdatabase: string;\n\tdialect: string;\n\ttables: SchemaIngestTable[];\n\tforce_reindex?: boolean;\n}\n\n/**\n * Route module for schema ingestion\n * Handles introspection and sync to backend\n */\nexport async function syncSchema(\n\tclient: ApiClient,\n\tqueryEngine: QueryEngine,\n\tdatabaseName: string,\n\toptions: SchemaSyncOptions,\n\tsignal?: AbortSignal,\n): Promise<IngestResponse> {\n\tconst tenantId = resolveTenantId(client, options.tenantId);\n\tconst adapter = queryEngine.getDatabase(databaseName);\n\n\tconst introspection = await adapter.introspect(\n\t\toptions.tables ? { tables: options.tables } : undefined,\n\t);\n\n\tconst payload = buildSchemaRequest(databaseName, adapter, introspection);\n\tif (options.forceReindex) {\n\t\tpayload.force_reindex = true;\n\t}\n\n\t// Generate a session id so backend telemetry can correlate all work for this sync\n\tconst sessionId = randomUUID();\n\n\tconst response = await client.post<IngestResponse>(\n\t\t\"/ingest\",\n\t\tpayload,\n\t\ttenantId,\n\t\toptions.userId,\n\t\toptions.scopes,\n\t\tsignal,\n\t\tsessionId,\n\t);\n\n\treturn response;\n}\n\nfunction resolveTenantId(client: ApiClient, tenantId?: string): string {\n\tconst resolved = tenantId ?? client.getDefaultTenantId();\n\tif (!resolved) {\n\t\tthrow new Error(\n\t\t\t\"tenantId is required. Provide it per request or via defaultTenantId option.\",\n\t\t);\n\t}\n\treturn resolved;\n}\n\nfunction buildSchemaRequest(\n\tdatabaseName: string,\n\tadapter: { getDialect: () => string },\n\tintrospection: SchemaIntrospection,\n): SchemaIngestRequest {\n\tconst dialect = adapter.getDialect();\n\tconst tables: SchemaIngestTable[] = introspection.tables.map((table) => ({\n\t\ttable_name: table.name,\n\t\tdescription: table.comment ?? `Table ${table.name}`,\n\t\tcolumns: table.columns.map((column) => ({\n\t\t\tname: column.name,\n\t\t\tdata_type: column.rawType ?? column.type,\n\t\t\tis_primary_key: Boolean(column.isPrimaryKey),\n\t\t\tdescription: column.comment ?? \"\",\n\t\t})),\n\t}));\n\n\treturn {\n\t\tdatabase: databaseName,\n\t\tdialect,\n\t\ttables,\n\t};\n}\n","import { randomUUID } from \"node:crypto\";\nimport type { ApiClient } from \"../core/client\";\nimport type { ParamRecord, QueryEngine } from \"../core/query-engine\";\n\nexport interface ContextDocument {\n\tsource?: string;\n\tpageContent: string;\n\tmetadata?: Record<string, unknown>;\n\tscore?: number;\n}\n\nexport interface ChartEnvelope {\n\tvegaLiteSpec: Record<string, unknown> | null;\n\tnotes: string | null;\n}\n\nexport interface AskOptions {\n\ttenantId?: string;\n\tuserId?: string;\n\tscopes?: string[];\n\tdatabase?: string;\n\tlastError?: string;\n\tpreviousSql?: string;\n\tmaxRetry?: number;\n\tchartMaxRetries?: number;\n}\n\nexport interface AskResponse {\n\tsql: string;\n\tparams: ParamRecord;\n\tparamMetadata: Array<Record<string, unknown>>;\n\trationale?: string;\n\tdialect: string;\n\tqueryId?: string;\n\trows: Array<Record<string, unknown>>;\n\tfields: string[];\n\tchart: ChartEnvelope;\n\tcontext?: ContextDocument[];\n\tattempts?: number;\n}\n\ninterface ServerQueryResponse {\n\tsuccess: boolean;\n\tsql: string;\n\tparams?: Array<Record<string, unknown>>;\n\tdialect: string;\n\tdatabase?: string;\n\ttable?: string;\n\trationale?: string;\n\tqueryId?: string;\n\tcontext?: ContextDocument[];\n}\n\ninterface ServerChartResponse {\n\tchart: Record<string, unknown> | null;\n\tnotes: string | null;\n}\n\n/**\n * Route module for natural language query generation\n * Simple orchestration following Ousterhout's principle\n */\nexport async function ask(\n\tclient: ApiClient,\n\tqueryEngine: QueryEngine,\n\tquestion: string,\n\toptions: AskOptions,\n\tsignal?: AbortSignal,\n): Promise<AskResponse> {\n\tconst tenantId = resolveTenantId(client, options.tenantId);\n\tconst sessionId = randomUUID();\n\tconst maxRetry = options.maxRetry ?? 0;\n\tlet attempt = 0;\n\tlet lastError: string | undefined = options.lastError;\n\tlet previousSql: string | undefined = options.previousSql;\n\n\twhile (attempt <= maxRetry) {\n\t\t// Step 1: Get SQL from backend\n\t\tconsole.log({ lastError, previousSql });\n\t\tconst queryResponse = await client.post<ServerQueryResponse>(\n\t\t\t\"/query\",\n\t\t\t{\n\t\t\t\tquestion,\n\t\t\t\t...(lastError ? { last_error: lastError } : {}),\n\t\t\t\t...(previousSql ? { previous_sql: previousSql } : {}),\n\t\t\t\t...(options.maxRetry ? { max_retry: options.maxRetry } : {}),\n\t\t\t},\n\t\t\ttenantId,\n\t\t\toptions.userId,\n\t\t\toptions.scopes,\n\t\t\tsignal,\n\t\t\tsessionId,\n\t\t);\n\n\t\tconst databaseName =\n\t\t\tqueryResponse.database ??\n\t\t\toptions.database ??\n\t\t\tqueryEngine.getDefaultDatabase();\n\t\tif (!databaseName) {\n\t\t\tthrow new Error(\n\t\t\t\t\"No database attached. Call attachPostgres/attachClickhouse first.\",\n\t\t\t);\n\t\t}\n\n\t\t// Step 2: Map and validate parameters\n\t\tconst paramMetadata = Array.isArray(queryResponse.params)\n\t\t\t? queryResponse.params\n\t\t\t: [];\n\t\tconst paramValues = queryEngine.mapGeneratedParams(paramMetadata);\n\n\t\t// Step 3: Execute SQL with tenant isolation\n\t\ttry {\n\t\t\tconst execution = await queryEngine.validateAndExecute(\n\t\t\t\tqueryResponse.sql,\n\t\t\t\tparamValues,\n\t\t\t\tdatabaseName,\n\t\t\t\ttenantId,\n\t\t\t);\n\t\t\tconst rows = execution.rows ?? [];\n\n\t\t\t// Step 4: Generate chart if we have data\n\t\t\tlet chart: ChartEnvelope = {\n\t\t\t\tvegaLiteSpec: null,\n\t\t\t\tnotes: rows.length === 0 ? \"Query returned no rows.\" : null,\n\t\t\t};\n\n\t\t\tif (rows.length > 0) {\n\t\t\t\tconst chartResponse = await client.post<ServerChartResponse>(\n\t\t\t\t\t\"/chart\",\n\t\t\t\t\t{\n\t\t\t\t\t\tquestion,\n\t\t\t\t\t\tsql: queryResponse.sql,\n\t\t\t\t\t\trationale: queryResponse.rationale,\n\t\t\t\t\t\tfields: execution.fields,\n\t\t\t\t\t\trows: anonymizeResults(rows),\n\t\t\t\t\t\tmax_retries: options.chartMaxRetries ?? 3,\n\t\t\t\t\t\tquery_id: queryResponse.queryId,\n\t\t\t\t\t},\n\t\t\t\t\ttenantId,\n\t\t\t\t\toptions.userId,\n\t\t\t\t\toptions.scopes,\n\t\t\t\t\tsignal,\n\t\t\t\t\tsessionId,\n\t\t\t\t);\n\n\t\t\t\tchart = {\n\t\t\t\t\tvegaLiteSpec: chartResponse.chart\n\t\t\t\t\t\t? {\n\t\t\t\t\t\t\t\t...chartResponse.chart,\n\t\t\t\t\t\t\t\tdata: { values: rows },\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t: null,\n\t\t\t\t\tnotes: chartResponse.notes,\n\t\t\t\t};\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\tsql: queryResponse.sql,\n\t\t\t\tparams: paramValues,\n\t\t\t\tparamMetadata,\n\t\t\t\trationale: queryResponse.rationale,\n\t\t\t\tdialect: queryResponse.dialect,\n\t\t\t\tqueryId: queryResponse.queryId,\n\t\t\t\trows,\n\t\t\t\tfields: execution.fields,\n\t\t\t\tchart,\n\t\t\t\tcontext: queryResponse.context,\n\t\t\t\tattempts: attempt + 1,\n\t\t\t};\n\t\t} catch (error) {\n\t\t\tattempt++;\n\n\t\t\t// If we've exhausted all retries, throw the error\n\t\t\tif (attempt > maxRetry) {\n\t\t\t\tthrow error;\n\t\t\t}\n\n\t\t\t// Save error and SQL for next retry\n\t\t\tlastError = error instanceof Error ? error.message : String(error);\n\t\t\tpreviousSql = queryResponse.sql;\n\n\t\t\t// Log retry attempt\n\t\t\tconsole.warn(\n\t\t\t\t`SQL execution failed (attempt ${attempt}/${maxRetry + 1}): ${lastError}. Retrying...`,\n\t\t\t);\n\t\t}\n\t}\n\n\t// This should never be reached, but TypeScript needs it\n\tthrow new Error(\"Unexpected error in ask retry loop\");\n}\n\nfunction resolveTenantId(client: ApiClient, tenantId?: string): string {\n\tconst resolved = tenantId ?? client.getDefaultTenantId();\n\tif (!resolved) {\n\t\tthrow new Error(\n\t\t\t\"tenantId is required. Provide it per request or via defaultTenantId option.\",\n\t\t);\n\t}\n\treturn resolved;\n}\n\nexport function anonymizeResults(\n\trows: Array<Record<string, unknown>>,\n): Array<Record<string, string>> {\n\tif (!rows?.length) return [];\n\treturn rows.map((row) => {\n\t\tconst masked: Record<string, string> = {};\n\t\tObject.entries(row).forEach(([key, value]) => {\n\t\t\tif (value === null) masked[key] = \"null\";\n\t\t\telse if (Array.isArray(value)) masked[key] = \"array\";\n\t\t\telse masked[key] = typeof value;\n\t\t});\n\t\treturn masked;\n\t});\n}\n","import {\n\tClickHouseAdapter,\n\ttype ClickHouseAdapterOptions,\n\ttype ClickHouseClientFn,\n} from \"./adapters/clickhouse\";\nimport {\n\tPostgresAdapter,\n\ttype PostgresAdapterOptions,\n\ttype PostgresClientFn,\n} from \"./adapters/postgres\";\nimport type { DatabaseAdapter, DatabaseDialect } from \"./adapters/types\";\nimport { ApiClient } from \"./core/client\";\nimport { type DatabaseMetadata, QueryEngine } from \"./core/query-engine\";\nimport * as activeChartsRoute from \"./routes/active-charts\";\nimport * as chartsRoute from \"./routes/charts\";\nimport * as ingestRoute from \"./routes/ingest\";\nimport * as queryRoute from \"./routes/query\";\nimport type { SchemaIntrospection } from \"./schema/types\";\n\n// Re-export all public types\nexport { ClickHouseAdapter, PostgresAdapter };\n\nexport type {\n\tClickHouseAdapterOptions,\n\tClickHouseClientFn,\n\tDatabaseAdapter,\n\tDatabaseDialect,\n\tPostgresAdapterOptions,\n\tPostgresClientFn,\n\tSchemaIntrospection,\n};\n\n// Re-export from query-engine\nexport type { ParamRecord, ParamValue } from \"./core/query-engine\";\nexport type {\n\tActiveChartCreateInput,\n\tActiveChartListOptions,\n\tActiveChartUpdateInput,\n\tSdkActiveChart,\n} from \"./routes/active-charts\";\n\nexport type {\n\tChartCreateInput,\n\tChartListOptions,\n\tChartUpdateInput,\n\tPaginatedResponse,\n\tPaginationInfo,\n\tPaginationQuery,\n\tSdkChart,\n} from \"./routes/charts\";\n// Re-export route types\nexport type {\n\tIngestResponse,\n\tSchemaSyncOptions,\n} from \"./routes/ingest\";\nexport type {\n\tAskOptions,\n\tAskResponse,\n\tChartEnvelope,\n\tContextDocument,\n} from \"./routes/query\";\n\n// Re-export anonymizeResults utility\nexport { anonymizeResults } from \"./routes/query\";\n\n/**\n * Main SDK class - Thin orchestrator\n * Delegates to deep modules (ApiClient, QueryEngine, route modules)\n * Following Ousterhout's principle: \"Simple interface hiding complexity\"\n */\nexport class QueryPanelSdkAPI {\n\tprivate readonly client: ApiClient;\n\tprivate readonly queryEngine: QueryEngine;\n\n\tconstructor(\n\t\tbaseUrl: string,\n\t\tprivateKey: string,\n\t\torganizationId: string,\n\t\toptions?: {\n\t\t\tdefaultTenantId?: string;\n\t\t\tadditionalHeaders?: Record<string, string>;\n\t\t\tfetch?: typeof fetch;\n\t\t},\n\t) {\n\t\tthis.client = new ApiClient(baseUrl, privateKey, organizationId, options);\n\t\tthis.queryEngine = new QueryEngine();\n\t}\n\n\t// Database attachment methods\n\n\tattachClickhouse(\n\t\tname: string,\n\t\tclientFn: ClickHouseClientFn,\n\t\toptions?: ClickHouseAdapterOptions & {\n\t\t\tdescription?: string;\n\t\t\ttags?: string[];\n\t\t\ttenantFieldName?: string;\n\t\t\ttenantFieldType?: string;\n\t\t\tenforceTenantIsolation?: boolean;\n\t\t},\n\t): void {\n\t\tconst adapter = new ClickHouseAdapter(clientFn, options);\n\n\t\tconst metadata: DatabaseMetadata = {\n\t\t\tname,\n\t\t\tdialect: \"clickhouse\",\n\t\t\tdescription: options?.description,\n\t\t\ttags: options?.tags,\n\t\t\ttenantFieldName: options?.tenantFieldName,\n\t\t\ttenantFieldType: options?.tenantFieldType ?? \"String\",\n\t\t\tenforceTenantIsolation: options?.tenantFieldName\n\t\t\t\t? (options?.enforceTenantIsolation ?? true)\n\t\t\t\t: undefined,\n\t\t};\n\n\t\tthis.queryEngine.attachDatabase(name, adapter, metadata);\n\t}\n\n\tattachPostgres(\n\t\tname: string,\n\t\tclientFn: PostgresClientFn,\n\t\toptions?: PostgresAdapterOptions & {\n\t\t\tdescription?: string;\n\t\t\ttags?: string[];\n\t\t\ttenantFieldName?: string;\n\t\t\tenforceTenantIsolation?: boolean;\n\t\t},\n\t): void {\n\t\tconst adapter = new PostgresAdapter(clientFn, options);\n\n\t\tconst metadata: DatabaseMetadata = {\n\t\t\tname,\n\t\t\tdialect: \"postgres\",\n\t\t\tdescription: options?.description,\n\t\t\ttags: options?.tags,\n\t\t\ttenantFieldName: options?.tenantFieldName,\n\t\t\tenforceTenantIsolation: options?.tenantFieldName\n\t\t\t\t? (options?.enforceTenantIsolation ?? true)\n\t\t\t\t: undefined,\n\t\t};\n\n\t\tthis.queryEngine.attachDatabase(name, adapter, metadata);\n\t}\n\n\tattachDatabase(name: string, adapter: DatabaseAdapter): void {\n\t\tconst metadata: DatabaseMetadata = {\n\t\t\tname,\n\t\t\tdialect: adapter.getDialect(),\n\t\t};\n\t\tthis.queryEngine.attachDatabase(name, adapter, metadata);\n\t}\n\n\t// Schema introspection and sync\n\n\tasync introspect(\n\t\tdatabaseName: string,\n\t\ttables?: string[],\n\t): Promise<SchemaIntrospection> {\n\t\tconst adapter = this.queryEngine.getDatabase(databaseName);\n\t\treturn await adapter.introspect(tables ? { tables } : undefined);\n\t}\n\n\tasync syncSchema(\n\t\tdatabaseName: string,\n\t\toptions: ingestRoute.SchemaSyncOptions,\n\t\tsignal?: AbortSignal,\n\t): Promise<ingestRoute.IngestResponse> {\n\t\treturn await ingestRoute.syncSchema(\n\t\t\tthis.client,\n\t\t\tthis.queryEngine,\n\t\t\tdatabaseName,\n\t\t\toptions,\n\t\t\tsignal,\n\t\t);\n\t}\n\n\t// Natural language query\n\n\tasync ask(\n\t\tquestion: string,\n\t\toptions: queryRoute.AskOptions,\n\t\tsignal?: AbortSignal,\n\t): Promise<queryRoute.AskResponse> {\n\t\treturn await queryRoute.ask(\n\t\t\tthis.client,\n\t\t\tthis.queryEngine,\n\t\t\tquestion,\n\t\t\toptions,\n\t\t\tsignal,\n\t\t);\n\t}\n\n\t// Chart CRUD operations\n\n\tasync createChart(\n\t\tbody: chartsRoute.ChartCreateInput,\n\t\toptions?: { tenantId?: string; userId?: string; scopes?: string[] },\n\t\tsignal?: AbortSignal,\n\t): Promise<chartsRoute.SdkChart> {\n\t\treturn await chartsRoute.createChart(this.client, body, options, signal);\n\t}\n\n\tasync listCharts(\n\t\toptions?: chartsRoute.ChartListOptions,\n\t\tsignal?: AbortSignal,\n\t): Promise<chartsRoute.PaginatedResponse<chartsRoute.SdkChart>> {\n\t\treturn await chartsRoute.listCharts(\n\t\t\tthis.client,\n\t\t\tthis.queryEngine,\n\t\t\toptions,\n\t\t\tsignal,\n\t\t);\n\t}\n\n\tasync getChart(\n\t\tid: string,\n\t\toptions?: { tenantId?: string; userId?: string; scopes?: string[] },\n\t\tsignal?: AbortSignal,\n\t): Promise<chartsRoute.SdkChart> {\n\t\treturn await chartsRoute.getChart(\n\t\t\tthis.client,\n\t\t\tthis.queryEngine,\n\t\t\tid,\n\t\t\toptions,\n\t\t\tsignal,\n\t\t);\n\t}\n\n\tasync updateChart(\n\t\tid: string,\n\t\tbody: chartsRoute.ChartUpdateInput,\n\t\toptions?: { tenantId?: string; userId?: string; scopes?: string[] },\n\t\tsignal?: AbortSignal,\n\t): Promise<chartsRoute.SdkChart> {\n\t\treturn await chartsRoute.updateChart(\n\t\t\tthis.client,\n\t\t\tid,\n\t\t\tbody,\n\t\t\toptions,\n\t\t\tsignal,\n\t\t);\n\t}\n\n\tasync deleteChart(\n\t\tid: string,\n\t\toptions?: { tenantId?: string; userId?: string; scopes?: string[] },\n\t\tsignal?: AbortSignal,\n\t): Promise<void> {\n\t\tawait chartsRoute.deleteChart(this.client, id, options, signal);\n\t}\n\n\t// Active Chart CRUD operations\n\n\tasync createActiveChart(\n\t\tbody: activeChartsRoute.ActiveChartCreateInput,\n\t\toptions?: { tenantId?: string; userId?: string; scopes?: string[] },\n\t\tsignal?: AbortSignal,\n\t): Promise<activeChartsRoute.SdkActiveChart> {\n\t\treturn await activeChartsRoute.createActiveChart(\n\t\t\tthis.client,\n\t\t\tbody,\n\t\t\toptions,\n\t\t\tsignal,\n\t\t);\n\t}\n\n\tasync listActiveCharts(\n\t\toptions?: activeChartsRoute.ActiveChartListOptions,\n\t\tsignal?: AbortSignal,\n\t): Promise<chartsRoute.PaginatedResponse<activeChartsRoute.SdkActiveChart>> {\n\t\treturn await activeChartsRoute.listActiveCharts(\n\t\t\tthis.client,\n\t\t\tthis.queryEngine,\n\t\t\toptions,\n\t\t\tsignal,\n\t\t);\n\t}\n\n\tasync getActiveChart(\n\t\tid: string,\n\t\toptions?: activeChartsRoute.ActiveChartListOptions,\n\t\tsignal?: AbortSignal,\n\t): Promise<activeChartsRoute.SdkActiveChart> {\n\t\treturn await activeChartsRoute.getActiveChart(\n\t\t\tthis.client,\n\t\t\tthis.queryEngine,\n\t\t\tid,\n\t\t\toptions,\n\t\t\tsignal,\n\t\t);\n\t}\n\n\tasync updateActiveChart(\n\t\tid: string,\n\t\tbody: activeChartsRoute.ActiveChartUpdateInput,\n\t\toptions?: { tenantId?: string; userId?: string; scopes?: string[] },\n\t\tsignal?: AbortSignal,\n\t): Promise<activeChartsRoute.SdkActiveChart> {\n\t\treturn await activeChartsRoute.updateActiveChart(\n\t\t\tthis.client,\n\t\t\tid,\n\t\t\tbody,\n\t\t\toptions,\n\t\t\tsignal,\n\t\t);\n\t}\n\n\tasync deleteActiveChart(\n\t\tid: string,\n\t\toptions?: { tenantId?: string; userId?: string; scopes?: string[] },\n\t\tsignal?: AbortSignal,\n\t): Promise<void> {\n\t\tawait activeChartsRoute.deleteActiveChart(this.client, id, options, signal);\n\t}\n}\n"],"mappings":"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","names":["normalizeTableFilter","asTableType","sanitize","resolveTenantId","resolveTenantId","randomUUID","resolveTenantId"]}
|
|
1
|
+
{"version":3,"sources":["../src/utils/clickhouse.ts","../src/adapters/clickhouse.ts","../src/adapters/postgres.ts","../src/core/client.ts","../src/core/query-engine.ts","../src/routes/charts.ts","../src/routes/active-charts.ts","../src/routes/ingest.ts","../src/routes/query.ts","../src/index.ts"],"sourcesContent":["const WRAPPER_REGEX =\n /^(Nullable|LowCardinality|SimpleAggregateFunction)\\((.+)\\)$/i;\n\nexport function isNullableType(type: string): boolean {\n return /Nullable\\s*\\(/i.test(type);\n}\n\nexport function unwrapTypeModifiers(type: string): string {\n let current = type.trim();\n let match = WRAPPER_REGEX.exec(current);\n while (match) {\n const inner = match[2];\n if (!inner) {\n break;\n }\n current = inner.trim();\n match = WRAPPER_REGEX.exec(current);\n }\n return current;\n}\n\nexport function extractPrecisionScale(type: string): {\n precision?: number;\n scale?: number;\n} {\n const unwrapped = unwrapTypeModifiers(type);\n const decimalMatch = unwrapped.match(/Decimal(?:\\d+)?\\((\\d+)\\s*,\\s*(\\d+)\\)/i);\n if (!decimalMatch) return {};\n const precision = decimalMatch[1];\n const scale = decimalMatch[2];\n if (!precision || !scale) return {};\n return {\n precision: Number.parseInt(precision, 10),\n scale: Number.parseInt(scale, 10),\n };\n}\n\nexport function extractFixedStringLength(type: string): number | undefined {\n const unwrapped = unwrapTypeModifiers(type);\n const match = unwrapped.match(/^(?:FixedString|StringFixed)\\((\\d+)\\)$/i);\n if (!match) return undefined;\n const length = match[1];\n if (!length) return undefined;\n return Number.parseInt(length, 10);\n}\n\nexport function parseKeyExpression(expression?: string | null): string[] {\n if (!expression) return [];\n let value = expression.trim();\n if (!value) return [];\n if (/^tuple\\s*\\(/i.test(value) && value.endsWith(\")\")) {\n value = value.replace(/^tuple\\s*\\(/i, \"\").replace(/\\)$/, \"\");\n }\n\n const columns: string[] = [];\n let depth = 0;\n let token = \"\";\n for (const ch of value) {\n if (ch === \"(\") {\n depth += 1;\n token += ch;\n continue;\n }\n if (ch === \")\") {\n depth = Math.max(0, depth - 1);\n token += ch;\n continue;\n }\n if (ch === \",\" && depth === 0) {\n const col = token.trim();\n if (col) columns.push(stripWrapper(col));\n token = \"\";\n continue;\n }\n token += ch;\n }\n const last = token.trim();\n if (last) columns.push(stripWrapper(last));\n return columns.filter(Boolean);\n}\n\nfunction stripWrapper(value: string): string {\n const noQuotes = stripQuotes(value);\n const withoutTicks = noQuotes.replace(/`/g, \"\").trim();\n const parts = withoutTicks.split(\".\");\n return parts[parts.length - 1]?.trim() ?? \"\";\n}\n\nfunction stripQuotes(value: string): string {\n if (\n (value.startsWith('\"') && value.endsWith('\"')) ||\n (value.startsWith(\"'\") && value.endsWith(\"'\"))\n ) {\n return value.slice(1, -1);\n }\n return value;\n}\n","import type {\n\tClickHouseSettings,\n\tDataFormat,\n\tQueryParams,\n} from \"@clickhouse/client\";\nimport type {\n\tColumnSchema,\n\tIntrospectOptions,\n\tSchemaIntrospection,\n\tTableSchema,\n} from \"../schema/types\";\nimport { parseKeyExpression, unwrapTypeModifiers } from \"../utils/clickhouse\";\nimport type { DatabaseAdapter, DatabaseExecutionResult } from \"./types\";\n\nexport interface ClickHouseAdapterOptions {\n\t/** Optional logical database name used in introspection metadata. */\n\tdatabase?: string;\n\t/** Override the default response format used for query execution. */\n\tdefaultFormat?: DataFormat;\n\t/**\n\t * Optional database kind label. Defaults to \"clickhouse\" but allows\n\t * sub-classing/custom branding if needed.\n\t */\n\tkind?: SchemaIntrospection[\"db\"][\"kind\"];\n\t/**\n\t * Optional allow-list of table names.\n\t * When specified, introspection and queries are restricted to these tables only.\n\t * ClickHouse tables are not schema-qualified, so just provide table names.\n\t */\n\tallowedTables?: string[];\n}\n\nexport type ClickHouseQueryResult = { json: () => Promise<unknown> };\n\nexport type ClickHouseClientFn = (\n\tparams: QueryParams,\n) => Promise<\n\t| ClickHouseQueryResult\n\t| Array<Record<string, unknown>>\n\t| Record<string, unknown>[]\n>;\n\ninterface QueryOptions {\n\tparams?: Record<string, unknown>;\n\tformat?: DataFormat;\n\tsettings?: ClickHouseSettings;\n}\n\ntype TableRow = {\n\tname: string;\n\tengine: string;\n\tcomment: string | null;\n\tprimary_key: string | null;\n};\n\ntype ColumnRow = {\n\ttable: string;\n\tname: string;\n\ttype: string;\n\tposition: number;\n\tcomment: string | null;\n\tis_in_primary_key: string | number | null;\n};\n\n/**\n * Simplified ClickHouse adapter following IngestRequest format\n * Removed: indexes, constraints, statistics\n * Kept only: tables, columns (name, type, isPrimaryKey, comment)\n */\nexport class ClickHouseAdapter implements DatabaseAdapter {\n\tprivate readonly databaseName: string;\n\tprivate readonly defaultFormat: QueryParams[\"format\"];\n\tprivate readonly kind: SchemaIntrospection[\"db\"][\"kind\"];\n\tprivate readonly allowedTables?: string[];\n\n\tconstructor(\n\t\tprivate readonly clientFn: ClickHouseClientFn,\n\t\toptions: ClickHouseAdapterOptions = {},\n\t) {\n\t\tthis.databaseName = options.database ?? \"default\";\n\t\tthis.defaultFormat = options.defaultFormat ?? \"JSONEachRow\";\n\t\tthis.kind = options.kind ?? \"clickhouse\";\n\t\tif (options.allowedTables) {\n\t\t\tthis.allowedTables = normalizeTableFilter(options.allowedTables);\n\t\t}\n\t}\n\n\tasync execute(\n\t\tsql: string,\n\t\tparams?: Record<string, string | number | boolean | string[] | number[]>,\n\t): Promise<DatabaseExecutionResult> {\n\t\t// Validate query against allowed tables if restrictions are in place\n\t\tif (this.allowedTables) {\n\t\t\tthis.validateQueryTables(sql);\n\t\t}\n\n\t\tconst queryOptions: QueryOptions = {\n\t\t\tformat: this.defaultFormat,\n\t\t};\n\t\tif (params) {\n\t\t\tqueryOptions.params = params;\n\t\t}\n\n\t\tconst rows = await this.query<Record<string, unknown>>(sql, queryOptions);\n\t\tconst fields = rows.length > 0 ? Object.keys(rows[0] ?? {}) : [];\n\t\treturn { fields, rows };\n\t}\n\n\tasync validate(\n\t\tsql: string,\n\t\tparams?: Record<string, string | number | boolean | string[] | number[]>,\n\t): Promise<void> {\n\t\tconst queryOptions: QueryOptions = {\n\t\t\tformat: this.defaultFormat,\n\t\t};\n\t\tif (params) {\n\t\t\tqueryOptions.params = params;\n\t\t}\n\n\t\tawait this.query(`EXPLAIN ${sql}`, queryOptions);\n\t}\n\n\tgetDialect() {\n\t\treturn \"clickhouse\" as const;\n\t}\n\n\t/**\n\t * Simplified introspection: only collect table/column metadata for IngestRequest\n\t * No indexes, constraints, or statistics\n\t */\n\tasync introspect(options?: IntrospectOptions): Promise<SchemaIntrospection> {\n\t\t// Use adapter-level allowedTables if no specific tables provided in options\n\t\tconst tablesToIntrospect = options?.tables\n\t\t\t? normalizeTableFilter(options.tables)\n\t\t\t: this.allowedTables;\n\t\tconst allowTables = tablesToIntrospect ?? [];\n\t\tconst hasFilter = allowTables.length > 0;\n\t\tconst queryParams: Record<string, unknown> = {\n\t\t\tdb: this.databaseName,\n\t\t};\n\t\tif (hasFilter) {\n\t\t\tqueryParams.tables = allowTables;\n\t\t}\n\n\t\tconst filterClause = hasFilter ? \" AND name IN {tables:Array(String)}\" : \"\";\n\t\tconst tables = await this.query<TableRow>(\n\t\t\t`SELECT name, engine, comment, primary_key\n FROM system.tables\n WHERE database = {db:String}${filterClause}\n ORDER BY name`,\n\t\t\t{ params: queryParams },\n\t\t);\n\n\t\tconst columnFilterClause = hasFilter\n\t\t\t? \" AND table IN {tables:Array(String)}\"\n\t\t\t: \"\";\n\t\tconst columns = await this.query<ColumnRow>(\n\t\t\t`SELECT table, name, type, position, comment, is_in_primary_key\n FROM system.columns\n WHERE database = {db:String}${columnFilterClause}\n ORDER BY table, position`,\n\t\t\t{ params: queryParams },\n\t\t);\n\n\t\tconst columnsByTable = new Map<string, ColumnSchema[]>();\n\t\tfor (const rawColumn of columns) {\n\t\t\tconst list = columnsByTable.get(rawColumn.table) ?? [];\n\t\t\tlist.push(transformColumnRow(rawColumn));\n\t\t\tcolumnsByTable.set(rawColumn.table, list);\n\t\t}\n\n\t\tconst tableSchemas: TableSchema[] = tables.map((table) => {\n\t\t\tconst tableColumns = columnsByTable.get(table.name) ?? [];\n\t\t\tconst primaryKeyColumns = parseKeyExpression(table.primary_key);\n\n\t\t\t// Mark columns as primary key\n\t\t\tfor (const column of tableColumns) {\n\t\t\t\tcolumn.isPrimaryKey =\n\t\t\t\t\tcolumn.isPrimaryKey || primaryKeyColumns.includes(column.name);\n\t\t\t}\n\n\t\t\tconst base: TableSchema = {\n\t\t\t\tname: table.name,\n\t\t\t\tschema: this.databaseName,\n\t\t\t\ttype: asTableType(table.engine),\n\t\t\t\tcolumns: tableColumns,\n\t\t\t};\n\n\t\t\tconst comment = sanitize(table.comment);\n\t\t\tif (comment !== undefined) {\n\t\t\t\tbase.comment = comment;\n\t\t\t}\n\n\t\t\treturn base;\n\t\t});\n\n\t\treturn {\n\t\t\tdb: {\n\t\t\t\tkind: this.kind,\n\t\t\t\tname: this.databaseName,\n\t\t\t},\n\t\t\ttables: tableSchemas,\n\t\t\tintrospectedAt: new Date().toISOString(),\n\t\t};\n\t}\n\n\tprivate validateQueryTables(sql: string): void {\n\t\tif (!this.allowedTables || this.allowedTables.length === 0) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst allowedSet = new Set(this.allowedTables);\n\n\t\t// Extract potential table references from SQL\n\t\tconst tablePattern =\n\t\t\t/(?:FROM|JOIN)\\s+(?:FINAL\\s+)?(?:(?:[a-zA-Z_][a-zA-Z0-9_]*)\\.)?([\"'`]?[a-zA-Z_][a-zA-Z0-9_]*[\"'`]?)/gi;\n\t\tconst matches = sql.matchAll(tablePattern);\n\n\t\tfor (const match of matches) {\n\t\t\tconst table = match[1]?.replace(/[\"'`]/g, \"\");\n\t\t\tif (table) {\n\t\t\t\tif (!allowedSet.has(table)) {\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t`Query references table \"${table}\" which is not in the allowed tables list`,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tasync close(): Promise<void> {\n\t\t// No-op: lifecycle of the underlying client is controlled by the caller.\n\t}\n\n\tprivate async query<T>(sql: string, options?: QueryOptions): Promise<T[]> {\n\t\tconst params: QueryParams = {\n\t\t\tquery: sql,\n\t\t};\n\n\t\tconst format = options?.format ?? this.defaultFormat;\n\t\tif (format !== undefined) {\n\t\t\tparams.format = format;\n\t\t}\n\n\t\tif (options?.params) {\n\t\t\tparams.query_params = options.params;\n\t\t}\n\n\t\tif (options?.settings) {\n\t\t\tparams.clickhouse_settings = options.settings;\n\t\t}\n\n\t\tconst result = await this.clientFn(params);\n\t\treturn this.extractRows<T>(result);\n\t}\n\n\tprivate async extractRows<T>(\n\t\tresult:\n\t\t\t| ClickHouseQueryResult\n\t\t\t| Array<Record<string, unknown>>\n\t\t\t| Record<string, unknown>[],\n\t): Promise<T[]> {\n\t\tif (Array.isArray(result)) {\n\t\t\treturn result as T[];\n\t\t}\n\n\t\tif (\n\t\t\tresult &&\n\t\t\ttypeof (result as ClickHouseQueryResult).json === \"function\"\n\t\t) {\n\t\t\tconst payload = await (result as ClickHouseQueryResult).json();\n\t\t\treturn normalizePayload<T>(payload);\n\t\t}\n\n\t\treturn [];\n\t}\n}\n\nfunction normalizePayload<T>(payload: unknown): T[] {\n\tif (Array.isArray(payload)) {\n\t\treturn payload as T[];\n\t}\n\tif (payload && typeof payload === \"object\") {\n\t\tconst maybeData = (payload as { data?: unknown }).data;\n\t\tif (Array.isArray(maybeData)) {\n\t\t\treturn maybeData as T[];\n\t\t}\n\t}\n\treturn [];\n}\n\nfunction normalizeTableFilter(tables?: string[] | null): string[] {\n\tif (!tables?.length) return [];\n\tconst seen = new Set<string>();\n\tconst normalized: string[] = [];\n\tfor (const table of tables) {\n\t\tif (!table) continue;\n\t\tconst trimmed = table.trim();\n\t\tif (!trimmed) continue;\n\t\tconst parts = trimmed.split(\".\");\n\t\tconst tableName = parts[parts.length - 1];\n\t\tif (!tableName || seen.has(tableName)) continue;\n\t\tseen.add(tableName);\n\t\tnormalized.push(tableName);\n\t}\n\treturn normalized;\n}\n\nfunction transformColumnRow(row: ColumnRow): ColumnSchema {\n\tconst unwrappedType = unwrapTypeModifiers(row.type);\n\n\tconst column: ColumnSchema = {\n\t\tname: row.name,\n\t\ttype: unwrappedType,\n\t\trawType: row.type,\n\t\tisPrimaryKey: Boolean(toNumber(row.is_in_primary_key)),\n\t};\n\n\tconst comment = sanitize(row.comment);\n\tif (comment !== undefined) column.comment = comment;\n\n\treturn column;\n}\n\nfunction asTableType(engine: unknown): TableSchema[\"type\"] {\n\tif (typeof engine === \"string\") {\n\t\tconst normalized = engine.toLowerCase();\n\t\t// ClickHouse view engines: View, MaterializedView, LiveView\n\t\tif (normalized.includes(\"view\")) {\n\t\t\treturn \"view\";\n\t\t}\n\t}\n\treturn \"table\";\n}\n\nfunction sanitize(value: unknown): string | undefined {\n\tif (value === null || value === undefined) return undefined;\n\tconst trimmed = String(value).trim();\n\treturn trimmed.length ? trimmed : undefined;\n}\n\nfunction toNumber(value: unknown): number | undefined {\n\tif (value === null || value === undefined) return undefined;\n\tif (typeof value === \"number\") return value;\n\tconst parsed = Number.parseFloat(String(value));\n\treturn Number.isNaN(parsed) ? undefined : parsed;\n}\n","import type {\n\tColumnSchema,\n\tIntrospectOptions,\n\tSchemaIntrospection,\n\tTableSchema,\n} from \"../schema/types\";\nimport type { DatabaseAdapter, DatabaseExecutionResult } from \"./types\";\n\nexport interface PostgresQueryResult {\n\trows: Array<Record<string, unknown>>;\n\tfields: Array<{ name: string }>;\n}\n\nexport type PostgresClientFn = (\n\tsql: string,\n\tparams?: unknown[],\n) => Promise<PostgresQueryResult>;\n\nexport interface PostgresAdapterOptions {\n\t/** Logical database name used in introspection metadata. */\n\tdatabase?: string;\n\t/** Schema to assume when a table is provided without qualification. */\n\tdefaultSchema?: string;\n\t/** Optional database kind label. Defaults to \"postgres\". */\n\tkind?: SchemaIntrospection[\"db\"][\"kind\"];\n\t/**\n\t * Optional allow-list of table names (schema-qualified or bare).\n\t * When specified, introspection and queries are restricted to these tables only.\n\t */\n\tallowedTables?: string[];\n}\n\ntype TableRow = {\n\ttable_name: string;\n\tschema_name: string;\n\ttable_type: string;\n\tcomment: string | null;\n};\n\ntype ColumnRow = {\n\ttable_name: string;\n\ttable_schema: string;\n\tcolumn_name: string;\n\tdata_type: string;\n\tudt_name: string | null;\n\tis_primary_key: boolean;\n\tdescription: string | null;\n};\n\ninterface NormalizedTable {\n\tschema: string;\n\ttable: string;\n}\n\n/**\n * Simplified PostgreSQL adapter following IngestRequest format\n * Removed: indexes, constraints, foreign keys, statistics\n * Kept only: tables, columns (name, type, isPrimaryKey, comment)\n */\nexport class PostgresAdapter implements DatabaseAdapter {\n\tprivate readonly databaseName: string;\n\tprivate readonly defaultSchema: string;\n\tprivate readonly kind: SchemaIntrospection[\"db\"][\"kind\"];\n\tprivate readonly allowedTables?: NormalizedTable[];\n\n\tconstructor(\n\t\tprivate readonly clientFn: PostgresClientFn,\n\t\toptions: PostgresAdapterOptions = {},\n\t) {\n\t\tthis.databaseName = options.database ?? \"postgres\";\n\t\tthis.defaultSchema = options.defaultSchema ?? \"public\";\n\t\tthis.kind = options.kind ?? \"postgres\";\n\t\tif (options.allowedTables) {\n\t\t\tthis.allowedTables = normalizeTableFilter(\n\t\t\t\toptions.allowedTables,\n\t\t\t\tthis.defaultSchema,\n\t\t\t);\n\t\t}\n\t}\n\n\tasync execute(\n\t\tsql: string,\n\t\tparams?: Record<string, string | number | boolean | string[] | number[]>,\n\t): Promise<DatabaseExecutionResult> {\n\t\t// Validate query against allowed tables if restrictions are in place\n\t\tif (this.allowedTables) {\n\t\t\tthis.validateQueryTables(sql);\n\t\t}\n\n\t\t// Convert named params to positional array for PostgreSQL\n\t\tlet paramArray: unknown[] | undefined;\n\t\tif (params) {\n\t\t\tparamArray = this.convertNamedToPositionalParams(params);\n\t\t}\n\n\t\tconst result = await this.clientFn(sql, paramArray);\n\t\tconst fields = result.fields.map((f) => f.name);\n\t\treturn { fields, rows: result.rows };\n\t}\n\n\tprivate validateQueryTables(sql: string): void {\n\t\tif (!this.allowedTables || this.allowedTables.length === 0) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst allowedSet = new Set(\n\t\t\tthis.allowedTables.map((t) => tableKey(t.schema, t.table)),\n\t\t);\n\n\t\t// Extract potential table references from SQL\n\t\tconst tablePattern =\n\t\t\t/(?:FROM|JOIN)\\s+(?:ONLY\\s+)?(?:([a-zA-Z_][a-zA-Z0-9_]*)\\.)?([\"']?[a-zA-Z_][a-zA-Z0-9_]*[\"']?)/gi;\n\t\tconst matches = sql.matchAll(tablePattern);\n\n\t\tfor (const match of matches) {\n\t\t\tconst schema = match[1] ?? this.defaultSchema;\n\t\t\tconst table = match[2]?.replace(/['\"]/g, \"\");\n\t\t\tif (table) {\n\t\t\t\tconst key = tableKey(schema, table);\n\t\t\t\tif (!allowedSet.has(key)) {\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t`Query references table \"${schema}.${table}\" which is not in the allowed tables list`,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Convert named params to positional array for PostgreSQL\n\t * PostgreSQL expects $1, $2, $3 in SQL and an array of values [val1, val2, val3]\n\t */\n\tprivate convertNamedToPositionalParams(\n\t\tparams: Record<string, string | number | boolean | string[] | number[]>,\n\t): unknown[] {\n\t\t// Separate numeric and named keys\n\t\tconst numericKeys = Object.keys(params)\n\t\t\t.filter((k) => /^\\d+$/.test(k))\n\t\t\t.map((k) => Number.parseInt(k, 10))\n\t\t\t.sort((a, b) => a - b);\n\n\t\tconst namedKeys = Object.keys(params)\n\t\t\t.filter((k) => !/^\\d+$/.test(k))\n\t\t\t.sort(); // Alphabetical order for consistency\n\n\t\t// Build positional array\n\t\tconst positionalParams: unknown[] = [];\n\n\t\t// First, add values from numeric keys (in sorted order)\n\t\tfor (const key of numericKeys) {\n\t\t\tlet val: unknown = params[String(key)];\n\t\t\tif (typeof val === \"string\") {\n\t\t\t\t// Resolve placeholder tokens like `<tenant_id>` to their named values\n\t\t\t\tconst match = val.match(/^<([a-zA-Z0-9_]+)>$/);\n\t\t\t\tconst namedKey = match?.[1];\n\t\t\t\tif (namedKey && namedKey in params) {\n\t\t\t\t\tval = params[namedKey as keyof typeof params];\n\t\t\t\t}\n\t\t\t}\n\t\t\tpositionalParams.push(val);\n\t\t}\n\n\t\t// Then, add values from named keys (in alphabetical order)\n\t\tfor (const key of namedKeys) {\n\t\t\tconst val = params[key];\n\t\t\tpositionalParams.push(val);\n\t\t}\n\n\t\treturn positionalParams;\n\t}\n\n\tasync validate(\n\t\tsql: string,\n\t\tparams?: Record<string, string | number | boolean | string[] | number[]>,\n\t): Promise<void> {\n\t\tlet paramArray: unknown[] | undefined;\n\t\tif (params) {\n\t\t\tparamArray = this.convertNamedToPositionalParams(params);\n\t\t}\n\n\t\tawait this.clientFn(`EXPLAIN ${sql}`, paramArray);\n\t}\n\n\tgetDialect() {\n\t\treturn \"postgres\" as const;\n\t}\n\n\t/**\n\t * Simplified introspection: only collect table/column metadata for IngestRequest\n\t * No indexes, constraints, or statistics\n\t */\n\tasync introspect(options?: IntrospectOptions): Promise<SchemaIntrospection> {\n\t\t// Use adapter-level allowedTables if no specific tables provided in options\n\t\tconst tablesToIntrospect = options?.tables\n\t\t\t? normalizeTableFilter(options.tables, this.defaultSchema)\n\t\t\t: this.allowedTables;\n\t\tconst normalizedTables = tablesToIntrospect ?? [];\n\n\t\tconst tablesResult = await this.clientFn(\n\t\t\tbuildTablesQuery(normalizedTables),\n\t\t);\n\t\tconst tableRows = tablesResult.rows as TableRow[];\n\n\t\tconst columnsResult = await this.clientFn(\n\t\t\tbuildColumnsQuery(normalizedTables),\n\t\t);\n\t\tconst columnRows = columnsResult.rows as ColumnRow[];\n\n\t\tconst tablesByKey = new Map<string, TableSchema>();\n\n\t\t// Build tables\n\t\tfor (const row of tableRows) {\n\t\t\tconst key = tableKey(row.schema_name, row.table_name);\n\t\t\tconst table: TableSchema = {\n\t\t\t\tname: row.table_name,\n\t\t\t\tschema: row.schema_name,\n\t\t\t\ttype: asTableType(row.table_type),\n\t\t\t\tcolumns: [],\n\t\t\t};\n\n\t\t\tconst comment = sanitize(row.comment);\n\t\t\tif (comment !== undefined) {\n\t\t\t\ttable.comment = comment;\n\t\t\t}\n\n\t\t\ttablesByKey.set(key, table);\n\t\t}\n\n\t\t// Build columns\n\t\tfor (const row of columnRows) {\n\t\t\tconst key = tableKey(row.table_schema, row.table_name);\n\t\t\tconst table = tablesByKey.get(key);\n\t\t\tif (!table) continue;\n\n\t\t\tconst column: ColumnSchema = {\n\t\t\t\tname: row.column_name,\n\t\t\t\ttype: row.data_type,\n\t\t\t\tisPrimaryKey: row.is_primary_key,\n\t\t\t};\n\n\t\t\tconst rawType = row.udt_name ?? undefined;\n\t\t\tif (rawType !== undefined) column.rawType = rawType;\n\n\t\t\tconst comment = sanitize(row.description);\n\t\t\tif (comment !== undefined) column.comment = comment;\n\n\t\t\ttable.columns.push(column);\n\t\t}\n\n\t\tconst tables = Array.from(tablesByKey.values()).sort((a, b) => {\n\t\t\tif (a.schema === b.schema) {\n\t\t\t\treturn a.name.localeCompare(b.name);\n\t\t\t}\n\t\t\treturn a.schema.localeCompare(b.schema);\n\t\t});\n\n\t\treturn {\n\t\t\tdb: {\n\t\t\t\tkind: this.kind,\n\t\t\t\tname: this.databaseName,\n\t\t\t},\n\t\t\ttables,\n\t\t\tintrospectedAt: new Date().toISOString(),\n\t\t};\n\t}\n}\n\nfunction normalizeTableFilter(\n\ttables: string[] | undefined,\n\tdefaultSchema: string,\n): NormalizedTable[] {\n\tif (!tables?.length) return [];\n\tconst normalized: NormalizedTable[] = [];\n\tconst seen = new Set<string>();\n\n\tfor (const raw of tables) {\n\t\tif (!raw) continue;\n\t\tconst trimmed = raw.trim();\n\t\tif (!trimmed) continue;\n\t\tconst parts = trimmed.split(\".\");\n\t\tconst table = parts.pop() ?? \"\";\n\t\tconst schema = parts.pop() ?? defaultSchema;\n\t\tif (!isSafeIdentifier(schema) || !isSafeIdentifier(table)) {\n\t\t\tcontinue;\n\t\t}\n\t\tconst key = tableKey(schema, table);\n\t\tif (seen.has(key)) continue;\n\t\tseen.add(key);\n\t\tnormalized.push({ schema, table });\n\t}\n\n\treturn normalized;\n}\n\nfunction buildTablesQuery(tables: NormalizedTable[]): string {\n\tconst filter = buildFilterClause(tables, \"n.nspname\", \"c.relname\");\n\treturn `SELECT\n c.relname AS table_name,\n n.nspname AS schema_name,\n CASE c.relkind\n WHEN 'r' THEN 'table'\n WHEN 'v' THEN 'view'\n WHEN 'm' THEN 'materialized_view'\n ELSE c.relkind::text\n END AS table_type,\n obj_description(c.oid) AS comment\n FROM pg_class c\n JOIN pg_namespace n ON n.oid = c.relnamespace\n WHERE n.nspname NOT IN ('pg_catalog', 'information_schema')\n AND c.relkind IN ('r', 'v', 'm')\n ${filter}\n ORDER BY n.nspname, c.relname;`;\n}\n\nfunction buildColumnsQuery(tables: NormalizedTable[]): string {\n\tconst filter = buildFilterClause(\n\t\ttables,\n\t\t\"cols.table_schema\",\n\t\t\"cols.table_name\",\n\t);\n\treturn `SELECT\n cols.table_name,\n cols.table_schema,\n cols.column_name,\n cols.data_type,\n cols.udt_name,\n pgd.description,\n EXISTS(\n SELECT 1\n FROM information_schema.table_constraints tc\n JOIN information_schema.key_column_usage kcu\n ON tc.constraint_name = kcu.constraint_name\n AND tc.table_schema = kcu.table_schema\n WHERE tc.constraint_type = 'PRIMARY KEY'\n AND tc.table_schema = cols.table_schema\n AND tc.table_name = cols.table_name\n AND kcu.column_name = cols.column_name\n ) AS is_primary_key\n FROM information_schema.columns cols\n LEFT JOIN pg_catalog.pg_class c\n ON c.relname = cols.table_name\n AND c.relkind IN ('r', 'v', 'm')\n LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace\n LEFT JOIN pg_catalog.pg_attribute attr\n ON attr.attrelid = c.oid\n AND attr.attname = cols.column_name\n LEFT JOIN pg_catalog.pg_description pgd\n ON pgd.objoid = attr.attrelid AND pgd.objsubid = attr.attnum\n WHERE cols.table_schema NOT IN ('pg_catalog', 'information_schema')\n ${filter}\n ORDER BY cols.table_schema, cols.table_name, cols.ordinal_position;`;\n}\n\nfunction buildFilterClause(\n\ttables: NormalizedTable[],\n\tschemaExpr: string,\n\ttableExpr: string,\n): string {\n\tif (!tables.length) return \"\";\n\tconst clauses = tables.map(({ schema, table }) => {\n\t\treturn `(${schemaExpr} = '${schema}' AND ${tableExpr} = '${table}')`;\n\t});\n\treturn `AND (${clauses.join(\" OR \")})`;\n}\n\nfunction tableKey(schema: string, table: string): string {\n\treturn `${schema}.${table}`;\n}\n\nfunction isSafeIdentifier(value: string): boolean {\n\treturn /^[A-Za-z_][A-Za-z0-9_]*$/.test(value);\n}\n\nfunction asTableType(value: string): TableSchema[\"type\"] {\n\tconst normalized = value.toLowerCase();\n\tif (normalized.includes(\"view\")) {\n\t\treturn normalized.includes(\"materialized\") ? \"materialized_view\" : \"view\";\n\t}\n\treturn \"table\";\n}\n\nfunction sanitize(value: unknown): string | undefined {\n\tif (value === null || value === undefined) return undefined;\n\tconst trimmed = String(value).trim();\n\treturn trimmed.length ? trimmed : undefined;\n}\n","import { createSign } from \"node:crypto\";\n\n/**\n * Deep module: Hides JWT signing and HTTP complexity behind simple interface\n * Following Ousterhout's principle: \"Pull complexity downward\"\n */\nexport class ApiClient {\n\tprivate readonly baseUrl: string;\n\tprivate readonly privateKey: string;\n\tprivate readonly organizationId: string;\n\tprivate readonly defaultTenantId?: string;\n\tprivate readonly additionalHeaders?: Record<string, string>;\n\tprivate readonly fetchImpl: typeof fetch;\n\n\tconstructor(\n\t\tbaseUrl: string,\n\t\tprivateKey: string,\n\t\torganizationId: string,\n\t\toptions?: {\n\t\t\tdefaultTenantId?: string;\n\t\t\tadditionalHeaders?: Record<string, string>;\n\t\t\tfetch?: typeof fetch;\n\t\t},\n\t) {\n\t\tif (!baseUrl) {\n\t\t\tthrow new Error(\"Base URL is required\");\n\t\t}\n\t\tif (!privateKey) {\n\t\t\tthrow new Error(\"Private key is required\");\n\t\t}\n\t\tif (!organizationId) {\n\t\t\tthrow new Error(\"Organization ID is required\");\n\t\t}\n\n\t\tthis.baseUrl = baseUrl.replace(/\\/+$/, \"\");\n\t\tthis.privateKey = privateKey;\n\t\tthis.organizationId = organizationId;\n\t\tthis.defaultTenantId = options?.defaultTenantId;\n\t\tthis.additionalHeaders = options?.additionalHeaders;\n\t\tthis.fetchImpl = options?.fetch ?? globalThis.fetch;\n\n\t\tif (!this.fetchImpl) {\n\t\t\tthrow new Error(\n\t\t\t\t\"Fetch implementation not found. Provide options.fetch or use Node 18+.\",\n\t\t\t);\n\t\t}\n\t}\n\n\tgetDefaultTenantId(): string | undefined {\n\t\treturn this.defaultTenantId;\n\t}\n\n\tasync get<T>(\n\t\tpath: string,\n\t\ttenantId: string,\n\t\tuserId?: string,\n\t\tscopes?: string[],\n\t\tsignal?: AbortSignal,\n\t\tsessionId?: string,\n\t): Promise<T> {\n\t\treturn await this.request<T>(path, {\n\t\t\tmethod: \"GET\",\n\t\t\theaders: await this.buildHeaders(\n\t\t\t\ttenantId,\n\t\t\t\tuserId,\n\t\t\t\tscopes,\n\t\t\t\tfalse,\n\t\t\t\tsessionId,\n\t\t\t),\n\t\t\tsignal,\n\t\t});\n\t}\n\n\tasync post<T>(\n\t\tpath: string,\n\t\tbody: unknown,\n\t\ttenantId: string,\n\t\tuserId?: string,\n\t\tscopes?: string[],\n\t\tsignal?: AbortSignal,\n\t\tsessionId?: string,\n\t): Promise<T> {\n\t\treturn await this.request<T>(path, {\n\t\t\tmethod: \"POST\",\n\t\t\theaders: await this.buildHeaders(\n\t\t\t\ttenantId,\n\t\t\t\tuserId,\n\t\t\t\tscopes,\n\t\t\t\ttrue,\n\t\t\t\tsessionId,\n\t\t\t),\n\t\t\tbody: JSON.stringify(body ?? {}),\n\t\t\tsignal,\n\t\t});\n\t}\n\n\tasync put<T>(\n\t\tpath: string,\n\t\tbody: unknown,\n\t\ttenantId: string,\n\t\tuserId?: string,\n\t\tscopes?: string[],\n\t\tsignal?: AbortSignal,\n\t\tsessionId?: string,\n\t): Promise<T> {\n\t\treturn await this.request<T>(path, {\n\t\t\tmethod: \"PUT\",\n\t\t\theaders: await this.buildHeaders(\n\t\t\t\ttenantId,\n\t\t\t\tuserId,\n\t\t\t\tscopes,\n\t\t\t\ttrue,\n\t\t\t\tsessionId,\n\t\t\t),\n\t\t\tbody: JSON.stringify(body ?? {}),\n\t\t\tsignal,\n\t\t});\n\t}\n\n\tasync delete<T = void>(\n\t\tpath: string,\n\t\ttenantId: string,\n\t\tuserId?: string,\n\t\tscopes?: string[],\n\t\tsignal?: AbortSignal,\n\t\tsessionId?: string,\n\t): Promise<T> {\n\t\treturn await this.request<T>(path, {\n\t\t\tmethod: \"DELETE\",\n\t\t\theaders: await this.buildHeaders(\n\t\t\t\ttenantId,\n\t\t\t\tuserId,\n\t\t\t\tscopes,\n\t\t\t\tfalse,\n\t\t\t\tsessionId,\n\t\t\t),\n\t\t\tsignal,\n\t\t});\n\t}\n\n\tprivate async request<T>(path: string, init: RequestInit): Promise<T> {\n\t\tconst response = await this.fetchImpl(`${this.baseUrl}${path}`, init);\n\t\tconst text = await response.text();\n\t\tlet json: any;\n\t\ttry {\n\t\t\tjson = text ? JSON.parse(text) : undefined;\n\t\t} catch {\n\t\t\tjson = undefined;\n\t\t}\n\n\t\tif (!response.ok) {\n\t\t\tconst error = new Error(\n\t\t\t\tjson?.error || response.statusText || \"Request failed\",\n\t\t\t);\n\t\t\t(error as any).status = response.status;\n\t\t\tif (json?.details) (error as any).details = json.details;\n\t\t\tthrow error;\n\t\t}\n\n\t\treturn json as T;\n\t}\n\n\tprivate async buildHeaders(\n\t\ttenantId: string,\n\t\tuserId?: string,\n\t\tscopes?: string[],\n\t\tincludeJson: boolean = true,\n\t\tsessionId?: string,\n\t): Promise<Record<string, string>> {\n\t\tconst token = await this.generateJWT(tenantId, userId, scopes);\n\t\tconst headers: Record<string, string> = {\n\t\t\tAuthorization: `Bearer ${token}`,\n\t\t\tAccept: \"application/json\",\n\t\t};\n\t\tif (includeJson) {\n\t\t\theaders[\"Content-Type\"] = \"application/json\";\n\t\t}\n\t\tif (sessionId) {\n\t\t\theaders[\"x-session-id\"] = sessionId;\n\t\t}\n\t\tif (this.additionalHeaders) {\n\t\t\tObject.assign(headers, this.additionalHeaders);\n\t\t}\n\t\treturn headers;\n\t}\n\n\tprivate async generateJWT(\n\t\ttenantId: string,\n\t\tuserId?: string,\n\t\tscopes?: string[],\n\t): Promise<string> {\n\t\tconst header = {\n\t\t\talg: \"RS256\",\n\t\t\ttyp: \"JWT\",\n\t\t};\n\n\t\tconst payload: Record<string, unknown> = {\n\t\t\torganizationId: this.organizationId,\n\t\t\ttenantId,\n\t\t};\n\n\t\tif (userId) payload.userId = userId;\n\t\tif (scopes?.length) payload.scopes = scopes;\n\n\t\tconst encodeJson = (obj: unknown): string => {\n\t\t\tconst json = JSON.stringify(obj);\n\t\t\tconst base64 = Buffer.from(json).toString(\"base64\");\n\t\t\t// base64url encoding: replace non-url chars and strip padding\n\t\t\treturn base64.replace(/\\+/g, \"-\").replace(/\\//g, \"_\").replace(/=+$/g, \"\");\n\t\t};\n\n\t\tconst encodedHeader = encodeJson(header);\n\t\tconst encodedPayload = encodeJson(payload);\n\t\tconst data = `${encodedHeader}.${encodedPayload}`;\n\n\t\tconst signer = createSign(\"RSA-SHA256\");\n\t\tsigner.update(data);\n\t\tsigner.end();\n\n\t\tconst signature = signer.sign(this.privateKey);\n\t\tconst encodedSignature = signature\n\t\t\t.toString(\"base64\")\n\t\t\t.replace(/\\+/g, \"-\")\n\t\t\t.replace(/\\//g, \"_\")\n\t\t\t.replace(/=+$/g, \"\");\n\n\t\treturn `${data}.${encodedSignature}`;\n\t}\n}\n","import type { DatabaseAdapter, DatabaseDialect } from \"../adapters/types\";\n\nexport type ParamValue = string | number | boolean | string[] | number[];\nexport type ParamRecord = Record<string, ParamValue>;\n\nexport interface DatabaseMetadata {\n\tname: string;\n\tdialect: DatabaseDialect;\n\tdescription?: string;\n\ttags?: string[];\n\ttenantFieldName?: string;\n\ttenantFieldType?: string;\n\tenforceTenantIsolation?: boolean;\n}\n\nexport interface DatabaseExecutionResult {\n\trows: Array<Record<string, unknown>>;\n\tfields: string[];\n}\n\n/**\n * Deep module: Hides SQL execution complexity and tenant isolation logic\n * Following Ousterhout's principle: \"Information hiding\"\n */\nexport class QueryEngine {\n\tprivate databases = new Map<string, DatabaseAdapter>();\n\tprivate databaseMetadata = new Map<string, DatabaseMetadata>();\n\tprivate defaultDatabase?: string;\n\n\tattachDatabase(name: string, adapter: DatabaseAdapter, metadata: DatabaseMetadata): void {\n\t\tthis.databases.set(name, adapter);\n\t\tthis.databaseMetadata.set(name, metadata);\n\t\tif (!this.defaultDatabase) {\n\t\t\tthis.defaultDatabase = name;\n\t\t}\n\t}\n\n\tgetDatabase(name?: string): DatabaseAdapter {\n\t\tconst dbName = name ?? this.defaultDatabase;\n\t\tif (!dbName) {\n\t\t\tthrow new Error(\"No database attached.\");\n\t\t}\n\t\tconst adapter = this.databases.get(dbName);\n\t\tif (!adapter) {\n\t\t\tthrow new Error(\n\t\t\t\t`Database '${dbName}' not found. Attached: ${Array.from(\n\t\t\t\t\tthis.databases.keys(),\n\t\t\t\t).join(\", \")}`,\n\t\t\t);\n\t\t}\n\t\treturn adapter;\n\t}\n\n\tgetDatabaseMetadata(name?: string): DatabaseMetadata | undefined {\n\t\tconst dbName = name ?? this.defaultDatabase;\n\t\tif (!dbName) return undefined;\n\t\treturn this.databaseMetadata.get(dbName);\n\t}\n\n\tgetDefaultDatabase(): string | undefined {\n\t\treturn this.defaultDatabase;\n\t}\n\n\tasync validateAndExecute(\n\t\tsql: string,\n\t\tparams: ParamRecord,\n\t\tdatabaseName: string,\n\t\ttenantId: string,\n\t): Promise<DatabaseExecutionResult> {\n\t\tconst adapter = this.getDatabase(databaseName);\n\t\tconst metadata = this.getDatabaseMetadata(databaseName);\n\n\t\t// Apply tenant isolation if configured\n\t\tlet finalSql = sql;\n\t\tif (metadata) {\n\t\t\tfinalSql = this.ensureTenantIsolation(sql, params, metadata, tenantId);\n\t\t}\n\n\t\t// Validate SQL\n\t\tawait adapter.validate(finalSql, params);\n\n\t\t// Execute\n\t\tconst result = await adapter.execute(finalSql, params);\n\t\treturn {\n\t\t\trows: result.rows,\n\t\t\tfields: result.fields,\n\t\t};\n\t}\n\n\tasync execute(\n\t\tsql: string,\n\t\tparams: ParamRecord | undefined,\n\t\tdatabaseName?: string,\n\t): Promise<Array<Record<string, unknown>>> {\n\t\ttry {\n\t\t\tconst adapter = this.getDatabase(databaseName);\n\t\t\tconst result = await adapter.execute(sql, params);\n\t\t\treturn result.rows;\n\t\t} catch (error) {\n\t\t\tconsole.warn(\n\t\t\t\t`Failed to execute SQL locally for database '${databaseName}':`,\n\t\t\t\terror,\n\t\t\t);\n\t\t\treturn [];\n\t\t}\n\t}\n\n\tmapGeneratedParams(params: Array<Record<string, unknown>>): ParamRecord {\n\t\tconst record: ParamRecord = {};\n\n\t\tparams.forEach((param, index) => {\n\t\t\tconst value = param.value as ParamValue | undefined;\n\t\t\tif (value === undefined) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst nameCandidate =\n\t\t\t\t(typeof param.name === \"string\" && param.name.trim()) ||\n\t\t\t\t(typeof param.placeholder === \"string\" && param.placeholder.trim()) ||\n\t\t\t\t(typeof param.position === \"number\" && String(param.position)) ||\n\t\t\t\tString(index + 1);\n\t\t\tconst key = nameCandidate.replace(/[{}:$]/g, \"\").trim();\n\t\t\trecord[key] = value;\n\t\t});\n\n\t\treturn record;\n\t}\n\n\tprivate ensureTenantIsolation(\n\t\tsql: string,\n\t\tparams: ParamRecord,\n\t\tmetadata: DatabaseMetadata,\n\t\ttenantId: string,\n\t): string {\n\t\tif (\n\t\t\t!metadata.tenantFieldName ||\n\t\t\tmetadata.enforceTenantIsolation === false\n\t\t) {\n\t\t\treturn sql;\n\t\t}\n\n\t\tconst tenantField = metadata.tenantFieldName;\n\t\tconst paramKey = tenantField;\n\t\tparams[paramKey] = tenantId;\n\n\t\tconst normalizedSql = sql.toLowerCase();\n\t\tif (normalizedSql.includes(tenantField.toLowerCase())) {\n\t\t\treturn sql;\n\t\t}\n\n\t\tconst tenantPredicate =\n\t\t\tmetadata.dialect === \"clickhouse\"\n\t\t\t\t? `${tenantField} = {${tenantField}:${metadata.tenantFieldType ?? \"String\"}}`\n\t\t\t\t: `${tenantField} = '${tenantId}'`;\n\n\t\tif (/\\bwhere\\b/i.test(sql)) {\n\t\t\treturn sql.replace(\n\t\t\t\t/\\bwhere\\b/i,\n\t\t\t\t(match) => `${match} ${tenantPredicate} AND `,\n\t\t\t);\n\t\t}\n\n\t\treturn `${sql} WHERE ${tenantPredicate}`;\n\t}\n}\n","import type { ApiClient } from \"../core/client\";\nimport type { ParamRecord, QueryEngine } from \"../core/query-engine\";\n\nexport interface SdkChart {\n\tid: string;\n\ttitle: string;\n\tdescription: string | null;\n\tsql: string;\n\tsql_params: Record<string, unknown> | null;\n\tvega_lite_spec: Record<string, unknown>;\n\tquery_id: string | null;\n\torganization_id: string | null;\n\ttenant_id: string | null;\n\tuser_id: string | null;\n\tcreated_at: string | null;\n\tupdated_at: string | null;\n\tactive?: boolean;\n\ttarget_db?: string | null;\n}\n\nexport interface ChartCreateInput {\n\ttitle: string;\n\tdescription?: string;\n\tsql: string;\n\tsql_params?: Record<string, unknown>;\n\tvega_lite_spec: Record<string, unknown>;\n\tquery_id?: string;\n\ttarget_db?: string;\n}\n\nexport interface ChartUpdateInput {\n\ttitle?: string;\n\tdescription?: string;\n\tsql?: string;\n\tsql_params?: Record<string, unknown>;\n\tvega_lite_spec?: Record<string, unknown>;\n\ttarget_db?: string;\n}\n\nexport interface PaginationQuery {\n\tpage?: number;\n\tlimit?: number;\n}\n\nexport interface PaginationInfo {\n\tpage: number;\n\tlimit: number;\n\ttotal: number;\n\ttotalPages: number;\n\thasNext: boolean;\n\thasPrev: boolean;\n}\n\nexport interface PaginatedResponse<T> {\n\tdata: T[];\n\tpagination: PaginationInfo;\n}\n\nexport interface ChartListOptions {\n\ttenantId?: string;\n\tuserId?: string;\n\tscopes?: string[];\n\tpagination?: PaginationQuery;\n\tsortBy?: \"title\" | \"user_id\" | \"created_at\" | \"updated_at\";\n\tsortDir?: \"asc\" | \"desc\";\n\ttitle?: string;\n\tuserFilter?: string;\n\tcreatedFrom?: string;\n\tcreatedTo?: string;\n\tupdatedFrom?: string;\n\tupdatedTo?: string;\n\tincludeData?: boolean;\n}\n\ninterface RequestOptions {\n\ttenantId?: string;\n\tuserId?: string;\n\tscopes?: string[];\n}\n\n/**\n * Route module for Chart CRUD operations\n * Simple pass-through to backend with optional data hydration\n */\nexport async function createChart(\n\tclient: ApiClient,\n\tbody: ChartCreateInput,\n\toptions?: RequestOptions,\n\tsignal?: AbortSignal,\n): Promise<SdkChart> {\n\tconst tenantId = resolveTenantId(client, options?.tenantId);\n\treturn await client.post<SdkChart>(\n\t\t\"/charts\",\n\t\tbody,\n\t\ttenantId,\n\t\toptions?.userId,\n\t\toptions?.scopes,\n\t\tsignal,\n\t);\n}\n\nexport async function listCharts(\n\tclient: ApiClient,\n\tqueryEngine: QueryEngine,\n\toptions?: ChartListOptions,\n\tsignal?: AbortSignal,\n): Promise<PaginatedResponse<SdkChart>> {\n\tconst tenantId = resolveTenantId(client, options?.tenantId);\n\tconst params = new URLSearchParams();\n\tif (options?.pagination?.page)\n\t\tparams.set(\"page\", `${options.pagination.page}`);\n\tif (options?.pagination?.limit)\n\t\tparams.set(\"limit\", `${options.pagination.limit}`);\n\tif (options?.sortBy) params.set(\"sort_by\", options.sortBy);\n\tif (options?.sortDir) params.set(\"sort_dir\", options.sortDir);\n\tif (options?.title) params.set(\"title\", options.title);\n\tif (options?.userFilter) params.set(\"user_id\", options.userFilter);\n\tif (options?.createdFrom) params.set(\"created_from\", options.createdFrom);\n\tif (options?.createdTo) params.set(\"created_to\", options.createdTo);\n\tif (options?.updatedFrom) params.set(\"updated_from\", options.updatedFrom);\n\tif (options?.updatedTo) params.set(\"updated_to\", options.updatedTo);\n\n\tconst response = await client.get<PaginatedResponse<SdkChart>>(\n\t\t`/charts${params.toString() ? `?${params.toString()}` : \"\"}`,\n\t\ttenantId,\n\t\toptions?.userId,\n\t\toptions?.scopes,\n\t\tsignal,\n\t);\n\n\tif (options?.includeData) {\n\t\tresponse.data = await Promise.all(\n\t\t\tresponse.data.map(async (chart) => ({\n\t\t\t\t...chart,\n\t\t\t\tvega_lite_spec: {\n\t\t\t\t\t...chart.vega_lite_spec,\n\t\t\t\t\tdata: {\n\t\t\t\t\t\tvalues: await queryEngine.execute(\n\t\t\t\t\t\t\tchart.sql,\n\t\t\t\t\t\t\t(chart.sql_params as ParamRecord | null) ?? undefined,\n\t\t\t\t\t\t\tchart.target_db ?? undefined,\n\t\t\t\t\t\t),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t})),\n\t\t);\n\t}\n\n\treturn response;\n}\n\nexport async function getChart(\n\tclient: ApiClient,\n\tqueryEngine: QueryEngine,\n\tid: string,\n\toptions?: RequestOptions,\n\tsignal?: AbortSignal,\n): Promise<SdkChart> {\n\tconst tenantId = resolveTenantId(client, options?.tenantId);\n\tconst chart = await client.get<SdkChart>(\n\t\t`/charts/${encodeURIComponent(id)}`,\n\t\ttenantId,\n\t\toptions?.userId,\n\t\toptions?.scopes,\n\t\tsignal,\n\t);\n\n\treturn {\n\t\t...chart,\n\t\tvega_lite_spec: {\n\t\t\t...chart.vega_lite_spec,\n\t\t\tdata: {\n\t\t\t\tvalues: await queryEngine.execute(\n\t\t\t\t\tchart.sql,\n\t\t\t\t\t(chart.sql_params as ParamRecord | null) ?? undefined,\n\t\t\t\t\tchart.target_db ?? undefined,\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t};\n}\n\nexport async function updateChart(\n\tclient: ApiClient,\n\tid: string,\n\tbody: ChartUpdateInput,\n\toptions?: RequestOptions,\n\tsignal?: AbortSignal,\n): Promise<SdkChart> {\n\tconst tenantId = resolveTenantId(client, options?.tenantId);\n\treturn await client.put<SdkChart>(\n\t\t`/charts/${encodeURIComponent(id)}`,\n\t\tbody,\n\t\ttenantId,\n\t\toptions?.userId,\n\t\toptions?.scopes,\n\t\tsignal,\n\t);\n}\n\nexport async function deleteChart(\n\tclient: ApiClient,\n\tid: string,\n\toptions?: RequestOptions,\n\tsignal?: AbortSignal,\n): Promise<void> {\n\tconst tenantId = resolveTenantId(client, options?.tenantId);\n\tawait client.delete(\n\t\t`/charts/${encodeURIComponent(id)}`,\n\t\ttenantId,\n\t\toptions?.userId,\n\t\toptions?.scopes,\n\t\tsignal,\n\t);\n}\n\nfunction resolveTenantId(client: ApiClient, tenantId?: string): string {\n\tconst resolved = tenantId ?? client.getDefaultTenantId();\n\tif (!resolved) {\n\t\tthrow new Error(\n\t\t\t\"tenantId is required. Provide it per request or via defaultTenantId option.\",\n\t\t);\n\t}\n\treturn resolved;\n}\n","import type { ApiClient } from \"../core/client\";\nimport type { QueryEngine } from \"../core/query-engine\";\nimport * as charts from \"./charts\";\n\nexport interface SdkActiveChart {\n\tid: string;\n\tchart_id: string;\n\torder: number | null;\n\tmeta: Record<string, unknown> | null;\n\torganization_id: string | null;\n\ttenant_id: string | null;\n\tuser_id: string | null;\n\tcreated_at: string | null;\n\tupdated_at: string | null;\n\tchart?: charts.SdkChart | null;\n}\n\nexport interface ActiveChartCreateInput {\n\tchart_id: string;\n\torder?: number;\n\tmeta?: Record<string, unknown>;\n}\n\nexport interface ActiveChartUpdateInput {\n\tchart_id?: string;\n\torder?: number;\n\tmeta?: Record<string, unknown>;\n}\n\nexport interface ActiveChartListOptions extends charts.ChartListOptions {\n\twithData?: boolean;\n}\n\ninterface RequestOptions {\n\ttenantId?: string;\n\tuserId?: string;\n\tscopes?: string[];\n}\n\n/**\n * Route module for Active Chart CRUD operations\n * Simple pass-through to backend with optional chart data hydration\n */\nexport async function createActiveChart(\n\tclient: ApiClient,\n\tbody: ActiveChartCreateInput,\n\toptions?: RequestOptions,\n\tsignal?: AbortSignal,\n): Promise<SdkActiveChart> {\n\tconst tenantId = resolveTenantId(client, options?.tenantId);\n\treturn await client.post<SdkActiveChart>(\n\t\t\"/active-charts\",\n\t\tbody,\n\t\ttenantId,\n\t\toptions?.userId,\n\t\toptions?.scopes,\n\t\tsignal,\n\t);\n}\n\nexport async function listActiveCharts(\n\tclient: ApiClient,\n\tqueryEngine: QueryEngine,\n\toptions?: ActiveChartListOptions,\n\tsignal?: AbortSignal,\n): Promise<charts.PaginatedResponse<SdkActiveChart>> {\n\tconst tenantId = resolveTenantId(client, options?.tenantId);\n\tconst params = new URLSearchParams();\n\tif (options?.pagination?.page)\n\t\tparams.set(\"page\", `${options.pagination.page}`);\n\tif (options?.pagination?.limit)\n\t\tparams.set(\"limit\", `${options.pagination.limit}`);\n\tif (options?.sortBy) params.set(\"sort_by\", options.sortBy);\n\tif (options?.sortDir) params.set(\"sort_dir\", options.sortDir);\n\tif (options?.title) params.set(\"name\", options.title);\n\tif (options?.userFilter) params.set(\"user_id\", options.userFilter);\n\tif (options?.createdFrom) params.set(\"created_from\", options.createdFrom);\n\tif (options?.createdTo) params.set(\"created_to\", options.createdTo);\n\tif (options?.updatedFrom) params.set(\"updated_from\", options.updatedFrom);\n\tif (options?.updatedTo) params.set(\"updated_to\", options.updatedTo);\n\n\tconst response = await client.get<\n\t\tcharts.PaginatedResponse<SdkActiveChart>\n\t>(\n\t\t`/active-charts${params.toString() ? `?${params.toString()}` : \"\"}`,\n\t\ttenantId,\n\t\toptions?.userId,\n\t\toptions?.scopes,\n\t\tsignal,\n\t);\n\n\tif (options?.withData) {\n\t\tresponse.data = await Promise.all(\n\t\t\tresponse.data.map(async (active) => ({\n\t\t\t\t...active,\n\t\t\t\tchart: active.chart\n\t\t\t\t\t? await charts.getChart(\n\t\t\t\t\t\t\tclient,\n\t\t\t\t\t\t\tqueryEngine,\n\t\t\t\t\t\t\tactive.chart_id,\n\t\t\t\t\t\t\toptions,\n\t\t\t\t\t\t\tsignal,\n\t\t\t\t\t\t)\n\t\t\t\t\t: null,\n\t\t\t})),\n\t\t);\n\t}\n\n\treturn response;\n}\n\nexport async function getActiveChart(\n\tclient: ApiClient,\n\tqueryEngine: QueryEngine,\n\tid: string,\n\toptions?: ActiveChartListOptions,\n\tsignal?: AbortSignal,\n): Promise<SdkActiveChart> {\n\tconst tenantId = resolveTenantId(client, options?.tenantId);\n\tconst active = await client.get<SdkActiveChart>(\n\t\t`/active-charts/${encodeURIComponent(id)}`,\n\t\ttenantId,\n\t\toptions?.userId,\n\t\toptions?.scopes,\n\t\tsignal,\n\t);\n\n\tif (options?.withData && active.chart_id) {\n\t\treturn {\n\t\t\t...active,\n\t\t\tchart: await charts.getChart(\n\t\t\t\tclient,\n\t\t\t\tqueryEngine,\n\t\t\t\tactive.chart_id,\n\t\t\t\toptions,\n\t\t\t\tsignal,\n\t\t\t),\n\t\t};\n\t}\n\n\treturn active;\n}\n\nexport async function updateActiveChart(\n\tclient: ApiClient,\n\tid: string,\n\tbody: ActiveChartUpdateInput,\n\toptions?: RequestOptions,\n\tsignal?: AbortSignal,\n): Promise<SdkActiveChart> {\n\tconst tenantId = resolveTenantId(client, options?.tenantId);\n\treturn await client.put<SdkActiveChart>(\n\t\t`/active-charts/${encodeURIComponent(id)}`,\n\t\tbody,\n\t\ttenantId,\n\t\toptions?.userId,\n\t\toptions?.scopes,\n\t\tsignal,\n\t);\n}\n\nexport async function deleteActiveChart(\n\tclient: ApiClient,\n\tid: string,\n\toptions?: RequestOptions,\n\tsignal?: AbortSignal,\n): Promise<void> {\n\tconst tenantId = resolveTenantId(client, options?.tenantId);\n\tawait client.delete(\n\t\t`/active-charts/${encodeURIComponent(id)}`,\n\t\ttenantId,\n\t\toptions?.userId,\n\t\toptions?.scopes,\n\t\tsignal,\n\t);\n}\n\nfunction resolveTenantId(client: ApiClient, tenantId?: string): string {\n\tconst resolved = tenantId ?? client.getDefaultTenantId();\n\tif (!resolved) {\n\t\tthrow new Error(\n\t\t\t\"tenantId is required. Provide it per request or via defaultTenantId option.\",\n\t\t);\n\t}\n\treturn resolved;\n}\n","import { randomUUID } from \"node:crypto\";\nimport type { ApiClient } from \"../core/client\";\nimport type { QueryEngine } from \"../core/query-engine\";\nimport type { SchemaIntrospection } from \"../schema/types\";\n\nexport interface IngestResponse {\n\tsuccess: boolean;\n\tmessage: string;\n\tchunks: number;\n\tchunks_with_annotations: number;\n\tschema_id?: string;\n\tschema_hash?: string;\n\tdrift_detected?: boolean;\n\tskipped?: boolean;\n}\n\nexport interface SchemaSyncOptions {\n\ttenantId?: string;\n\tuserId?: string;\n\tscopes?: string[];\n\ttables?: string[];\n\tforceReindex?: boolean;\n}\n\ninterface SchemaIngestColumn {\n\tname: string;\n\tdata_type: string;\n\tis_primary_key: boolean;\n\tdescription: string;\n}\n\ninterface SchemaIngestTable {\n\ttable_name: string;\n\tdescription: string;\n\tcolumns: SchemaIngestColumn[];\n}\n\ninterface SchemaIngestRequest {\n\tdatabase: string;\n\tdialect: string;\n\ttables: SchemaIngestTable[];\n\tforce_reindex?: boolean;\n\ttenant_settings?: {\n\t\ttenantFieldName: string;\n\t\ttenantFieldType: string;\n\t\tenforceTenantIsolation: boolean;\n\t};\n}\n\n/**\n * Route module for schema ingestion\n * Handles introspection and sync to backend\n */\nexport async function syncSchema(\n\tclient: ApiClient,\n\tqueryEngine: QueryEngine,\n\tdatabaseName: string,\n\toptions: SchemaSyncOptions,\n\tsignal?: AbortSignal,\n): Promise<IngestResponse> {\n\tconst tenantId = resolveTenantId(client, options.tenantId);\n\tconst adapter = queryEngine.getDatabase(databaseName);\n\tconst metadata = queryEngine.getDatabaseMetadata(databaseName);\n\n\tconst introspection = await adapter.introspect(\n\t\toptions.tables ? { tables: options.tables } : undefined,\n\t);\n\n\tconst payload = buildSchemaRequest(databaseName, adapter, introspection, metadata);\n\tif (options.forceReindex) {\n\t\tpayload.force_reindex = true;\n\t}\n\n\t// Generate a session id so backend telemetry can correlate all work for this sync\n\tconst sessionId = randomUUID();\n\n\tconst response = await client.post<IngestResponse>(\n\t\t\"/ingest\",\n\t\tpayload,\n\t\ttenantId,\n\t\toptions.userId,\n\t\toptions.scopes,\n\t\tsignal,\n\t\tsessionId,\n\t);\n\n\treturn response;\n}\n\nfunction resolveTenantId(client: ApiClient, tenantId?: string): string {\n\tconst resolved = tenantId ?? client.getDefaultTenantId();\n\tif (!resolved) {\n\t\tthrow new Error(\n\t\t\t\"tenantId is required. Provide it per request or via defaultTenantId option.\",\n\t\t);\n\t}\n\treturn resolved;\n}\n\nfunction buildSchemaRequest(\n\tdatabaseName: string,\n\tadapter: { getDialect: () => string },\n\tintrospection: SchemaIntrospection,\n\tmetadata?: {\n\t\ttenantFieldName?: string;\n\t\ttenantFieldType?: string;\n\t\tenforceTenantIsolation?: boolean;\n\t},\n): SchemaIngestRequest {\n\tconst dialect = adapter.getDialect();\n\tconst tables: SchemaIngestTable[] = introspection.tables.map((table) => ({\n\t\ttable_name: table.name,\n\t\tdescription: table.comment ?? `Table ${table.name}`,\n\t\tcolumns: table.columns.map((column) => ({\n\t\t\tname: column.name,\n\t\t\tdata_type: column.rawType ?? column.type,\n\t\t\tis_primary_key: Boolean(column.isPrimaryKey),\n\t\t\tdescription: column.comment ?? \"\",\n\t\t})),\n\t}));\n\n\tconst request: SchemaIngestRequest = {\n\t\tdatabase: databaseName,\n\t\tdialect,\n\t\ttables,\n\t};\n\n\t// Include tenant_settings if configured in the database metadata\n\tif (\n\t\tmetadata?.tenantFieldName &&\n\t\tmetadata?.tenantFieldType &&\n\t\tmetadata?.enforceTenantIsolation !== undefined\n\t) {\n\t\trequest.tenant_settings = {\n\t\t\ttenantFieldName: metadata.tenantFieldName,\n\t\t\ttenantFieldType: metadata.tenantFieldType,\n\t\t\tenforceTenantIsolation: metadata.enforceTenantIsolation,\n\t\t};\n\t}\n\n\treturn request;\n}\n","import { randomUUID } from \"node:crypto\";\nimport type { ApiClient } from \"../core/client\";\nimport type { ParamRecord, QueryEngine } from \"../core/query-engine\";\n\nexport interface ContextDocument {\n\tsource?: string;\n\tpageContent: string;\n\tmetadata?: Record<string, unknown>;\n\tscore?: number;\n}\n\nexport interface ChartEnvelope {\n\tvegaLiteSpec: Record<string, unknown> | null;\n\tnotes: string | null;\n}\n\nexport interface AskOptions {\n\ttenantId?: string;\n\tuserId?: string;\n\tscopes?: string[];\n\tdatabase?: string;\n\tlastError?: string;\n\tpreviousSql?: string;\n\tmaxRetry?: number;\n\tchartMaxRetries?: number;\n}\n\nexport interface AskResponse {\n\tsql: string;\n\tparams: ParamRecord;\n\tparamMetadata: Array<Record<string, unknown>>;\n\trationale?: string;\n\tdialect: string;\n\tqueryId?: string;\n\trows: Array<Record<string, unknown>>;\n\tfields: string[];\n\tchart: ChartEnvelope;\n\tcontext?: ContextDocument[];\n\tattempts?: number;\n\ttarget_db?: string;\n}\n\ninterface ServerQueryResponse {\n\tsuccess: boolean;\n\tsql: string;\n\tparams?: Array<Record<string, unknown>>;\n\tdialect: string;\n\tdatabase?: string;\n\ttable?: string;\n\trationale?: string;\n\tqueryId?: string;\n\tcontext?: ContextDocument[];\n}\n\ninterface ServerChartResponse {\n\tchart: Record<string, unknown> | null;\n\tnotes: string | null;\n}\n\n/**\n * Route module for natural language query generation\n * Simple orchestration following Ousterhout's principle\n */\nexport async function ask(\n\tclient: ApiClient,\n\tqueryEngine: QueryEngine,\n\tquestion: string,\n\toptions: AskOptions,\n\tsignal?: AbortSignal,\n): Promise<AskResponse> {\n\tconst tenantId = resolveTenantId(client, options.tenantId);\n\tconst sessionId = randomUUID();\n\tconst maxRetry = options.maxRetry ?? 0;\n\tlet attempt = 0;\n\tlet lastError: string | undefined = options.lastError;\n\tlet previousSql: string | undefined = options.previousSql;\n\n\twhile (attempt <= maxRetry) {\n\t\t// Step 1: Get SQL from backend\n\t\tconsole.log({ lastError, previousSql });\n\t\tconst queryResponse = await client.post<ServerQueryResponse>(\n\t\t\t\"/query\",\n\t\t\t{\n\t\t\t\tquestion,\n\t\t\t\t...(lastError ? { last_error: lastError } : {}),\n\t\t\t\t...(previousSql ? { previous_sql: previousSql } : {}),\n\t\t\t\t...(options.maxRetry ? { max_retry: options.maxRetry } : {}),\n\t\t\t},\n\t\t\ttenantId,\n\t\t\toptions.userId,\n\t\t\toptions.scopes,\n\t\t\tsignal,\n\t\t\tsessionId,\n\t\t);\n\n\t\tconst databaseName =\n\t\t\tqueryResponse.database ??\n\t\t\toptions.database ??\n\t\t\tqueryEngine.getDefaultDatabase();\n\t\tif (!databaseName) {\n\t\t\tthrow new Error(\n\t\t\t\t\"No database attached. Call attachPostgres/attachClickhouse first.\",\n\t\t\t);\n\t\t}\n\n\t\t// Step 2: Map and validate parameters\n\t\tconst paramMetadata = Array.isArray(queryResponse.params)\n\t\t\t? queryResponse.params\n\t\t\t: [];\n\t\tconst paramValues = queryEngine.mapGeneratedParams(paramMetadata);\n\n\t\t// Step 3: Execute SQL with tenant isolation\n\t\ttry {\n\t\t\tconst execution = await queryEngine.validateAndExecute(\n\t\t\t\tqueryResponse.sql,\n\t\t\t\tparamValues,\n\t\t\t\tdatabaseName,\n\t\t\t\ttenantId,\n\t\t\t);\n\t\t\tconst rows = execution.rows ?? [];\n\n\t\t\t// Step 4: Generate chart if we have data\n\t\t\tlet chart: ChartEnvelope = {\n\t\t\t\tvegaLiteSpec: null,\n\t\t\t\tnotes: rows.length === 0 ? \"Query returned no rows.\" : null,\n\t\t\t};\n\n\t\t\tif (rows.length > 0) {\n\t\t\t\tconst chartResponse = await client.post<ServerChartResponse>(\n\t\t\t\t\t\"/chart\",\n\t\t\t\t\t{\n\t\t\t\t\t\tquestion,\n\t\t\t\t\t\tsql: queryResponse.sql,\n\t\t\t\t\t\trationale: queryResponse.rationale,\n\t\t\t\t\t\tfields: execution.fields,\n\t\t\t\t\t\trows: anonymizeResults(rows),\n\t\t\t\t\t\tmax_retries: options.chartMaxRetries ?? 3,\n\t\t\t\t\t\tquery_id: queryResponse.queryId,\n\t\t\t\t\t},\n\t\t\t\t\ttenantId,\n\t\t\t\t\toptions.userId,\n\t\t\t\t\toptions.scopes,\n\t\t\t\t\tsignal,\n\t\t\t\t\tsessionId,\n\t\t\t\t);\n\n\t\t\t\tchart = {\n\t\t\t\t\tvegaLiteSpec: chartResponse.chart\n\t\t\t\t\t\t? {\n\t\t\t\t\t\t\t\t...chartResponse.chart,\n\t\t\t\t\t\t\t\tdata: { values: rows },\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t: null,\n\t\t\t\t\tnotes: chartResponse.notes,\n\t\t\t\t};\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\tsql: queryResponse.sql,\n\t\t\t\tparams: paramValues,\n\t\t\t\tparamMetadata,\n\t\t\t\trationale: queryResponse.rationale,\n\t\t\t\tdialect: queryResponse.dialect,\n\t\t\t\tqueryId: queryResponse.queryId,\n\t\t\t\trows,\n\t\t\t\tfields: execution.fields,\n\t\t\t\tchart,\n\t\t\t\tcontext: queryResponse.context,\n\t\t\t\tattempts: attempt + 1,\n\t\t\t\ttarget_db: databaseName,\n\t\t\t};\n\t\t} catch (error) {\n\t\t\tattempt++;\n\n\t\t\t// If we've exhausted all retries, throw the error\n\t\t\tif (attempt > maxRetry) {\n\t\t\t\tthrow error;\n\t\t\t}\n\n\t\t\t// Save error and SQL for next retry\n\t\t\tlastError = error instanceof Error ? error.message : String(error);\n\t\t\tpreviousSql = queryResponse.sql;\n\n\t\t\t// Log retry attempt\n\t\t\tconsole.warn(\n\t\t\t\t`SQL execution failed (attempt ${attempt}/${maxRetry + 1}): ${lastError}. Retrying...`,\n\t\t\t);\n\t\t}\n\t}\n\n\t// This should never be reached, but TypeScript needs it\n\tthrow new Error(\"Unexpected error in ask retry loop\");\n}\n\nfunction resolveTenantId(client: ApiClient, tenantId?: string): string {\n\tconst resolved = tenantId ?? client.getDefaultTenantId();\n\tif (!resolved) {\n\t\tthrow new Error(\n\t\t\t\"tenantId is required. Provide it per request or via defaultTenantId option.\",\n\t\t);\n\t}\n\treturn resolved;\n}\n\nexport function anonymizeResults(\n\trows: Array<Record<string, unknown>>,\n): Array<Record<string, string>> {\n\tif (!rows?.length) return [];\n\treturn rows.map((row) => {\n\t\tconst masked: Record<string, string> = {};\n\t\tObject.entries(row).forEach(([key, value]) => {\n\t\t\tif (value === null) masked[key] = \"null\";\n\t\t\telse if (Array.isArray(value)) masked[key] = \"array\";\n\t\t\telse masked[key] = typeof value;\n\t\t});\n\t\treturn masked;\n\t});\n}\n","import {\n\tClickHouseAdapter,\n\ttype ClickHouseAdapterOptions,\n\ttype ClickHouseClientFn,\n} from \"./adapters/clickhouse\";\nimport {\n\tPostgresAdapter,\n\ttype PostgresAdapterOptions,\n\ttype PostgresClientFn,\n} from \"./adapters/postgres\";\nimport type { DatabaseAdapter, DatabaseDialect } from \"./adapters/types\";\nimport { ApiClient } from \"./core/client\";\nimport { type DatabaseMetadata, QueryEngine } from \"./core/query-engine\";\nimport * as activeChartsRoute from \"./routes/active-charts\";\nimport * as chartsRoute from \"./routes/charts\";\nimport * as ingestRoute from \"./routes/ingest\";\nimport * as queryRoute from \"./routes/query\";\nimport type { SchemaIntrospection } from \"./schema/types\";\n\n// Re-export all public types\nexport { ClickHouseAdapter, PostgresAdapter };\n\nexport type {\n\tClickHouseAdapterOptions,\n\tClickHouseClientFn,\n\tDatabaseAdapter,\n\tDatabaseDialect,\n\tPostgresAdapterOptions,\n\tPostgresClientFn,\n\tSchemaIntrospection,\n};\n\n// Re-export from query-engine\nexport type { ParamRecord, ParamValue } from \"./core/query-engine\";\nexport type {\n\tActiveChartCreateInput,\n\tActiveChartListOptions,\n\tActiveChartUpdateInput,\n\tSdkActiveChart,\n} from \"./routes/active-charts\";\n\nexport type {\n\tChartCreateInput,\n\tChartListOptions,\n\tChartUpdateInput,\n\tPaginatedResponse,\n\tPaginationInfo,\n\tPaginationQuery,\n\tSdkChart,\n} from \"./routes/charts\";\n// Re-export route types\nexport type {\n\tIngestResponse,\n\tSchemaSyncOptions,\n} from \"./routes/ingest\";\nexport type {\n\tAskOptions,\n\tAskResponse,\n\tChartEnvelope,\n\tContextDocument,\n} from \"./routes/query\";\n\n// Re-export anonymizeResults utility\nexport { anonymizeResults } from \"./routes/query\";\n\n/**\n * Main SDK class - Thin orchestrator\n * Delegates to deep modules (ApiClient, QueryEngine, route modules)\n * Following Ousterhout's principle: \"Simple interface hiding complexity\"\n */\nexport class QueryPanelSdkAPI {\n\tprivate readonly client: ApiClient;\n\tprivate readonly queryEngine: QueryEngine;\n\n\tconstructor(\n\t\tbaseUrl: string,\n\t\tprivateKey: string,\n\t\torganizationId: string,\n\t\toptions?: {\n\t\t\tdefaultTenantId?: string;\n\t\t\tadditionalHeaders?: Record<string, string>;\n\t\t\tfetch?: typeof fetch;\n\t\t},\n\t) {\n\t\tthis.client = new ApiClient(baseUrl, privateKey, organizationId, options);\n\t\tthis.queryEngine = new QueryEngine();\n\t}\n\n\t// Database attachment methods\n\n\tattachClickhouse(\n\t\tname: string,\n\t\tclientFn: ClickHouseClientFn,\n\t\toptions?: ClickHouseAdapterOptions & {\n\t\t\tdescription?: string;\n\t\t\ttags?: string[];\n\t\t\ttenantFieldName?: string;\n\t\t\ttenantFieldType?: string;\n\t\t\tenforceTenantIsolation?: boolean;\n\t\t},\n\t): void {\n\t\tconst adapter = new ClickHouseAdapter(clientFn, options);\n\n\t\tconst metadata: DatabaseMetadata = {\n\t\t\tname,\n\t\t\tdialect: \"clickhouse\",\n\t\t\tdescription: options?.description,\n\t\t\ttags: options?.tags,\n\t\t\ttenantFieldName: options?.tenantFieldName,\n\t\t\ttenantFieldType: options?.tenantFieldType ?? \"String\",\n\t\t\tenforceTenantIsolation: options?.tenantFieldName\n\t\t\t\t? (options?.enforceTenantIsolation ?? true)\n\t\t\t\t: undefined,\n\t\t};\n\n\t\tthis.queryEngine.attachDatabase(name, adapter, metadata);\n\t}\n\n\tattachPostgres(\n\t\tname: string,\n\t\tclientFn: PostgresClientFn,\n\t\toptions?: PostgresAdapterOptions & {\n\t\t\tdescription?: string;\n\t\t\ttags?: string[];\n\t\t\ttenantFieldName?: string;\n\t\t\tenforceTenantIsolation?: boolean;\n\t\t},\n\t): void {\n\t\tconst adapter = new PostgresAdapter(clientFn, options);\n\n\t\tconst metadata: DatabaseMetadata = {\n\t\t\tname,\n\t\t\tdialect: \"postgres\",\n\t\t\tdescription: options?.description,\n\t\t\ttags: options?.tags,\n\t\t\ttenantFieldName: options?.tenantFieldName,\n\t\t\tenforceTenantIsolation: options?.tenantFieldName\n\t\t\t\t? (options?.enforceTenantIsolation ?? true)\n\t\t\t\t: undefined,\n\t\t};\n\n\t\tthis.queryEngine.attachDatabase(name, adapter, metadata);\n\t}\n\n\tattachDatabase(name: string, adapter: DatabaseAdapter): void {\n\t\tconst metadata: DatabaseMetadata = {\n\t\t\tname,\n\t\t\tdialect: adapter.getDialect(),\n\t\t};\n\t\tthis.queryEngine.attachDatabase(name, adapter, metadata);\n\t}\n\n\t// Schema introspection and sync\n\n\tasync introspect(\n\t\tdatabaseName: string,\n\t\ttables?: string[],\n\t): Promise<SchemaIntrospection> {\n\t\tconst adapter = this.queryEngine.getDatabase(databaseName);\n\t\treturn await adapter.introspect(tables ? { tables } : undefined);\n\t}\n\n\tasync syncSchema(\n\t\tdatabaseName: string,\n\t\toptions: ingestRoute.SchemaSyncOptions,\n\t\tsignal?: AbortSignal,\n\t): Promise<ingestRoute.IngestResponse> {\n\t\treturn await ingestRoute.syncSchema(\n\t\t\tthis.client,\n\t\t\tthis.queryEngine,\n\t\t\tdatabaseName,\n\t\t\toptions,\n\t\t\tsignal,\n\t\t);\n\t}\n\n\t// Natural language query\n\n\tasync ask(\n\t\tquestion: string,\n\t\toptions: queryRoute.AskOptions,\n\t\tsignal?: AbortSignal,\n\t): Promise<queryRoute.AskResponse> {\n\t\treturn await queryRoute.ask(\n\t\t\tthis.client,\n\t\t\tthis.queryEngine,\n\t\t\tquestion,\n\t\t\toptions,\n\t\t\tsignal,\n\t\t);\n\t}\n\n\t// Chart CRUD operations\n\n\tasync createChart(\n\t\tbody: chartsRoute.ChartCreateInput,\n\t\toptions?: { tenantId?: string; userId?: string; scopes?: string[] },\n\t\tsignal?: AbortSignal,\n\t): Promise<chartsRoute.SdkChart> {\n\t\treturn await chartsRoute.createChart(this.client, body, options, signal);\n\t}\n\n\tasync listCharts(\n\t\toptions?: chartsRoute.ChartListOptions,\n\t\tsignal?: AbortSignal,\n\t): Promise<chartsRoute.PaginatedResponse<chartsRoute.SdkChart>> {\n\t\treturn await chartsRoute.listCharts(\n\t\t\tthis.client,\n\t\t\tthis.queryEngine,\n\t\t\toptions,\n\t\t\tsignal,\n\t\t);\n\t}\n\n\tasync getChart(\n\t\tid: string,\n\t\toptions?: { tenantId?: string; userId?: string; scopes?: string[] },\n\t\tsignal?: AbortSignal,\n\t): Promise<chartsRoute.SdkChart> {\n\t\treturn await chartsRoute.getChart(\n\t\t\tthis.client,\n\t\t\tthis.queryEngine,\n\t\t\tid,\n\t\t\toptions,\n\t\t\tsignal,\n\t\t);\n\t}\n\n\tasync updateChart(\n\t\tid: string,\n\t\tbody: chartsRoute.ChartUpdateInput,\n\t\toptions?: { tenantId?: string; userId?: string; scopes?: string[] },\n\t\tsignal?: AbortSignal,\n\t): Promise<chartsRoute.SdkChart> {\n\t\treturn await chartsRoute.updateChart(\n\t\t\tthis.client,\n\t\t\tid,\n\t\t\tbody,\n\t\t\toptions,\n\t\t\tsignal,\n\t\t);\n\t}\n\n\tasync deleteChart(\n\t\tid: string,\n\t\toptions?: { tenantId?: string; userId?: string; scopes?: string[] },\n\t\tsignal?: AbortSignal,\n\t): Promise<void> {\n\t\tawait chartsRoute.deleteChart(this.client, id, options, signal);\n\t}\n\n\t// Active Chart CRUD operations\n\n\tasync createActiveChart(\n\t\tbody: activeChartsRoute.ActiveChartCreateInput,\n\t\toptions?: { tenantId?: string; userId?: string; scopes?: string[] },\n\t\tsignal?: AbortSignal,\n\t): Promise<activeChartsRoute.SdkActiveChart> {\n\t\treturn await activeChartsRoute.createActiveChart(\n\t\t\tthis.client,\n\t\t\tbody,\n\t\t\toptions,\n\t\t\tsignal,\n\t\t);\n\t}\n\n\tasync listActiveCharts(\n\t\toptions?: activeChartsRoute.ActiveChartListOptions,\n\t\tsignal?: AbortSignal,\n\t): Promise<chartsRoute.PaginatedResponse<activeChartsRoute.SdkActiveChart>> {\n\t\treturn await activeChartsRoute.listActiveCharts(\n\t\t\tthis.client,\n\t\t\tthis.queryEngine,\n\t\t\toptions,\n\t\t\tsignal,\n\t\t);\n\t}\n\n\tasync getActiveChart(\n\t\tid: string,\n\t\toptions?: activeChartsRoute.ActiveChartListOptions,\n\t\tsignal?: AbortSignal,\n\t): Promise<activeChartsRoute.SdkActiveChart> {\n\t\treturn await activeChartsRoute.getActiveChart(\n\t\t\tthis.client,\n\t\t\tthis.queryEngine,\n\t\t\tid,\n\t\t\toptions,\n\t\t\tsignal,\n\t\t);\n\t}\n\n\tasync updateActiveChart(\n\t\tid: string,\n\t\tbody: activeChartsRoute.ActiveChartUpdateInput,\n\t\toptions?: { tenantId?: string; userId?: string; scopes?: string[] },\n\t\tsignal?: AbortSignal,\n\t): Promise<activeChartsRoute.SdkActiveChart> {\n\t\treturn await activeChartsRoute.updateActiveChart(\n\t\t\tthis.client,\n\t\t\tid,\n\t\t\tbody,\n\t\t\toptions,\n\t\t\tsignal,\n\t\t);\n\t}\n\n\tasync deleteActiveChart(\n\t\tid: string,\n\t\toptions?: { tenantId?: string; userId?: string; scopes?: string[] },\n\t\tsignal?: AbortSignal,\n\t): Promise<void> {\n\t\tawait activeChartsRoute.deleteActiveChart(this.client, id, options, signal);\n\t}\n}\n"],"mappings":"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","names":["normalizeTableFilter","asTableType","sanitize","resolveTenantId","resolveTenantId","randomUUID","resolveTenantId"]}
|