@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 +797 -1824
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +218 -138
- package/dist/index.d.ts +218 -138
- package/dist/index.js +796 -1821
- package/dist/index.js.map +1 -1
- package/package.json +73 -73
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
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
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
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
|
|
595
|
-
if (
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
const
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
return
|
|
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
|
-
//
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
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
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
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
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
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
|
-
|
|
630
|
-
|
|
876
|
+
attachDatabase(name, adapter) {
|
|
877
|
+
this.databases.set(name, adapter);
|
|
878
|
+
if (!this.defaultDatabase) {
|
|
879
|
+
this.defaultDatabase = name;
|
|
880
|
+
}
|
|
631
881
|
}
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
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
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
}
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
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
|
-
|
|
677
|
-
|
|
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
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
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
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
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
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
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
|
-
|
|
741
|
-
|
|
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
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
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
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
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
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
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
|
-
|
|
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
|
-
|
|
814
|
-
|
|
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
|
-
|
|
817
|
-
|
|
818
|
-
|
|
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
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
if (
|
|
828
|
-
|
|
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
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
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
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
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
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
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
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
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
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
if (
|
|
1469
|
-
|
|
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
|
|
1221
|
+
return response;
|
|
1472
1222
|
}
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
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
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
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
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
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
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
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
|
-
|
|
1274
|
+
return adapter;
|
|
1621
1275
|
}
|
|
1622
|
-
|
|
1623
|
-
if (
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
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
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
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
|
-
|
|
1634
|
-
return this;
|
|
1296
|
+
return resolved;
|
|
1635
1297
|
}
|
|
1636
|
-
async
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
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 (
|
|
1686
|
-
|
|
1687
|
-
}
|
|
1688
|
-
if (this.#protectedHeader) {
|
|
1689
|
-
jws.protected = protectedHeaderString;
|
|
1304
|
+
if (includeJson) {
|
|
1305
|
+
headers["Content-Type"] = "application/json";
|
|
1690
1306
|
}
|
|
1691
|
-
|
|
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
|
-
|
|
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
|
|
1313
|
+
return headers;
|
|
1760
1314
|
}
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
|
|
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
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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
|
-
|
|
1878
|
-
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
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
|
-
|
|
1923
|
-
|
|
1389
|
+
database: databaseName,
|
|
1390
|
+
dialect,
|
|
1391
|
+
tables
|
|
1924
1392
|
};
|
|
1925
1393
|
}
|
|
1926
|
-
|
|
1927
|
-
|
|
1928
|
-
|
|
1929
|
-
|
|
1930
|
-
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
|
|
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
|
|
2269
|
-
|
|
2270
|
-
|
|
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
|
-
`
|
|
1445
|
+
`Failed to execute SQL locally for database '${database}':`,
|
|
1446
|
+
error
|
|
2327
1447
|
);
|
|
1448
|
+
return [];
|
|
2328
1449
|
}
|
|
2329
1450
|
}
|
|
2330
|
-
|
|
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,
|