@querypanel/node-sdk 1.0.36 → 1.0.37
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/README.md +20 -1
- package/dist/index.cjs +76 -17
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +76 -17
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
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 executeChartQuery(queryEngine, chart, tenantId),\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 executeChartQuery(queryEngine, chart, tenantId),\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\nasync function executeChartQuery(\n\tqueryEngine: QueryEngine,\n\tchart: SdkChart,\n\ttenantId: string,\n): Promise<Record<string, unknown>[]> {\n\tconst databaseName = chart.target_db ?? queryEngine.getDefaultDatabase();\n\tif (!databaseName) {\n\t\tconsole.warn(\"No database available to execute chart query\");\n\t\treturn [];\n\t}\n\ttry {\n\t\tconst result = await queryEngine.validateAndExecute(\n\t\t\tchart.sql,\n\t\t\t(chart.sql_params as ParamRecord | null) ?? {},\n\t\t\tdatabaseName,\n\t\t\ttenantId,\n\t\t);\n\t\treturn result.rows;\n\t} catch (error) {\n\t\tconsole.warn(`Failed to execute chart query: ${error}`);\n\t\treturn [];\n\t}\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"]}
|
|
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","/**\n * Deep module: Hides JWT signing and HTTP complexity behind simple interface\n * Following Ousterhout's principle: \"Pull complexity downward\"\n */\n\n// Web Crypto API type declarations (available in Node.js 18+, Deno, and Bun)\n// Minimal type declaration for server-side use without DOM types\n// This matches the Web Crypto API CryptoKey interface\ninterface CryptoKey {\n\treadonly type: \"public\" | \"private\" | \"secret\";\n\treadonly extractable: boolean;\n\treadonly algorithm: { name: string };\n\treadonly usages: Array<\n\t\t| \"encrypt\"\n\t\t| \"decrypt\"\n\t\t| \"sign\"\n\t\t| \"verify\"\n\t\t| \"deriveKey\"\n\t\t| \"deriveBits\"\n\t\t| \"wrapKey\"\n\t\t| \"unwrapKey\"\n\t>;\n}\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\tprivate cryptoKey: CryptoKey | null = null;\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\t/**\n\t * Base64URL encode a string (works in both Node.js 18+ and Deno)\n\t */\n\tprivate base64UrlEncode(str: string): string {\n\t\t// Convert string to bytes\n\t\tconst bytes = new TextEncoder().encode(str);\n\n\t\t// btoa is available in both Node.js 18+ and Deno\n\t\t// Convert bytes to binary string efficiently (handle large arrays)\n\t\tlet binary = \"\";\n\t\tconst chunkSize = 8192; // Process in chunks to avoid stack overflow\n\t\tfor (let i = 0; i < bytes.length; i += chunkSize) {\n\t\t\tconst chunk = bytes.slice(i, i + chunkSize);\n\t\t\tbinary += String.fromCharCode(...chunk);\n\t\t}\n\n\t\tconst base64 = btoa(binary);\n\n\t\t// Convert to base64url: replace non-url chars and strip padding\n\t\treturn base64.replace(/\\+/g, \"-\").replace(/\\//g, \"_\").replace(/=+$/g, \"\");\n\t}\n\n\t/**\n\t * Base64URL encode from Uint8Array (for binary data like signatures)\n\t */\n\tprivate base64UrlEncodeBytes(bytes: Uint8Array): string {\n\t\t// Convert bytes to binary string efficiently (handle large arrays)\n\t\tlet binary = \"\";\n\t\tconst chunkSize = 8192; // Process in chunks to avoid stack overflow\n\t\tfor (let i = 0; i < bytes.length; i += chunkSize) {\n\t\t\tconst chunk = bytes.slice(i, i + chunkSize);\n\t\t\tbinary += String.fromCharCode(...chunk);\n\t\t}\n\n\t\tconst base64 = btoa(binary);\n\n\t\t// Convert to base64url: replace non-url chars and strip padding\n\t\treturn base64.replace(/\\+/g, \"-\").replace(/\\//g, \"_\").replace(/=+$/g, \"\");\n\t}\n\n\t/**\n\t * Import the private key into Web Crypto API format (cached after first import)\n\t */\n\tprivate async getCryptoKey(): Promise<CryptoKey> {\n\t\tif (this.cryptoKey) {\n\t\t\treturn this.cryptoKey;\n\t\t}\n\n\t\t// Import the private key for Web Crypto API\n\t\t// Works in both Node.js 18+ and Deno\n\t\tthis.cryptoKey = await crypto.subtle.importKey(\n\t\t\t\"pkcs8\",\n\t\t\tthis.privateKeyToArrayBuffer(this.privateKey),\n\t\t\t{\n\t\t\t\tname: \"RSASSA-PKCS1-v1_5\",\n\t\t\t\thash: \"SHA-256\",\n\t\t\t},\n\t\t\tfalse,\n\t\t\t[\"sign\"],\n\t\t);\n\n\t\treturn this.cryptoKey;\n\t}\n\n\t/**\n\t * Convert PEM private key to ArrayBuffer for Web Crypto API\n\t */\n\tprivate privateKeyToArrayBuffer(pem: string): ArrayBuffer {\n\t\t// Remove PEM headers and whitespace\n\t\tconst pemHeader = \"-----BEGIN PRIVATE KEY-----\";\n\t\tconst pemFooter = \"-----END PRIVATE KEY-----\";\n\t\tconst pemContents = pem\n\t\t\t.replace(pemHeader, \"\")\n\t\t\t.replace(pemFooter, \"\")\n\t\t\t.replace(/\\s/g, \"\");\n\n\t\t// Decode base64 to binary string, then to ArrayBuffer\n\t\tconst binaryString = atob(pemContents);\n\t\tconst bytes = new Uint8Array(binaryString.length);\n\t\tfor (let i = 0; i < binaryString.length; i++) {\n\t\t\tbytes[i] = binaryString.charCodeAt(i);\n\t\t}\n\t\treturn bytes.buffer;\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 encodedHeader = this.base64UrlEncode(JSON.stringify(header));\n\t\tconst encodedPayload = this.base64UrlEncode(JSON.stringify(payload));\n\t\tconst data = `${encodedHeader}.${encodedPayload}`;\n\n\t\t// Sign using Web Crypto API (works in both Node.js 18+ and Deno)\n\t\tconst key = await this.getCryptoKey();\n\t\tconst dataBytes = new TextEncoder().encode(data);\n\t\tconst signature = await crypto.subtle.sign(\n\t\t\t{\n\t\t\t\tname: \"RSASSA-PKCS1-v1_5\",\n\t\t\t},\n\t\t\tkey,\n\t\t\tdataBytes,\n\t\t);\n\n\t\t// Convert signature ArrayBuffer to base64url\n\t\tconst signatureBytes = new Uint8Array(signature);\n\t\tconst encodedSignature = this.base64UrlEncodeBytes(signatureBytes);\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 executeChartQuery(queryEngine, chart, tenantId),\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 executeChartQuery(queryEngine, chart, tenantId),\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\nasync function executeChartQuery(\n\tqueryEngine: QueryEngine,\n\tchart: SdkChart,\n\ttenantId: string,\n): Promise<Record<string, unknown>[]> {\n\tconst databaseName = chart.target_db ?? queryEngine.getDefaultDatabase();\n\tif (!databaseName) {\n\t\tconsole.warn(\"No database available to execute chart query\");\n\t\treturn [];\n\t}\n\ttry {\n\t\tconst result = await queryEngine.validateAndExecute(\n\t\t\tchart.sql,\n\t\t\t(chart.sql_params as ParamRecord | null) ?? {},\n\t\t\tdatabaseName,\n\t\t\ttenantId,\n\t\t);\n\t\treturn result.rows;\n\t} catch (error) {\n\t\tconsole.warn(`Failed to execute chart query: ${error}`);\n\t\treturn [];\n\t}\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","// randomUUID is available via global crypto.randomUUID() in Node.js 18+ and Deno\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 = crypto.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","// randomUUID is available via global crypto.randomUUID() in Node.js 18+ and Deno\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 = crypto.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":";AAAA,IAAM,gBACJ;AAMK,SAAS,oBAAoB,MAAsB;AACxD,MAAI,UAAU,KAAK,KAAK;AACxB,MAAI,QAAQ,cAAc,KAAK,OAAO;AACtC,SAAO,OAAO;AACZ,UAAM,QAAQ,MAAM,CAAC;AACrB,QAAI,CAAC,OAAO;AACV;AAAA,IACF;AACA,cAAU,MAAM,KAAK;AACrB,YAAQ,cAAc,KAAK,OAAO;AAAA,EACpC;AACA,SAAO;AACT;AA2BO,SAAS,mBAAmB,YAAsC;AACvE,MAAI,CAAC,WAAY,QAAO,CAAC;AACzB,MAAI,QAAQ,WAAW,KAAK;AAC5B,MAAI,CAAC,MAAO,QAAO,CAAC;AACpB,MAAI,eAAe,KAAK,KAAK,KAAK,MAAM,SAAS,GAAG,GAAG;AACrD,YAAQ,MAAM,QAAQ,gBAAgB,EAAE,EAAE,QAAQ,OAAO,EAAE;AAAA,EAC7D;AAEA,QAAM,UAAoB,CAAC;AAC3B,MAAI,QAAQ;AACZ,MAAI,QAAQ;AACZ,aAAW,MAAM,OAAO;AACtB,QAAI,OAAO,KAAK;AACd,eAAS;AACT,eAAS;AACT;AAAA,IACF;AACA,QAAI,OAAO,KAAK;AACd,cAAQ,KAAK,IAAI,GAAG,QAAQ,CAAC;AAC7B,eAAS;AACT;AAAA,IACF;AACA,QAAI,OAAO,OAAO,UAAU,GAAG;AAC7B,YAAM,MAAM,MAAM,KAAK;AACvB,UAAI,IAAK,SAAQ,KAAK,aAAa,GAAG,CAAC;AACvC,cAAQ;AACR;AAAA,IACF;AACA,aAAS;AAAA,EACX;AACA,QAAM,OAAO,MAAM,KAAK;AACxB,MAAI,KAAM,SAAQ,KAAK,aAAa,IAAI,CAAC;AACzC,SAAO,QAAQ,OAAO,OAAO;AAC/B;AAEA,SAAS,aAAa,OAAuB;AAC3C,QAAM,WAAW,YAAY,KAAK;AAClC,QAAM,eAAe,SAAS,QAAQ,MAAM,EAAE,EAAE,KAAK;AACrD,QAAM,QAAQ,aAAa,MAAM,GAAG;AACpC,SAAO,MAAM,MAAM,SAAS,CAAC,GAAG,KAAK,KAAK;AAC5C;AAEA,SAAS,YAAY,OAAuB;AAC1C,MACG,MAAM,WAAW,GAAG,KAAK,MAAM,SAAS,GAAG,KAC3C,MAAM,WAAW,GAAG,KAAK,MAAM,SAAS,GAAG,GAC5C;AACA,WAAO,MAAM,MAAM,GAAG,EAAE;AAAA,EAC1B;AACA,SAAO;AACT;;;AC3BO,IAAM,oBAAN,MAAmD;AAAA,EAMzD,YACkB,UACjB,UAAoC,CAAC,GACpC;AAFgB;AAGjB,SAAK,eAAe,QAAQ,YAAY;AACxC,SAAK,gBAAgB,QAAQ,iBAAiB;AAC9C,SAAK,OAAO,QAAQ,QAAQ;AAC5B,QAAI,QAAQ,eAAe;AAC1B,WAAK,gBAAgB,qBAAqB,QAAQ,aAAa;AAAA,IAChE;AAAA,EACD;AAAA,EAfiB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAcjB,MAAM,QACL,KACA,QACmC;AAEnC,QAAI,KAAK,eAAe;AACvB,WAAK,oBAAoB,GAAG;AAAA,IAC7B;AAEA,UAAM,eAA6B;AAAA,MAClC,QAAQ,KAAK;AAAA,IACd;AACA,QAAI,QAAQ;AACX,mBAAa,SAAS;AAAA,IACvB;AAEA,UAAM,OAAO,MAAM,KAAK,MAA+B,KAAK,YAAY;AACxE,UAAM,SAAS,KAAK,SAAS,IAAI,OAAO,KAAK,KAAK,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC;AAC/D,WAAO,EAAE,QAAQ,KAAK;AAAA,EACvB;AAAA,EAEA,MAAM,SACL,KACA,QACgB;AAChB,UAAM,eAA6B;AAAA,MAClC,QAAQ,KAAK;AAAA,IACd;AACA,QAAI,QAAQ;AACX,mBAAa,SAAS;AAAA,IACvB;AAEA,UAAM,KAAK,MAAM,WAAW,GAAG,IAAI,YAAY;AAAA,EAChD;AAAA,EAEA,aAAa;AACZ,WAAO;AAAA,EACR;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,WAAW,SAA2D;AAE3E,UAAM,qBAAqB,SAAS,SACjC,qBAAqB,QAAQ,MAAM,IACnC,KAAK;AACR,UAAM,cAAc,sBAAsB,CAAC;AAC3C,UAAM,YAAY,YAAY,SAAS;AACvC,UAAM,cAAuC;AAAA,MAC5C,IAAI,KAAK;AAAA,IACV;AACA,QAAI,WAAW;AACd,kBAAY,SAAS;AAAA,IACtB;AAEA,UAAM,eAAe,YAAY,wCAAwC;AACzE,UAAM,SAAS,MAAM,KAAK;AAAA,MACzB;AAAA;AAAA,qCAEkC,YAAY;AAAA;AAAA,MAE9C,EAAE,QAAQ,YAAY;AAAA,IACvB;AAEA,UAAM,qBAAqB,YACxB,yCACA;AACH,UAAM,UAAU,MAAM,KAAK;AAAA,MAC1B;AAAA;AAAA,qCAEkC,kBAAkB;AAAA;AAAA,MAEpD,EAAE,QAAQ,YAAY;AAAA,IACvB;AAEA,UAAM,iBAAiB,oBAAI,IAA4B;AACvD,eAAW,aAAa,SAAS;AAChC,YAAM,OAAO,eAAe,IAAI,UAAU,KAAK,KAAK,CAAC;AACrD,WAAK,KAAK,mBAAmB,SAAS,CAAC;AACvC,qBAAe,IAAI,UAAU,OAAO,IAAI;AAAA,IACzC;AAEA,UAAM,eAA8B,OAAO,IAAI,CAAC,UAAU;AACzD,YAAM,eAAe,eAAe,IAAI,MAAM,IAAI,KAAK,CAAC;AACxD,YAAM,oBAAoB,mBAAmB,MAAM,WAAW;AAG9D,iBAAW,UAAU,cAAc;AAClC,eAAO,eACN,OAAO,gBAAgB,kBAAkB,SAAS,OAAO,IAAI;AAAA,MAC/D;AAEA,YAAM,OAAoB;AAAA,QACzB,MAAM,MAAM;AAAA,QACZ,QAAQ,KAAK;AAAA,QACb,MAAM,YAAY,MAAM,MAAM;AAAA,QAC9B,SAAS;AAAA,MACV;AAEA,YAAM,UAAU,SAAS,MAAM,OAAO;AACtC,UAAI,YAAY,QAAW;AAC1B,aAAK,UAAU;AAAA,MAChB;AAEA,aAAO;AAAA,IACR,CAAC;AAED,WAAO;AAAA,MACN,IAAI;AAAA,QACH,MAAM,KAAK;AAAA,QACX,MAAM,KAAK;AAAA,MACZ;AAAA,MACA,QAAQ;AAAA,MACR,iBAAgB,oBAAI,KAAK,GAAE,YAAY;AAAA,IACxC;AAAA,EACD;AAAA,EAEQ,oBAAoB,KAAmB;AAC9C,QAAI,CAAC,KAAK,iBAAiB,KAAK,cAAc,WAAW,GAAG;AAC3D;AAAA,IACD;AAEA,UAAM,aAAa,IAAI,IAAI,KAAK,aAAa;AAG7C,UAAM,eACL;AACD,UAAM,UAAU,IAAI,SAAS,YAAY;AAEzC,eAAW,SAAS,SAAS;AAC5B,YAAM,QAAQ,MAAM,CAAC,GAAG,QAAQ,UAAU,EAAE;AAC5C,UAAI,OAAO;AACV,YAAI,CAAC,WAAW,IAAI,KAAK,GAAG;AAC3B,gBAAM,IAAI;AAAA,YACT,2BAA2B,KAAK;AAAA,UACjC;AAAA,QACD;AAAA,MACD;AAAA,IACD;AAAA,EACD;AAAA,EAEA,MAAM,QAAuB;AAAA,EAE7B;AAAA,EAEA,MAAc,MAAS,KAAa,SAAsC;AACzE,UAAM,SAAsB;AAAA,MAC3B,OAAO;AAAA,IACR;AAEA,UAAM,SAAS,SAAS,UAAU,KAAK;AACvC,QAAI,WAAW,QAAW;AACzB,aAAO,SAAS;AAAA,IACjB;AAEA,QAAI,SAAS,QAAQ;AACpB,aAAO,eAAe,QAAQ;AAAA,IAC/B;AAEA,QAAI,SAAS,UAAU;AACtB,aAAO,sBAAsB,QAAQ;AAAA,IACtC;AAEA,UAAM,SAAS,MAAM,KAAK,SAAS,MAAM;AACzC,WAAO,KAAK,YAAe,MAAM;AAAA,EAClC;AAAA,EAEA,MAAc,YACb,QAIe;AACf,QAAI,MAAM,QAAQ,MAAM,GAAG;AAC1B,aAAO;AAAA,IACR;AAEA,QACC,UACA,OAAQ,OAAiC,SAAS,YACjD;AACD,YAAM,UAAU,MAAO,OAAiC,KAAK;AAC7D,aAAO,iBAAoB,OAAO;AAAA,IACnC;AAEA,WAAO,CAAC;AAAA,EACT;AACD;AAEA,SAAS,iBAAoB,SAAuB;AACnD,MAAI,MAAM,QAAQ,OAAO,GAAG;AAC3B,WAAO;AAAA,EACR;AACA,MAAI,WAAW,OAAO,YAAY,UAAU;AAC3C,UAAM,YAAa,QAA+B;AAClD,QAAI,MAAM,QAAQ,SAAS,GAAG;AAC7B,aAAO;AAAA,IACR;AAAA,EACD;AACA,SAAO,CAAC;AACT;AAEA,SAAS,qBAAqB,QAAoC;AACjE,MAAI,CAAC,QAAQ,OAAQ,QAAO,CAAC;AAC7B,QAAM,OAAO,oBAAI,IAAY;AAC7B,QAAM,aAAuB,CAAC;AAC9B,aAAW,SAAS,QAAQ;AAC3B,QAAI,CAAC,MAAO;AACZ,UAAM,UAAU,MAAM,KAAK;AAC3B,QAAI,CAAC,QAAS;AACd,UAAM,QAAQ,QAAQ,MAAM,GAAG;AAC/B,UAAM,YAAY,MAAM,MAAM,SAAS,CAAC;AACxC,QAAI,CAAC,aAAa,KAAK,IAAI,SAAS,EAAG;AACvC,SAAK,IAAI,SAAS;AAClB,eAAW,KAAK,SAAS;AAAA,EAC1B;AACA,SAAO;AACR;AAEA,SAAS,mBAAmB,KAA8B;AACzD,QAAM,gBAAgB,oBAAoB,IAAI,IAAI;AAElD,QAAM,SAAuB;AAAA,IAC5B,MAAM,IAAI;AAAA,IACV,MAAM;AAAA,IACN,SAAS,IAAI;AAAA,IACb,cAAc,QAAQ,SAAS,IAAI,iBAAiB,CAAC;AAAA,EACtD;AAEA,QAAM,UAAU,SAAS,IAAI,OAAO;AACpC,MAAI,YAAY,OAAW,QAAO,UAAU;AAE5C,SAAO;AACR;AAEA,SAAS,YAAY,QAAsC;AAC1D,MAAI,OAAO,WAAW,UAAU;AAC/B,UAAM,aAAa,OAAO,YAAY;AAEtC,QAAI,WAAW,SAAS,MAAM,GAAG;AAChC,aAAO;AAAA,IACR;AAAA,EACD;AACA,SAAO;AACR;AAEA,SAAS,SAAS,OAAoC;AACrD,MAAI,UAAU,QAAQ,UAAU,OAAW,QAAO;AAClD,QAAM,UAAU,OAAO,KAAK,EAAE,KAAK;AACnC,SAAO,QAAQ,SAAS,UAAU;AACnC;AAEA,SAAS,SAAS,OAAoC;AACrD,MAAI,UAAU,QAAQ,UAAU,OAAW,QAAO;AAClD,MAAI,OAAO,UAAU,SAAU,QAAO;AACtC,QAAM,SAAS,OAAO,WAAW,OAAO,KAAK,CAAC;AAC9C,SAAO,OAAO,MAAM,MAAM,IAAI,SAAY;AAC3C;;;AC/RO,IAAM,kBAAN,MAAiD;AAAA,EAMvD,YACkB,UACjB,UAAkC,CAAC,GAClC;AAFgB;AAGjB,SAAK,eAAe,QAAQ,YAAY;AACxC,SAAK,gBAAgB,QAAQ,iBAAiB;AAC9C,SAAK,OAAO,QAAQ,QAAQ;AAC5B,QAAI,QAAQ,eAAe;AAC1B,WAAK,gBAAgBA;AAAA,QACpB,QAAQ;AAAA,QACR,KAAK;AAAA,MACN;AAAA,IACD;AAAA,EACD;AAAA,EAlBiB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAiBjB,MAAM,QACL,KACA,QACmC;AAEnC,QAAI,KAAK,eAAe;AACvB,WAAK,oBAAoB,GAAG;AAAA,IAC7B;AAGA,QAAI;AACJ,QAAI,QAAQ;AACX,mBAAa,KAAK,+BAA+B,MAAM;AAAA,IACxD;AAEA,UAAM,SAAS,MAAM,KAAK,SAAS,KAAK,UAAU;AAClD,UAAM,SAAS,OAAO,OAAO,IAAI,CAAC,MAAM,EAAE,IAAI;AAC9C,WAAO,EAAE,QAAQ,MAAM,OAAO,KAAK;AAAA,EACpC;AAAA,EAEQ,oBAAoB,KAAmB;AAC9C,QAAI,CAAC,KAAK,iBAAiB,KAAK,cAAc,WAAW,GAAG;AAC3D;AAAA,IACD;AAEA,UAAM,aAAa,IAAI;AAAA,MACtB,KAAK,cAAc,IAAI,CAAC,MAAM,SAAS,EAAE,QAAQ,EAAE,KAAK,CAAC;AAAA,IAC1D;AAGA,UAAM,eACL;AACD,UAAM,UAAU,IAAI,SAAS,YAAY;AAEzC,eAAW,SAAS,SAAS;AAC5B,YAAM,SAAS,MAAM,CAAC,KAAK,KAAK;AAChC,YAAM,QAAQ,MAAM,CAAC,GAAG,QAAQ,SAAS,EAAE;AAC3C,UAAI,OAAO;AACV,cAAM,MAAM,SAAS,QAAQ,KAAK;AAClC,YAAI,CAAC,WAAW,IAAI,GAAG,GAAG;AACzB,gBAAM,IAAI;AAAA,YACT,2BAA2B,MAAM,IAAI,KAAK;AAAA,UAC3C;AAAA,QACD;AAAA,MACD;AAAA,IACD;AAAA,EACD;AAAA;AAAA;AAAA;AAAA;AAAA,EAMQ,+BACP,QACY;AAEZ,UAAM,cAAc,OAAO,KAAK,MAAM,EACpC,OAAO,CAAC,MAAM,QAAQ,KAAK,CAAC,CAAC,EAC7B,IAAI,CAAC,MAAM,OAAO,SAAS,GAAG,EAAE,CAAC,EACjC,KAAK,CAAC,GAAG,MAAM,IAAI,CAAC;AAEtB,UAAM,YAAY,OAAO,KAAK,MAAM,EAClC,OAAO,CAAC,MAAM,CAAC,QAAQ,KAAK,CAAC,CAAC,EAC9B,KAAK;AAGP,UAAM,mBAA8B,CAAC;AAGrC,eAAW,OAAO,aAAa;AAC9B,UAAI,MAAe,OAAO,OAAO,GAAG,CAAC;AACrC,UAAI,OAAO,QAAQ,UAAU;AAE5B,cAAM,QAAQ,IAAI,MAAM,qBAAqB;AAC7C,cAAM,WAAW,QAAQ,CAAC;AAC1B,YAAI,YAAY,YAAY,QAAQ;AACnC,gBAAM,OAAO,QAA+B;AAAA,QAC7C;AAAA,MACD;AACA,uBAAiB,KAAK,GAAG;AAAA,IAC1B;AAGA,eAAW,OAAO,WAAW;AAC5B,YAAM,MAAM,OAAO,GAAG;AACtB,uBAAiB,KAAK,GAAG;AAAA,IAC1B;AAEA,WAAO;AAAA,EACR;AAAA,EAEA,MAAM,SACL,KACA,QACgB;AAChB,QAAI;AACJ,QAAI,QAAQ;AACX,mBAAa,KAAK,+BAA+B,MAAM;AAAA,IACxD;AAEA,UAAM,KAAK,SAAS,WAAW,GAAG,IAAI,UAAU;AAAA,EACjD;AAAA,EAEA,aAAa;AACZ,WAAO;AAAA,EACR;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,WAAW,SAA2D;AAE3E,UAAM,qBAAqB,SAAS,SACjCA,sBAAqB,QAAQ,QAAQ,KAAK,aAAa,IACvD,KAAK;AACR,UAAM,mBAAmB,sBAAsB,CAAC;AAEhD,UAAM,eAAe,MAAM,KAAK;AAAA,MAC/B,iBAAiB,gBAAgB;AAAA,IAClC;AACA,UAAM,YAAY,aAAa;AAE/B,UAAM,gBAAgB,MAAM,KAAK;AAAA,MAChC,kBAAkB,gBAAgB;AAAA,IACnC;AACA,UAAM,aAAa,cAAc;AAEjC,UAAM,cAAc,oBAAI,IAAyB;AAGjD,eAAW,OAAO,WAAW;AAC5B,YAAM,MAAM,SAAS,IAAI,aAAa,IAAI,UAAU;AACpD,YAAM,QAAqB;AAAA,QAC1B,MAAM,IAAI;AAAA,QACV,QAAQ,IAAI;AAAA,QACZ,MAAMC,aAAY,IAAI,UAAU;AAAA,QAChC,SAAS,CAAC;AAAA,MACX;AAEA,YAAM,UAAUC,UAAS,IAAI,OAAO;AACpC,UAAI,YAAY,QAAW;AAC1B,cAAM,UAAU;AAAA,MACjB;AAEA,kBAAY,IAAI,KAAK,KAAK;AAAA,IAC3B;AAGA,eAAW,OAAO,YAAY;AAC7B,YAAM,MAAM,SAAS,IAAI,cAAc,IAAI,UAAU;AACrD,YAAM,QAAQ,YAAY,IAAI,GAAG;AACjC,UAAI,CAAC,MAAO;AAEZ,YAAM,SAAuB;AAAA,QAC5B,MAAM,IAAI;AAAA,QACV,MAAM,IAAI;AAAA,QACV,cAAc,IAAI;AAAA,MACnB;AAEA,YAAM,UAAU,IAAI,YAAY;AAChC,UAAI,YAAY,OAAW,QAAO,UAAU;AAE5C,YAAM,UAAUA,UAAS,IAAI,WAAW;AACxC,UAAI,YAAY,OAAW,QAAO,UAAU;AAE5C,YAAM,QAAQ,KAAK,MAAM;AAAA,IAC1B;AAEA,UAAM,SAAS,MAAM,KAAK,YAAY,OAAO,CAAC,EAAE,KAAK,CAAC,GAAG,MAAM;AAC9D,UAAI,EAAE,WAAW,EAAE,QAAQ;AAC1B,eAAO,EAAE,KAAK,cAAc,EAAE,IAAI;AAAA,MACnC;AACA,aAAO,EAAE,OAAO,cAAc,EAAE,MAAM;AAAA,IACvC,CAAC;AAED,WAAO;AAAA,MACN,IAAI;AAAA,QACH,MAAM,KAAK;AAAA,QACX,MAAM,KAAK;AAAA,MACZ;AAAA,MACA;AAAA,MACA,iBAAgB,oBAAI,KAAK,GAAE,YAAY;AAAA,IACxC;AAAA,EACD;AACD;AAEA,SAASF,sBACR,QACA,eACoB;AACpB,MAAI,CAAC,QAAQ,OAAQ,QAAO,CAAC;AAC7B,QAAM,aAAgC,CAAC;AACvC,QAAM,OAAO,oBAAI,IAAY;AAE7B,aAAW,OAAO,QAAQ;AACzB,QAAI,CAAC,IAAK;AACV,UAAM,UAAU,IAAI,KAAK;AACzB,QAAI,CAAC,QAAS;AACd,UAAM,QAAQ,QAAQ,MAAM,GAAG;AAC/B,UAAM,QAAQ,MAAM,IAAI,KAAK;AAC7B,UAAM,SAAS,MAAM,IAAI,KAAK;AAC9B,QAAI,CAAC,iBAAiB,MAAM,KAAK,CAAC,iBAAiB,KAAK,GAAG;AAC1D;AAAA,IACD;AACA,UAAM,MAAM,SAAS,QAAQ,KAAK;AAClC,QAAI,KAAK,IAAI,GAAG,EAAG;AACnB,SAAK,IAAI,GAAG;AACZ,eAAW,KAAK,EAAE,QAAQ,MAAM,CAAC;AAAA,EAClC;AAEA,SAAO;AACR;AAEA,SAAS,iBAAiB,QAAmC;AAC5D,QAAM,SAAS,kBAAkB,QAAQ,aAAa,WAAW;AACjE,SAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAcF,MAAM;AAAA;AAEZ;AAEA,SAAS,kBAAkB,QAAmC;AAC7D,QAAM,SAAS;AAAA,IACd;AAAA,IACA;AAAA,IACA;AAAA,EACD;AACA,SAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MA6BF,MAAM;AAAA;AAEZ;AAEA,SAAS,kBACR,QACA,YACA,WACS;AACT,MAAI,CAAC,OAAO,OAAQ,QAAO;AAC3B,QAAM,UAAU,OAAO,IAAI,CAAC,EAAE,QAAQ,MAAM,MAAM;AACjD,WAAO,IAAI,UAAU,OAAO,MAAM,SAAS,SAAS,OAAO,KAAK;AAAA,EACjE,CAAC;AACD,SAAO,QAAQ,QAAQ,KAAK,MAAM,CAAC;AACpC;AAEA,SAAS,SAAS,QAAgB,OAAuB;AACxD,SAAO,GAAG,MAAM,IAAI,KAAK;AAC1B;AAEA,SAAS,iBAAiB,OAAwB;AACjD,SAAO,2BAA2B,KAAK,KAAK;AAC7C;AAEA,SAASC,aAAY,OAAoC;AACxD,QAAM,aAAa,MAAM,YAAY;AACrC,MAAI,WAAW,SAAS,MAAM,GAAG;AAChC,WAAO,WAAW,SAAS,cAAc,IAAI,sBAAsB;AAAA,EACpE;AACA,SAAO;AACR;AAEA,SAASC,UAAS,OAAoC;AACrD,MAAI,UAAU,QAAQ,UAAU,OAAW,QAAO;AAClD,QAAM,UAAU,OAAO,KAAK,EAAE,KAAK;AACnC,SAAO,QAAQ,SAAS,UAAU;AACnC;;;ACzWO,IAAM,YAAN,MAAgB;AAAA,EACL;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACT,YAA8B;AAAA,EAEtC,YACC,SACA,YACA,gBACA,SAKC;AACD,QAAI,CAAC,SAAS;AACb,YAAM,IAAI,MAAM,sBAAsB;AAAA,IACvC;AACA,QAAI,CAAC,YAAY;AAChB,YAAM,IAAI,MAAM,yBAAyB;AAAA,IAC1C;AACA,QAAI,CAAC,gBAAgB;AACpB,YAAM,IAAI,MAAM,6BAA6B;AAAA,IAC9C;AAEA,SAAK,UAAU,QAAQ,QAAQ,QAAQ,EAAE;AACzC,SAAK,aAAa;AAClB,SAAK,iBAAiB;AACtB,SAAK,kBAAkB,SAAS;AAChC,SAAK,oBAAoB,SAAS;AAClC,SAAK,YAAY,SAAS,SAAS,WAAW;AAE9C,QAAI,CAAC,KAAK,WAAW;AACpB,YAAM,IAAI;AAAA,QACT;AAAA,MACD;AAAA,IACD;AAAA,EACD;AAAA,EAEA,qBAAyC;AACxC,WAAO,KAAK;AAAA,EACb;AAAA,EAEA,MAAM,IACL,MACA,UACA,QACA,QACA,QACA,WACa;AACb,WAAO,MAAM,KAAK,QAAW,MAAM;AAAA,MAClC,QAAQ;AAAA,MACR,SAAS,MAAM,KAAK;AAAA,QACnB;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACD;AAAA,MACA;AAAA,IACD,CAAC;AAAA,EACF;AAAA,EAEA,MAAM,KACL,MACA,MACA,UACA,QACA,QACA,QACA,WACa;AACb,WAAO,MAAM,KAAK,QAAW,MAAM;AAAA,MAClC,QAAQ;AAAA,MACR,SAAS,MAAM,KAAK;AAAA,QACnB;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACD;AAAA,MACA,MAAM,KAAK,UAAU,QAAQ,CAAC,CAAC;AAAA,MAC/B;AAAA,IACD,CAAC;AAAA,EACF;AAAA,EAEA,MAAM,IACL,MACA,MACA,UACA,QACA,QACA,QACA,WACa;AACb,WAAO,MAAM,KAAK,QAAW,MAAM;AAAA,MAClC,QAAQ;AAAA,MACR,SAAS,MAAM,KAAK;AAAA,QACnB;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACD;AAAA,MACA,MAAM,KAAK,UAAU,QAAQ,CAAC,CAAC;AAAA,MAC/B;AAAA,IACD,CAAC;AAAA,EACF;AAAA,EAEA,MAAM,OACL,MACA,UACA,QACA,QACA,QACA,WACa;AACb,WAAO,MAAM,KAAK,QAAW,MAAM;AAAA,MAClC,QAAQ;AAAA,MACR,SAAS,MAAM,KAAK;AAAA,QACnB;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACD;AAAA,MACA;AAAA,IACD,CAAC;AAAA,EACF;AAAA,EAEA,MAAc,QAAW,MAAc,MAA+B;AACrE,UAAM,WAAW,MAAM,KAAK,UAAU,GAAG,KAAK,OAAO,GAAG,IAAI,IAAI,IAAI;AACpE,UAAM,OAAO,MAAM,SAAS,KAAK;AACjC,QAAI;AACJ,QAAI;AACH,aAAO,OAAO,KAAK,MAAM,IAAI,IAAI;AAAA,IAClC,QAAQ;AACP,aAAO;AAAA,IACR;AAEA,QAAI,CAAC,SAAS,IAAI;AACjB,YAAM,QAAQ,IAAI;AAAA,QACjB,MAAM,SAAS,SAAS,cAAc;AAAA,MACvC;AACA,MAAC,MAAc,SAAS,SAAS;AACjC,UAAI,MAAM,QAAS,CAAC,MAAc,UAAU,KAAK;AACjD,YAAM;AAAA,IACP;AAEA,WAAO;AAAA,EACR;AAAA,EAEA,MAAc,aACb,UACA,QACA,QACA,cAAuB,MACvB,WACkC;AAClC,UAAM,QAAQ,MAAM,KAAK,YAAY,UAAU,QAAQ,MAAM;AAC7D,UAAM,UAAkC;AAAA,MACvC,eAAe,UAAU,KAAK;AAAA,MAC9B,QAAQ;AAAA,IACT;AACA,QAAI,aAAa;AAChB,cAAQ,cAAc,IAAI;AAAA,IAC3B;AACA,QAAI,WAAW;AACd,cAAQ,cAAc,IAAI;AAAA,IAC3B;AACA,QAAI,KAAK,mBAAmB;AAC3B,aAAO,OAAO,SAAS,KAAK,iBAAiB;AAAA,IAC9C;AACA,WAAO;AAAA,EACR;AAAA;AAAA;AAAA;AAAA,EAKQ,gBAAgB,KAAqB;AAE5C,UAAM,QAAQ,IAAI,YAAY,EAAE,OAAO,GAAG;AAI1C,QAAI,SAAS;AACb,UAAM,YAAY;AAClB,aAAS,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK,WAAW;AACjD,YAAM,QAAQ,MAAM,MAAM,GAAG,IAAI,SAAS;AAC1C,gBAAU,OAAO,aAAa,GAAG,KAAK;AAAA,IACvC;AAEA,UAAM,SAAS,KAAK,MAAM;AAG1B,WAAO,OAAO,QAAQ,OAAO,GAAG,EAAE,QAAQ,OAAO,GAAG,EAAE,QAAQ,QAAQ,EAAE;AAAA,EACzE;AAAA;AAAA;AAAA;AAAA,EAKQ,qBAAqB,OAA2B;AAEvD,QAAI,SAAS;AACb,UAAM,YAAY;AAClB,aAAS,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK,WAAW;AACjD,YAAM,QAAQ,MAAM,MAAM,GAAG,IAAI,SAAS;AAC1C,gBAAU,OAAO,aAAa,GAAG,KAAK;AAAA,IACvC;AAEA,UAAM,SAAS,KAAK,MAAM;AAG1B,WAAO,OAAO,QAAQ,OAAO,GAAG,EAAE,QAAQ,OAAO,GAAG,EAAE,QAAQ,QAAQ,EAAE;AAAA,EACzE;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,eAAmC;AAChD,QAAI,KAAK,WAAW;AACnB,aAAO,KAAK;AAAA,IACb;AAIA,SAAK,YAAY,MAAM,OAAO,OAAO;AAAA,MACpC;AAAA,MACA,KAAK,wBAAwB,KAAK,UAAU;AAAA,MAC5C;AAAA,QACC,MAAM;AAAA,QACN,MAAM;AAAA,MACP;AAAA,MACA;AAAA,MACA,CAAC,MAAM;AAAA,IACR;AAEA,WAAO,KAAK;AAAA,EACb;AAAA;AAAA;AAAA;AAAA,EAKQ,wBAAwB,KAA0B;AAEzD,UAAM,YAAY;AAClB,UAAM,YAAY;AAClB,UAAM,cAAc,IAClB,QAAQ,WAAW,EAAE,EACrB,QAAQ,WAAW,EAAE,EACrB,QAAQ,OAAO,EAAE;AAGnB,UAAM,eAAe,KAAK,WAAW;AACrC,UAAM,QAAQ,IAAI,WAAW,aAAa,MAAM;AAChD,aAAS,IAAI,GAAG,IAAI,aAAa,QAAQ,KAAK;AAC7C,YAAM,CAAC,IAAI,aAAa,WAAW,CAAC;AAAA,IACrC;AACA,WAAO,MAAM;AAAA,EACd;AAAA,EAEA,MAAc,YACb,UACA,QACA,QACkB;AAClB,UAAM,SAAS;AAAA,MACd,KAAK;AAAA,MACL,KAAK;AAAA,IACN;AAEA,UAAM,UAAmC;AAAA,MACxC,gBAAgB,KAAK;AAAA,MACrB;AAAA,IACD;AAEA,QAAI,OAAQ,SAAQ,SAAS;AAC7B,QAAI,QAAQ,OAAQ,SAAQ,SAAS;AAErC,UAAM,gBAAgB,KAAK,gBAAgB,KAAK,UAAU,MAAM,CAAC;AACjE,UAAM,iBAAiB,KAAK,gBAAgB,KAAK,UAAU,OAAO,CAAC;AACnE,UAAM,OAAO,GAAG,aAAa,IAAI,cAAc;AAG/C,UAAM,MAAM,MAAM,KAAK,aAAa;AACpC,UAAM,YAAY,IAAI,YAAY,EAAE,OAAO,IAAI;AAC/C,UAAM,YAAY,MAAM,OAAO,OAAO;AAAA,MACrC;AAAA,QACC,MAAM;AAAA,MACP;AAAA,MACA;AAAA,MACA;AAAA,IACD;AAGA,UAAM,iBAAiB,IAAI,WAAW,SAAS;AAC/C,UAAM,mBAAmB,KAAK,qBAAqB,cAAc;AAEjE,WAAO,GAAG,IAAI,IAAI,gBAAgB;AAAA,EACnC;AACD;;;ACjTO,IAAM,cAAN,MAAkB;AAAA,EAChB,YAAY,oBAAI,IAA6B;AAAA,EAC7C,mBAAmB,oBAAI,IAA8B;AAAA,EACrD;AAAA,EAER,eAAe,MAAc,SAA0B,UAAkC;AACxF,SAAK,UAAU,IAAI,MAAM,OAAO;AAChC,SAAK,iBAAiB,IAAI,MAAM,QAAQ;AACxC,QAAI,CAAC,KAAK,iBAAiB;AAC1B,WAAK,kBAAkB;AAAA,IACxB;AAAA,EACD;AAAA,EAEA,YAAY,MAAgC;AAC3C,UAAM,SAAS,QAAQ,KAAK;AAC5B,QAAI,CAAC,QAAQ;AACZ,YAAM,IAAI,MAAM,uBAAuB;AAAA,IACxC;AACA,UAAM,UAAU,KAAK,UAAU,IAAI,MAAM;AACzC,QAAI,CAAC,SAAS;AACb,YAAM,IAAI;AAAA,QACT,aAAa,MAAM,0BAA0B,MAAM;AAAA,UAClD,KAAK,UAAU,KAAK;AAAA,QACrB,EAAE,KAAK,IAAI,CAAC;AAAA,MACb;AAAA,IACD;AACA,WAAO;AAAA,EACR;AAAA,EAEA,oBAAoB,MAA6C;AAChE,UAAM,SAAS,QAAQ,KAAK;AAC5B,QAAI,CAAC,OAAQ,QAAO;AACpB,WAAO,KAAK,iBAAiB,IAAI,MAAM;AAAA,EACxC;AAAA,EAEA,qBAAyC;AACxC,WAAO,KAAK;AAAA,EACb;AAAA,EAEA,MAAM,mBACL,KACA,QACA,cACA,UACmC;AACnC,UAAM,UAAU,KAAK,YAAY,YAAY;AAC7C,UAAM,WAAW,KAAK,oBAAoB,YAAY;AAGtD,QAAI,WAAW;AACf,QAAI,UAAU;AACb,iBAAW,KAAK,sBAAsB,KAAK,QAAQ,UAAU,QAAQ;AAAA,IACtE;AAGA,UAAM,QAAQ,SAAS,UAAU,MAAM;AAGvC,UAAM,SAAS,MAAM,QAAQ,QAAQ,UAAU,MAAM;AACrD,WAAO;AAAA,MACN,MAAM,OAAO;AAAA,MACb,QAAQ,OAAO;AAAA,IAChB;AAAA,EACD;AAAA,EAEA,MAAM,QACL,KACA,QACA,cAC0C;AAC1C,QAAI;AACH,YAAM,UAAU,KAAK,YAAY,YAAY;AAC7C,YAAM,SAAS,MAAM,QAAQ,QAAQ,KAAK,MAAM;AAChD,aAAO,OAAO;AAAA,IACf,SAAS,OAAO;AACf,cAAQ;AAAA,QACP,+CAA+C,YAAY;AAAA,QAC3D;AAAA,MACD;AACA,aAAO,CAAC;AAAA,IACT;AAAA,EACD;AAAA,EAEA,mBAAmB,QAAqD;AACvE,UAAM,SAAsB,CAAC;AAE7B,WAAO,QAAQ,CAAC,OAAO,UAAU;AAChC,YAAM,QAAQ,MAAM;AACpB,UAAI,UAAU,QAAW;AACxB;AAAA,MACD;AACA,YAAM,gBACJ,OAAO,MAAM,SAAS,YAAY,MAAM,KAAK,KAAK,KAClD,OAAO,MAAM,gBAAgB,YAAY,MAAM,YAAY,KAAK,KAChE,OAAO,MAAM,aAAa,YAAY,OAAO,MAAM,QAAQ,KAC5D,OAAO,QAAQ,CAAC;AACjB,YAAM,MAAM,cAAc,QAAQ,WAAW,EAAE,EAAE,KAAK;AACtD,aAAO,GAAG,IAAI;AAAA,IACf,CAAC;AAED,WAAO;AAAA,EACR;AAAA,EAEQ,sBACP,KACA,QACA,UACA,UACS;AACT,QACC,CAAC,SAAS,mBACV,SAAS,2BAA2B,OACnC;AACD,aAAO;AAAA,IACR;AAEA,UAAM,cAAc,SAAS;AAC7B,UAAM,WAAW;AACjB,WAAO,QAAQ,IAAI;AAEnB,UAAM,gBAAgB,IAAI,YAAY;AACtC,QAAI,cAAc,SAAS,YAAY,YAAY,CAAC,GAAG;AACtD,aAAO;AAAA,IACR;AAEA,UAAM,kBACL,SAAS,YAAY,eAClB,GAAG,WAAW,OAAO,WAAW,IAAI,SAAS,mBAAmB,QAAQ,MACxE,GAAG,WAAW,OAAO,QAAQ;AAEjC,QAAI,aAAa,KAAK,GAAG,GAAG;AAC3B,aAAO,IAAI;AAAA,QACV;AAAA,QACA,CAAC,UAAU,GAAG,KAAK,IAAI,eAAe;AAAA,MACvC;AAAA,IACD;AAEA,WAAO,GAAG,GAAG,UAAU,eAAe;AAAA,EACvC;AACD;;;AC/EA,eAAsB,YACrB,QACA,MACA,SACA,QACoB;AACpB,QAAM,WAAW,gBAAgB,QAAQ,SAAS,QAAQ;AAC1D,SAAO,MAAM,OAAO;AAAA,IACnB;AAAA,IACA;AAAA,IACA;AAAA,IACA,SAAS;AAAA,IACT,SAAS;AAAA,IACT;AAAA,EACD;AACD;AAEA,eAAsB,WACrB,QACA,aACA,SACA,QACuC;AACvC,QAAM,WAAW,gBAAgB,QAAQ,SAAS,QAAQ;AAC1D,QAAM,SAAS,IAAI,gBAAgB;AACnC,MAAI,SAAS,YAAY;AACxB,WAAO,IAAI,QAAQ,GAAG,QAAQ,WAAW,IAAI,EAAE;AAChD,MAAI,SAAS,YAAY;AACxB,WAAO,IAAI,SAAS,GAAG,QAAQ,WAAW,KAAK,EAAE;AAClD,MAAI,SAAS,OAAQ,QAAO,IAAI,WAAW,QAAQ,MAAM;AACzD,MAAI,SAAS,QAAS,QAAO,IAAI,YAAY,QAAQ,OAAO;AAC5D,MAAI,SAAS,MAAO,QAAO,IAAI,SAAS,QAAQ,KAAK;AACrD,MAAI,SAAS,WAAY,QAAO,IAAI,WAAW,QAAQ,UAAU;AACjE,MAAI,SAAS,YAAa,QAAO,IAAI,gBAAgB,QAAQ,WAAW;AACxE,MAAI,SAAS,UAAW,QAAO,IAAI,cAAc,QAAQ,SAAS;AAClE,MAAI,SAAS,YAAa,QAAO,IAAI,gBAAgB,QAAQ,WAAW;AACxE,MAAI,SAAS,UAAW,QAAO,IAAI,cAAc,QAAQ,SAAS;AAElE,QAAM,WAAW,MAAM,OAAO;AAAA,IAC7B,UAAU,OAAO,SAAS,IAAI,IAAI,OAAO,SAAS,CAAC,KAAK,EAAE;AAAA,IAC1D;AAAA,IACA,SAAS;AAAA,IACT,SAAS;AAAA,IACT;AAAA,EACD;AAEA,MAAI,SAAS,aAAa;AACzB,aAAS,OAAO,MAAM,QAAQ;AAAA,MAC7B,SAAS,KAAK,IAAI,OAAO,WAAW;AAAA,QACnC,GAAG;AAAA,QACH,gBAAgB;AAAA,UACf,GAAG,MAAM;AAAA,UACT,MAAM;AAAA,YACL,QAAQ,MAAM,kBAAkB,aAAa,OAAO,QAAQ;AAAA,UAC7D;AAAA,QACD;AAAA,MACD,EAAE;AAAA,IACH;AAAA,EACD;AAEA,SAAO;AACR;AAEA,eAAsB,SACrB,QACA,aACA,IACA,SACA,QACoB;AACpB,QAAM,WAAW,gBAAgB,QAAQ,SAAS,QAAQ;AAC1D,QAAM,QAAQ,MAAM,OAAO;AAAA,IAC1B,WAAW,mBAAmB,EAAE,CAAC;AAAA,IACjC;AAAA,IACA,SAAS;AAAA,IACT,SAAS;AAAA,IACT;AAAA,EACD;AAEA,SAAO;AAAA,IACN,GAAG;AAAA,IACH,gBAAgB;AAAA,MACf,GAAG,MAAM;AAAA,MACT,MAAM;AAAA,QACL,QAAQ,MAAM,kBAAkB,aAAa,OAAO,QAAQ;AAAA,MAC7D;AAAA,IACD;AAAA,EACD;AACD;AAEA,eAAsB,YACrB,QACA,IACA,MACA,SACA,QACoB;AACpB,QAAM,WAAW,gBAAgB,QAAQ,SAAS,QAAQ;AAC1D,SAAO,MAAM,OAAO;AAAA,IACnB,WAAW,mBAAmB,EAAE,CAAC;AAAA,IACjC;AAAA,IACA;AAAA,IACA,SAAS;AAAA,IACT,SAAS;AAAA,IACT;AAAA,EACD;AACD;AAEA,eAAsB,YACrB,QACA,IACA,SACA,QACgB;AAChB,QAAM,WAAW,gBAAgB,QAAQ,SAAS,QAAQ;AAC1D,QAAM,OAAO;AAAA,IACZ,WAAW,mBAAmB,EAAE,CAAC;AAAA,IACjC;AAAA,IACA,SAAS;AAAA,IACT,SAAS;AAAA,IACT;AAAA,EACD;AACD;AAEA,SAAS,gBAAgB,QAAmB,UAA2B;AACtE,QAAM,WAAW,YAAY,OAAO,mBAAmB;AACvD,MAAI,CAAC,UAAU;AACd,UAAM,IAAI;AAAA,MACT;AAAA,IACD;AAAA,EACD;AACA,SAAO;AACR;AAEA,eAAe,kBACd,aACA,OACA,UACqC;AACrC,QAAM,eAAe,MAAM,aAAa,YAAY,mBAAmB;AACvE,MAAI,CAAC,cAAc;AAClB,YAAQ,KAAK,8CAA8C;AAC3D,WAAO,CAAC;AAAA,EACT;AACA,MAAI;AACH,UAAM,SAAS,MAAM,YAAY;AAAA,MAChC,MAAM;AAAA,MACL,MAAM,cAAqC,CAAC;AAAA,MAC7C;AAAA,MACA;AAAA,IACD;AACA,WAAO,OAAO;AAAA,EACf,SAAS,OAAO;AACf,YAAQ,KAAK,kCAAkC,KAAK,EAAE;AACtD,WAAO,CAAC;AAAA,EACT;AACD;;;ACrMA,eAAsB,kBACrB,QACA,MACA,SACA,QAC0B;AAC1B,QAAM,WAAWC,iBAAgB,QAAQ,SAAS,QAAQ;AAC1D,SAAO,MAAM,OAAO;AAAA,IACnB;AAAA,IACA;AAAA,IACA;AAAA,IACA,SAAS;AAAA,IACT,SAAS;AAAA,IACT;AAAA,EACD;AACD;AAEA,eAAsB,iBACrB,QACA,aACA,SACA,QACoD;AACpD,QAAM,WAAWA,iBAAgB,QAAQ,SAAS,QAAQ;AAC1D,QAAM,SAAS,IAAI,gBAAgB;AACnC,MAAI,SAAS,YAAY;AACxB,WAAO,IAAI,QAAQ,GAAG,QAAQ,WAAW,IAAI,EAAE;AAChD,MAAI,SAAS,YAAY;AACxB,WAAO,IAAI,SAAS,GAAG,QAAQ,WAAW,KAAK,EAAE;AAClD,MAAI,SAAS,OAAQ,QAAO,IAAI,WAAW,QAAQ,MAAM;AACzD,MAAI,SAAS,QAAS,QAAO,IAAI,YAAY,QAAQ,OAAO;AAC5D,MAAI,SAAS,MAAO,QAAO,IAAI,QAAQ,QAAQ,KAAK;AACpD,MAAI,SAAS,WAAY,QAAO,IAAI,WAAW,QAAQ,UAAU;AACjE,MAAI,SAAS,YAAa,QAAO,IAAI,gBAAgB,QAAQ,WAAW;AACxE,MAAI,SAAS,UAAW,QAAO,IAAI,cAAc,QAAQ,SAAS;AAClE,MAAI,SAAS,YAAa,QAAO,IAAI,gBAAgB,QAAQ,WAAW;AACxE,MAAI,SAAS,UAAW,QAAO,IAAI,cAAc,QAAQ,SAAS;AAElE,QAAM,WAAW,MAAM,OAAO;AAAA,IAG7B,iBAAiB,OAAO,SAAS,IAAI,IAAI,OAAO,SAAS,CAAC,KAAK,EAAE;AAAA,IACjE;AAAA,IACA,SAAS;AAAA,IACT,SAAS;AAAA,IACT;AAAA,EACD;AAEA,MAAI,SAAS,UAAU;AACtB,aAAS,OAAO,MAAM,QAAQ;AAAA,MAC7B,SAAS,KAAK,IAAI,OAAO,YAAY;AAAA,QACpC,GAAG;AAAA,QACH,OAAO,OAAO,QACX,MAAa;AAAA,UACb;AAAA,UACA;AAAA,UACA,OAAO;AAAA,UACP;AAAA,UACA;AAAA,QACD,IACC;AAAA,MACJ,EAAE;AAAA,IACH;AAAA,EACD;AAEA,SAAO;AACR;AAEA,eAAsB,eACrB,QACA,aACA,IACA,SACA,QAC0B;AAC1B,QAAM,WAAWA,iBAAgB,QAAQ,SAAS,QAAQ;AAC1D,QAAM,SAAS,MAAM,OAAO;AAAA,IAC3B,kBAAkB,mBAAmB,EAAE,CAAC;AAAA,IACxC;AAAA,IACA,SAAS;AAAA,IACT,SAAS;AAAA,IACT;AAAA,EACD;AAEA,MAAI,SAAS,YAAY,OAAO,UAAU;AACzC,WAAO;AAAA,MACN,GAAG;AAAA,MACH,OAAO,MAAa;AAAA,QACnB;AAAA,QACA;AAAA,QACA,OAAO;AAAA,QACP;AAAA,QACA;AAAA,MACD;AAAA,IACD;AAAA,EACD;AAEA,SAAO;AACR;AAEA,eAAsB,kBACrB,QACA,IACA,MACA,SACA,QAC0B;AAC1B,QAAM,WAAWA,iBAAgB,QAAQ,SAAS,QAAQ;AAC1D,SAAO,MAAM,OAAO;AAAA,IACnB,kBAAkB,mBAAmB,EAAE,CAAC;AAAA,IACxC;AAAA,IACA;AAAA,IACA,SAAS;AAAA,IACT,SAAS;AAAA,IACT;AAAA,EACD;AACD;AAEA,eAAsB,kBACrB,QACA,IACA,SACA,QACgB;AAChB,QAAM,WAAWA,iBAAgB,QAAQ,SAAS,QAAQ;AAC1D,QAAM,OAAO;AAAA,IACZ,kBAAkB,mBAAmB,EAAE,CAAC;AAAA,IACxC;AAAA,IACA,SAAS;AAAA,IACT,SAAS;AAAA,IACT;AAAA,EACD;AACD;AAEA,SAASA,iBAAgB,QAAmB,UAA2B;AACtE,QAAM,WAAW,YAAY,OAAO,mBAAmB;AACvD,MAAI,CAAC,UAAU;AACd,UAAM,IAAI;AAAA,MACT;AAAA,IACD;AAAA,EACD;AACA,SAAO;AACR;;;ACpIA,eAAsB,WACrB,QACA,aACA,cACA,SACA,QAC0B;AAC1B,QAAM,WAAWC,iBAAgB,QAAQ,QAAQ,QAAQ;AACzD,QAAM,UAAU,YAAY,YAAY,YAAY;AACpD,QAAM,WAAW,YAAY,oBAAoB,YAAY;AAE7D,QAAM,gBAAgB,MAAM,QAAQ;AAAA,IACnC,QAAQ,SAAS,EAAE,QAAQ,QAAQ,OAAO,IAAI;AAAA,EAC/C;AAEA,QAAM,UAAU,mBAAmB,cAAc,SAAS,eAAe,QAAQ;AACjF,MAAI,QAAQ,cAAc;AACzB,YAAQ,gBAAgB;AAAA,EACzB;AAGA,QAAM,YAAY,OAAO,WAAW;AAEpC,QAAM,WAAW,MAAM,OAAO;AAAA,IAC7B;AAAA,IACA;AAAA,IACA;AAAA,IACA,QAAQ;AAAA,IACR,QAAQ;AAAA,IACR;AAAA,IACA;AAAA,EACD;AAEA,SAAO;AACR;AAEA,SAASA,iBAAgB,QAAmB,UAA2B;AACtE,QAAM,WAAW,YAAY,OAAO,mBAAmB;AACvD,MAAI,CAAC,UAAU;AACd,UAAM,IAAI;AAAA,MACT;AAAA,IACD;AAAA,EACD;AACA,SAAO;AACR;AAEA,SAAS,mBACR,cACA,SACA,eACA,UAKsB;AACtB,QAAM,UAAU,QAAQ,WAAW;AACnC,QAAM,SAA8B,cAAc,OAAO,IAAI,CAAC,WAAW;AAAA,IACxE,YAAY,MAAM;AAAA,IAClB,aAAa,MAAM,WAAW,SAAS,MAAM,IAAI;AAAA,IACjD,SAAS,MAAM,QAAQ,IAAI,CAAC,YAAY;AAAA,MACvC,MAAM,OAAO;AAAA,MACb,WAAW,OAAO,WAAW,OAAO;AAAA,MACpC,gBAAgB,QAAQ,OAAO,YAAY;AAAA,MAC3C,aAAa,OAAO,WAAW;AAAA,IAChC,EAAE;AAAA,EACH,EAAE;AAEF,QAAM,UAA+B;AAAA,IACpC,UAAU;AAAA,IACV;AAAA,IACA;AAAA,EACD;AAGA,MACC,UAAU,mBACV,UAAU,mBACV,UAAU,2BAA2B,QACpC;AACD,YAAQ,kBAAkB;AAAA,MACzB,iBAAiB,SAAS;AAAA,MAC1B,iBAAiB,SAAS;AAAA,MAC1B,wBAAwB,SAAS;AAAA,IAClC;AAAA,EACD;AAEA,SAAO;AACR;;;AC9EA,eAAsB,IACrB,QACA,aACA,UACA,SACA,QACuB;AACvB,QAAM,WAAWC,iBAAgB,QAAQ,QAAQ,QAAQ;AACzD,QAAM,YAAY,OAAO,WAAW;AACpC,QAAM,WAAW,QAAQ,YAAY;AACrC,MAAI,UAAU;AACd,MAAI,YAAgC,QAAQ;AAC5C,MAAI,cAAkC,QAAQ;AAE9C,SAAO,WAAW,UAAU;AAE3B,YAAQ,IAAI,EAAE,WAAW,YAAY,CAAC;AACtC,UAAM,gBAAgB,MAAM,OAAO;AAAA,MAClC;AAAA,MACA;AAAA,QACC;AAAA,QACA,GAAI,YAAY,EAAE,YAAY,UAAU,IAAI,CAAC;AAAA,QAC7C,GAAI,cAAc,EAAE,cAAc,YAAY,IAAI,CAAC;AAAA,QACnD,GAAI,QAAQ,WAAW,EAAE,WAAW,QAAQ,SAAS,IAAI,CAAC;AAAA,MAC3D;AAAA,MACA;AAAA,MACA,QAAQ;AAAA,MACR,QAAQ;AAAA,MACR;AAAA,MACA;AAAA,IACD;AAEA,UAAM,eACL,cAAc,YACd,QAAQ,YACR,YAAY,mBAAmB;AAChC,QAAI,CAAC,cAAc;AAClB,YAAM,IAAI;AAAA,QACT;AAAA,MACD;AAAA,IACD;AAGA,UAAM,gBAAgB,MAAM,QAAQ,cAAc,MAAM,IACrD,cAAc,SACd,CAAC;AACJ,UAAM,cAAc,YAAY,mBAAmB,aAAa;AAGhE,QAAI;AACH,YAAM,YAAY,MAAM,YAAY;AAAA,QACnC,cAAc;AAAA,QACd;AAAA,QACA;AAAA,QACA;AAAA,MACD;AACA,YAAM,OAAO,UAAU,QAAQ,CAAC;AAGhC,UAAI,QAAuB;AAAA,QAC1B,cAAc;AAAA,QACd,OAAO,KAAK,WAAW,IAAI,4BAA4B;AAAA,MACxD;AAEA,UAAI,KAAK,SAAS,GAAG;AACpB,cAAM,gBAAgB,MAAM,OAAO;AAAA,UAClC;AAAA,UACA;AAAA,YACC;AAAA,YACA,KAAK,cAAc;AAAA,YACnB,WAAW,cAAc;AAAA,YACzB,QAAQ,UAAU;AAAA,YAClB,MAAM,iBAAiB,IAAI;AAAA,YAC3B,aAAa,QAAQ,mBAAmB;AAAA,YACxC,UAAU,cAAc;AAAA,UACzB;AAAA,UACA;AAAA,UACA,QAAQ;AAAA,UACR,QAAQ;AAAA,UACR;AAAA,UACA;AAAA,QACD;AAEA,gBAAQ;AAAA,UACP,cAAc,cAAc,QACzB;AAAA,YACA,GAAG,cAAc;AAAA,YACjB,MAAM,EAAE,QAAQ,KAAK;AAAA,UACtB,IACC;AAAA,UACH,OAAO,cAAc;AAAA,QACtB;AAAA,MACD;AAEA,aAAO;AAAA,QACN,KAAK,cAAc;AAAA,QACnB,QAAQ;AAAA,QACR;AAAA,QACA,WAAW,cAAc;AAAA,QACzB,SAAS,cAAc;AAAA,QACvB,SAAS,cAAc;AAAA,QACvB;AAAA,QACA,QAAQ,UAAU;AAAA,QAClB;AAAA,QACA,SAAS,cAAc;AAAA,QACvB,UAAU,UAAU;AAAA,QACpB,WAAW;AAAA,MACZ;AAAA,IACD,SAAS,OAAO;AACf;AAGA,UAAI,UAAU,UAAU;AACvB,cAAM;AAAA,MACP;AAGA,kBAAY,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AACjE,oBAAc,cAAc;AAG5B,cAAQ;AAAA,QACP,iCAAiC,OAAO,IAAI,WAAW,CAAC,MAAM,SAAS;AAAA,MACxE;AAAA,IACD;AAAA,EACD;AAGA,QAAM,IAAI,MAAM,oCAAoC;AACrD;AAEA,SAASA,iBAAgB,QAAmB,UAA2B;AACtE,QAAM,WAAW,YAAY,OAAO,mBAAmB;AACvD,MAAI,CAAC,UAAU;AACd,UAAM,IAAI;AAAA,MACT;AAAA,IACD;AAAA,EACD;AACA,SAAO;AACR;AAEO,SAAS,iBACf,MACgC;AAChC,MAAI,CAAC,MAAM,OAAQ,QAAO,CAAC;AAC3B,SAAO,KAAK,IAAI,CAAC,QAAQ;AACxB,UAAM,SAAiC,CAAC;AACxC,WAAO,QAAQ,GAAG,EAAE,QAAQ,CAAC,CAAC,KAAK,KAAK,MAAM;AAC7C,UAAI,UAAU,KAAM,QAAO,GAAG,IAAI;AAAA,eACzB,MAAM,QAAQ,KAAK,EAAG,QAAO,GAAG,IAAI;AAAA,UACxC,QAAO,GAAG,IAAI,OAAO;AAAA,IAC3B,CAAC;AACD,WAAO;AAAA,EACR,CAAC;AACF;;;ACnJO,IAAM,mBAAN,MAAuB;AAAA,EACZ;AAAA,EACA;AAAA,EAEjB,YACC,SACA,YACA,gBACA,SAKC;AACD,SAAK,SAAS,IAAI,UAAU,SAAS,YAAY,gBAAgB,OAAO;AACxE,SAAK,cAAc,IAAI,YAAY;AAAA,EACpC;AAAA;AAAA,EAIA,iBACC,MACA,UACA,SAOO;AACP,UAAM,UAAU,IAAI,kBAAkB,UAAU,OAAO;AAEvD,UAAM,WAA6B;AAAA,MAClC;AAAA,MACA,SAAS;AAAA,MACT,aAAa,SAAS;AAAA,MACtB,MAAM,SAAS;AAAA,MACf,iBAAiB,SAAS;AAAA,MAC1B,iBAAiB,SAAS,mBAAmB;AAAA,MAC7C,wBAAwB,SAAS,kBAC7B,SAAS,0BAA0B,OACpC;AAAA,IACJ;AAEA,SAAK,YAAY,eAAe,MAAM,SAAS,QAAQ;AAAA,EACxD;AAAA,EAEA,eACC,MACA,UACA,SAMO;AACP,UAAM,UAAU,IAAI,gBAAgB,UAAU,OAAO;AAErD,UAAM,WAA6B;AAAA,MAClC;AAAA,MACA,SAAS;AAAA,MACT,aAAa,SAAS;AAAA,MACtB,MAAM,SAAS;AAAA,MACf,iBAAiB,SAAS;AAAA,MAC1B,wBAAwB,SAAS,kBAC7B,SAAS,0BAA0B,OACpC;AAAA,IACJ;AAEA,SAAK,YAAY,eAAe,MAAM,SAAS,QAAQ;AAAA,EACxD;AAAA,EAEA,eAAe,MAAc,SAAgC;AAC5D,UAAM,WAA6B;AAAA,MAClC;AAAA,MACA,SAAS,QAAQ,WAAW;AAAA,IAC7B;AACA,SAAK,YAAY,eAAe,MAAM,SAAS,QAAQ;AAAA,EACxD;AAAA;AAAA,EAIA,MAAM,WACL,cACA,QAC+B;AAC/B,UAAM,UAAU,KAAK,YAAY,YAAY,YAAY;AACzD,WAAO,MAAM,QAAQ,WAAW,SAAS,EAAE,OAAO,IAAI,MAAS;AAAA,EAChE;AAAA,EAEA,MAAM,WACL,cACA,SACA,QACsC;AACtC,WAAO,MAAkB;AAAA,MACxB,KAAK;AAAA,MACL,KAAK;AAAA,MACL;AAAA,MACA;AAAA,MACA;AAAA,IACD;AAAA,EACD;AAAA;AAAA,EAIA,MAAM,IACL,UACA,SACA,QACkC;AAClC,WAAO,MAAiB;AAAA,MACvB,KAAK;AAAA,MACL,KAAK;AAAA,MACL;AAAA,MACA;AAAA,MACA;AAAA,IACD;AAAA,EACD;AAAA;AAAA,EAIA,MAAM,YACL,MACA,SACA,QACgC;AAChC,WAAO,MAAkB,YAAY,KAAK,QAAQ,MAAM,SAAS,MAAM;AAAA,EACxE;AAAA,EAEA,MAAM,WACL,SACA,QAC+D;AAC/D,WAAO,MAAkB;AAAA,MACxB,KAAK;AAAA,MACL,KAAK;AAAA,MACL;AAAA,MACA;AAAA,IACD;AAAA,EACD;AAAA,EAEA,MAAM,SACL,IACA,SACA,QACgC;AAChC,WAAO,MAAkB;AAAA,MACxB,KAAK;AAAA,MACL,KAAK;AAAA,MACL;AAAA,MACA;AAAA,MACA;AAAA,IACD;AAAA,EACD;AAAA,EAEA,MAAM,YACL,IACA,MACA,SACA,QACgC;AAChC,WAAO,MAAkB;AAAA,MACxB,KAAK;AAAA,MACL;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACD;AAAA,EACD;AAAA,EAEA,MAAM,YACL,IACA,SACA,QACgB;AAChB,UAAkB,YAAY,KAAK,QAAQ,IAAI,SAAS,MAAM;AAAA,EAC/D;AAAA;AAAA,EAIA,MAAM,kBACL,MACA,SACA,QAC4C;AAC5C,WAAO,MAAwB;AAAA,MAC9B,KAAK;AAAA,MACL;AAAA,MACA;AAAA,MACA;AAAA,IACD;AAAA,EACD;AAAA,EAEA,MAAM,iBACL,SACA,QAC2E;AAC3E,WAAO,MAAwB;AAAA,MAC9B,KAAK;AAAA,MACL,KAAK;AAAA,MACL;AAAA,MACA;AAAA,IACD;AAAA,EACD;AAAA,EAEA,MAAM,eACL,IACA,SACA,QAC4C;AAC5C,WAAO,MAAwB;AAAA,MAC9B,KAAK;AAAA,MACL,KAAK;AAAA,MACL;AAAA,MACA;AAAA,MACA;AAAA,IACD;AAAA,EACD;AAAA,EAEA,MAAM,kBACL,IACA,MACA,SACA,QAC4C;AAC5C,WAAO,MAAwB;AAAA,MAC9B,KAAK;AAAA,MACL;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACD;AAAA,EACD;AAAA,EAEA,MAAM,kBACL,IACA,SACA,QACgB;AAChB,UAAwB,kBAAkB,KAAK,QAAQ,IAAI,SAAS,MAAM;AAAA,EAC3E;AACD;","names":["normalizeTableFilter","asTableType","sanitize","resolveTenantId","resolveTenantId","resolveTenantId"]}
|