@querypanel/node-sdk 1.0.28 → 1.0.29

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,5 +1,12 @@
1
+ // src/index.ts
2
+ import { createHash, randomUUID } from "crypto";
3
+ import { importPKCS8, SignJWT } from "jose";
4
+
1
5
  // src/utils/clickhouse.ts
2
6
  var WRAPPER_REGEX = /^(Nullable|LowCardinality|SimpleAggregateFunction)\((.+)\)$/i;
7
+ function isNullableType(type) {
8
+ return /Nullable\s*\(/i.test(type);
9
+ }
3
10
  function unwrapTypeModifiers(type) {
4
11
  let current = type.trim();
5
12
  let match = WRAPPER_REGEX.exec(current);
@@ -13,6 +20,26 @@ function unwrapTypeModifiers(type) {
13
20
  }
14
21
  return current;
15
22
  }
23
+ function extractPrecisionScale(type) {
24
+ const unwrapped = unwrapTypeModifiers(type);
25
+ const decimalMatch = unwrapped.match(/Decimal(?:\d+)?\((\d+)\s*,\s*(\d+)\)/i);
26
+ if (!decimalMatch) return {};
27
+ const precision = decimalMatch[1];
28
+ const scale = decimalMatch[2];
29
+ if (!precision || !scale) return {};
30
+ return {
31
+ precision: Number.parseInt(precision, 10),
32
+ scale: Number.parseInt(scale, 10)
33
+ };
34
+ }
35
+ function extractFixedStringLength(type) {
36
+ const unwrapped = unwrapTypeModifiers(type);
37
+ const match = unwrapped.match(/^(?:FixedString|StringFixed)\((\d+)\)$/i);
38
+ if (!match) return void 0;
39
+ const length = match[1];
40
+ if (!length) return void 0;
41
+ return Number.parseInt(length, 10);
42
+ }
16
43
  function parseKeyExpression(expression) {
17
44
  if (!expression) return [];
18
45
  let value = expression.trim();
@@ -100,10 +127,6 @@ var ClickHouseAdapter = class {
100
127
  getDialect() {
101
128
  return "clickhouse";
102
129
  }
103
- /**
104
- * Simplified introspection: only collect table/column metadata for IngestRequest
105
- * No indexes, constraints, or statistics
106
- */
107
130
  async introspect(options) {
108
131
  const tablesToIntrospect = options?.tables ? normalizeTableFilter(options.tables) : this.allowedTables;
109
132
  const allowTables = tablesToIntrospect ?? [];
@@ -116,7 +139,7 @@ var ClickHouseAdapter = class {
116
139
  }
117
140
  const filterClause = hasFilter ? " AND name IN {tables:Array(String)}" : "";
118
141
  const tables = await this.query(
119
- `SELECT name, engine, comment, primary_key
142
+ `SELECT name, engine, comment, total_rows, total_bytes, primary_key, sorting_key
120
143
  FROM system.tables
121
144
  WHERE database = {db:String}${filterClause}
122
145
  ORDER BY name`,
@@ -124,7 +147,7 @@ var ClickHouseAdapter = class {
124
147
  );
125
148
  const columnFilterClause = hasFilter ? " AND table IN {tables:Array(String)}" : "";
126
149
  const columns = await this.query(
127
- `SELECT table, name, type, position, comment, is_in_primary_key
150
+ `SELECT table, name, type, position, default_kind, default_expression, comment, is_in_primary_key
128
151
  FROM system.columns
129
152
  WHERE database = {db:String}${columnFilterClause}
130
153
  ORDER BY table, position`,
@@ -139,19 +162,44 @@ var ClickHouseAdapter = class {
139
162
  const tableSchemas = tables.map((table) => {
140
163
  const tableColumns = columnsByTable.get(table.name) ?? [];
141
164
  const primaryKeyColumns = parseKeyExpression(table.primary_key);
165
+ const totalRows = toNumber(table.total_rows);
166
+ const totalBytes = toNumber(table.total_bytes);
142
167
  for (const column of tableColumns) {
143
168
  column.isPrimaryKey = column.isPrimaryKey || primaryKeyColumns.includes(column.name);
144
169
  }
170
+ const indexes = primaryKeyColumns.length ? [
171
+ {
172
+ name: "primary_key",
173
+ columns: primaryKeyColumns,
174
+ unique: true,
175
+ type: "PRIMARY KEY",
176
+ ...table.primary_key ? { definition: table.primary_key } : {}
177
+ }
178
+ ] : [];
179
+ const constraints = primaryKeyColumns.length ? [
180
+ {
181
+ name: "primary_key",
182
+ type: "PRIMARY KEY",
183
+ columns: primaryKeyColumns
184
+ }
185
+ ] : [];
145
186
  const base = {
146
187
  name: table.name,
147
188
  schema: this.databaseName,
148
189
  type: asTableType(table.engine),
149
- columns: tableColumns
190
+ engine: table.engine,
191
+ columns: tableColumns,
192
+ indexes,
193
+ constraints
150
194
  };
151
195
  const comment = sanitize(table.comment);
152
196
  if (comment !== void 0) {
153
197
  base.comment = comment;
154
198
  }
199
+ const statistics = buildTableStatistics(totalRows, totalBytes);
200
+ if (statistics) {
201
+ base.statistics = statistics;
202
+ }
155
203
  return base;
156
204
  });
157
205
  return {
@@ -163,6 +211,10 @@ var ClickHouseAdapter = class {
163
211
  introspectedAt: (/* @__PURE__ */ new Date()).toISOString()
164
212
  };
165
213
  }
214
+ /**
215
+ * Validate that the SQL query only references allowed tables.
216
+ * This is a basic validation that extracts table-like patterns from the query.
217
+ */
166
218
  validateQueryTables(sql) {
167
219
  if (!this.allowedTables || this.allowedTables.length === 0) {
168
220
  return;
@@ -240,15 +292,29 @@ function normalizeTableFilter(tables) {
240
292
  return normalized;
241
293
  }
242
294
  function transformColumnRow(row) {
295
+ const nullable = isNullableType(row.type);
243
296
  const unwrappedType = unwrapTypeModifiers(row.type);
297
+ const { precision, scale } = extractPrecisionScale(row.type);
298
+ const maxLength = extractFixedStringLength(row.type);
244
299
  const column = {
245
300
  name: row.name,
246
301
  type: unwrappedType,
247
302
  rawType: row.type,
248
- isPrimaryKey: Boolean(toNumber(row.is_in_primary_key))
303
+ nullable,
304
+ isPrimaryKey: Boolean(toNumber(row.is_in_primary_key)),
305
+ isForeignKey: false
249
306
  };
307
+ const defaultKind = sanitize(row.default_kind);
308
+ if (defaultKind !== void 0) column.defaultKind = defaultKind;
309
+ const defaultExpression = sanitize(row.default_expression);
310
+ if (defaultExpression !== void 0) {
311
+ column.defaultExpression = defaultExpression;
312
+ }
250
313
  const comment = sanitize(row.comment);
251
314
  if (comment !== void 0) column.comment = comment;
315
+ if (maxLength !== void 0) column.maxLength = maxLength;
316
+ if (precision !== void 0) column.precision = precision;
317
+ if (scale !== void 0) column.scale = scale;
252
318
  return column;
253
319
  }
254
320
  function asTableType(engine) {
@@ -260,6 +326,13 @@ function asTableType(engine) {
260
326
  }
261
327
  return "table";
262
328
  }
329
+ function buildTableStatistics(totalRows, totalBytes) {
330
+ if (totalRows === void 0 && totalBytes === void 0) return void 0;
331
+ const stats = {};
332
+ if (totalRows !== void 0) stats.totalRows = totalRows;
333
+ if (totalBytes !== void 0) stats.totalBytes = totalBytes;
334
+ return stats;
335
+ }
263
336
  function sanitize(value) {
264
337
  if (value === null || value === void 0) return void 0;
265
338
  const trimmed = String(value).trim();
@@ -302,6 +375,10 @@ var PostgresAdapter = class {
302
375
  const fields = result.fields.map((f) => f.name);
303
376
  return { fields, rows: result.rows };
304
377
  }
378
+ /**
379
+ * Validate that the SQL query only references allowed tables.
380
+ * This is a basic validation that extracts table-like patterns from the query.
381
+ */
305
382
  validateQueryTables(sql) {
306
383
  if (!this.allowedTables || this.allowedTables.length === 0) {
307
384
  return;
@@ -327,6 +404,11 @@ var PostgresAdapter = class {
327
404
  /**
328
405
  * Convert named params to positional array for PostgreSQL
329
406
  * PostgreSQL expects $1, $2, $3 in SQL and an array of values [val1, val2, val3]
407
+ *
408
+ * Supports two formats:
409
+ * 1. Numeric keys: { '1': 'value1', '2': 'value2' } - maps directly to $1, $2
410
+ * 2. Named keys: { 'tenant_id': 'value' } - values extracted in alphabetical order
411
+ * 3. Mixed: { '1': 'value1', 'tenant_id': 'value' } - numeric keys first, then named keys
330
412
  */
331
413
  convertNamedToPositionalParams(params) {
332
414
  const numericKeys = Object.keys(params).filter((k) => /^\d+$/.test(k)).map((k) => Number.parseInt(k, 10)).sort((a, b) => a - b);
@@ -359,10 +441,6 @@ var PostgresAdapter = class {
359
441
  getDialect() {
360
442
  return "postgres";
361
443
  }
362
- /**
363
- * Simplified introspection: only collect table/column metadata for IngestRequest
364
- * No indexes, constraints, or statistics
365
- */
366
444
  async introspect(options) {
367
445
  const tablesToIntrospect = options?.tables ? normalizeTableFilter2(options.tables, this.defaultSchema) : this.allowedTables;
368
446
  const normalizedTables = tablesToIntrospect ?? [];
@@ -374,20 +452,39 @@ var PostgresAdapter = class {
374
452
  buildColumnsQuery(normalizedTables)
375
453
  );
376
454
  const columnRows = columnsResult.rows;
455
+ const constraintsResult = await this.clientFn(
456
+ buildConstraintsQuery(normalizedTables)
457
+ );
458
+ const constraintRows = constraintsResult.rows;
459
+ const indexesResult = await this.clientFn(
460
+ buildIndexesQuery(normalizedTables)
461
+ );
462
+ const indexRows = indexesResult.rows;
377
463
  const tablesByKey = /* @__PURE__ */ new Map();
464
+ const columnsByKey = /* @__PURE__ */ new Map();
378
465
  for (const row of tableRows) {
379
466
  const key = tableKey(row.schema_name, row.table_name);
467
+ const statistics = buildTableStatistics2(
468
+ toNumber2(row.total_rows),
469
+ toNumber2(row.total_bytes)
470
+ );
380
471
  const table = {
381
472
  name: row.table_name,
382
473
  schema: row.schema_name,
383
474
  type: asTableType2(row.table_type),
384
- columns: []
475
+ columns: [],
476
+ indexes: [],
477
+ constraints: []
385
478
  };
386
479
  const comment = sanitize2(row.comment);
387
480
  if (comment !== void 0) {
388
481
  table.comment = comment;
389
482
  }
483
+ if (statistics) {
484
+ table.statistics = statistics;
485
+ }
390
486
  tablesByKey.set(key, table);
487
+ columnsByKey.set(key, /* @__PURE__ */ new Map());
391
488
  }
392
489
  for (const row of columnRows) {
393
490
  const key = tableKey(row.table_schema, row.table_name);
@@ -396,13 +493,80 @@ var PostgresAdapter = class {
396
493
  const column = {
397
494
  name: row.column_name,
398
495
  type: row.data_type,
399
- isPrimaryKey: row.is_primary_key
496
+ nullable: row.is_nullable.toUpperCase() === "YES",
497
+ isPrimaryKey: false,
498
+ isForeignKey: false
400
499
  };
401
500
  const rawType = row.udt_name ?? void 0;
402
501
  if (rawType !== void 0) column.rawType = rawType;
502
+ const defaultExpression = sanitize2(row.column_default);
503
+ if (defaultExpression !== void 0)
504
+ column.defaultExpression = defaultExpression;
403
505
  const comment = sanitize2(row.description);
404
506
  if (comment !== void 0) column.comment = comment;
507
+ const maxLength = row.character_maximum_length ?? void 0;
508
+ if (maxLength !== void 0) column.maxLength = maxLength;
509
+ const precision = row.numeric_precision ?? void 0;
510
+ if (precision !== void 0) column.precision = precision;
511
+ const scale = row.numeric_scale ?? void 0;
512
+ if (scale !== void 0) column.scale = scale;
405
513
  table.columns.push(column);
514
+ columnsByKey.get(key)?.set(row.column_name, column);
515
+ }
516
+ const constraintGroups = groupConstraints(constraintRows);
517
+ for (const group of constraintGroups) {
518
+ const key = tableKey(group.table_schema, group.table_name);
519
+ const table = tablesByKey.get(key);
520
+ if (!table) continue;
521
+ const constraint = {
522
+ name: group.constraint_name,
523
+ type: group.constraint_type,
524
+ columns: [...group.columns]
525
+ };
526
+ if (group.type === "FOREIGN KEY") {
527
+ if (group.foreign_table_name) {
528
+ const referencedTable = group.foreign_table_schema ? `${group.foreign_table_schema}.${group.foreign_table_name}` : group.foreign_table_name;
529
+ constraint.referencedTable = referencedTable;
530
+ }
531
+ if (group.foreign_columns.length) {
532
+ constraint.referencedColumns = [...group.foreign_columns];
533
+ }
534
+ }
535
+ table.constraints.push(constraint);
536
+ for (let index = 0; index < group.columns.length; index += 1) {
537
+ const columnName = group.columns[index];
538
+ if (!columnName) continue;
539
+ const column = columnsByKey.get(key)?.get(columnName);
540
+ if (!column) continue;
541
+ if (group.type === "PRIMARY KEY") {
542
+ column.isPrimaryKey = true;
543
+ }
544
+ if (group.type === "FOREIGN KEY") {
545
+ column.isForeignKey = true;
546
+ if (group.foreign_table_name) {
547
+ column.foreignKeyTable = group.foreign_table_schema ? `${group.foreign_table_schema}.${group.foreign_table_name}` : group.foreign_table_name;
548
+ }
549
+ const referencedColumn = group.foreign_columns[index];
550
+ if (referencedColumn) {
551
+ column.foreignKeyColumn = referencedColumn;
552
+ }
553
+ }
554
+ }
555
+ }
556
+ for (const row of indexRows) {
557
+ const key = tableKey(row.schema_name, row.table_name);
558
+ const table = tablesByKey.get(key);
559
+ if (!table) continue;
560
+ const columns = coerceStringArray(row.column_names).map((c) => c.trim()).filter(Boolean);
561
+ const index = {
562
+ name: row.index_name,
563
+ columns,
564
+ unique: Boolean(row.indisunique),
565
+ type: columns.length === 1 ? "INDEX" : "COMPOSITE INDEX"
566
+ };
567
+ const definition = sanitize2(row.definition);
568
+ if (definition !== void 0) index.definition = definition;
569
+ table.indexes.push(index);
406
570
  }
407
571
  const tables = Array.from(tablesByKey.values()).sort((a, b) => {
408
572
  if (a.schema === b.schema) {
@@ -420,6 +584,36 @@ var PostgresAdapter = class {
420
584
  };
421
585
  }
422
586
  };
587
+ function groupConstraints(rows) {
588
+ const groups = /* @__PURE__ */ new Map();
589
+ for (const row of rows) {
590
+ const key = `${row.table_schema}.${row.table_name}.${row.constraint_name}`;
591
+ let group = groups.get(key);
592
+ if (!group) {
593
+ group = {
594
+ table_schema: row.table_schema,
595
+ table_name: row.table_name,
596
+ constraint_name: row.constraint_name,
597
+ constraint_type: row.constraint_type,
598
+ columns: [],
599
+ foreign_columns: [],
600
+ type: row.constraint_type
601
+ };
602
+ groups.set(key, group);
603
+ }
604
+ if (row.column_name) {
605
+ group.columns.push(row.column_name);
606
+ }
607
+ if (row.constraint_type === "FOREIGN KEY") {
608
+ group.foreign_table_schema = row.foreign_table_schema;
609
+ group.foreign_table_name = row.foreign_table_name;
610
+ if (row.foreign_column_name) {
611
+ group.foreign_columns.push(row.foreign_column_name);
612
+ }
613
+ }
614
+ }
615
+ return Array.from(groups.values());
616
+ }
423
617
  function normalizeTableFilter2(tables, defaultSchema) {
424
618
  if (!tables?.length) return [];
425
619
  const normalized = [];
@@ -452,7 +646,9 @@ function buildTablesQuery(tables) {
452
646
  WHEN 'm' THEN 'materialized_view'
453
647
  ELSE c.relkind::text
454
648
  END AS table_type,
455
- obj_description(c.oid) AS comment
649
+ obj_description(c.oid) AS comment,
650
+ c.reltuples AS total_rows,
651
+ pg_total_relation_size(c.oid) AS total_bytes
456
652
  FROM pg_class c
457
653
  JOIN pg_namespace n ON n.oid = c.relnamespace
458
654
  WHERE n.nspname NOT IN ('pg_catalog', 'information_schema')
@@ -472,18 +668,13 @@ function buildColumnsQuery(tables) {
472
668
  cols.column_name,
473
669
  cols.data_type,
474
670
  cols.udt_name,
475
- pgd.description,
476
- EXISTS(
477
- SELECT 1
478
- FROM information_schema.table_constraints tc
479
- JOIN information_schema.key_column_usage kcu
480
- ON tc.constraint_name = kcu.constraint_name
481
- AND tc.table_schema = kcu.table_schema
482
- WHERE tc.constraint_type = 'PRIMARY KEY'
483
- AND tc.table_schema = cols.table_schema
484
- AND tc.table_name = cols.table_name
485
- AND kcu.column_name = cols.column_name
486
- ) AS is_primary_key
671
+ cols.is_nullable,
672
+ cols.column_default,
673
+ cols.character_maximum_length,
674
+ cols.numeric_precision,
675
+ cols.numeric_scale,
676
+ cols.ordinal_position,
677
+ pgd.description
487
678
  FROM information_schema.columns cols
488
679
  LEFT JOIN pg_catalog.pg_class c
489
680
  ON c.relname = cols.table_name
@@ -498,6 +689,50 @@ function buildColumnsQuery(tables) {
498
689
  ${filter}
499
690
  ORDER BY cols.table_schema, cols.table_name, cols.ordinal_position;`;
500
691
  }
692
+ function buildConstraintsQuery(tables) {
693
+ const filter = buildFilterClause(tables, "tc.table_schema", "tc.table_name");
694
+ return `SELECT
695
+ tc.table_schema,
696
+ tc.table_name,
697
+ tc.constraint_name,
698
+ tc.constraint_type,
699
+ kcu.column_name,
700
+ ccu.table_schema AS foreign_table_schema,
701
+ ccu.table_name AS foreign_table_name,
702
+ ccu.column_name AS foreign_column_name
703
+ FROM information_schema.table_constraints tc
704
+ LEFT JOIN information_schema.key_column_usage kcu
705
+ ON tc.constraint_name = kcu.constraint_name
706
+ AND tc.table_schema = kcu.table_schema
707
+ LEFT JOIN information_schema.constraint_column_usage ccu
708
+ ON ccu.constraint_name = tc.constraint_name
709
+ AND ccu.table_schema = tc.table_schema
710
+ WHERE tc.constraint_type IN ('PRIMARY KEY', 'UNIQUE', 'FOREIGN KEY')
711
+ AND tc.table_schema NOT IN ('pg_catalog', 'information_schema')
712
+ ${filter}
713
+ ORDER BY tc.table_schema, tc.table_name, tc.constraint_name, kcu.ordinal_position;`;
714
+ }
715
+ function buildIndexesQuery(tables) {
716
+ const filter = buildFilterClause(tables, "n.nspname", "c.relname");
717
+ return `SELECT
718
+ n.nspname AS schema_name,
719
+ c.relname AS table_name,
720
+ ci.relname AS index_name,
721
+ idx.indisunique,
722
+ array_remove(
723
+ array_agg(pg_get_indexdef(idx.indexrelid, g.k, true) ORDER BY g.k),
724
+ NULL
725
+ ) AS column_names,
726
+ pg_get_indexdef(idx.indexrelid) AS definition
727
+ FROM pg_class c
728
+ JOIN pg_namespace n ON n.oid = c.relnamespace
729
+ JOIN pg_index idx ON idx.indrelid = c.oid
730
+ JOIN pg_class ci ON ci.oid = idx.indexrelid
731
+ JOIN LATERAL generate_subscripts(idx.indkey, 1) AS g(k) ON true
732
+ WHERE n.nspname NOT IN ('pg_catalog', 'information_schema')
733
+ ${filter}
734
+ GROUP BY n.nspname, c.relname, ci.relname, idx.indisunique, idx.indexrelid;`;
735
+ }
501
736
  function buildFilterClause(tables, schemaExpr, tableExpr) {
502
737
  if (!tables.length) return "";
503
738
  const clauses = tables.map(({ schema, table }) => {
@@ -518,1264 +753,568 @@ function asTableType2(value) {
518
753
  }
519
754
  return "table";
520
755
  }
756
+ function buildTableStatistics2(totalRows, totalBytes) {
757
+ if (totalRows === void 0 && totalBytes === void 0) return void 0;
758
+ const stats = {};
759
+ if (totalRows !== void 0) stats.totalRows = totalRows;
760
+ if (totalBytes !== void 0) stats.totalBytes = totalBytes;
761
+ return stats;
762
+ }
521
763
  function sanitize2(value) {
522
764
  if (value === null || value === void 0) return void 0;
523
765
  const trimmed = String(value).trim();
524
766
  return trimmed.length ? trimmed : void 0;
525
767
  }
526
-
527
- // node_modules/jose/dist/webapi/lib/buffer_utils.js
528
- var encoder = new TextEncoder();
529
- var decoder = new TextDecoder();
530
- var MAX_INT32 = 2 ** 32;
531
- function concat(...buffers) {
532
- const size = buffers.reduce((acc, { length }) => acc + length, 0);
533
- const buf = new Uint8Array(size);
534
- let i = 0;
535
- for (const buffer of buffers) {
536
- buf.set(buffer, i);
537
- i += buffer.length;
538
- }
539
- return buf;
540
- }
541
- function encode(string) {
542
- const bytes = new Uint8Array(string.length);
543
- for (let i = 0; i < string.length; i++) {
544
- const code = string.charCodeAt(i);
545
- if (code > 127) {
546
- throw new TypeError("non-ASCII string encountered in encode()");
547
- }
548
- bytes[i] = code;
549
- }
550
- return bytes;
551
- }
552
-
553
- // node_modules/jose/dist/webapi/lib/base64.js
554
- function encodeBase64(input) {
555
- if (Uint8Array.prototype.toBase64) {
556
- return input.toBase64();
557
- }
558
- const CHUNK_SIZE = 32768;
559
- const arr = [];
560
- for (let i = 0; i < input.length; i += CHUNK_SIZE) {
561
- arr.push(String.fromCharCode.apply(null, input.subarray(i, i + CHUNK_SIZE)));
562
- }
563
- return btoa(arr.join(""));
768
+ function toNumber2(value) {
769
+ if (value === null || value === void 0) return void 0;
770
+ if (typeof value === "number") return value;
771
+ const parsed = Number.parseFloat(String(value));
772
+ return Number.isNaN(parsed) ? void 0 : parsed;
564
773
  }
565
- function decodeBase64(encoded) {
566
- if (Uint8Array.fromBase64) {
567
- return Uint8Array.fromBase64(encoded);
568
- }
569
- const binary = atob(encoded);
570
- const bytes = new Uint8Array(binary.length);
571
- for (let i = 0; i < binary.length; i++) {
572
- bytes[i] = binary.charCodeAt(i);
573
- }
574
- return bytes;
774
+ function coerceStringArray(value) {
775
+ if (!value) return [];
776
+ if (Array.isArray(value)) {
777
+ return value.map((entry) => String(entry));
778
+ }
779
+ const text = String(value).trim();
780
+ if (!text) return [];
781
+ const withoutBraces = text.startsWith("{") && text.endsWith("}") ? text.slice(1, -1) : text;
782
+ if (!withoutBraces) return [];
783
+ return withoutBraces.split(",").map((part) => part.trim().replace(/^"(.+)"$/, "$1")).filter(Boolean);
575
784
  }
576
785
 
577
- // node_modules/jose/dist/webapi/util/base64url.js
578
- function decode(input) {
579
- if (Uint8Array.fromBase64) {
580
- return Uint8Array.fromBase64(typeof input === "string" ? input : decoder.decode(input), {
581
- alphabet: "base64url"
582
- });
583
- }
584
- let encoded = input;
585
- if (encoded instanceof Uint8Array) {
586
- encoded = decoder.decode(encoded);
786
+ // src/index.ts
787
+ var QueryPanelSdkAPI = class {
788
+ baseUrl;
789
+ privateKey;
790
+ organizationId;
791
+ defaultTenantId;
792
+ additionalHeaders;
793
+ fetchImpl;
794
+ cachedPrivateKey;
795
+ databases = /* @__PURE__ */ new Map();
796
+ databaseMetadata = /* @__PURE__ */ new Map();
797
+ defaultDatabase;
798
+ lastSyncHashes = /* @__PURE__ */ new Map();
799
+ syncedDatabases = /* @__PURE__ */ new Set();
800
+ constructor(baseUrl, privateKey, organizationId, options) {
801
+ if (!baseUrl) {
802
+ throw new Error("Base URL is required");
803
+ }
804
+ if (!privateKey) {
805
+ throw new Error("Private key is required");
806
+ }
807
+ if (!organizationId) {
808
+ throw new Error("Organization ID is required");
809
+ }
810
+ this.baseUrl = baseUrl.replace(/\/+$/, "");
811
+ this.privateKey = privateKey;
812
+ this.organizationId = organizationId;
813
+ this.defaultTenantId = options?.defaultTenantId;
814
+ this.additionalHeaders = options?.additionalHeaders;
815
+ this.fetchImpl = options?.fetch ?? globalThis.fetch;
816
+ if (!this.fetchImpl) {
817
+ throw new Error(
818
+ "Fetch implementation not found. Provide options.fetch or use Node 18+."
819
+ );
820
+ }
587
821
  }
588
- encoded = encoded.replace(/-/g, "+").replace(/_/g, "/");
589
- try {
590
- return decodeBase64(encoded);
591
- } catch {
592
- throw new TypeError("The input to be decoded is not correctly encoded.");
822
+ attachClickhouse(name, clientFn, options) {
823
+ const adapter = new ClickHouseAdapter(clientFn, options);
824
+ this.attachDatabase(name, adapter);
825
+ const metadata = {
826
+ name,
827
+ dialect: "clickhouse",
828
+ description: options?.description,
829
+ tags: options?.tags,
830
+ tenantFieldName: options?.tenantFieldName,
831
+ tenantFieldType: options?.tenantFieldType ?? "String",
832
+ enforceTenantIsolation: options?.tenantFieldName ? options?.enforceTenantIsolation ?? true : void 0
833
+ };
834
+ this.databaseMetadata.set(name, metadata);
593
835
  }
594
- }
595
- function encode2(input) {
596
- let unencoded = input;
597
- if (typeof unencoded === "string") {
598
- unencoded = encoder.encode(unencoded);
836
+ attachPostgres(name, clientFn, options) {
837
+ const adapter = new PostgresAdapter(clientFn, options);
838
+ this.attachDatabase(name, adapter);
839
+ const metadata = {
840
+ name,
841
+ dialect: "postgres",
842
+ description: options?.description,
843
+ tags: options?.tags,
844
+ tenantFieldName: options?.tenantFieldName,
845
+ enforceTenantIsolation: options?.tenantFieldName ? options?.enforceTenantIsolation ?? true : void 0
846
+ };
847
+ this.databaseMetadata.set(name, metadata);
599
848
  }
600
- if (Uint8Array.prototype.toBase64) {
601
- return unencoded.toBase64({ alphabet: "base64url", omitPadding: true });
849
+ attachDatabase(name, adapter) {
850
+ this.databases.set(name, adapter);
851
+ if (!this.defaultDatabase) {
852
+ this.defaultDatabase = name;
853
+ }
602
854
  }
603
- return encodeBase64(unencoded).replace(/=/g, "").replace(/\+/g, "-").replace(/\//g, "_");
604
- }
605
-
606
- // node_modules/jose/dist/webapi/util/errors.js
607
- var JOSEError = class extends Error {
608
- static code = "ERR_JOSE_GENERIC";
609
- code = "ERR_JOSE_GENERIC";
610
- constructor(message2, options) {
611
- super(message2, options);
612
- this.name = this.constructor.name;
613
- Error.captureStackTrace?.(this, this.constructor);
855
+ async syncSchema(databaseName, options, signal) {
856
+ const tenantId = this.resolveTenantId(options.tenantId);
857
+ const adapter = this.getDatabase(databaseName);
858
+ const introspection = await adapter.introspect(
859
+ options.tables ? { tables: options.tables } : void 0
860
+ );
861
+ const payload = this.buildSchemaRequest(
862
+ databaseName,
863
+ adapter,
864
+ introspection
865
+ );
866
+ const hash = this.hashSchemaRequest(payload);
867
+ const previousHash = this.lastSyncHashes.get(databaseName);
868
+ if (!options.force && previousHash === hash) {
869
+ return {
870
+ success: true,
871
+ message: "Schema unchanged; skipping ingestion",
872
+ chunks: 0,
873
+ chunks_with_annotations: 0,
874
+ schema_hash: hash,
875
+ skipped: true
876
+ };
877
+ }
878
+ const sessionId = randomUUID();
879
+ const response = await this.post(
880
+ "/ingest",
881
+ payload,
882
+ tenantId,
883
+ options.userId,
884
+ options.scopes,
885
+ signal,
886
+ sessionId
887
+ );
888
+ this.lastSyncHashes.set(databaseName, hash);
889
+ this.syncedDatabases.add(databaseName);
890
+ return response;
614
891
  }
615
- };
616
- var JOSENotSupported = class extends JOSEError {
617
- static code = "ERR_JOSE_NOT_SUPPORTED";
618
- code = "ERR_JOSE_NOT_SUPPORTED";
619
- };
620
- var JWSInvalid = class extends JOSEError {
621
- static code = "ERR_JWS_INVALID";
622
- code = "ERR_JWS_INVALID";
623
- };
624
- var JWTInvalid = class extends JOSEError {
625
- static code = "ERR_JWT_INVALID";
626
- code = "ERR_JWT_INVALID";
627
- };
628
-
629
- // node_modules/jose/dist/webapi/lib/crypto_key.js
630
- var unusable = (name, prop = "algorithm.name") => new TypeError(`CryptoKey does not support this operation, its ${prop} must be ${name}`);
631
- var isAlgorithm = (algorithm, name) => algorithm.name === name;
632
- function getHashLength(hash) {
633
- return parseInt(hash.name.slice(4), 10);
634
- }
635
- function getNamedCurve(alg) {
636
- switch (alg) {
637
- case "ES256":
638
- return "P-256";
639
- case "ES384":
640
- return "P-384";
641
- case "ES512":
642
- return "P-521";
643
- default:
644
- throw new Error("unreachable");
892
+ async ingestKnowledgeBaseChunks(payload, options, signal) {
893
+ const tenantId = this.resolveTenantId(
894
+ payload.tenantId ?? options?.tenantId
895
+ );
896
+ return await this.post(
897
+ "/knowledge-base/chunks",
898
+ {
899
+ organization_id: this.organizationId,
900
+ tenant_id: tenantId,
901
+ database: payload.database,
902
+ dialect: payload.dialect,
903
+ tables: payload.tables
904
+ },
905
+ tenantId,
906
+ options?.userId,
907
+ options?.scopes,
908
+ signal
909
+ );
645
910
  }
646
- }
647
- function checkUsage(key, usage) {
648
- if (usage && !key.usages.includes(usage)) {
649
- throw new TypeError(`CryptoKey does not support this operation, its usages must include ${usage}.`);
911
+ async introspect(databaseName, tables) {
912
+ const adapter = this.getDatabase(databaseName);
913
+ return await adapter.introspect(tables ? { tables } : void 0);
650
914
  }
651
- }
652
- function checkSigCryptoKey(key, alg, usage) {
653
- switch (alg) {
654
- case "HS256":
655
- case "HS384":
656
- case "HS512": {
657
- if (!isAlgorithm(key.algorithm, "HMAC"))
658
- throw unusable("HMAC");
659
- const expected = parseInt(alg.slice(2), 10);
660
- const actual = getHashLength(key.algorithm.hash);
661
- if (actual !== expected)
662
- throw unusable(`SHA-${expected}`, "algorithm.hash");
663
- break;
664
- }
665
- case "RS256":
666
- case "RS384":
667
- case "RS512": {
668
- if (!isAlgorithm(key.algorithm, "RSASSA-PKCS1-v1_5"))
669
- throw unusable("RSASSA-PKCS1-v1_5");
670
- const expected = parseInt(alg.slice(2), 10);
671
- const actual = getHashLength(key.algorithm.hash);
672
- if (actual !== expected)
673
- throw unusable(`SHA-${expected}`, "algorithm.hash");
674
- break;
675
- }
676
- case "PS256":
677
- case "PS384":
678
- case "PS512": {
679
- if (!isAlgorithm(key.algorithm, "RSA-PSS"))
680
- throw unusable("RSA-PSS");
681
- const expected = parseInt(alg.slice(2), 10);
682
- const actual = getHashLength(key.algorithm.hash);
683
- if (actual !== expected)
684
- throw unusable(`SHA-${expected}`, "algorithm.hash");
685
- break;
686
- }
687
- case "Ed25519":
688
- case "EdDSA": {
689
- if (!isAlgorithm(key.algorithm, "Ed25519"))
690
- throw unusable("Ed25519");
691
- break;
915
+ async ask(question, options, signal) {
916
+ const tenantId = this.resolveTenantId(options.tenantId);
917
+ await this.ensureSchemasSynced(
918
+ tenantId,
919
+ options.userId,
920
+ options.scopes,
921
+ options.disableAutoSync
922
+ );
923
+ const sessionId = randomUUID();
924
+ const queryResponse = await this.post(
925
+ "/query",
926
+ {
927
+ question,
928
+ ...options.lastError ? { last_error: options.lastError } : {},
929
+ ...options.previousSql ? { previous_sql: options.previousSql } : {},
930
+ ...options.maxRetry ? { max_retry: options.maxRetry } : {}
931
+ },
932
+ tenantId,
933
+ options.userId,
934
+ options.scopes,
935
+ signal,
936
+ sessionId
937
+ );
938
+ const databaseName = options.database ?? this.defaultDatabase;
939
+ if (!databaseName) {
940
+ throw new Error(
941
+ "No database attached. Call attachPostgres/attachClickhouse first."
942
+ );
692
943
  }
693
- case "ML-DSA-44":
694
- case "ML-DSA-65":
695
- case "ML-DSA-87": {
696
- if (!isAlgorithm(key.algorithm, alg))
697
- throw unusable(alg);
698
- break;
944
+ const adapter = this.getDatabase(databaseName);
945
+ const paramMetadata = Array.isArray(queryResponse.params) ? queryResponse.params : [];
946
+ const paramValues = this.mapGeneratedParams(paramMetadata);
947
+ const metadata = this.databaseMetadata.get(databaseName);
948
+ if (metadata) {
949
+ queryResponse.sql = this.ensureTenantIsolation(
950
+ queryResponse.sql,
951
+ paramValues,
952
+ metadata,
953
+ tenantId
954
+ );
699
955
  }
700
- case "ES256":
701
- case "ES384":
702
- case "ES512": {
703
- if (!isAlgorithm(key.algorithm, "ECDSA"))
704
- throw unusable("ECDSA");
705
- const expected = getNamedCurve(alg);
706
- const actual = key.algorithm.namedCurve;
707
- if (actual !== expected)
708
- throw unusable(expected, "algorithm.namedCurve");
709
- break;
956
+ await adapter.validate(queryResponse.sql, paramValues);
957
+ const execution = await adapter.execute(queryResponse.sql, paramValues);
958
+ const rows = execution.rows ?? [];
959
+ let chart = {
960
+ vegaLiteSpec: null,
961
+ notes: rows.length === 0 ? "Query returned no rows." : null
962
+ };
963
+ if (rows.length > 0) {
964
+ const chartResponse = await this.post(
965
+ "/chart",
966
+ {
967
+ question,
968
+ sql: queryResponse.sql,
969
+ rationale: queryResponse.rationale,
970
+ fields: execution.fields,
971
+ rows: anonymizeResults(rows),
972
+ max_retries: options.chartMaxRetries ?? 3,
973
+ query_id: queryResponse.queryId
974
+ },
975
+ tenantId,
976
+ options.userId,
977
+ options.scopes,
978
+ signal,
979
+ sessionId
980
+ );
981
+ chart = {
982
+ vegaLiteSpec: chartResponse.chart ? {
983
+ ...chartResponse.chart,
984
+ data: { values: rows }
985
+ } : null,
986
+ notes: chartResponse.notes
987
+ };
710
988
  }
711
- default:
712
- throw new TypeError("CryptoKey does not support this operation");
989
+ return {
990
+ sql: queryResponse.sql,
991
+ params: paramValues,
992
+ paramMetadata,
993
+ rationale: queryResponse.rationale,
994
+ dialect: queryResponse.dialect,
995
+ queryId: queryResponse.queryId,
996
+ rows,
997
+ fields: execution.fields,
998
+ chart,
999
+ context: queryResponse.context
1000
+ };
713
1001
  }
714
- checkUsage(key, usage);
715
- }
716
-
717
- // node_modules/jose/dist/webapi/lib/invalid_key_input.js
718
- function message(msg, actual, ...types) {
719
- types = types.filter(Boolean);
720
- if (types.length > 2) {
721
- const last = types.pop();
722
- msg += `one of type ${types.join(", ")}, or ${last}.`;
723
- } else if (types.length === 2) {
724
- msg += `one of type ${types[0]} or ${types[1]}.`;
725
- } else {
726
- msg += `of type ${types[0]}.`;
727
- }
728
- if (actual == null) {
729
- msg += ` Received ${actual}`;
730
- } else if (typeof actual === "function" && actual.name) {
731
- msg += ` Received function ${actual.name}`;
732
- } else if (typeof actual === "object" && actual != null) {
733
- if (actual.constructor?.name) {
734
- msg += ` Received an instance of ${actual.constructor.name}`;
735
- }
1002
+ async upsertAnnotation(input, options, signal) {
1003
+ const tenantId = this.resolveTenantId(input.tenantId ?? options?.tenantId);
1004
+ const response = await this.post(
1005
+ "/knowledge-base/annotations",
1006
+ {
1007
+ organization_id: this.organizationId,
1008
+ tenant_id: tenantId,
1009
+ target_identifier: input.targetIdentifier,
1010
+ content: input.content,
1011
+ user_id: input.userId
1012
+ },
1013
+ tenantId,
1014
+ options?.userId,
1015
+ options?.scopes,
1016
+ signal
1017
+ );
1018
+ return response.annotation;
736
1019
  }
737
- return msg;
738
- }
739
- var invalidKeyInput = (actual, ...types) => message("Key must be ", actual, ...types);
740
- var withAlg = (alg, actual, ...types) => message(`Key for the ${alg} algorithm must be `, actual, ...types);
741
-
742
- // node_modules/jose/dist/webapi/lib/is_key_like.js
743
- var isCryptoKey = (key) => {
744
- if (key?.[Symbol.toStringTag] === "CryptoKey")
745
- return true;
746
- try {
747
- return key instanceof CryptoKey;
748
- } catch {
749
- return false;
1020
+ async listAnnotations(options, signal) {
1021
+ const tenantId = this.resolveTenantId(options?.tenantId);
1022
+ const response = await this.get(
1023
+ "/knowledge-base/annotations",
1024
+ tenantId,
1025
+ options?.userId,
1026
+ options?.scopes,
1027
+ signal
1028
+ );
1029
+ return response.annotations;
750
1030
  }
751
- };
752
- var isKeyObject = (key) => key?.[Symbol.toStringTag] === "KeyObject";
753
- var isKeyLike = (key) => isCryptoKey(key) || isKeyObject(key);
754
-
755
- // node_modules/jose/dist/webapi/lib/is_disjoint.js
756
- function isDisjoint(...headers) {
757
- const sources = headers.filter(Boolean);
758
- if (sources.length === 0 || sources.length === 1) {
759
- return true;
760
- }
761
- let acc;
762
- for (const header of sources) {
763
- const parameters = Object.keys(header);
764
- if (!acc || acc.size === 0) {
765
- acc = new Set(parameters);
766
- continue;
767
- }
768
- for (const parameter of parameters) {
769
- if (acc.has(parameter)) {
770
- return false;
1031
+ async getAnnotation(targetIdentifier, options, signal) {
1032
+ const tenantId = this.resolveTenantId(options?.tenantId);
1033
+ const response = await this.get(
1034
+ `/knowledge-base/annotations/${encodeURIComponent(targetIdentifier)}`,
1035
+ tenantId,
1036
+ options?.userId,
1037
+ options?.scopes,
1038
+ signal
1039
+ ).catch((error) => {
1040
+ if (error?.status === 404) {
1041
+ return { success: false, annotation: null };
771
1042
  }
772
- acc.add(parameter);
773
- }
774
- }
775
- return true;
776
- }
777
-
778
- // node_modules/jose/dist/webapi/lib/is_object.js
779
- var isObjectLike = (value) => typeof value === "object" && value !== null;
780
- function isObject(input) {
781
- if (!isObjectLike(input) || Object.prototype.toString.call(input) !== "[object Object]") {
782
- return false;
1043
+ throw error;
1044
+ });
1045
+ return response.annotation ?? null;
783
1046
  }
784
- if (Object.getPrototypeOf(input) === null) {
785
- return true;
1047
+ async deleteAnnotation(targetIdentifier, options, signal) {
1048
+ const tenantId = this.resolveTenantId(options?.tenantId);
1049
+ await this.delete(
1050
+ `/knowledge-base/annotations/${encodeURIComponent(targetIdentifier)}`,
1051
+ tenantId,
1052
+ options?.userId,
1053
+ options?.scopes,
1054
+ signal
1055
+ );
786
1056
  }
787
- let proto = input;
788
- while (Object.getPrototypeOf(proto) !== null) {
789
- proto = Object.getPrototypeOf(proto);
1057
+ async createChart(body, options, signal) {
1058
+ const tenantId = this.resolveTenantId(options?.tenantId);
1059
+ return await this.post(
1060
+ "/charts",
1061
+ body,
1062
+ tenantId,
1063
+ options?.userId,
1064
+ options?.scopes,
1065
+ signal
1066
+ );
790
1067
  }
791
- return Object.getPrototypeOf(input) === proto;
792
- }
793
-
794
- // node_modules/jose/dist/webapi/lib/check_key_length.js
795
- function checkKeyLength(alg, key) {
796
- if (alg.startsWith("RS") || alg.startsWith("PS")) {
797
- const { modulusLength } = key.algorithm;
798
- if (typeof modulusLength !== "number" || modulusLength < 2048) {
799
- throw new TypeError(`${alg} requires key modulusLength to be 2048 bits or larger`);
1068
+ async listCharts(options, signal) {
1069
+ const tenantId = this.resolveTenantId(options?.tenantId);
1070
+ const params = new URLSearchParams();
1071
+ if (options?.pagination?.page)
1072
+ params.set("page", `${options.pagination.page}`);
1073
+ if (options?.pagination?.limit)
1074
+ params.set("limit", `${options.pagination.limit}`);
1075
+ if (options?.sortBy) params.set("sort_by", options.sortBy);
1076
+ if (options?.sortDir) params.set("sort_dir", options.sortDir);
1077
+ if (options?.title) params.set("title", options.title);
1078
+ if (options?.userFilter) params.set("user_id", options.userFilter);
1079
+ if (options?.createdFrom) params.set("created_from", options.createdFrom);
1080
+ if (options?.createdTo) params.set("created_to", options.createdTo);
1081
+ if (options?.updatedFrom) params.set("updated_from", options.updatedFrom);
1082
+ if (options?.updatedTo) params.set("updated_to", options.updatedTo);
1083
+ const response = await this.get(
1084
+ `/charts${params.toString() ? `?${params.toString()}` : ""}`,
1085
+ tenantId,
1086
+ options?.userId,
1087
+ options?.scopes,
1088
+ signal
1089
+ );
1090
+ if (options?.includeData) {
1091
+ response.data = await Promise.all(
1092
+ response.data.map(async (chart) => ({
1093
+ ...chart,
1094
+ vega_lite_spec: {
1095
+ ...chart.vega_lite_spec,
1096
+ data: {
1097
+ values: await this.runSafeQueryOnClient(
1098
+ chart.sql,
1099
+ chart.database ?? void 0,
1100
+ chart.sql_params ?? void 0
1101
+ )
1102
+ }
1103
+ }
1104
+ }))
1105
+ );
800
1106
  }
1107
+ return response;
801
1108
  }
802
- }
803
-
804
- // node_modules/jose/dist/webapi/lib/asn1.js
805
- var bytesEqual = (a, b) => {
806
- if (a.byteLength !== b.length)
807
- return false;
808
- for (let i = 0; i < a.byteLength; i++) {
809
- if (a[i] !== b[i])
810
- return false;
811
- }
812
- return true;
813
- };
814
- var createASN1State = (data) => ({ data, pos: 0 });
815
- var parseLength = (state) => {
816
- const first = state.data[state.pos++];
817
- if (first & 128) {
818
- const lengthOfLen = first & 127;
819
- let length = 0;
820
- for (let i = 0; i < lengthOfLen; i++) {
821
- length = length << 8 | state.data[state.pos++];
822
- }
823
- return length;
824
- }
825
- return first;
826
- };
827
- var expectTag = (state, expectedTag, errorMessage) => {
828
- if (state.data[state.pos++] !== expectedTag) {
829
- throw new Error(errorMessage);
830
- }
831
- };
832
- var getSubarray = (state, length) => {
833
- const result = state.data.subarray(state.pos, state.pos + length);
834
- state.pos += length;
835
- return result;
836
- };
837
- var parseAlgorithmOID = (state) => {
838
- expectTag(state, 6, "Expected algorithm OID");
839
- const oidLen = parseLength(state);
840
- return getSubarray(state, oidLen);
841
- };
842
- function parsePKCS8Header(state) {
843
- expectTag(state, 48, "Invalid PKCS#8 structure");
844
- parseLength(state);
845
- expectTag(state, 2, "Expected version field");
846
- const verLen = parseLength(state);
847
- state.pos += verLen;
848
- expectTag(state, 48, "Expected algorithm identifier");
849
- const algIdLen = parseLength(state);
850
- const algIdStart = state.pos;
851
- return { algIdStart, algIdLength: algIdLen };
852
- }
853
- var parseECAlgorithmIdentifier = (state) => {
854
- const algOid = parseAlgorithmOID(state);
855
- if (bytesEqual(algOid, [43, 101, 110])) {
856
- return "X25519";
857
- }
858
- if (!bytesEqual(algOid, [42, 134, 72, 206, 61, 2, 1])) {
859
- throw new Error("Unsupported key algorithm");
860
- }
861
- expectTag(state, 6, "Expected curve OID");
862
- const curveOidLen = parseLength(state);
863
- const curveOid = getSubarray(state, curveOidLen);
864
- for (const { name, oid } of [
865
- { name: "P-256", oid: [42, 134, 72, 206, 61, 3, 1, 7] },
866
- { name: "P-384", oid: [43, 129, 4, 0, 34] },
867
- { name: "P-521", oid: [43, 129, 4, 0, 35] }
868
- ]) {
869
- if (bytesEqual(curveOid, oid)) {
870
- return name;
871
- }
872
- }
873
- throw new Error("Unsupported named curve");
874
- };
875
- var genericImport = async (keyFormat, keyData, alg, options) => {
876
- let algorithm;
877
- let keyUsages;
878
- const isPublic = keyFormat === "spki";
879
- const getSigUsages = () => isPublic ? ["verify"] : ["sign"];
880
- const getEncUsages = () => isPublic ? ["encrypt", "wrapKey"] : ["decrypt", "unwrapKey"];
881
- switch (alg) {
882
- case "PS256":
883
- case "PS384":
884
- case "PS512":
885
- algorithm = { name: "RSA-PSS", hash: `SHA-${alg.slice(-3)}` };
886
- keyUsages = getSigUsages();
887
- break;
888
- case "RS256":
889
- case "RS384":
890
- case "RS512":
891
- algorithm = { name: "RSASSA-PKCS1-v1_5", hash: `SHA-${alg.slice(-3)}` };
892
- keyUsages = getSigUsages();
893
- break;
894
- case "RSA-OAEP":
895
- case "RSA-OAEP-256":
896
- case "RSA-OAEP-384":
897
- case "RSA-OAEP-512":
898
- algorithm = {
899
- name: "RSA-OAEP",
900
- hash: `SHA-${parseInt(alg.slice(-3), 10) || 1}`
901
- };
902
- keyUsages = getEncUsages();
903
- break;
904
- case "ES256":
905
- case "ES384":
906
- case "ES512": {
907
- const curveMap = { ES256: "P-256", ES384: "P-384", ES512: "P-521" };
908
- algorithm = { name: "ECDSA", namedCurve: curveMap[alg] };
909
- keyUsages = getSigUsages();
910
- break;
911
- }
912
- case "ECDH-ES":
913
- case "ECDH-ES+A128KW":
914
- case "ECDH-ES+A192KW":
915
- case "ECDH-ES+A256KW": {
916
- try {
917
- const namedCurve = options.getNamedCurve(keyData);
918
- algorithm = namedCurve === "X25519" ? { name: "X25519" } : { name: "ECDH", namedCurve };
919
- } catch (cause) {
920
- throw new JOSENotSupported("Invalid or unsupported key format");
921
- }
922
- keyUsages = isPublic ? [] : ["deriveBits"];
923
- break;
924
- }
925
- case "Ed25519":
926
- case "EdDSA":
927
- algorithm = { name: "Ed25519" };
928
- keyUsages = getSigUsages();
929
- break;
930
- case "ML-DSA-44":
931
- case "ML-DSA-65":
932
- case "ML-DSA-87":
933
- algorithm = { name: alg };
934
- keyUsages = getSigUsages();
935
- break;
936
- default:
937
- throw new JOSENotSupported('Invalid or unsupported "alg" (Algorithm) value');
938
- }
939
- return crypto.subtle.importKey(keyFormat, keyData, algorithm, options?.extractable ?? (isPublic ? true : false), keyUsages);
940
- };
941
- var processPEMData = (pem, pattern) => {
942
- return decodeBase64(pem.replace(pattern, ""));
943
- };
944
- var fromPKCS8 = (pem, alg, options) => {
945
- const keyData = processPEMData(pem, /(?:-----(?:BEGIN|END) PRIVATE KEY-----|\s)/g);
946
- let opts = options;
947
- if (alg?.startsWith?.("ECDH-ES")) {
948
- opts ||= {};
949
- opts.getNamedCurve = (keyData2) => {
950
- const state = createASN1State(keyData2);
951
- parsePKCS8Header(state);
952
- return parseECAlgorithmIdentifier(state);
953
- };
954
- }
955
- return genericImport("pkcs8", keyData, alg, opts);
956
- };
957
-
958
- // node_modules/jose/dist/webapi/lib/jwk_to_key.js
959
- function subtleMapping(jwk) {
960
- let algorithm;
961
- let keyUsages;
962
- switch (jwk.kty) {
963
- case "AKP": {
964
- switch (jwk.alg) {
965
- case "ML-DSA-44":
966
- case "ML-DSA-65":
967
- case "ML-DSA-87":
968
- algorithm = { name: jwk.alg };
969
- keyUsages = jwk.priv ? ["sign"] : ["verify"];
970
- break;
971
- default:
972
- throw new JOSENotSupported('Invalid or unsupported JWK "alg" (Algorithm) Parameter value');
973
- }
974
- break;
975
- }
976
- case "RSA": {
977
- switch (jwk.alg) {
978
- case "PS256":
979
- case "PS384":
980
- case "PS512":
981
- algorithm = { name: "RSA-PSS", hash: `SHA-${jwk.alg.slice(-3)}` };
982
- keyUsages = jwk.d ? ["sign"] : ["verify"];
983
- break;
984
- case "RS256":
985
- case "RS384":
986
- case "RS512":
987
- algorithm = { name: "RSASSA-PKCS1-v1_5", hash: `SHA-${jwk.alg.slice(-3)}` };
988
- keyUsages = jwk.d ? ["sign"] : ["verify"];
989
- break;
990
- case "RSA-OAEP":
991
- case "RSA-OAEP-256":
992
- case "RSA-OAEP-384":
993
- case "RSA-OAEP-512":
994
- algorithm = {
995
- name: "RSA-OAEP",
996
- hash: `SHA-${parseInt(jwk.alg.slice(-3), 10) || 1}`
997
- };
998
- keyUsages = jwk.d ? ["decrypt", "unwrapKey"] : ["encrypt", "wrapKey"];
999
- break;
1000
- default:
1001
- throw new JOSENotSupported('Invalid or unsupported JWK "alg" (Algorithm) Parameter value');
1002
- }
1003
- break;
1004
- }
1005
- case "EC": {
1006
- switch (jwk.alg) {
1007
- case "ES256":
1008
- algorithm = { name: "ECDSA", namedCurve: "P-256" };
1009
- keyUsages = jwk.d ? ["sign"] : ["verify"];
1010
- break;
1011
- case "ES384":
1012
- algorithm = { name: "ECDSA", namedCurve: "P-384" };
1013
- keyUsages = jwk.d ? ["sign"] : ["verify"];
1014
- break;
1015
- case "ES512":
1016
- algorithm = { name: "ECDSA", namedCurve: "P-521" };
1017
- keyUsages = jwk.d ? ["sign"] : ["verify"];
1018
- break;
1019
- case "ECDH-ES":
1020
- case "ECDH-ES+A128KW":
1021
- case "ECDH-ES+A192KW":
1022
- case "ECDH-ES+A256KW":
1023
- algorithm = { name: "ECDH", namedCurve: jwk.crv };
1024
- keyUsages = jwk.d ? ["deriveBits"] : [];
1025
- break;
1026
- default:
1027
- throw new JOSENotSupported('Invalid or unsupported JWK "alg" (Algorithm) Parameter value');
1028
- }
1029
- break;
1030
- }
1031
- case "OKP": {
1032
- switch (jwk.alg) {
1033
- case "Ed25519":
1034
- case "EdDSA":
1035
- algorithm = { name: "Ed25519" };
1036
- keyUsages = jwk.d ? ["sign"] : ["verify"];
1037
- break;
1038
- case "ECDH-ES":
1039
- case "ECDH-ES+A128KW":
1040
- case "ECDH-ES+A192KW":
1041
- case "ECDH-ES+A256KW":
1042
- algorithm = { name: jwk.crv };
1043
- keyUsages = jwk.d ? ["deriveBits"] : [];
1044
- break;
1045
- default:
1046
- throw new JOSENotSupported('Invalid or unsupported JWK "alg" (Algorithm) Parameter value');
1047
- }
1048
- break;
1049
- }
1050
- default:
1051
- throw new JOSENotSupported('Invalid or unsupported JWK "kty" (Key Type) Parameter value');
1052
- }
1053
- return { algorithm, keyUsages };
1054
- }
1055
- async function jwkToKey(jwk) {
1056
- if (!jwk.alg) {
1057
- throw new TypeError('"alg" argument is required when "jwk.alg" is not present');
1058
- }
1059
- const { algorithm, keyUsages } = subtleMapping(jwk);
1060
- const keyData = { ...jwk };
1061
- if (keyData.kty !== "AKP") {
1062
- delete keyData.alg;
1063
- }
1064
- delete keyData.use;
1065
- return crypto.subtle.importKey("jwk", keyData, algorithm, jwk.ext ?? (jwk.d || jwk.priv ? false : true), jwk.key_ops ?? keyUsages);
1066
- }
1067
-
1068
- // node_modules/jose/dist/webapi/key/import.js
1069
- async function importPKCS8(pkcs8, alg, options) {
1070
- if (typeof pkcs8 !== "string" || pkcs8.indexOf("-----BEGIN PRIVATE KEY-----") !== 0) {
1071
- throw new TypeError('"pkcs8" must be PKCS#8 formatted string');
1072
- }
1073
- return fromPKCS8(pkcs8, alg, options);
1074
- }
1075
-
1076
- // node_modules/jose/dist/webapi/lib/validate_crit.js
1077
- function validateCrit(Err, recognizedDefault, recognizedOption, protectedHeader, joseHeader) {
1078
- if (joseHeader.crit !== void 0 && protectedHeader?.crit === void 0) {
1079
- throw new Err('"crit" (Critical) Header Parameter MUST be integrity protected');
1080
- }
1081
- if (!protectedHeader || protectedHeader.crit === void 0) {
1082
- return /* @__PURE__ */ new Set();
1083
- }
1084
- if (!Array.isArray(protectedHeader.crit) || protectedHeader.crit.length === 0 || protectedHeader.crit.some((input) => typeof input !== "string" || input.length === 0)) {
1085
- throw new Err('"crit" (Critical) Header Parameter MUST be an array of non-empty strings when present');
1086
- }
1087
- let recognized;
1088
- if (recognizedOption !== void 0) {
1089
- recognized = new Map([...Object.entries(recognizedOption), ...recognizedDefault.entries()]);
1090
- } else {
1091
- recognized = recognizedDefault;
1092
- }
1093
- for (const parameter of protectedHeader.crit) {
1094
- if (!recognized.has(parameter)) {
1095
- throw new JOSENotSupported(`Extension Header Parameter "${parameter}" is not recognized`);
1096
- }
1097
- if (joseHeader[parameter] === void 0) {
1098
- throw new Err(`Extension Header Parameter "${parameter}" is missing`);
1099
- }
1100
- if (recognized.get(parameter) && protectedHeader[parameter] === void 0) {
1101
- throw new Err(`Extension Header Parameter "${parameter}" MUST be integrity protected`);
1102
- }
1103
- }
1104
- return new Set(protectedHeader.crit);
1105
- }
1106
-
1107
- // node_modules/jose/dist/webapi/lib/is_jwk.js
1108
- var isJWK = (key) => isObject(key) && typeof key.kty === "string";
1109
- var isPrivateJWK = (key) => key.kty !== "oct" && (key.kty === "AKP" && typeof key.priv === "string" || typeof key.d === "string");
1110
- var isPublicJWK = (key) => key.kty !== "oct" && key.d === void 0 && key.priv === void 0;
1111
- var isSecretJWK = (key) => key.kty === "oct" && typeof key.k === "string";
1112
-
1113
- // node_modules/jose/dist/webapi/lib/normalize_key.js
1114
- var cache;
1115
- var handleJWK = async (key, jwk, alg, freeze = false) => {
1116
- cache ||= /* @__PURE__ */ new WeakMap();
1117
- let cached = cache.get(key);
1118
- if (cached?.[alg]) {
1119
- return cached[alg];
1120
- }
1121
- const cryptoKey = await jwkToKey({ ...jwk, alg });
1122
- if (freeze)
1123
- Object.freeze(key);
1124
- if (!cached) {
1125
- cache.set(key, { [alg]: cryptoKey });
1126
- } else {
1127
- cached[alg] = cryptoKey;
1128
- }
1129
- return cryptoKey;
1130
- };
1131
- var handleKeyObject = (keyObject, alg) => {
1132
- cache ||= /* @__PURE__ */ new WeakMap();
1133
- let cached = cache.get(keyObject);
1134
- if (cached?.[alg]) {
1135
- return cached[alg];
1136
- }
1137
- const isPublic = keyObject.type === "public";
1138
- const extractable = isPublic ? true : false;
1139
- let cryptoKey;
1140
- if (keyObject.asymmetricKeyType === "x25519") {
1141
- switch (alg) {
1142
- case "ECDH-ES":
1143
- case "ECDH-ES+A128KW":
1144
- case "ECDH-ES+A192KW":
1145
- case "ECDH-ES+A256KW":
1146
- break;
1147
- default:
1148
- throw new TypeError("given KeyObject instance cannot be used for this algorithm");
1149
- }
1150
- cryptoKey = keyObject.toCryptoKey(keyObject.asymmetricKeyType, extractable, isPublic ? [] : ["deriveBits"]);
1151
- }
1152
- if (keyObject.asymmetricKeyType === "ed25519") {
1153
- if (alg !== "EdDSA" && alg !== "Ed25519") {
1154
- throw new TypeError("given KeyObject instance cannot be used for this algorithm");
1155
- }
1156
- cryptoKey = keyObject.toCryptoKey(keyObject.asymmetricKeyType, extractable, [
1157
- isPublic ? "verify" : "sign"
1158
- ]);
1159
- }
1160
- switch (keyObject.asymmetricKeyType) {
1161
- case "ml-dsa-44":
1162
- case "ml-dsa-65":
1163
- case "ml-dsa-87": {
1164
- if (alg !== keyObject.asymmetricKeyType.toUpperCase()) {
1165
- throw new TypeError("given KeyObject instance cannot be used for this algorithm");
1166
- }
1167
- cryptoKey = keyObject.toCryptoKey(keyObject.asymmetricKeyType, extractable, [
1168
- isPublic ? "verify" : "sign"
1169
- ]);
1170
- }
1171
- }
1172
- if (keyObject.asymmetricKeyType === "rsa") {
1173
- let hash;
1174
- switch (alg) {
1175
- case "RSA-OAEP":
1176
- hash = "SHA-1";
1177
- break;
1178
- case "RS256":
1179
- case "PS256":
1180
- case "RSA-OAEP-256":
1181
- hash = "SHA-256";
1182
- break;
1183
- case "RS384":
1184
- case "PS384":
1185
- case "RSA-OAEP-384":
1186
- hash = "SHA-384";
1187
- break;
1188
- case "RS512":
1189
- case "PS512":
1190
- case "RSA-OAEP-512":
1191
- hash = "SHA-512";
1192
- break;
1193
- default:
1194
- throw new TypeError("given KeyObject instance cannot be used for this algorithm");
1195
- }
1196
- if (alg.startsWith("RSA-OAEP")) {
1197
- return keyObject.toCryptoKey({
1198
- name: "RSA-OAEP",
1199
- hash
1200
- }, extractable, isPublic ? ["encrypt"] : ["decrypt"]);
1201
- }
1202
- cryptoKey = keyObject.toCryptoKey({
1203
- name: alg.startsWith("PS") ? "RSA-PSS" : "RSASSA-PKCS1-v1_5",
1204
- hash
1205
- }, extractable, [isPublic ? "verify" : "sign"]);
1206
- }
1207
- if (keyObject.asymmetricKeyType === "ec") {
1208
- const nist = /* @__PURE__ */ new Map([
1209
- ["prime256v1", "P-256"],
1210
- ["secp384r1", "P-384"],
1211
- ["secp521r1", "P-521"]
1212
- ]);
1213
- const namedCurve = nist.get(keyObject.asymmetricKeyDetails?.namedCurve);
1214
- if (!namedCurve) {
1215
- throw new TypeError("given KeyObject instance cannot be used for this algorithm");
1216
- }
1217
- if (alg === "ES256" && namedCurve === "P-256") {
1218
- cryptoKey = keyObject.toCryptoKey({
1219
- name: "ECDSA",
1220
- namedCurve
1221
- }, extractable, [isPublic ? "verify" : "sign"]);
1222
- }
1223
- if (alg === "ES384" && namedCurve === "P-384") {
1224
- cryptoKey = keyObject.toCryptoKey({
1225
- name: "ECDSA",
1226
- namedCurve
1227
- }, extractable, [isPublic ? "verify" : "sign"]);
1228
- }
1229
- if (alg === "ES512" && namedCurve === "P-521") {
1230
- cryptoKey = keyObject.toCryptoKey({
1231
- name: "ECDSA",
1232
- namedCurve
1233
- }, extractable, [isPublic ? "verify" : "sign"]);
1234
- }
1235
- if (alg.startsWith("ECDH-ES")) {
1236
- cryptoKey = keyObject.toCryptoKey({
1237
- name: "ECDH",
1238
- namedCurve
1239
- }, extractable, isPublic ? [] : ["deriveBits"]);
1240
- }
1241
- }
1242
- if (!cryptoKey) {
1243
- throw new TypeError("given KeyObject instance cannot be used for this algorithm");
1244
- }
1245
- if (!cached) {
1246
- cache.set(keyObject, { [alg]: cryptoKey });
1247
- } else {
1248
- cached[alg] = cryptoKey;
1249
- }
1250
- return cryptoKey;
1251
- };
1252
- async function normalizeKey(key, alg) {
1253
- if (key instanceof Uint8Array) {
1254
- return key;
1255
- }
1256
- if (isCryptoKey(key)) {
1257
- return key;
1258
- }
1259
- if (isKeyObject(key)) {
1260
- if (key.type === "secret") {
1261
- return key.export();
1262
- }
1263
- if ("toCryptoKey" in key && typeof key.toCryptoKey === "function") {
1264
- try {
1265
- return handleKeyObject(key, alg);
1266
- } catch (err) {
1267
- if (err instanceof TypeError) {
1268
- throw err;
1109
+ async getChart(id, options, signal) {
1110
+ const tenantId = this.resolveTenantId(options?.tenantId);
1111
+ const chart = await this.get(
1112
+ `/charts/${encodeURIComponent(id)}`,
1113
+ tenantId,
1114
+ options?.userId,
1115
+ options?.scopes,
1116
+ signal
1117
+ );
1118
+ return {
1119
+ ...chart,
1120
+ vega_lite_spec: {
1121
+ ...chart.vega_lite_spec,
1122
+ data: {
1123
+ values: await this.runSafeQueryOnClient(
1124
+ chart.sql,
1125
+ chart.database ?? void 0,
1126
+ chart.sql_params ?? void 0
1127
+ )
1269
1128
  }
1270
1129
  }
1271
- }
1272
- let jwk = key.export({ format: "jwk" });
1273
- return handleJWK(key, jwk, alg);
1274
- }
1275
- if (isJWK(key)) {
1276
- if (key.k) {
1277
- return decode(key.k);
1278
- }
1279
- return handleJWK(key, key, alg, true);
1280
- }
1281
- throw new Error("unreachable");
1282
- }
1283
-
1284
- // node_modules/jose/dist/webapi/lib/check_key_type.js
1285
- var tag = (key) => key?.[Symbol.toStringTag];
1286
- var jwkMatchesOp = (alg, key, usage) => {
1287
- if (key.use !== void 0) {
1288
- let expected;
1289
- switch (usage) {
1290
- case "sign":
1291
- case "verify":
1292
- expected = "sig";
1293
- break;
1294
- case "encrypt":
1295
- case "decrypt":
1296
- expected = "enc";
1297
- break;
1298
- }
1299
- if (key.use !== expected) {
1300
- throw new TypeError(`Invalid key for this operation, its "use" must be "${expected}" when present`);
1301
- }
1302
- }
1303
- if (key.alg !== void 0 && key.alg !== alg) {
1304
- throw new TypeError(`Invalid key for this operation, its "alg" must be "${alg}" when present`);
1305
- }
1306
- if (Array.isArray(key.key_ops)) {
1307
- let expectedKeyOp;
1308
- switch (true) {
1309
- case (usage === "sign" || usage === "verify"):
1310
- case alg === "dir":
1311
- case alg.includes("CBC-HS"):
1312
- expectedKeyOp = usage;
1313
- break;
1314
- case alg.startsWith("PBES2"):
1315
- expectedKeyOp = "deriveBits";
1316
- break;
1317
- case /^A\d{3}(?:GCM)?(?:KW)?$/.test(alg):
1318
- if (!alg.includes("GCM") && alg.endsWith("KW")) {
1319
- expectedKeyOp = usage === "encrypt" ? "wrapKey" : "unwrapKey";
1320
- } else {
1321
- expectedKeyOp = usage;
1322
- }
1323
- break;
1324
- case (usage === "encrypt" && alg.startsWith("RSA")):
1325
- expectedKeyOp = "wrapKey";
1326
- break;
1327
- case usage === "decrypt":
1328
- expectedKeyOp = alg.startsWith("RSA") ? "unwrapKey" : "deriveBits";
1329
- break;
1330
- }
1331
- if (expectedKeyOp && key.key_ops?.includes?.(expectedKeyOp) === false) {
1332
- throw new TypeError(`Invalid key for this operation, its "key_ops" must include "${expectedKeyOp}" when present`);
1333
- }
1334
- }
1335
- return true;
1336
- };
1337
- var symmetricTypeCheck = (alg, key, usage) => {
1338
- if (key instanceof Uint8Array)
1339
- return;
1340
- if (isJWK(key)) {
1341
- if (isSecretJWK(key) && jwkMatchesOp(alg, key, usage))
1342
- return;
1343
- throw new TypeError(`JSON Web Key for symmetric algorithms must have JWK "kty" (Key Type) equal to "oct" and the JWK "k" (Key Value) present`);
1344
- }
1345
- if (!isKeyLike(key)) {
1346
- throw new TypeError(withAlg(alg, key, "CryptoKey", "KeyObject", "JSON Web Key", "Uint8Array"));
1347
- }
1348
- if (key.type !== "secret") {
1349
- throw new TypeError(`${tag(key)} instances for symmetric algorithms must be of type "secret"`);
1350
- }
1351
- };
1352
- var asymmetricTypeCheck = (alg, key, usage) => {
1353
- if (isJWK(key)) {
1354
- switch (usage) {
1355
- case "decrypt":
1356
- case "sign":
1357
- if (isPrivateJWK(key) && jwkMatchesOp(alg, key, usage))
1358
- return;
1359
- throw new TypeError(`JSON Web Key for this operation be a private JWK`);
1360
- case "encrypt":
1361
- case "verify":
1362
- if (isPublicJWK(key) && jwkMatchesOp(alg, key, usage))
1363
- return;
1364
- throw new TypeError(`JSON Web Key for this operation be a public JWK`);
1365
- }
1366
- }
1367
- if (!isKeyLike(key)) {
1368
- throw new TypeError(withAlg(alg, key, "CryptoKey", "KeyObject", "JSON Web Key"));
1369
- }
1370
- if (key.type === "secret") {
1371
- throw new TypeError(`${tag(key)} instances for asymmetric algorithms must not be of type "secret"`);
1372
- }
1373
- if (key.type === "public") {
1374
- switch (usage) {
1375
- case "sign":
1376
- throw new TypeError(`${tag(key)} instances for asymmetric algorithm signing must be of type "private"`);
1377
- case "decrypt":
1378
- throw new TypeError(`${tag(key)} instances for asymmetric algorithm decryption must be of type "private"`);
1379
- }
1130
+ };
1380
1131
  }
1381
- if (key.type === "private") {
1382
- switch (usage) {
1383
- case "verify":
1384
- throw new TypeError(`${tag(key)} instances for asymmetric algorithm verifying must be of type "public"`);
1385
- case "encrypt":
1386
- throw new TypeError(`${tag(key)} instances for asymmetric algorithm encryption must be of type "public"`);
1387
- }
1132
+ async updateChart(id, body, options, signal) {
1133
+ const tenantId = this.resolveTenantId(options?.tenantId);
1134
+ return await this.put(
1135
+ `/charts/${encodeURIComponent(id)}`,
1136
+ body,
1137
+ tenantId,
1138
+ options?.userId,
1139
+ options?.scopes,
1140
+ signal
1141
+ );
1388
1142
  }
1389
- };
1390
- function checkKeyType(alg, key, usage) {
1391
- switch (alg.substring(0, 2)) {
1392
- case "A1":
1393
- case "A2":
1394
- case "di":
1395
- case "HS":
1396
- case "PB":
1397
- symmetricTypeCheck(alg, key, usage);
1398
- break;
1399
- default:
1400
- asymmetricTypeCheck(alg, key, usage);
1143
+ async deleteChart(id, options, signal) {
1144
+ const tenantId = this.resolveTenantId(options?.tenantId);
1145
+ await this.delete(
1146
+ `/charts/${encodeURIComponent(id)}`,
1147
+ tenantId,
1148
+ options?.userId,
1149
+ options?.scopes,
1150
+ signal
1151
+ );
1401
1152
  }
1402
- }
1403
-
1404
- // node_modules/jose/dist/webapi/lib/subtle_dsa.js
1405
- function subtleAlgorithm(alg, algorithm) {
1406
- const hash = `SHA-${alg.slice(-3)}`;
1407
- switch (alg) {
1408
- case "HS256":
1409
- case "HS384":
1410
- case "HS512":
1411
- return { hash, name: "HMAC" };
1412
- case "PS256":
1413
- case "PS384":
1414
- case "PS512":
1415
- return { hash, name: "RSA-PSS", saltLength: parseInt(alg.slice(-3), 10) >> 3 };
1416
- case "RS256":
1417
- case "RS384":
1418
- case "RS512":
1419
- return { hash, name: "RSASSA-PKCS1-v1_5" };
1420
- case "ES256":
1421
- case "ES384":
1422
- case "ES512":
1423
- return { hash, name: "ECDSA", namedCurve: algorithm.namedCurve };
1424
- case "Ed25519":
1425
- case "EdDSA":
1426
- return { name: "Ed25519" };
1427
- case "ML-DSA-44":
1428
- case "ML-DSA-65":
1429
- case "ML-DSA-87":
1430
- return { name: alg };
1431
- default:
1432
- throw new JOSENotSupported(`alg ${alg} is not supported either by JOSE or your javascript runtime`);
1153
+ async createActiveChart(body, options, signal) {
1154
+ const tenantId = this.resolveTenantId(options?.tenantId);
1155
+ return await this.post(
1156
+ "/active-charts",
1157
+ body,
1158
+ tenantId,
1159
+ options?.userId,
1160
+ options?.scopes,
1161
+ signal
1162
+ );
1433
1163
  }
1434
- }
1435
-
1436
- // node_modules/jose/dist/webapi/lib/get_sign_verify_key.js
1437
- async function getSigKey(alg, key, usage) {
1438
- if (key instanceof Uint8Array) {
1439
- if (!alg.startsWith("HS")) {
1440
- throw new TypeError(invalidKeyInput(key, "CryptoKey", "KeyObject", "JSON Web Key"));
1164
+ async listActiveCharts(options, signal) {
1165
+ const tenantId = this.resolveTenantId(options?.tenantId);
1166
+ const params = new URLSearchParams();
1167
+ if (options?.pagination?.page)
1168
+ params.set("page", `${options.pagination.page}`);
1169
+ if (options?.pagination?.limit)
1170
+ params.set("limit", `${options.pagination.limit}`);
1171
+ if (options?.sortBy) params.set("sort_by", options.sortBy);
1172
+ if (options?.sortDir) params.set("sort_dir", options.sortDir);
1173
+ if (options?.title) params.set("name", options.title);
1174
+ if (options?.userFilter) params.set("user_id", options.userFilter);
1175
+ if (options?.createdFrom) params.set("created_from", options.createdFrom);
1176
+ if (options?.createdTo) params.set("created_to", options.createdTo);
1177
+ if (options?.updatedFrom) params.set("updated_from", options.updatedFrom);
1178
+ if (options?.updatedTo) params.set("updated_to", options.updatedTo);
1179
+ const response = await this.get(
1180
+ `/active-charts${params.toString() ? `?${params.toString()}` : ""}`,
1181
+ tenantId,
1182
+ options?.userId,
1183
+ options?.scopes,
1184
+ signal
1185
+ );
1186
+ if (options?.withData) {
1187
+ response.data = await Promise.all(
1188
+ response.data.map(async (active) => ({
1189
+ ...active,
1190
+ chart: active.chart ? await this.getChart(active.chart_id, options, signal) : null
1191
+ }))
1192
+ );
1441
1193
  }
1442
- return crypto.subtle.importKey("raw", key, { hash: `SHA-${alg.slice(-3)}`, name: "HMAC" }, false, [usage]);
1194
+ return response;
1443
1195
  }
1444
- checkSigCryptoKey(key, alg, usage);
1445
- return key;
1446
- }
1447
-
1448
- // node_modules/jose/dist/webapi/lib/jwt_claims_set.js
1449
- var epoch = (date) => Math.floor(date.getTime() / 1e3);
1450
- var minute = 60;
1451
- var hour = minute * 60;
1452
- var day = hour * 24;
1453
- var week = day * 7;
1454
- var year = day * 365.25;
1455
- var REGEX = /^(\+|\-)? ?(\d+|\d+\.\d+) ?(seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|weeks?|w|years?|yrs?|y)(?: (ago|from now))?$/i;
1456
- function secs(str) {
1457
- const matched = REGEX.exec(str);
1458
- if (!matched || matched[4] && matched[1]) {
1459
- throw new TypeError("Invalid time period format");
1460
- }
1461
- const value = parseFloat(matched[2]);
1462
- const unit = matched[3].toLowerCase();
1463
- let numericDate;
1464
- switch (unit) {
1465
- case "sec":
1466
- case "secs":
1467
- case "second":
1468
- case "seconds":
1469
- case "s":
1470
- numericDate = Math.round(value);
1471
- break;
1472
- case "minute":
1473
- case "minutes":
1474
- case "min":
1475
- case "mins":
1476
- case "m":
1477
- numericDate = Math.round(value * minute);
1478
- break;
1479
- case "hour":
1480
- case "hours":
1481
- case "hr":
1482
- case "hrs":
1483
- case "h":
1484
- numericDate = Math.round(value * hour);
1485
- break;
1486
- case "day":
1487
- case "days":
1488
- case "d":
1489
- numericDate = Math.round(value * day);
1490
- break;
1491
- case "week":
1492
- case "weeks":
1493
- case "w":
1494
- numericDate = Math.round(value * week);
1495
- break;
1496
- default:
1497
- numericDate = Math.round(value * year);
1498
- break;
1499
- }
1500
- if (matched[1] === "-" || matched[4] === "ago") {
1501
- return -numericDate;
1502
- }
1503
- return numericDate;
1504
- }
1505
- function validateInput(label, input) {
1506
- if (!Number.isFinite(input)) {
1507
- throw new TypeError(`Invalid ${label} input`);
1508
- }
1509
- return input;
1510
- }
1511
- var JWTClaimsBuilder = class {
1512
- #payload;
1513
- constructor(payload) {
1514
- if (!isObject(payload)) {
1515
- throw new TypeError("JWT Claims Set MUST be an object");
1196
+ async getActiveChart(id, options, signal) {
1197
+ const tenantId = this.resolveTenantId(options?.tenantId);
1198
+ const active = await this.get(
1199
+ `/active-charts/${encodeURIComponent(id)}`,
1200
+ tenantId,
1201
+ options?.userId,
1202
+ options?.scopes,
1203
+ signal
1204
+ );
1205
+ if (options?.withData && active.chart_id) {
1206
+ return {
1207
+ ...active,
1208
+ chart: await this.getChart(active.chart_id, options, signal)
1209
+ };
1516
1210
  }
1517
- this.#payload = structuredClone(payload);
1518
- }
1519
- data() {
1520
- return encoder.encode(JSON.stringify(this.#payload));
1211
+ return active;
1521
1212
  }
1522
- get iss() {
1523
- return this.#payload.iss;
1524
- }
1525
- set iss(value) {
1526
- this.#payload.iss = value;
1527
- }
1528
- get sub() {
1529
- return this.#payload.sub;
1530
- }
1531
- set sub(value) {
1532
- this.#payload.sub = value;
1533
- }
1534
- get aud() {
1535
- return this.#payload.aud;
1536
- }
1537
- set aud(value) {
1538
- this.#payload.aud = value;
1539
- }
1540
- set jti(value) {
1541
- this.#payload.jti = value;
1542
- }
1543
- set nbf(value) {
1544
- if (typeof value === "number") {
1545
- this.#payload.nbf = validateInput("setNotBefore", value);
1546
- } else if (value instanceof Date) {
1547
- this.#payload.nbf = validateInput("setNotBefore", epoch(value));
1548
- } else {
1549
- this.#payload.nbf = epoch(/* @__PURE__ */ new Date()) + secs(value);
1550
- }
1213
+ async updateActiveChart(id, body, options, signal) {
1214
+ const tenantId = this.resolveTenantId(options?.tenantId);
1215
+ return await this.put(
1216
+ `/active-charts/${encodeURIComponent(id)}`,
1217
+ body,
1218
+ tenantId,
1219
+ options?.userId,
1220
+ options?.scopes,
1221
+ signal
1222
+ );
1551
1223
  }
1552
- set exp(value) {
1553
- if (typeof value === "number") {
1554
- this.#payload.exp = validateInput("setExpirationTime", value);
1555
- } else if (value instanceof Date) {
1556
- this.#payload.exp = validateInput("setExpirationTime", epoch(value));
1557
- } else {
1558
- this.#payload.exp = epoch(/* @__PURE__ */ new Date()) + secs(value);
1559
- }
1224
+ async deleteActiveChart(id, options, signal) {
1225
+ const tenantId = this.resolveTenantId(options?.tenantId);
1226
+ await this.delete(
1227
+ `/active-charts/${encodeURIComponent(id)}`,
1228
+ tenantId,
1229
+ options?.userId,
1230
+ options?.scopes,
1231
+ signal
1232
+ );
1560
1233
  }
1561
- set iat(value) {
1562
- if (value === void 0) {
1563
- this.#payload.iat = epoch(/* @__PURE__ */ new Date());
1564
- } else if (value instanceof Date) {
1565
- this.#payload.iat = validateInput("setIssuedAt", epoch(value));
1566
- } else if (typeof value === "string") {
1567
- this.#payload.iat = validateInput("setIssuedAt", epoch(/* @__PURE__ */ new Date()) + secs(value));
1568
- } else {
1569
- this.#payload.iat = validateInput("setIssuedAt", value);
1234
+ getDatabase(name) {
1235
+ const dbName = name ?? this.defaultDatabase;
1236
+ if (!dbName) {
1237
+ throw new Error("No database attached.");
1570
1238
  }
1571
- }
1572
- };
1573
-
1574
- // node_modules/jose/dist/webapi/lib/sign.js
1575
- async function sign(alg, key, data) {
1576
- const cryptoKey = await getSigKey(alg, key, "sign");
1577
- checkKeyLength(alg, cryptoKey);
1578
- const signature = await crypto.subtle.sign(subtleAlgorithm(alg, cryptoKey.algorithm), cryptoKey, data);
1579
- return new Uint8Array(signature);
1580
- }
1581
-
1582
- // node_modules/jose/dist/webapi/jws/flattened/sign.js
1583
- var FlattenedSign = class {
1584
- #payload;
1585
- #protectedHeader;
1586
- #unprotectedHeader;
1587
- constructor(payload) {
1588
- if (!(payload instanceof Uint8Array)) {
1589
- throw new TypeError("payload must be an instance of Uint8Array");
1239
+ const adapter = this.databases.get(dbName);
1240
+ if (!adapter) {
1241
+ throw new Error(
1242
+ `Database '${dbName}' not found. Attached: ${Array.from(
1243
+ this.databases.keys()
1244
+ ).join(", ")}`
1245
+ );
1590
1246
  }
1591
- this.#payload = payload;
1247
+ return adapter;
1592
1248
  }
1593
- setProtectedHeader(protectedHeader) {
1594
- if (this.#protectedHeader) {
1595
- throw new TypeError("setProtectedHeader can only be called once");
1596
- }
1597
- this.#protectedHeader = protectedHeader;
1598
- return this;
1249
+ async ensureSchemasSynced(tenantId, userId, scopes, disableAutoSync) {
1250
+ if (disableAutoSync) return;
1251
+ const unsynced = Array.from(this.databases.keys()).filter(
1252
+ (name) => !this.syncedDatabases.has(name)
1253
+ );
1254
+ await Promise.all(
1255
+ unsynced.map(
1256
+ (name) => this.syncSchema(name, { tenantId, userId, scopes }).catch((error) => {
1257
+ console.warn(`Failed to sync schema for ${name}:`, error);
1258
+ })
1259
+ )
1260
+ );
1599
1261
  }
1600
- setUnprotectedHeader(unprotectedHeader) {
1601
- if (this.#unprotectedHeader) {
1602
- throw new TypeError("setUnprotectedHeader can only be called once");
1262
+ resolveTenantId(tenantId) {
1263
+ const resolved = tenantId ?? this.defaultTenantId;
1264
+ if (!resolved) {
1265
+ throw new Error(
1266
+ "tenantId is required. Provide it per request or via defaultTenantId option."
1267
+ );
1603
1268
  }
1604
- this.#unprotectedHeader = unprotectedHeader;
1605
- return this;
1269
+ return resolved;
1606
1270
  }
1607
- async sign(key, options) {
1608
- if (!this.#protectedHeader && !this.#unprotectedHeader) {
1609
- throw new JWSInvalid("either setProtectedHeader or setUnprotectedHeader must be called before #sign()");
1610
- }
1611
- if (!isDisjoint(this.#protectedHeader, this.#unprotectedHeader)) {
1612
- throw new JWSInvalid("JWS Protected and JWS Unprotected Header Parameter names must be disjoint");
1613
- }
1614
- const joseHeader = {
1615
- ...this.#protectedHeader,
1616
- ...this.#unprotectedHeader
1617
- };
1618
- const extensions = validateCrit(JWSInvalid, /* @__PURE__ */ new Map([["b64", true]]), options?.crit, this.#protectedHeader, joseHeader);
1619
- let b64 = true;
1620
- if (extensions.has("b64")) {
1621
- b64 = this.#protectedHeader.b64;
1622
- if (typeof b64 !== "boolean") {
1623
- throw new JWSInvalid('The "b64" (base64url-encode payload) Header Parameter must be a boolean');
1624
- }
1625
- }
1626
- const { alg } = joseHeader;
1627
- if (typeof alg !== "string" || !alg) {
1628
- throw new JWSInvalid('JWS "alg" (Algorithm) Header Parameter missing or invalid');
1629
- }
1630
- checkKeyType(alg, key, "sign");
1631
- let payloadS;
1632
- let payloadB;
1633
- if (b64) {
1634
- payloadS = encode2(this.#payload);
1635
- payloadB = encode(payloadS);
1636
- } else {
1637
- payloadB = this.#payload;
1638
- payloadS = "";
1639
- }
1640
- let protectedHeaderString;
1641
- let protectedHeaderBytes;
1642
- if (this.#protectedHeader) {
1643
- protectedHeaderString = encode2(JSON.stringify(this.#protectedHeader));
1644
- protectedHeaderBytes = encode(protectedHeaderString);
1645
- } else {
1646
- protectedHeaderString = "";
1647
- protectedHeaderBytes = new Uint8Array();
1648
- }
1649
- const data = concat(protectedHeaderBytes, encode("."), payloadB);
1650
- const k = await normalizeKey(key, alg);
1651
- const signature = await sign(alg, k, data);
1652
- const jws = {
1653
- signature: encode2(signature),
1654
- payload: payloadS
1271
+ async headers(tenantId, userId, scopes, includeJson = true, sessionId) {
1272
+ const token = await this.generateJWT(tenantId, userId, scopes);
1273
+ const headers = {
1274
+ Authorization: `Bearer ${token}`,
1275
+ Accept: "application/json"
1655
1276
  };
1656
- if (this.#unprotectedHeader) {
1657
- jws.header = this.#unprotectedHeader;
1658
- }
1659
- if (this.#protectedHeader) {
1660
- jws.protected = protectedHeaderString;
1277
+ if (includeJson) {
1278
+ headers["Content-Type"] = "application/json";
1661
1279
  }
1662
- return jws;
1663
- }
1664
- };
1665
-
1666
- // node_modules/jose/dist/webapi/jws/compact/sign.js
1667
- var CompactSign = class {
1668
- #flattened;
1669
- constructor(payload) {
1670
- this.#flattened = new FlattenedSign(payload);
1671
- }
1672
- setProtectedHeader(protectedHeader) {
1673
- this.#flattened.setProtectedHeader(protectedHeader);
1674
- return this;
1675
- }
1676
- async sign(key, options) {
1677
- const jws = await this.#flattened.sign(key, options);
1678
- if (jws.payload === void 0) {
1679
- throw new TypeError("use the flattened module for creating JWS with b64: false");
1280
+ if (sessionId) {
1281
+ headers["x-session-id"] = sessionId;
1680
1282
  }
1681
- return `${jws.protected}.${jws.payload}.${jws.signature}`;
1682
- }
1683
- };
1684
-
1685
- // node_modules/jose/dist/webapi/jwt/sign.js
1686
- var SignJWT = class {
1687
- #protectedHeader;
1688
- #jwt;
1689
- constructor(payload = {}) {
1690
- this.#jwt = new JWTClaimsBuilder(payload);
1691
- }
1692
- setIssuer(issuer) {
1693
- this.#jwt.iss = issuer;
1694
- return this;
1695
- }
1696
- setSubject(subject) {
1697
- this.#jwt.sub = subject;
1698
- return this;
1699
- }
1700
- setAudience(audience) {
1701
- this.#jwt.aud = audience;
1702
- return this;
1703
- }
1704
- setJti(jwtId) {
1705
- this.#jwt.jti = jwtId;
1706
- return this;
1707
- }
1708
- setNotBefore(input) {
1709
- this.#jwt.nbf = input;
1710
- return this;
1711
- }
1712
- setExpirationTime(input) {
1713
- this.#jwt.exp = input;
1714
- return this;
1715
- }
1716
- setIssuedAt(input) {
1717
- this.#jwt.iat = input;
1718
- return this;
1719
- }
1720
- setProtectedHeader(protectedHeader) {
1721
- this.#protectedHeader = protectedHeader;
1722
- return this;
1723
- }
1724
- async sign(key, options) {
1725
- const sig = new CompactSign(this.#jwt.data());
1726
- sig.setProtectedHeader(this.#protectedHeader);
1727
- if (Array.isArray(this.#protectedHeader?.crit) && this.#protectedHeader.crit.includes("b64") && this.#protectedHeader.b64 === false) {
1728
- throw new JWTInvalid("JWTs MUST NOT use unencoded payload");
1283
+ if (this.additionalHeaders) {
1284
+ Object.assign(headers, this.additionalHeaders);
1729
1285
  }
1730
- return sig.sign(key, options);
1286
+ return headers;
1731
1287
  }
1732
- };
1733
-
1734
- // src/core/client.ts
1735
- var ApiClient = class {
1736
- baseUrl;
1737
- privateKey;
1738
- organizationId;
1739
- defaultTenantId;
1740
- additionalHeaders;
1741
- fetchImpl;
1742
- cachedPrivateKey;
1743
- constructor(baseUrl, privateKey, organizationId, options) {
1744
- if (!baseUrl) {
1745
- throw new Error("Base URL is required");
1746
- }
1747
- if (!privateKey) {
1748
- throw new Error("Private key is required");
1749
- }
1750
- if (!organizationId) {
1751
- throw new Error("Organization ID is required");
1288
+ async request(path, init) {
1289
+ const response = await this.fetchImpl(`${this.baseUrl}${path}`, init);
1290
+ const text = await response.text();
1291
+ let json;
1292
+ try {
1293
+ json = text ? JSON.parse(text) : void 0;
1294
+ } catch {
1295
+ json = void 0;
1752
1296
  }
1753
- this.baseUrl = baseUrl.replace(/\/+$/, "");
1754
- this.privateKey = privateKey;
1755
- this.organizationId = organizationId;
1756
- this.defaultTenantId = options?.defaultTenantId;
1757
- this.additionalHeaders = options?.additionalHeaders;
1758
- this.fetchImpl = options?.fetch ?? globalThis.fetch;
1759
- if (!this.fetchImpl) {
1760
- throw new Error(
1761
- "Fetch implementation not found. Provide options.fetch or use Node 18+."
1297
+ if (!response.ok) {
1298
+ const error = new Error(
1299
+ json?.error || response.statusText || "Request failed"
1762
1300
  );
1301
+ error.status = response.status;
1302
+ if (json?.details) error.details = json.details;
1303
+ throw error;
1763
1304
  }
1764
- }
1765
- getDefaultTenantId() {
1766
- return this.defaultTenantId;
1305
+ return json;
1767
1306
  }
1768
1307
  async get(path, tenantId, userId, scopes, signal, sessionId) {
1769
1308
  return await this.request(path, {
1770
1309
  method: "GET",
1771
- headers: await this.buildHeaders(tenantId, userId, scopes, false, sessionId),
1310
+ headers: await this.headers(tenantId, userId, scopes, false, sessionId),
1772
1311
  signal
1773
1312
  });
1774
1313
  }
1775
1314
  async post(path, body, tenantId, userId, scopes, signal, sessionId) {
1776
1315
  return await this.request(path, {
1777
1316
  method: "POST",
1778
- headers: await this.buildHeaders(tenantId, userId, scopes, true, sessionId),
1317
+ headers: await this.headers(tenantId, userId, scopes, true, sessionId),
1779
1318
  body: JSON.stringify(body ?? {}),
1780
1319
  signal
1781
1320
  });
@@ -1783,7 +1322,7 @@ var ApiClient = class {
1783
1322
  async put(path, body, tenantId, userId, scopes, signal, sessionId) {
1784
1323
  return await this.request(path, {
1785
1324
  method: "PUT",
1786
- headers: await this.buildHeaders(tenantId, userId, scopes, true, sessionId),
1325
+ headers: await this.headers(tenantId, userId, scopes, true, sessionId),
1787
1326
  body: JSON.stringify(body ?? {}),
1788
1327
  signal
1789
1328
  });
@@ -1791,46 +1330,10 @@ var ApiClient = class {
1791
1330
  async delete(path, tenantId, userId, scopes, signal, sessionId) {
1792
1331
  return await this.request(path, {
1793
1332
  method: "DELETE",
1794
- headers: await this.buildHeaders(tenantId, userId, scopes, false, sessionId),
1333
+ headers: await this.headers(tenantId, userId, scopes, false, sessionId),
1795
1334
  signal
1796
1335
  });
1797
1336
  }
1798
- async request(path, init) {
1799
- const response = await this.fetchImpl(`${this.baseUrl}${path}`, init);
1800
- const text = await response.text();
1801
- let json;
1802
- try {
1803
- json = text ? JSON.parse(text) : void 0;
1804
- } catch {
1805
- json = void 0;
1806
- }
1807
- if (!response.ok) {
1808
- const error = new Error(
1809
- json?.error || response.statusText || "Request failed"
1810
- );
1811
- error.status = response.status;
1812
- if (json?.details) error.details = json.details;
1813
- throw error;
1814
- }
1815
- return json;
1816
- }
1817
- async buildHeaders(tenantId, userId, scopes, includeJson = true, sessionId) {
1818
- const token = await this.generateJWT(tenantId, userId, scopes);
1819
- const headers = {
1820
- Authorization: `Bearer ${token}`,
1821
- Accept: "application/json"
1822
- };
1823
- if (includeJson) {
1824
- headers["Content-Type"] = "application/json";
1825
- }
1826
- if (sessionId) {
1827
- headers["x-session-id"] = sessionId;
1828
- }
1829
- if (this.additionalHeaders) {
1830
- Object.assign(headers, this.additionalHeaders);
1831
- }
1832
- return headers;
1833
- }
1834
1337
  async generateJWT(tenantId, userId, scopes) {
1835
1338
  if (!this.cachedPrivateKey) {
1836
1339
  this.cachedPrivateKey = await importPKCS8(this.privateKey, "RS256");
@@ -1843,69 +1346,34 @@ var ApiClient = class {
1843
1346
  if (scopes?.length) payload.scopes = scopes;
1844
1347
  return await new SignJWT(payload).setProtectedHeader({ alg: "RS256" }).setIssuedAt().setExpirationTime("1h").sign(this.cachedPrivateKey);
1845
1348
  }
1846
- };
1847
-
1848
- // src/core/query-engine.ts
1849
- var QueryEngine = class {
1850
- databases = /* @__PURE__ */ new Map();
1851
- databaseMetadata = /* @__PURE__ */ new Map();
1852
- defaultDatabase;
1853
- attachDatabase(name, adapter, metadata) {
1854
- this.databases.set(name, adapter);
1855
- this.databaseMetadata.set(name, metadata);
1856
- if (!this.defaultDatabase) {
1857
- this.defaultDatabase = name;
1858
- }
1859
- }
1860
- getDatabase(name) {
1861
- const dbName = name ?? this.defaultDatabase;
1862
- if (!dbName) {
1863
- throw new Error("No database attached.");
1864
- }
1865
- const adapter = this.databases.get(dbName);
1866
- if (!adapter) {
1867
- throw new Error(
1868
- `Database '${dbName}' not found. Attached: ${Array.from(
1869
- this.databases.keys()
1870
- ).join(", ")}`
1871
- );
1872
- }
1873
- return adapter;
1874
- }
1875
- getDatabaseMetadata(name) {
1876
- const dbName = name ?? this.defaultDatabase;
1877
- if (!dbName) return void 0;
1878
- return this.databaseMetadata.get(dbName);
1879
- }
1880
- getDefaultDatabase() {
1881
- return this.defaultDatabase;
1882
- }
1883
- async validateAndExecute(sql, params, databaseName, tenantId) {
1884
- const adapter = this.getDatabase(databaseName);
1885
- const metadata = this.getDatabaseMetadata(databaseName);
1886
- let finalSql = sql;
1887
- if (metadata) {
1888
- finalSql = this.ensureTenantIsolation(sql, params, metadata, tenantId);
1889
- }
1890
- await adapter.validate(finalSql, params);
1891
- const result = await adapter.execute(finalSql, params);
1349
+ buildSchemaRequest(databaseName, adapter, introspection) {
1350
+ const dialect = adapter.getDialect();
1351
+ const tables = introspection.tables.map((table) => ({
1352
+ table_name: table.name,
1353
+ description: table.comment ?? `Table ${table.name}`,
1354
+ columns: table.columns.map((column) => ({
1355
+ name: column.name,
1356
+ data_type: column.rawType ?? column.type,
1357
+ is_primary_key: Boolean(column.isPrimaryKey),
1358
+ description: column.comment ?? ""
1359
+ }))
1360
+ }));
1892
1361
  return {
1893
- rows: result.rows,
1894
- fields: result.fields
1362
+ database: databaseName,
1363
+ dialect,
1364
+ tables
1895
1365
  };
1896
1366
  }
1897
- async execute(sql, params, databaseName) {
1898
- try {
1899
- const adapter = this.getDatabase(databaseName);
1900
- const result = await adapter.execute(sql, params);
1901
- return result.rows;
1902
- } catch (error) {
1903
- console.warn(
1904
- `Failed to execute SQL locally for database '${databaseName}':`,
1905
- error
1906
- );
1907
- return [];
1908
- }
1367
+ hashSchemaRequest(payload) {
1368
+ const normalized = payload.tables.map((table) => ({
1369
+ name: table.table_name,
1370
+ columns: table.columns.map((column) => ({
1371
+ name: column.name,
1372
+ type: column.data_type,
1373
+ primary: column.is_primary_key
1374
+ }))
1375
+ }));
1376
+ return createHash("sha256").update(JSON.stringify(normalized)).digest("hex");
1909
1377
  }
1910
1378
  mapGeneratedParams(params) {
1911
1379
  const record = {};
@@ -1940,375 +1408,20 @@ var QueryEngine = class {
1940
1408
  }
1941
1409
  return `${sql} WHERE ${tenantPredicate}`;
1942
1410
  }
1943
- };
1944
-
1945
- // src/routes/charts.ts
1946
- async function createChart(client, body, options, signal) {
1947
- const tenantId = resolveTenantId(client, options?.tenantId);
1948
- return await client.post(
1949
- "/charts",
1950
- body,
1951
- tenantId,
1952
- options?.userId,
1953
- options?.scopes,
1954
- signal
1955
- );
1956
- }
1957
- async function listCharts(client, queryEngine, options, signal) {
1958
- const tenantId = resolveTenantId(client, options?.tenantId);
1959
- const params = new URLSearchParams();
1960
- if (options?.pagination?.page)
1961
- params.set("page", `${options.pagination.page}`);
1962
- if (options?.pagination?.limit)
1963
- params.set("limit", `${options.pagination.limit}`);
1964
- if (options?.sortBy) params.set("sort_by", options.sortBy);
1965
- if (options?.sortDir) params.set("sort_dir", options.sortDir);
1966
- if (options?.title) params.set("title", options.title);
1967
- if (options?.userFilter) params.set("user_id", options.userFilter);
1968
- if (options?.createdFrom) params.set("created_from", options.createdFrom);
1969
- if (options?.createdTo) params.set("created_to", options.createdTo);
1970
- if (options?.updatedFrom) params.set("updated_from", options.updatedFrom);
1971
- if (options?.updatedTo) params.set("updated_to", options.updatedTo);
1972
- const response = await client.get(
1973
- `/charts${params.toString() ? `?${params.toString()}` : ""}`,
1974
- tenantId,
1975
- options?.userId,
1976
- options?.scopes,
1977
- signal
1978
- );
1979
- if (options?.includeData) {
1980
- response.data = await Promise.all(
1981
- response.data.map(async (chart) => ({
1982
- ...chart,
1983
- vega_lite_spec: {
1984
- ...chart.vega_lite_spec,
1985
- data: {
1986
- values: await queryEngine.execute(
1987
- chart.sql,
1988
- chart.sql_params ?? void 0,
1989
- chart.target_db ?? void 0
1990
- )
1991
- }
1992
- }
1993
- }))
1994
- );
1995
- }
1996
- return response;
1997
- }
1998
- async function getChart(client, queryEngine, id, options, signal) {
1999
- const tenantId = resolveTenantId(client, options?.tenantId);
2000
- const chart = await client.get(
2001
- `/charts/${encodeURIComponent(id)}`,
2002
- tenantId,
2003
- options?.userId,
2004
- options?.scopes,
2005
- signal
2006
- );
2007
- return {
2008
- ...chart,
2009
- vega_lite_spec: {
2010
- ...chart.vega_lite_spec,
2011
- data: {
2012
- values: await queryEngine.execute(
2013
- chart.sql,
2014
- chart.sql_params ?? void 0,
2015
- chart.target_db ?? void 0
2016
- )
2017
- }
2018
- }
2019
- };
2020
- }
2021
- async function updateChart(client, id, body, options, signal) {
2022
- const tenantId = resolveTenantId(client, options?.tenantId);
2023
- return await client.put(
2024
- `/charts/${encodeURIComponent(id)}`,
2025
- body,
2026
- tenantId,
2027
- options?.userId,
2028
- options?.scopes,
2029
- signal
2030
- );
2031
- }
2032
- async function deleteChart(client, id, options, signal) {
2033
- const tenantId = resolveTenantId(client, options?.tenantId);
2034
- await client.delete(
2035
- `/charts/${encodeURIComponent(id)}`,
2036
- tenantId,
2037
- options?.userId,
2038
- options?.scopes,
2039
- signal
2040
- );
2041
- }
2042
- function resolveTenantId(client, tenantId) {
2043
- const resolved = tenantId ?? client.getDefaultTenantId();
2044
- if (!resolved) {
2045
- throw new Error(
2046
- "tenantId is required. Provide it per request or via defaultTenantId option."
2047
- );
2048
- }
2049
- return resolved;
2050
- }
2051
-
2052
- // src/routes/active-charts.ts
2053
- async function createActiveChart(client, body, options, signal) {
2054
- const tenantId = resolveTenantId2(client, options?.tenantId);
2055
- return await client.post(
2056
- "/active-charts",
2057
- body,
2058
- tenantId,
2059
- options?.userId,
2060
- options?.scopes,
2061
- signal
2062
- );
2063
- }
2064
- async function listActiveCharts(client, queryEngine, options, signal) {
2065
- const tenantId = resolveTenantId2(client, options?.tenantId);
2066
- const params = new URLSearchParams();
2067
- if (options?.pagination?.page)
2068
- params.set("page", `${options.pagination.page}`);
2069
- if (options?.pagination?.limit)
2070
- params.set("limit", `${options.pagination.limit}`);
2071
- if (options?.sortBy) params.set("sort_by", options.sortBy);
2072
- if (options?.sortDir) params.set("sort_dir", options.sortDir);
2073
- if (options?.title) params.set("name", options.title);
2074
- if (options?.userFilter) params.set("user_id", options.userFilter);
2075
- if (options?.createdFrom) params.set("created_from", options.createdFrom);
2076
- if (options?.createdTo) params.set("created_to", options.createdTo);
2077
- if (options?.updatedFrom) params.set("updated_from", options.updatedFrom);
2078
- if (options?.updatedTo) params.set("updated_to", options.updatedTo);
2079
- const response = await client.get(
2080
- `/active-charts${params.toString() ? `?${params.toString()}` : ""}`,
2081
- tenantId,
2082
- options?.userId,
2083
- options?.scopes,
2084
- signal
2085
- );
2086
- if (options?.withData) {
2087
- response.data = await Promise.all(
2088
- response.data.map(async (active) => ({
2089
- ...active,
2090
- chart: active.chart ? await getChart(
2091
- client,
2092
- queryEngine,
2093
- active.chart_id,
2094
- options,
2095
- signal
2096
- ) : null
2097
- }))
2098
- );
2099
- }
2100
- return response;
2101
- }
2102
- async function getActiveChart(client, queryEngine, id, options, signal) {
2103
- const tenantId = resolveTenantId2(client, options?.tenantId);
2104
- const active = await client.get(
2105
- `/active-charts/${encodeURIComponent(id)}`,
2106
- tenantId,
2107
- options?.userId,
2108
- options?.scopes,
2109
- signal
2110
- );
2111
- if (options?.withData && active.chart_id) {
2112
- return {
2113
- ...active,
2114
- chart: await getChart(
2115
- client,
2116
- queryEngine,
2117
- active.chart_id,
2118
- options,
2119
- signal
2120
- )
2121
- };
2122
- }
2123
- return active;
2124
- }
2125
- async function updateActiveChart(client, id, body, options, signal) {
2126
- const tenantId = resolveTenantId2(client, options?.tenantId);
2127
- return await client.put(
2128
- `/active-charts/${encodeURIComponent(id)}`,
2129
- body,
2130
- tenantId,
2131
- options?.userId,
2132
- options?.scopes,
2133
- signal
2134
- );
2135
- }
2136
- async function deleteActiveChart(client, id, options, signal) {
2137
- const tenantId = resolveTenantId2(client, options?.tenantId);
2138
- await client.delete(
2139
- `/active-charts/${encodeURIComponent(id)}`,
2140
- tenantId,
2141
- options?.userId,
2142
- options?.scopes,
2143
- signal
2144
- );
2145
- }
2146
- function resolveTenantId2(client, tenantId) {
2147
- const resolved = tenantId ?? client.getDefaultTenantId();
2148
- if (!resolved) {
2149
- throw new Error(
2150
- "tenantId is required. Provide it per request or via defaultTenantId option."
2151
- );
2152
- }
2153
- return resolved;
2154
- }
2155
-
2156
- // src/routes/ingest.ts
2157
- import { randomUUID } from "crypto";
2158
- async function syncSchema(client, queryEngine, databaseName, options, signal) {
2159
- const tenantId = resolveTenantId3(client, options.tenantId);
2160
- const adapter = queryEngine.getDatabase(databaseName);
2161
- const introspection = await adapter.introspect(
2162
- options.tables ? { tables: options.tables } : void 0
2163
- );
2164
- const payload = buildSchemaRequest(databaseName, adapter, introspection);
2165
- const sessionId = randomUUID();
2166
- const response = await client.post(
2167
- "/ingest",
2168
- payload,
2169
- tenantId,
2170
- options.userId,
2171
- options.scopes,
2172
- signal,
2173
- sessionId
2174
- );
2175
- return response;
2176
- }
2177
- function resolveTenantId3(client, tenantId) {
2178
- const resolved = tenantId ?? client.getDefaultTenantId();
2179
- if (!resolved) {
2180
- throw new Error(
2181
- "tenantId is required. Provide it per request or via defaultTenantId option."
2182
- );
2183
- }
2184
- return resolved;
2185
- }
2186
- function buildSchemaRequest(databaseName, adapter, introspection) {
2187
- const dialect = adapter.getDialect();
2188
- const tables = introspection.tables.map((table) => ({
2189
- table_name: table.name,
2190
- description: table.comment ?? `Table ${table.name}`,
2191
- columns: table.columns.map((column) => ({
2192
- name: column.name,
2193
- data_type: column.rawType ?? column.type,
2194
- is_primary_key: Boolean(column.isPrimaryKey),
2195
- description: column.comment ?? ""
2196
- }))
2197
- }));
2198
- return {
2199
- database: databaseName,
2200
- dialect,
2201
- tables
2202
- };
2203
- }
2204
-
2205
- // src/routes/query.ts
2206
- import { randomUUID as randomUUID2 } from "crypto";
2207
- async function ask(client, queryEngine, question, options, signal) {
2208
- const tenantId = resolveTenantId4(client, options.tenantId);
2209
- const sessionId = randomUUID2();
2210
- const maxRetry = options.maxRetry ?? 0;
2211
- let attempt = 0;
2212
- let lastError = options.lastError;
2213
- let previousSql = options.previousSql;
2214
- while (attempt <= maxRetry) {
2215
- console.log({ lastError, previousSql });
2216
- const queryResponse = await client.post(
2217
- "/query",
2218
- {
2219
- question,
2220
- ...lastError ? { last_error: lastError } : {},
2221
- ...previousSql ? { previous_sql: previousSql } : {},
2222
- ...options.maxRetry ? { max_retry: options.maxRetry } : {}
2223
- },
2224
- tenantId,
2225
- options.userId,
2226
- options.scopes,
2227
- signal,
2228
- sessionId
2229
- );
2230
- const databaseName = queryResponse.database ?? options.database ?? queryEngine.getDefaultDatabase();
2231
- if (!databaseName) {
2232
- throw new Error(
2233
- "No database attached. Call attachPostgres/attachClickhouse first."
2234
- );
2235
- }
2236
- const paramMetadata = Array.isArray(queryResponse.params) ? queryResponse.params : [];
2237
- const paramValues = queryEngine.mapGeneratedParams(paramMetadata);
1411
+ async runSafeQueryOnClient(sql, database, params) {
2238
1412
  try {
2239
- const execution = await queryEngine.validateAndExecute(
2240
- queryResponse.sql,
2241
- paramValues,
2242
- databaseName,
2243
- tenantId
2244
- );
2245
- const rows = execution.rows ?? [];
2246
- let chart = {
2247
- vegaLiteSpec: null,
2248
- notes: rows.length === 0 ? "Query returned no rows." : null
2249
- };
2250
- if (rows.length > 0) {
2251
- const chartResponse = await client.post(
2252
- "/chart",
2253
- {
2254
- question,
2255
- sql: queryResponse.sql,
2256
- rationale: queryResponse.rationale,
2257
- fields: execution.fields,
2258
- rows: anonymizeResults(rows),
2259
- max_retries: options.chartMaxRetries ?? 3,
2260
- query_id: queryResponse.queryId
2261
- },
2262
- tenantId,
2263
- options.userId,
2264
- options.scopes,
2265
- signal,
2266
- sessionId
2267
- );
2268
- chart = {
2269
- vegaLiteSpec: chartResponse.chart ? {
2270
- ...chartResponse.chart,
2271
- data: { values: rows }
2272
- } : null,
2273
- notes: chartResponse.notes
2274
- };
2275
- }
2276
- return {
2277
- sql: queryResponse.sql,
2278
- params: paramValues,
2279
- paramMetadata,
2280
- rationale: queryResponse.rationale,
2281
- dialect: queryResponse.dialect,
2282
- queryId: queryResponse.queryId,
2283
- rows,
2284
- fields: execution.fields,
2285
- chart,
2286
- context: queryResponse.context,
2287
- attempts: attempt + 1
2288
- };
1413
+ const adapter = this.getDatabase(database);
1414
+ const result = await adapter.execute(sql, params);
1415
+ return result.rows;
2289
1416
  } catch (error) {
2290
- attempt++;
2291
- if (attempt > maxRetry) {
2292
- throw error;
2293
- }
2294
- lastError = error instanceof Error ? error.message : String(error);
2295
- previousSql = queryResponse.sql;
2296
1417
  console.warn(
2297
- `SQL execution failed (attempt ${attempt}/${maxRetry + 1}): ${lastError}. Retrying...`
1418
+ `Failed to execute SQL locally for database '${database}':`,
1419
+ error
2298
1420
  );
1421
+ return [];
2299
1422
  }
2300
1423
  }
2301
- throw new Error("Unexpected error in ask retry loop");
2302
- }
2303
- function resolveTenantId4(client, tenantId) {
2304
- const resolved = tenantId ?? client.getDefaultTenantId();
2305
- if (!resolved) {
2306
- throw new Error(
2307
- "tenantId is required. Provide it per request or via defaultTenantId option."
2308
- );
2309
- }
2310
- return resolved;
2311
- }
1424
+ };
2312
1425
  function anonymizeResults(rows) {
2313
1426
  if (!rows?.length) return [];
2314
1427
  return rows.map((row) => {
@@ -2321,144 +1434,6 @@ function anonymizeResults(rows) {
2321
1434
  return masked;
2322
1435
  });
2323
1436
  }
2324
-
2325
- // src/index.ts
2326
- var QueryPanelSdkAPI = class {
2327
- client;
2328
- queryEngine;
2329
- constructor(baseUrl, privateKey, organizationId, options) {
2330
- this.client = new ApiClient(baseUrl, privateKey, organizationId, options);
2331
- this.queryEngine = new QueryEngine();
2332
- }
2333
- // Database attachment methods
2334
- attachClickhouse(name, clientFn, options) {
2335
- const adapter = new ClickHouseAdapter(clientFn, options);
2336
- const metadata = {
2337
- name,
2338
- dialect: "clickhouse",
2339
- description: options?.description,
2340
- tags: options?.tags,
2341
- tenantFieldName: options?.tenantFieldName,
2342
- tenantFieldType: options?.tenantFieldType ?? "String",
2343
- enforceTenantIsolation: options?.tenantFieldName ? options?.enforceTenantIsolation ?? true : void 0
2344
- };
2345
- this.queryEngine.attachDatabase(name, adapter, metadata);
2346
- }
2347
- attachPostgres(name, clientFn, options) {
2348
- const adapter = new PostgresAdapter(clientFn, options);
2349
- const metadata = {
2350
- name,
2351
- dialect: "postgres",
2352
- description: options?.description,
2353
- tags: options?.tags,
2354
- tenantFieldName: options?.tenantFieldName,
2355
- enforceTenantIsolation: options?.tenantFieldName ? options?.enforceTenantIsolation ?? true : void 0
2356
- };
2357
- this.queryEngine.attachDatabase(name, adapter, metadata);
2358
- }
2359
- attachDatabase(name, adapter) {
2360
- const metadata = {
2361
- name,
2362
- dialect: adapter.getDialect()
2363
- };
2364
- this.queryEngine.attachDatabase(name, adapter, metadata);
2365
- }
2366
- // Schema introspection and sync
2367
- async introspect(databaseName, tables) {
2368
- const adapter = this.queryEngine.getDatabase(databaseName);
2369
- return await adapter.introspect(tables ? { tables } : void 0);
2370
- }
2371
- async syncSchema(databaseName, options, signal) {
2372
- return await syncSchema(
2373
- this.client,
2374
- this.queryEngine,
2375
- databaseName,
2376
- options,
2377
- signal
2378
- );
2379
- }
2380
- // Natural language query
2381
- async ask(question, options, signal) {
2382
- return await ask(
2383
- this.client,
2384
- this.queryEngine,
2385
- question,
2386
- options,
2387
- signal
2388
- );
2389
- }
2390
- // Chart CRUD operations
2391
- async createChart(body, options, signal) {
2392
- return await createChart(this.client, body, options, signal);
2393
- }
2394
- async listCharts(options, signal) {
2395
- return await listCharts(
2396
- this.client,
2397
- this.queryEngine,
2398
- options,
2399
- signal
2400
- );
2401
- }
2402
- async getChart(id, options, signal) {
2403
- return await getChart(
2404
- this.client,
2405
- this.queryEngine,
2406
- id,
2407
- options,
2408
- signal
2409
- );
2410
- }
2411
- async updateChart(id, body, options, signal) {
2412
- return await updateChart(
2413
- this.client,
2414
- id,
2415
- body,
2416
- options,
2417
- signal
2418
- );
2419
- }
2420
- async deleteChart(id, options, signal) {
2421
- await deleteChart(this.client, id, options, signal);
2422
- }
2423
- // Active Chart CRUD operations
2424
- async createActiveChart(body, options, signal) {
2425
- return await createActiveChart(
2426
- this.client,
2427
- body,
2428
- options,
2429
- signal
2430
- );
2431
- }
2432
- async listActiveCharts(options, signal) {
2433
- return await listActiveCharts(
2434
- this.client,
2435
- this.queryEngine,
2436
- options,
2437
- signal
2438
- );
2439
- }
2440
- async getActiveChart(id, options, signal) {
2441
- return await getActiveChart(
2442
- this.client,
2443
- this.queryEngine,
2444
- id,
2445
- options,
2446
- signal
2447
- );
2448
- }
2449
- async updateActiveChart(id, body, options, signal) {
2450
- return await updateActiveChart(
2451
- this.client,
2452
- id,
2453
- body,
2454
- options,
2455
- signal
2456
- );
2457
- }
2458
- async deleteActiveChart(id, options, signal) {
2459
- await deleteActiveChart(this.client, id, options, signal);
2460
- }
2461
- };
2462
1437
  export {
2463
1438
  ClickHouseAdapter,
2464
1439
  PostgresAdapter,