@querypanel/node-sdk 1.0.56 → 1.0.57
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 +684 -32
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +455 -8
- package/dist/index.d.ts +455 -8
- package/dist/index.js +683 -32
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -30,6 +30,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
30
30
|
// src/index.ts
|
|
31
31
|
var index_exports = {};
|
|
32
32
|
__export(index_exports, {
|
|
33
|
+
CallbackApiClient: () => CallbackApiClient,
|
|
33
34
|
ClickHouseAdapter: () => ClickHouseAdapter,
|
|
34
35
|
PostgresAdapter: () => PostgresAdapter,
|
|
35
36
|
QueryErrorCode: () => QueryErrorCode,
|
|
@@ -367,29 +368,31 @@ var PostgresAdapter = class {
|
|
|
367
368
|
}
|
|
368
369
|
}
|
|
369
370
|
/**
|
|
370
|
-
* Convert
|
|
371
|
-
* PostgreSQL expects $1, $2, $3 in SQL and an array of values [val1, val2, val3]
|
|
371
|
+
* Convert params to positional array for PostgreSQL.
|
|
372
|
+
* PostgreSQL expects $1, $2, $3 in SQL and an array of values [val1, val2, val3].
|
|
373
|
+
* When the record has numeric keys ("1", "2", "3") — e.g. from mapGeneratedParams —
|
|
374
|
+
* use only those in order so placeholder order matches SQL. Otherwise fall back to
|
|
375
|
+
* named keys in alphabetical order for backward compatibility.
|
|
372
376
|
*/
|
|
373
377
|
convertNamedToPositionalParams(params) {
|
|
374
378
|
const numericKeys = Object.keys(params).filter((k) => /^\d+$/.test(k)).map((k) => Number.parseInt(k, 10)).sort((a, b) => a - b);
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
379
|
+
if (numericKeys.length > 0) {
|
|
380
|
+
const positionalParams = [];
|
|
381
|
+
for (const key of numericKeys) {
|
|
382
|
+
let val = params[String(key)];
|
|
383
|
+
if (typeof val === "string") {
|
|
384
|
+
const match = val.match(/^<([a-zA-Z0-9_]+)>$/);
|
|
385
|
+
const namedKey = match?.[1];
|
|
386
|
+
if (namedKey && namedKey in params) {
|
|
387
|
+
val = params[namedKey];
|
|
388
|
+
}
|
|
384
389
|
}
|
|
390
|
+
positionalParams.push(val);
|
|
385
391
|
}
|
|
386
|
-
positionalParams
|
|
387
|
-
}
|
|
388
|
-
for (const key of namedKeys) {
|
|
389
|
-
const val = params[key];
|
|
390
|
-
positionalParams.push(val);
|
|
392
|
+
return positionalParams;
|
|
391
393
|
}
|
|
392
|
-
|
|
394
|
+
const namedKeys = Object.keys(params).filter((k) => !/^\d+$/.test(k)).sort();
|
|
395
|
+
return namedKeys.map((key) => params[key]);
|
|
393
396
|
}
|
|
394
397
|
async validate(sql, params) {
|
|
395
398
|
let paramArray;
|
|
@@ -601,6 +604,13 @@ var ApiClient = class {
|
|
|
601
604
|
getDefaultTenantId() {
|
|
602
605
|
return this.defaultTenantId;
|
|
603
606
|
}
|
|
607
|
+
/**
|
|
608
|
+
* Create a JWT for the given tenant (and optional userId, scopes).
|
|
609
|
+
* Use this when you need to pass a token to the embed (e.g. frontend or demo).
|
|
610
|
+
*/
|
|
611
|
+
async createJwt(tenantId, userId, scopes) {
|
|
612
|
+
return await this.generateJWT(tenantId, userId, scopes);
|
|
613
|
+
}
|
|
604
614
|
async get(path, tenantId, userId, scopes, signal, sessionId) {
|
|
605
615
|
return await this.request(path, {
|
|
606
616
|
method: "GET",
|
|
@@ -813,6 +823,111 @@ var ApiClient = class {
|
|
|
813
823
|
}
|
|
814
824
|
};
|
|
815
825
|
|
|
826
|
+
// src/core/callback-client.ts
|
|
827
|
+
var CallbackApiClient = class {
|
|
828
|
+
requestHandler;
|
|
829
|
+
defaultTenantId;
|
|
830
|
+
constructor(requestHandler, options) {
|
|
831
|
+
this.requestHandler = requestHandler;
|
|
832
|
+
this.defaultTenantId = options?.defaultTenantId;
|
|
833
|
+
}
|
|
834
|
+
getDefaultTenantId() {
|
|
835
|
+
return this.defaultTenantId;
|
|
836
|
+
}
|
|
837
|
+
async request(opts) {
|
|
838
|
+
const { data, headers } = await this.requestHandler({
|
|
839
|
+
method: opts.method,
|
|
840
|
+
path: opts.path,
|
|
841
|
+
body: opts.body,
|
|
842
|
+
tenantId: opts.tenantId,
|
|
843
|
+
userId: opts.userId,
|
|
844
|
+
scopes: opts.scopes,
|
|
845
|
+
signal: opts.signal,
|
|
846
|
+
sessionId: opts.sessionId
|
|
847
|
+
});
|
|
848
|
+
return { data, headers };
|
|
849
|
+
}
|
|
850
|
+
async get(path, tenantId, userId, scopes, signal, sessionId) {
|
|
851
|
+
const { data } = await this.request({
|
|
852
|
+
method: "GET",
|
|
853
|
+
path,
|
|
854
|
+
tenantId,
|
|
855
|
+
userId,
|
|
856
|
+
scopes,
|
|
857
|
+
signal,
|
|
858
|
+
sessionId
|
|
859
|
+
});
|
|
860
|
+
return data;
|
|
861
|
+
}
|
|
862
|
+
async post(path, body, tenantId, userId, scopes, signal, sessionId) {
|
|
863
|
+
const { data } = await this.request({
|
|
864
|
+
method: "POST",
|
|
865
|
+
path,
|
|
866
|
+
body,
|
|
867
|
+
tenantId,
|
|
868
|
+
userId,
|
|
869
|
+
scopes,
|
|
870
|
+
signal,
|
|
871
|
+
sessionId
|
|
872
|
+
});
|
|
873
|
+
return data;
|
|
874
|
+
}
|
|
875
|
+
async postWithHeaders(path, body, tenantId, userId, scopes, signal, sessionId) {
|
|
876
|
+
const { data, headers } = await this.request({
|
|
877
|
+
method: "POST",
|
|
878
|
+
path,
|
|
879
|
+
body,
|
|
880
|
+
tenantId,
|
|
881
|
+
userId,
|
|
882
|
+
scopes,
|
|
883
|
+
signal,
|
|
884
|
+
sessionId
|
|
885
|
+
});
|
|
886
|
+
return {
|
|
887
|
+
data,
|
|
888
|
+
headers: headers ?? new Headers()
|
|
889
|
+
};
|
|
890
|
+
}
|
|
891
|
+
async put(path, body, tenantId, userId, scopes, signal, sessionId) {
|
|
892
|
+
const { data } = await this.request({
|
|
893
|
+
method: "PUT",
|
|
894
|
+
path,
|
|
895
|
+
body,
|
|
896
|
+
tenantId,
|
|
897
|
+
userId,
|
|
898
|
+
scopes,
|
|
899
|
+
signal,
|
|
900
|
+
sessionId
|
|
901
|
+
});
|
|
902
|
+
return data;
|
|
903
|
+
}
|
|
904
|
+
async patch(path, body, tenantId, userId, scopes, signal, sessionId) {
|
|
905
|
+
const { data } = await this.request({
|
|
906
|
+
method: "PATCH",
|
|
907
|
+
path,
|
|
908
|
+
body,
|
|
909
|
+
tenantId,
|
|
910
|
+
userId,
|
|
911
|
+
scopes,
|
|
912
|
+
signal,
|
|
913
|
+
sessionId
|
|
914
|
+
});
|
|
915
|
+
return data;
|
|
916
|
+
}
|
|
917
|
+
async delete(path, tenantId, userId, scopes, signal, sessionId) {
|
|
918
|
+
const { data } = await this.request({
|
|
919
|
+
method: "DELETE",
|
|
920
|
+
path,
|
|
921
|
+
tenantId,
|
|
922
|
+
userId,
|
|
923
|
+
scopes,
|
|
924
|
+
signal,
|
|
925
|
+
sessionId
|
|
926
|
+
});
|
|
927
|
+
return data;
|
|
928
|
+
}
|
|
929
|
+
};
|
|
930
|
+
|
|
816
931
|
// src/core/query-engine.ts
|
|
817
932
|
var QueryEngine = class {
|
|
818
933
|
databases = /* @__PURE__ */ new Map();
|
|
@@ -875,6 +990,12 @@ var QueryEngine = class {
|
|
|
875
990
|
return [];
|
|
876
991
|
}
|
|
877
992
|
}
|
|
993
|
+
/**
|
|
994
|
+
* Maps API params (array in SQL placeholder order $1, $2, $3) to ParamRecord.
|
|
995
|
+
* Sets both numeric keys ("1", "2", "3") and named keys so that:
|
|
996
|
+
* - Postgres adapter uses numeric order for positional params (matches SQL).
|
|
997
|
+
* - Named keys remain for tenant isolation / other lookups.
|
|
998
|
+
*/
|
|
878
999
|
mapGeneratedParams(params) {
|
|
879
1000
|
const record = {};
|
|
880
1001
|
params.forEach((param, index) => {
|
|
@@ -882,6 +1003,7 @@ var QueryEngine = class {
|
|
|
882
1003
|
if (value === void 0) {
|
|
883
1004
|
return;
|
|
884
1005
|
}
|
|
1006
|
+
record[String(index + 1)] = value;
|
|
885
1007
|
const nameCandidate = typeof param.name === "string" && param.name.trim() || typeof param.placeholder === "string" && param.placeholder.trim() || typeof param.position === "number" && String(param.position) || String(index + 1);
|
|
886
1008
|
const key = nameCandidate.replace(/[{}:$]/g, "").trim();
|
|
887
1009
|
record[key] = value;
|
|
@@ -1210,10 +1332,161 @@ function resolveTenantId2(client, tenantId) {
|
|
|
1210
1332
|
return resolved;
|
|
1211
1333
|
}
|
|
1212
1334
|
|
|
1335
|
+
// src/routes/dashboards.ts
|
|
1336
|
+
function resolveTenantId3(client, tenantId) {
|
|
1337
|
+
const resolved = tenantId ?? client.getDefaultTenantId();
|
|
1338
|
+
if (resolved === void 0) {
|
|
1339
|
+
throw new Error("tenantId is required (option or client default)");
|
|
1340
|
+
}
|
|
1341
|
+
return resolved;
|
|
1342
|
+
}
|
|
1343
|
+
async function createDashboard(client, body, options, signal) {
|
|
1344
|
+
const tenantId = resolveTenantId3(client, options?.tenantId);
|
|
1345
|
+
return await client.post(
|
|
1346
|
+
"/dashboards",
|
|
1347
|
+
body,
|
|
1348
|
+
tenantId,
|
|
1349
|
+
options?.userId,
|
|
1350
|
+
options?.scopes,
|
|
1351
|
+
signal
|
|
1352
|
+
);
|
|
1353
|
+
}
|
|
1354
|
+
async function listDashboards(client, options, signal) {
|
|
1355
|
+
const tenantId = resolveTenantId3(client, options?.tenantId);
|
|
1356
|
+
const params = new URLSearchParams();
|
|
1357
|
+
if (options?.pagination?.page) {
|
|
1358
|
+
params.set("page", options.pagination.page.toString());
|
|
1359
|
+
}
|
|
1360
|
+
if (options?.pagination?.limit) {
|
|
1361
|
+
params.set("limit", options.pagination.limit.toString());
|
|
1362
|
+
}
|
|
1363
|
+
if (options?.status) {
|
|
1364
|
+
params.set("status", options.status);
|
|
1365
|
+
}
|
|
1366
|
+
if (options?.sortBy) {
|
|
1367
|
+
params.set("sort_by", options.sortBy);
|
|
1368
|
+
}
|
|
1369
|
+
if (options?.sortDir) {
|
|
1370
|
+
params.set("sort_dir", options.sortDir);
|
|
1371
|
+
}
|
|
1372
|
+
return await client.get(
|
|
1373
|
+
`/dashboards?${params.toString()}`,
|
|
1374
|
+
tenantId,
|
|
1375
|
+
options?.userId,
|
|
1376
|
+
options?.scopes,
|
|
1377
|
+
signal
|
|
1378
|
+
);
|
|
1379
|
+
}
|
|
1380
|
+
async function getDashboard(client, id, options, signal) {
|
|
1381
|
+
const tenantId = resolveTenantId3(client, options?.tenantId);
|
|
1382
|
+
return await client.get(
|
|
1383
|
+
`/dashboards/${id}`,
|
|
1384
|
+
tenantId,
|
|
1385
|
+
options?.userId,
|
|
1386
|
+
options?.scopes,
|
|
1387
|
+
signal
|
|
1388
|
+
);
|
|
1389
|
+
}
|
|
1390
|
+
async function getDashboardForTenant(client, id, tenantId, options, signal) {
|
|
1391
|
+
const params = new URLSearchParams();
|
|
1392
|
+
params.set("tenant_id", tenantId);
|
|
1393
|
+
return await client.get(
|
|
1394
|
+
`/dashboards/${id}/for-tenant?${params.toString()}`,
|
|
1395
|
+
tenantId,
|
|
1396
|
+
options?.userId,
|
|
1397
|
+
options?.scopes,
|
|
1398
|
+
signal
|
|
1399
|
+
);
|
|
1400
|
+
}
|
|
1401
|
+
async function updateDashboard(client, id, body, options, signal) {
|
|
1402
|
+
const tenantId = resolveTenantId3(client, options?.tenantId);
|
|
1403
|
+
return await client.put(
|
|
1404
|
+
`/dashboards/${id}`,
|
|
1405
|
+
body,
|
|
1406
|
+
tenantId,
|
|
1407
|
+
options?.userId,
|
|
1408
|
+
options?.scopes,
|
|
1409
|
+
signal
|
|
1410
|
+
);
|
|
1411
|
+
}
|
|
1412
|
+
async function updateDashboardStatus(client, id, status, options, signal) {
|
|
1413
|
+
const tenantId = resolveTenantId3(client, options?.tenantId);
|
|
1414
|
+
return await client.patch(
|
|
1415
|
+
`/dashboards/${id}/status`,
|
|
1416
|
+
{ status },
|
|
1417
|
+
tenantId,
|
|
1418
|
+
options?.userId,
|
|
1419
|
+
options?.scopes,
|
|
1420
|
+
signal
|
|
1421
|
+
);
|
|
1422
|
+
}
|
|
1423
|
+
async function deleteDashboard(client, id, options, signal) {
|
|
1424
|
+
const tenantId = resolveTenantId3(client, options?.tenantId);
|
|
1425
|
+
await client.delete(
|
|
1426
|
+
`/dashboards/${id}`,
|
|
1427
|
+
tenantId,
|
|
1428
|
+
options?.userId,
|
|
1429
|
+
options?.scopes,
|
|
1430
|
+
signal
|
|
1431
|
+
);
|
|
1432
|
+
}
|
|
1433
|
+
async function forkDashboard(client, id, input, options, signal) {
|
|
1434
|
+
const tenantId = resolveTenantId3(client, options?.tenantId);
|
|
1435
|
+
return await client.post(
|
|
1436
|
+
`/dashboards/${id}/fork`,
|
|
1437
|
+
input,
|
|
1438
|
+
tenantId,
|
|
1439
|
+
options?.userId,
|
|
1440
|
+
options?.scopes,
|
|
1441
|
+
signal
|
|
1442
|
+
);
|
|
1443
|
+
}
|
|
1444
|
+
async function updateFork(client, forkId, input, options, signal) {
|
|
1445
|
+
const tenantId = resolveTenantId3(client, options?.tenantId);
|
|
1446
|
+
return await client.put(
|
|
1447
|
+
`/dashboards/forks/${forkId}`,
|
|
1448
|
+
input,
|
|
1449
|
+
tenantId,
|
|
1450
|
+
options?.userId,
|
|
1451
|
+
options?.scopes,
|
|
1452
|
+
signal
|
|
1453
|
+
);
|
|
1454
|
+
}
|
|
1455
|
+
async function rollbackFork(client, forkId, tenantId, options, signal) {
|
|
1456
|
+
return await client.post(
|
|
1457
|
+
`/dashboards/forks/${forkId}/rollback`,
|
|
1458
|
+
{ tenant_id: tenantId },
|
|
1459
|
+
tenantId,
|
|
1460
|
+
options?.userId,
|
|
1461
|
+
options?.scopes,
|
|
1462
|
+
signal
|
|
1463
|
+
);
|
|
1464
|
+
}
|
|
1465
|
+
async function deleteFork(client, forkId, tenantId, options, signal) {
|
|
1466
|
+
const params = new URLSearchParams();
|
|
1467
|
+
params.set("tenant_id", tenantId);
|
|
1468
|
+
await client.delete(
|
|
1469
|
+
`/dashboards/forks/${forkId}?${params.toString()}`,
|
|
1470
|
+
tenantId,
|
|
1471
|
+
options?.userId,
|
|
1472
|
+
options?.scopes,
|
|
1473
|
+
signal
|
|
1474
|
+
);
|
|
1475
|
+
}
|
|
1476
|
+
async function listForksForTenant(client, tenantId, options, signal) {
|
|
1477
|
+
return await client.get(
|
|
1478
|
+
`/dashboards/customer/${tenantId}`,
|
|
1479
|
+
tenantId,
|
|
1480
|
+
options?.userId,
|
|
1481
|
+
options?.scopes,
|
|
1482
|
+
signal
|
|
1483
|
+
);
|
|
1484
|
+
}
|
|
1485
|
+
|
|
1213
1486
|
// src/routes/ingest.ts
|
|
1214
1487
|
var import_node_crypto2 = __toESM(require("crypto"), 1);
|
|
1215
1488
|
async function syncSchema(client, queryEngine, databaseName, options, signal) {
|
|
1216
|
-
const tenantId =
|
|
1489
|
+
const tenantId = resolveTenantId4(client, options.tenantId);
|
|
1217
1490
|
const adapter = queryEngine.getDatabase(databaseName);
|
|
1218
1491
|
const metadata = queryEngine.getDatabaseMetadata(databaseName);
|
|
1219
1492
|
const introspection = await adapter.introspect(
|
|
@@ -1235,7 +1508,7 @@ async function syncSchema(client, queryEngine, databaseName, options, signal) {
|
|
|
1235
1508
|
);
|
|
1236
1509
|
return response;
|
|
1237
1510
|
}
|
|
1238
|
-
function
|
|
1511
|
+
function resolveTenantId4(client, tenantId) {
|
|
1239
1512
|
const resolved = tenantId ?? client.getDefaultTenantId();
|
|
1240
1513
|
if (!resolved) {
|
|
1241
1514
|
throw new Error(
|
|
@@ -1277,7 +1550,7 @@ var import_node_crypto4 = __toESM(require("crypto"), 1);
|
|
|
1277
1550
|
// src/routes/query.ts
|
|
1278
1551
|
var import_node_crypto3 = __toESM(require("crypto"), 1);
|
|
1279
1552
|
async function ask(client, queryEngine, question, options, signal) {
|
|
1280
|
-
const tenantId =
|
|
1553
|
+
const tenantId = resolveTenantId5(client, options.tenantId);
|
|
1281
1554
|
const sessionId = import_node_crypto3.default.randomUUID();
|
|
1282
1555
|
const querypanelSessionId = options.querypanelSessionId ?? sessionId;
|
|
1283
1556
|
const maxRetry = options.maxRetry ?? 0;
|
|
@@ -1432,7 +1705,7 @@ async function ask(client, queryEngine, question, options, signal) {
|
|
|
1432
1705
|
}
|
|
1433
1706
|
throw new Error("Unexpected error in ask retry loop");
|
|
1434
1707
|
}
|
|
1435
|
-
function
|
|
1708
|
+
function resolveTenantId5(client, tenantId) {
|
|
1436
1709
|
const resolved = tenantId ?? client.getDefaultTenantId();
|
|
1437
1710
|
if (!resolved) {
|
|
1438
1711
|
throw new Error(
|
|
@@ -1588,7 +1861,7 @@ function stripVizSpecOnlyHints(hints) {
|
|
|
1588
1861
|
const { kind: _kind, ...rest } = hints;
|
|
1589
1862
|
return rest;
|
|
1590
1863
|
}
|
|
1591
|
-
function
|
|
1864
|
+
function resolveTenantId6(client, tenantId) {
|
|
1592
1865
|
const resolved = tenantId ?? client.getDefaultTenantId();
|
|
1593
1866
|
if (!resolved) {
|
|
1594
1867
|
throw new Error(
|
|
@@ -1598,7 +1871,7 @@ function resolveTenantId5(client, tenantId) {
|
|
|
1598
1871
|
return resolved;
|
|
1599
1872
|
}
|
|
1600
1873
|
async function modifyChart(client, queryEngine, input, options, signal) {
|
|
1601
|
-
const tenantId =
|
|
1874
|
+
const tenantId = resolveTenantId6(client, options?.tenantId);
|
|
1602
1875
|
const sessionId = import_node_crypto4.default.randomUUID();
|
|
1603
1876
|
const querypanelSessionId = options?.querypanelSessionId ?? sessionId;
|
|
1604
1877
|
const hasQuerypanelSessionContext = !!options?.querypanelSessionId;
|
|
@@ -1766,7 +2039,7 @@ async function modifyChart(client, queryEngine, input, options, signal) {
|
|
|
1766
2039
|
|
|
1767
2040
|
// src/routes/sessions.ts
|
|
1768
2041
|
async function listSessions(client, options, signal) {
|
|
1769
|
-
const tenantId =
|
|
2042
|
+
const tenantId = resolveTenantId7(client, options?.tenantId);
|
|
1770
2043
|
const params = new URLSearchParams();
|
|
1771
2044
|
if (options?.pagination?.page)
|
|
1772
2045
|
params.set("page", `${options.pagination.page}`);
|
|
@@ -1789,7 +2062,7 @@ async function listSessions(client, options, signal) {
|
|
|
1789
2062
|
);
|
|
1790
2063
|
}
|
|
1791
2064
|
async function getSession(client, sessionId, options, signal) {
|
|
1792
|
-
const tenantId =
|
|
2065
|
+
const tenantId = resolveTenantId7(client, options?.tenantId);
|
|
1793
2066
|
const params = new URLSearchParams();
|
|
1794
2067
|
if (options?.includeTurns !== void 0) {
|
|
1795
2068
|
params.set("include_turns", `${options.includeTurns}`);
|
|
@@ -1803,7 +2076,7 @@ async function getSession(client, sessionId, options, signal) {
|
|
|
1803
2076
|
);
|
|
1804
2077
|
}
|
|
1805
2078
|
async function updateSession(client, sessionId, body, options, signal) {
|
|
1806
|
-
const tenantId =
|
|
2079
|
+
const tenantId = resolveTenantId7(client, options?.tenantId);
|
|
1807
2080
|
return await client.patch(
|
|
1808
2081
|
`/sessions/${encodeURIComponent(sessionId)}`,
|
|
1809
2082
|
body,
|
|
@@ -1814,7 +2087,7 @@ async function updateSession(client, sessionId, body, options, signal) {
|
|
|
1814
2087
|
);
|
|
1815
2088
|
}
|
|
1816
2089
|
async function deleteSession(client, sessionId, options, signal) {
|
|
1817
|
-
const tenantId =
|
|
2090
|
+
const tenantId = resolveTenantId7(client, options?.tenantId);
|
|
1818
2091
|
await client.delete(
|
|
1819
2092
|
`/sessions/${encodeURIComponent(sessionId)}`,
|
|
1820
2093
|
tenantId,
|
|
@@ -1823,7 +2096,7 @@ async function deleteSession(client, sessionId, options, signal) {
|
|
|
1823
2096
|
signal
|
|
1824
2097
|
);
|
|
1825
2098
|
}
|
|
1826
|
-
function
|
|
2099
|
+
function resolveTenantId7(client, tenantId) {
|
|
1827
2100
|
const resolved = tenantId ?? client.getDefaultTenantId();
|
|
1828
2101
|
if (!resolved) {
|
|
1829
2102
|
throw new Error(
|
|
@@ -1836,7 +2109,7 @@ function resolveTenantId6(client, tenantId) {
|
|
|
1836
2109
|
// src/routes/vizspec.ts
|
|
1837
2110
|
var import_node_crypto5 = __toESM(require("crypto"), 1);
|
|
1838
2111
|
async function generateVizSpec(client, input, options, signal) {
|
|
1839
|
-
const tenantId =
|
|
2112
|
+
const tenantId = resolveTenantId8(client, options?.tenantId);
|
|
1840
2113
|
const sessionId = import_node_crypto5.default.randomUUID();
|
|
1841
2114
|
const response = await client.post(
|
|
1842
2115
|
"/vizspec",
|
|
@@ -1858,7 +2131,7 @@ async function generateVizSpec(client, input, options, signal) {
|
|
|
1858
2131
|
);
|
|
1859
2132
|
return response;
|
|
1860
2133
|
}
|
|
1861
|
-
function
|
|
2134
|
+
function resolveTenantId8(client, tenantId) {
|
|
1862
2135
|
const resolved = tenantId ?? client.getDefaultTenantId();
|
|
1863
2136
|
if (!resolved) {
|
|
1864
2137
|
throw new Error(
|
|
@@ -1869,13 +2142,62 @@ function resolveTenantId7(client, tenantId) {
|
|
|
1869
2142
|
}
|
|
1870
2143
|
|
|
1871
2144
|
// src/index.ts
|
|
1872
|
-
var QueryPanelSdkAPI = class {
|
|
2145
|
+
var QueryPanelSdkAPI = class _QueryPanelSdkAPI {
|
|
1873
2146
|
client;
|
|
1874
2147
|
queryEngine;
|
|
1875
2148
|
constructor(baseUrl, privateKey, organizationId, options) {
|
|
1876
|
-
|
|
2149
|
+
if (options?.api) {
|
|
2150
|
+
this.client = options.api;
|
|
2151
|
+
} else {
|
|
2152
|
+
if (!baseUrl) throw new Error("Base URL is required");
|
|
2153
|
+
if (!privateKey) throw new Error("Private key is required");
|
|
2154
|
+
if (!organizationId) throw new Error("Organization ID is required");
|
|
2155
|
+
this.client = new ApiClient(baseUrl, privateKey, organizationId, {
|
|
2156
|
+
defaultTenantId: options?.defaultTenantId,
|
|
2157
|
+
additionalHeaders: options?.additionalHeaders,
|
|
2158
|
+
fetch: options?.fetch
|
|
2159
|
+
});
|
|
2160
|
+
}
|
|
2161
|
+
if (!organizationId) throw new Error("Organization ID is required");
|
|
1877
2162
|
this.queryEngine = new QueryEngine();
|
|
1878
2163
|
}
|
|
2164
|
+
/**
|
|
2165
|
+
* Create an SDK instance that uses a request callback instead of HTTP.
|
|
2166
|
+
* Use this when calling the SDK from within your own API so that "API" calls
|
|
2167
|
+
* are handled in-process (e.g. by invoking querypanel-sdk services directly)
|
|
2168
|
+
* and do not cause recursion.
|
|
2169
|
+
*
|
|
2170
|
+
* @param organizationId - Organization identifier
|
|
2171
|
+
* @param requestHandler - Callback invoked for each logical API request (method, path, body, tenantId, etc.)
|
|
2172
|
+
* @param options - Optional defaultTenantId
|
|
2173
|
+
* @returns QueryPanelSdkAPI instance; attach databases and call ask(), syncSchema(), etc. as usual
|
|
2174
|
+
*
|
|
2175
|
+
* @example
|
|
2176
|
+
* ```ts
|
|
2177
|
+
* const qp = QueryPanelSdkAPI.withCallbacks(
|
|
2178
|
+
* process.env.ORGANIZATION_ID!,
|
|
2179
|
+
* async (opts) => {
|
|
2180
|
+
* // Call your in-process services (e.g. querypanel-sdk logic) instead of HTTP
|
|
2181
|
+
* if (opts.path === '/query' || opts.path === '/v2/query') {
|
|
2182
|
+
* const result = await yourSqlGenerator.generate(opts.body, opts.tenantId);
|
|
2183
|
+
* return { data: result, headers: new Headers({ 'x-querypanel-session-id': result.sessionId }) };
|
|
2184
|
+
* }
|
|
2185
|
+
* if (opts.path === '/chart') return { data: await yourChartService.generate(opts.body) };
|
|
2186
|
+
* // ... other paths
|
|
2187
|
+
* return { data: await yourProxy(opts) };
|
|
2188
|
+
* },
|
|
2189
|
+
* { defaultTenantId: process.env.DEFAULT_TENANT_ID }
|
|
2190
|
+
* );
|
|
2191
|
+
* qp.attachPostgres('db', createClient, { tenantFieldName: 'tenant_id' });
|
|
2192
|
+
* const result = await qp.ask('Top 10 orders', { tenantId: 't1', database: 'db' });
|
|
2193
|
+
* ```
|
|
2194
|
+
*/
|
|
2195
|
+
static withCallbacks(organizationId, requestHandler, options) {
|
|
2196
|
+
const api = new CallbackApiClient(requestHandler, {
|
|
2197
|
+
defaultTenantId: options?.defaultTenantId
|
|
2198
|
+
});
|
|
2199
|
+
return new _QueryPanelSdkAPI("", "", organizationId, { api });
|
|
2200
|
+
}
|
|
1879
2201
|
// Database attachment methods
|
|
1880
2202
|
attachClickhouse(name, clientFn, options) {
|
|
1881
2203
|
const adapter = new ClickHouseAdapter(clientFn, options);
|
|
@@ -1989,6 +2311,48 @@ var QueryPanelSdkAPI = class {
|
|
|
1989
2311
|
signal
|
|
1990
2312
|
);
|
|
1991
2313
|
}
|
|
2314
|
+
// Embedded dashboard / JWT
|
|
2315
|
+
/**
|
|
2316
|
+
* Creates a JWT for the given tenant (and optional userId, scopes).
|
|
2317
|
+
* Use this when you need to pass a token to the embed (e.g. frontend or demo).
|
|
2318
|
+
* Only available when using the HTTP client (ApiClient); not available when using withCallbacks.
|
|
2319
|
+
*/
|
|
2320
|
+
async createJwt(options) {
|
|
2321
|
+
const tenantId = options.tenantId?.trim();
|
|
2322
|
+
if (!tenantId) {
|
|
2323
|
+
throw new Error("tenantId is required");
|
|
2324
|
+
}
|
|
2325
|
+
if (!(this.client instanceof ApiClient)) {
|
|
2326
|
+
throw new Error(
|
|
2327
|
+
"createJwt is not available when using withCallbacks. Use the SDK with baseUrl + privateKey to create JWTs."
|
|
2328
|
+
);
|
|
2329
|
+
}
|
|
2330
|
+
return await this.client.createJwt(
|
|
2331
|
+
tenantId,
|
|
2332
|
+
options.userId,
|
|
2333
|
+
options.scopes
|
|
2334
|
+
);
|
|
2335
|
+
}
|
|
2336
|
+
/**
|
|
2337
|
+
* Runs SQL against an attached database with tenant isolation applied.
|
|
2338
|
+
* Used by embed run-sql (e.g. dashboard chart execution). Requires a database
|
|
2339
|
+
* to be attached (e.g. via attachPostgres) and options.tenantId.
|
|
2340
|
+
*/
|
|
2341
|
+
async runSqlForDashboard(input, options) {
|
|
2342
|
+
const tenantId = options.tenantId?.trim();
|
|
2343
|
+
if (!tenantId) {
|
|
2344
|
+
throw new Error("tenantId is required");
|
|
2345
|
+
}
|
|
2346
|
+
const databaseName = input.database ?? "db";
|
|
2347
|
+
const params = input.params ?? {};
|
|
2348
|
+
const result = await this.queryEngine.validateAndExecute(
|
|
2349
|
+
input.sql,
|
|
2350
|
+
params,
|
|
2351
|
+
databaseName,
|
|
2352
|
+
tenantId
|
|
2353
|
+
);
|
|
2354
|
+
return { rows: result.rows, fields: result.fields };
|
|
2355
|
+
}
|
|
1992
2356
|
// VizSpec generation
|
|
1993
2357
|
/**
|
|
1994
2358
|
* Generates a VizSpec visualization specification from query results.
|
|
@@ -2432,9 +2796,297 @@ var QueryPanelSdkAPI = class {
|
|
|
2432
2796
|
async deleteActiveChart(id, options, signal) {
|
|
2433
2797
|
await deleteActiveChart(this.client, id, options, signal);
|
|
2434
2798
|
}
|
|
2799
|
+
// Dashboard CRUD operations
|
|
2800
|
+
/**
|
|
2801
|
+
* Creates a new dashboard with BlockNote content.
|
|
2802
|
+
*
|
|
2803
|
+
* @param body - Dashboard configuration including name and BlockNote content
|
|
2804
|
+
* @param options - Tenant, user, and scope options
|
|
2805
|
+
* @param signal - Optional AbortSignal for cancellation
|
|
2806
|
+
* @returns Created dashboard
|
|
2807
|
+
*
|
|
2808
|
+
* @example
|
|
2809
|
+
* ```typescript
|
|
2810
|
+
* const dashboard = await qp.createDashboard({
|
|
2811
|
+
* name: "Sales Dashboard",
|
|
2812
|
+
* description: "Monthly sales metrics",
|
|
2813
|
+
* content_json: blockNoteContent,
|
|
2814
|
+
* editor_type: "blocknote",
|
|
2815
|
+
* }, { tenantId: "tenant_123" });
|
|
2816
|
+
* ```
|
|
2817
|
+
*/
|
|
2818
|
+
async createDashboard(body, options, signal) {
|
|
2819
|
+
return await createDashboard(
|
|
2820
|
+
this.client,
|
|
2821
|
+
body,
|
|
2822
|
+
options,
|
|
2823
|
+
signal
|
|
2824
|
+
);
|
|
2825
|
+
}
|
|
2826
|
+
/**
|
|
2827
|
+
* Lists dashboards with pagination and filtering.
|
|
2828
|
+
*
|
|
2829
|
+
* @param options - Filtering and pagination options
|
|
2830
|
+
* @param signal - Optional AbortSignal for cancellation
|
|
2831
|
+
* @returns Paginated list of dashboards
|
|
2832
|
+
*
|
|
2833
|
+
* @example
|
|
2834
|
+
* ```typescript
|
|
2835
|
+
* const dashboards = await qp.listDashboards({
|
|
2836
|
+
* tenantId: "tenant_123",
|
|
2837
|
+
* status: "deployed",
|
|
2838
|
+
* pagination: { page: 1, limit: 10 },
|
|
2839
|
+
* });
|
|
2840
|
+
* ```
|
|
2841
|
+
*/
|
|
2842
|
+
async listDashboards(options, signal) {
|
|
2843
|
+
return await listDashboards(this.client, options, signal);
|
|
2844
|
+
}
|
|
2845
|
+
/**
|
|
2846
|
+
* Gets a dashboard by ID.
|
|
2847
|
+
*
|
|
2848
|
+
* @param id - Dashboard ID
|
|
2849
|
+
* @param options - Tenant, user, and scope options
|
|
2850
|
+
* @param signal - Optional AbortSignal for cancellation
|
|
2851
|
+
* @returns Dashboard details
|
|
2852
|
+
*
|
|
2853
|
+
* @example
|
|
2854
|
+
* ```typescript
|
|
2855
|
+
* const dashboard = await qp.getDashboard("dash_123", {
|
|
2856
|
+
* tenantId: "tenant_123",
|
|
2857
|
+
* });
|
|
2858
|
+
* ```
|
|
2859
|
+
*/
|
|
2860
|
+
async getDashboard(id, options, signal) {
|
|
2861
|
+
return await getDashboard(
|
|
2862
|
+
this.client,
|
|
2863
|
+
id,
|
|
2864
|
+
options,
|
|
2865
|
+
signal
|
|
2866
|
+
);
|
|
2867
|
+
}
|
|
2868
|
+
/**
|
|
2869
|
+
* Gets a dashboard for a specific tenant.
|
|
2870
|
+
* Returns customer fork if exists, otherwise returns the original dashboard.
|
|
2871
|
+
*
|
|
2872
|
+
* @param id - Dashboard ID
|
|
2873
|
+
* @param tenantId - Tenant ID to check for fork
|
|
2874
|
+
* @param options - Additional auth options
|
|
2875
|
+
* @param signal - Optional AbortSignal for cancellation
|
|
2876
|
+
* @returns Dashboard (fork if exists, original otherwise)
|
|
2877
|
+
*
|
|
2878
|
+
* @example
|
|
2879
|
+
* ```typescript
|
|
2880
|
+
* const dashboard = await qp.getDashboardForTenant(
|
|
2881
|
+
* "dash_123",
|
|
2882
|
+
* "tenant_456",
|
|
2883
|
+
* );
|
|
2884
|
+
* ```
|
|
2885
|
+
*/
|
|
2886
|
+
async getDashboardForTenant(id, tenantId, options, signal) {
|
|
2887
|
+
return await getDashboardForTenant(
|
|
2888
|
+
this.client,
|
|
2889
|
+
id,
|
|
2890
|
+
tenantId,
|
|
2891
|
+
options,
|
|
2892
|
+
signal
|
|
2893
|
+
);
|
|
2894
|
+
}
|
|
2895
|
+
/**
|
|
2896
|
+
* Updates a dashboard.
|
|
2897
|
+
*
|
|
2898
|
+
* @param id - Dashboard ID to update
|
|
2899
|
+
* @param body - Fields to update
|
|
2900
|
+
* @param options - Tenant, user, and scope options
|
|
2901
|
+
* @param signal - Optional AbortSignal for cancellation
|
|
2902
|
+
* @returns Updated dashboard
|
|
2903
|
+
*
|
|
2904
|
+
* @example
|
|
2905
|
+
* ```typescript
|
|
2906
|
+
* const updated = await qp.updateDashboard("dash_123", {
|
|
2907
|
+
* name: "Updated Dashboard",
|
|
2908
|
+
* content_json: newBlockNoteContent,
|
|
2909
|
+
* }, { tenantId: "tenant_123" });
|
|
2910
|
+
* ```
|
|
2911
|
+
*/
|
|
2912
|
+
async updateDashboard(id, body, options, signal) {
|
|
2913
|
+
return await updateDashboard(
|
|
2914
|
+
this.client,
|
|
2915
|
+
id,
|
|
2916
|
+
body,
|
|
2917
|
+
options,
|
|
2918
|
+
signal
|
|
2919
|
+
);
|
|
2920
|
+
}
|
|
2921
|
+
/**
|
|
2922
|
+
* Updates dashboard status (deploy/undeploy).
|
|
2923
|
+
*
|
|
2924
|
+
* @param id - Dashboard ID
|
|
2925
|
+
* @param status - New status
|
|
2926
|
+
* @param options - Tenant, user, and scope options
|
|
2927
|
+
* @param signal - Optional AbortSignal for cancellation
|
|
2928
|
+
* @returns Updated dashboard
|
|
2929
|
+
*
|
|
2930
|
+
* @example
|
|
2931
|
+
* ```typescript
|
|
2932
|
+
* const deployed = await qp.updateDashboardStatus(
|
|
2933
|
+
* "dash_123",
|
|
2934
|
+
* "deployed",
|
|
2935
|
+
* { tenantId: "tenant_123" },
|
|
2936
|
+
* );
|
|
2937
|
+
* ```
|
|
2938
|
+
*/
|
|
2939
|
+
async updateDashboardStatus(id, status, options, signal) {
|
|
2940
|
+
return await updateDashboardStatus(
|
|
2941
|
+
this.client,
|
|
2942
|
+
id,
|
|
2943
|
+
status,
|
|
2944
|
+
options,
|
|
2945
|
+
signal
|
|
2946
|
+
);
|
|
2947
|
+
}
|
|
2948
|
+
/**
|
|
2949
|
+
* Deletes a dashboard.
|
|
2950
|
+
*
|
|
2951
|
+
* @param id - Dashboard ID to delete
|
|
2952
|
+
* @param options - Tenant, user, and scope options
|
|
2953
|
+
* @param signal - Optional AbortSignal for cancellation
|
|
2954
|
+
*
|
|
2955
|
+
* @example
|
|
2956
|
+
* ```typescript
|
|
2957
|
+
* await qp.deleteDashboard("dash_123", { tenantId: "tenant_123" });
|
|
2958
|
+
* ```
|
|
2959
|
+
*/
|
|
2960
|
+
async deleteDashboard(id, options, signal) {
|
|
2961
|
+
await deleteDashboard(this.client, id, options, signal);
|
|
2962
|
+
}
|
|
2963
|
+
// Dashboard Fork operations (Customer Customization)
|
|
2964
|
+
/**
|
|
2965
|
+
* Forks a dashboard for customer customization (copy-on-write).
|
|
2966
|
+
*
|
|
2967
|
+
* Creates a full copy of the dashboard that the customer can edit independently.
|
|
2968
|
+
* The original dashboard remains unchanged.
|
|
2969
|
+
*
|
|
2970
|
+
* @param id - Dashboard ID to fork
|
|
2971
|
+
* @param input - Fork configuration with tenant_id
|
|
2972
|
+
* @param options - Additional auth options
|
|
2973
|
+
* @param signal - Optional AbortSignal for cancellation
|
|
2974
|
+
* @returns Forked dashboard
|
|
2975
|
+
*
|
|
2976
|
+
* @example
|
|
2977
|
+
* ```typescript
|
|
2978
|
+
* const fork = await qp.forkDashboard("dash_123", {
|
|
2979
|
+
* tenant_id: "tenant_456",
|
|
2980
|
+
* name: "Customer's Custom Dashboard",
|
|
2981
|
+
* });
|
|
2982
|
+
* ```
|
|
2983
|
+
*/
|
|
2984
|
+
async forkDashboard(id, input, options, signal) {
|
|
2985
|
+
return await forkDashboard(
|
|
2986
|
+
this.client,
|
|
2987
|
+
id,
|
|
2988
|
+
input,
|
|
2989
|
+
options,
|
|
2990
|
+
signal
|
|
2991
|
+
);
|
|
2992
|
+
}
|
|
2993
|
+
/**
|
|
2994
|
+
* Updates a customer fork.
|
|
2995
|
+
*
|
|
2996
|
+
* @param forkId - Fork ID to update
|
|
2997
|
+
* @param input - Update data including tenant_id
|
|
2998
|
+
* @param options - Additional auth options
|
|
2999
|
+
* @param signal - Optional AbortSignal for cancellation
|
|
3000
|
+
* @returns Updated fork
|
|
3001
|
+
*
|
|
3002
|
+
* @example
|
|
3003
|
+
* ```typescript
|
|
3004
|
+
* const updated = await qp.updateFork("fork_123", {
|
|
3005
|
+
* tenant_id: "tenant_456",
|
|
3006
|
+
* content_json: newBlockNoteContent,
|
|
3007
|
+
* });
|
|
3008
|
+
* ```
|
|
3009
|
+
*/
|
|
3010
|
+
async updateFork(forkId, input, options, signal) {
|
|
3011
|
+
return await updateFork(
|
|
3012
|
+
this.client,
|
|
3013
|
+
forkId,
|
|
3014
|
+
input,
|
|
3015
|
+
options,
|
|
3016
|
+
signal
|
|
3017
|
+
);
|
|
3018
|
+
}
|
|
3019
|
+
/**
|
|
3020
|
+
* Rollbacks a fork to the original dashboard.
|
|
3021
|
+
* This deletes the fork and the customer will see the original again.
|
|
3022
|
+
*
|
|
3023
|
+
* @param forkId - Fork ID to rollback
|
|
3024
|
+
* @param tenantId - Tenant ID
|
|
3025
|
+
* @param options - Additional auth options
|
|
3026
|
+
* @param signal - Optional AbortSignal for cancellation
|
|
3027
|
+
* @returns Original dashboard
|
|
3028
|
+
*
|
|
3029
|
+
* @example
|
|
3030
|
+
* ```typescript
|
|
3031
|
+
* const original = await qp.rollbackFork("fork_123", "tenant_456");
|
|
3032
|
+
* ```
|
|
3033
|
+
*/
|
|
3034
|
+
async rollbackFork(forkId, tenantId, options, signal) {
|
|
3035
|
+
return await rollbackFork(
|
|
3036
|
+
this.client,
|
|
3037
|
+
forkId,
|
|
3038
|
+
tenantId,
|
|
3039
|
+
options,
|
|
3040
|
+
signal
|
|
3041
|
+
);
|
|
3042
|
+
}
|
|
3043
|
+
/**
|
|
3044
|
+
* Deletes a customer fork.
|
|
3045
|
+
*
|
|
3046
|
+
* @param forkId - Fork ID to delete
|
|
3047
|
+
* @param tenantId - Tenant ID
|
|
3048
|
+
* @param options - Additional auth options
|
|
3049
|
+
* @param signal - Optional AbortSignal for cancellation
|
|
3050
|
+
*
|
|
3051
|
+
* @example
|
|
3052
|
+
* ```typescript
|
|
3053
|
+
* await qp.deleteFork("fork_123", "tenant_456");
|
|
3054
|
+
* ```
|
|
3055
|
+
*/
|
|
3056
|
+
async deleteFork(forkId, tenantId, options, signal) {
|
|
3057
|
+
await deleteFork(
|
|
3058
|
+
this.client,
|
|
3059
|
+
forkId,
|
|
3060
|
+
tenantId,
|
|
3061
|
+
options,
|
|
3062
|
+
signal
|
|
3063
|
+
);
|
|
3064
|
+
}
|
|
3065
|
+
/**
|
|
3066
|
+
* Lists all customer forks for a tenant.
|
|
3067
|
+
*
|
|
3068
|
+
* @param tenantId - Tenant ID
|
|
3069
|
+
* @param options - Additional auth options
|
|
3070
|
+
* @param signal - Optional AbortSignal for cancellation
|
|
3071
|
+
* @returns Array of forks
|
|
3072
|
+
*
|
|
3073
|
+
* @example
|
|
3074
|
+
* ```typescript
|
|
3075
|
+
* const forks = await qp.listForksForTenant("tenant_456");
|
|
3076
|
+
* ```
|
|
3077
|
+
*/
|
|
3078
|
+
async listForksForTenant(tenantId, options, signal) {
|
|
3079
|
+
return await listForksForTenant(
|
|
3080
|
+
this.client,
|
|
3081
|
+
tenantId,
|
|
3082
|
+
options,
|
|
3083
|
+
signal
|
|
3084
|
+
);
|
|
3085
|
+
}
|
|
2435
3086
|
};
|
|
2436
3087
|
// Annotate the CommonJS export names for ESM import in node:
|
|
2437
3088
|
0 && (module.exports = {
|
|
3089
|
+
CallbackApiClient,
|
|
2438
3090
|
ClickHouseAdapter,
|
|
2439
3091
|
PostgresAdapter,
|
|
2440
3092
|
QueryErrorCode,
|