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