@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.js
CHANGED
|
@@ -326,29 +326,31 @@ var PostgresAdapter = class {
|
|
|
326
326
|
}
|
|
327
327
|
}
|
|
328
328
|
/**
|
|
329
|
-
* Convert
|
|
330
|
-
* PostgreSQL expects $1, $2, $3 in SQL and an array of values [val1, val2, val3]
|
|
329
|
+
* Convert params to positional array for PostgreSQL.
|
|
330
|
+
* PostgreSQL expects $1, $2, $3 in SQL and an array of values [val1, val2, val3].
|
|
331
|
+
* When the record has numeric keys ("1", "2", "3") — e.g. from mapGeneratedParams —
|
|
332
|
+
* use only those in order so placeholder order matches SQL. Otherwise fall back to
|
|
333
|
+
* named keys in alphabetical order for backward compatibility.
|
|
331
334
|
*/
|
|
332
335
|
convertNamedToPositionalParams(params) {
|
|
333
336
|
const numericKeys = Object.keys(params).filter((k) => /^\d+$/.test(k)).map((k) => Number.parseInt(k, 10)).sort((a, b) => a - b);
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
337
|
+
if (numericKeys.length > 0) {
|
|
338
|
+
const positionalParams = [];
|
|
339
|
+
for (const key of numericKeys) {
|
|
340
|
+
let val = params[String(key)];
|
|
341
|
+
if (typeof val === "string") {
|
|
342
|
+
const match = val.match(/^<([a-zA-Z0-9_]+)>$/);
|
|
343
|
+
const namedKey = match?.[1];
|
|
344
|
+
if (namedKey && namedKey in params) {
|
|
345
|
+
val = params[namedKey];
|
|
346
|
+
}
|
|
343
347
|
}
|
|
348
|
+
positionalParams.push(val);
|
|
344
349
|
}
|
|
345
|
-
positionalParams
|
|
346
|
-
}
|
|
347
|
-
for (const key of namedKeys) {
|
|
348
|
-
const val = params[key];
|
|
349
|
-
positionalParams.push(val);
|
|
350
|
+
return positionalParams;
|
|
350
351
|
}
|
|
351
|
-
|
|
352
|
+
const namedKeys = Object.keys(params).filter((k) => !/^\d+$/.test(k)).sort();
|
|
353
|
+
return namedKeys.map((key) => params[key]);
|
|
352
354
|
}
|
|
353
355
|
async validate(sql, params) {
|
|
354
356
|
let paramArray;
|
|
@@ -560,6 +562,13 @@ var ApiClient = class {
|
|
|
560
562
|
getDefaultTenantId() {
|
|
561
563
|
return this.defaultTenantId;
|
|
562
564
|
}
|
|
565
|
+
/**
|
|
566
|
+
* Create a JWT for the given tenant (and optional userId, scopes).
|
|
567
|
+
* Use this when you need to pass a token to the embed (e.g. frontend or demo).
|
|
568
|
+
*/
|
|
569
|
+
async createJwt(tenantId, userId, scopes) {
|
|
570
|
+
return await this.generateJWT(tenantId, userId, scopes);
|
|
571
|
+
}
|
|
563
572
|
async get(path, tenantId, userId, scopes, signal, sessionId) {
|
|
564
573
|
return await this.request(path, {
|
|
565
574
|
method: "GET",
|
|
@@ -772,6 +781,111 @@ var ApiClient = class {
|
|
|
772
781
|
}
|
|
773
782
|
};
|
|
774
783
|
|
|
784
|
+
// src/core/callback-client.ts
|
|
785
|
+
var CallbackApiClient = class {
|
|
786
|
+
requestHandler;
|
|
787
|
+
defaultTenantId;
|
|
788
|
+
constructor(requestHandler, options) {
|
|
789
|
+
this.requestHandler = requestHandler;
|
|
790
|
+
this.defaultTenantId = options?.defaultTenantId;
|
|
791
|
+
}
|
|
792
|
+
getDefaultTenantId() {
|
|
793
|
+
return this.defaultTenantId;
|
|
794
|
+
}
|
|
795
|
+
async request(opts) {
|
|
796
|
+
const { data, headers } = await this.requestHandler({
|
|
797
|
+
method: opts.method,
|
|
798
|
+
path: opts.path,
|
|
799
|
+
body: opts.body,
|
|
800
|
+
tenantId: opts.tenantId,
|
|
801
|
+
userId: opts.userId,
|
|
802
|
+
scopes: opts.scopes,
|
|
803
|
+
signal: opts.signal,
|
|
804
|
+
sessionId: opts.sessionId
|
|
805
|
+
});
|
|
806
|
+
return { data, headers };
|
|
807
|
+
}
|
|
808
|
+
async get(path, tenantId, userId, scopes, signal, sessionId) {
|
|
809
|
+
const { data } = await this.request({
|
|
810
|
+
method: "GET",
|
|
811
|
+
path,
|
|
812
|
+
tenantId,
|
|
813
|
+
userId,
|
|
814
|
+
scopes,
|
|
815
|
+
signal,
|
|
816
|
+
sessionId
|
|
817
|
+
});
|
|
818
|
+
return data;
|
|
819
|
+
}
|
|
820
|
+
async post(path, body, tenantId, userId, scopes, signal, sessionId) {
|
|
821
|
+
const { data } = await this.request({
|
|
822
|
+
method: "POST",
|
|
823
|
+
path,
|
|
824
|
+
body,
|
|
825
|
+
tenantId,
|
|
826
|
+
userId,
|
|
827
|
+
scopes,
|
|
828
|
+
signal,
|
|
829
|
+
sessionId
|
|
830
|
+
});
|
|
831
|
+
return data;
|
|
832
|
+
}
|
|
833
|
+
async postWithHeaders(path, body, tenantId, userId, scopes, signal, sessionId) {
|
|
834
|
+
const { data, headers } = await this.request({
|
|
835
|
+
method: "POST",
|
|
836
|
+
path,
|
|
837
|
+
body,
|
|
838
|
+
tenantId,
|
|
839
|
+
userId,
|
|
840
|
+
scopes,
|
|
841
|
+
signal,
|
|
842
|
+
sessionId
|
|
843
|
+
});
|
|
844
|
+
return {
|
|
845
|
+
data,
|
|
846
|
+
headers: headers ?? new Headers()
|
|
847
|
+
};
|
|
848
|
+
}
|
|
849
|
+
async put(path, body, tenantId, userId, scopes, signal, sessionId) {
|
|
850
|
+
const { data } = await this.request({
|
|
851
|
+
method: "PUT",
|
|
852
|
+
path,
|
|
853
|
+
body,
|
|
854
|
+
tenantId,
|
|
855
|
+
userId,
|
|
856
|
+
scopes,
|
|
857
|
+
signal,
|
|
858
|
+
sessionId
|
|
859
|
+
});
|
|
860
|
+
return data;
|
|
861
|
+
}
|
|
862
|
+
async patch(path, body, tenantId, userId, scopes, signal, sessionId) {
|
|
863
|
+
const { data } = await this.request({
|
|
864
|
+
method: "PATCH",
|
|
865
|
+
path,
|
|
866
|
+
body,
|
|
867
|
+
tenantId,
|
|
868
|
+
userId,
|
|
869
|
+
scopes,
|
|
870
|
+
signal,
|
|
871
|
+
sessionId
|
|
872
|
+
});
|
|
873
|
+
return data;
|
|
874
|
+
}
|
|
875
|
+
async delete(path, tenantId, userId, scopes, signal, sessionId) {
|
|
876
|
+
const { data } = await this.request({
|
|
877
|
+
method: "DELETE",
|
|
878
|
+
path,
|
|
879
|
+
tenantId,
|
|
880
|
+
userId,
|
|
881
|
+
scopes,
|
|
882
|
+
signal,
|
|
883
|
+
sessionId
|
|
884
|
+
});
|
|
885
|
+
return data;
|
|
886
|
+
}
|
|
887
|
+
};
|
|
888
|
+
|
|
775
889
|
// src/core/query-engine.ts
|
|
776
890
|
var QueryEngine = class {
|
|
777
891
|
databases = /* @__PURE__ */ new Map();
|
|
@@ -834,6 +948,12 @@ var QueryEngine = class {
|
|
|
834
948
|
return [];
|
|
835
949
|
}
|
|
836
950
|
}
|
|
951
|
+
/**
|
|
952
|
+
* Maps API params (array in SQL placeholder order $1, $2, $3) to ParamRecord.
|
|
953
|
+
* Sets both numeric keys ("1", "2", "3") and named keys so that:
|
|
954
|
+
* - Postgres adapter uses numeric order for positional params (matches SQL).
|
|
955
|
+
* - Named keys remain for tenant isolation / other lookups.
|
|
956
|
+
*/
|
|
837
957
|
mapGeneratedParams(params) {
|
|
838
958
|
const record = {};
|
|
839
959
|
params.forEach((param, index) => {
|
|
@@ -841,6 +961,7 @@ var QueryEngine = class {
|
|
|
841
961
|
if (value === void 0) {
|
|
842
962
|
return;
|
|
843
963
|
}
|
|
964
|
+
record[String(index + 1)] = value;
|
|
844
965
|
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);
|
|
845
966
|
const key = nameCandidate.replace(/[{}:$]/g, "").trim();
|
|
846
967
|
record[key] = value;
|
|
@@ -1169,10 +1290,161 @@ function resolveTenantId2(client, tenantId) {
|
|
|
1169
1290
|
return resolved;
|
|
1170
1291
|
}
|
|
1171
1292
|
|
|
1293
|
+
// src/routes/dashboards.ts
|
|
1294
|
+
function resolveTenantId3(client, tenantId) {
|
|
1295
|
+
const resolved = tenantId ?? client.getDefaultTenantId();
|
|
1296
|
+
if (resolved === void 0) {
|
|
1297
|
+
throw new Error("tenantId is required (option or client default)");
|
|
1298
|
+
}
|
|
1299
|
+
return resolved;
|
|
1300
|
+
}
|
|
1301
|
+
async function createDashboard(client, body, options, signal) {
|
|
1302
|
+
const tenantId = resolveTenantId3(client, options?.tenantId);
|
|
1303
|
+
return await client.post(
|
|
1304
|
+
"/dashboards",
|
|
1305
|
+
body,
|
|
1306
|
+
tenantId,
|
|
1307
|
+
options?.userId,
|
|
1308
|
+
options?.scopes,
|
|
1309
|
+
signal
|
|
1310
|
+
);
|
|
1311
|
+
}
|
|
1312
|
+
async function listDashboards(client, options, signal) {
|
|
1313
|
+
const tenantId = resolveTenantId3(client, options?.tenantId);
|
|
1314
|
+
const params = new URLSearchParams();
|
|
1315
|
+
if (options?.pagination?.page) {
|
|
1316
|
+
params.set("page", options.pagination.page.toString());
|
|
1317
|
+
}
|
|
1318
|
+
if (options?.pagination?.limit) {
|
|
1319
|
+
params.set("limit", options.pagination.limit.toString());
|
|
1320
|
+
}
|
|
1321
|
+
if (options?.status) {
|
|
1322
|
+
params.set("status", options.status);
|
|
1323
|
+
}
|
|
1324
|
+
if (options?.sortBy) {
|
|
1325
|
+
params.set("sort_by", options.sortBy);
|
|
1326
|
+
}
|
|
1327
|
+
if (options?.sortDir) {
|
|
1328
|
+
params.set("sort_dir", options.sortDir);
|
|
1329
|
+
}
|
|
1330
|
+
return await client.get(
|
|
1331
|
+
`/dashboards?${params.toString()}`,
|
|
1332
|
+
tenantId,
|
|
1333
|
+
options?.userId,
|
|
1334
|
+
options?.scopes,
|
|
1335
|
+
signal
|
|
1336
|
+
);
|
|
1337
|
+
}
|
|
1338
|
+
async function getDashboard(client, id, options, signal) {
|
|
1339
|
+
const tenantId = resolveTenantId3(client, options?.tenantId);
|
|
1340
|
+
return await client.get(
|
|
1341
|
+
`/dashboards/${id}`,
|
|
1342
|
+
tenantId,
|
|
1343
|
+
options?.userId,
|
|
1344
|
+
options?.scopes,
|
|
1345
|
+
signal
|
|
1346
|
+
);
|
|
1347
|
+
}
|
|
1348
|
+
async function getDashboardForTenant(client, id, tenantId, options, signal) {
|
|
1349
|
+
const params = new URLSearchParams();
|
|
1350
|
+
params.set("tenant_id", tenantId);
|
|
1351
|
+
return await client.get(
|
|
1352
|
+
`/dashboards/${id}/for-tenant?${params.toString()}`,
|
|
1353
|
+
tenantId,
|
|
1354
|
+
options?.userId,
|
|
1355
|
+
options?.scopes,
|
|
1356
|
+
signal
|
|
1357
|
+
);
|
|
1358
|
+
}
|
|
1359
|
+
async function updateDashboard(client, id, body, options, signal) {
|
|
1360
|
+
const tenantId = resolveTenantId3(client, options?.tenantId);
|
|
1361
|
+
return await client.put(
|
|
1362
|
+
`/dashboards/${id}`,
|
|
1363
|
+
body,
|
|
1364
|
+
tenantId,
|
|
1365
|
+
options?.userId,
|
|
1366
|
+
options?.scopes,
|
|
1367
|
+
signal
|
|
1368
|
+
);
|
|
1369
|
+
}
|
|
1370
|
+
async function updateDashboardStatus(client, id, status, options, signal) {
|
|
1371
|
+
const tenantId = resolveTenantId3(client, options?.tenantId);
|
|
1372
|
+
return await client.patch(
|
|
1373
|
+
`/dashboards/${id}/status`,
|
|
1374
|
+
{ status },
|
|
1375
|
+
tenantId,
|
|
1376
|
+
options?.userId,
|
|
1377
|
+
options?.scopes,
|
|
1378
|
+
signal
|
|
1379
|
+
);
|
|
1380
|
+
}
|
|
1381
|
+
async function deleteDashboard(client, id, options, signal) {
|
|
1382
|
+
const tenantId = resolveTenantId3(client, options?.tenantId);
|
|
1383
|
+
await client.delete(
|
|
1384
|
+
`/dashboards/${id}`,
|
|
1385
|
+
tenantId,
|
|
1386
|
+
options?.userId,
|
|
1387
|
+
options?.scopes,
|
|
1388
|
+
signal
|
|
1389
|
+
);
|
|
1390
|
+
}
|
|
1391
|
+
async function forkDashboard(client, id, input, options, signal) {
|
|
1392
|
+
const tenantId = resolveTenantId3(client, options?.tenantId);
|
|
1393
|
+
return await client.post(
|
|
1394
|
+
`/dashboards/${id}/fork`,
|
|
1395
|
+
input,
|
|
1396
|
+
tenantId,
|
|
1397
|
+
options?.userId,
|
|
1398
|
+
options?.scopes,
|
|
1399
|
+
signal
|
|
1400
|
+
);
|
|
1401
|
+
}
|
|
1402
|
+
async function updateFork(client, forkId, input, options, signal) {
|
|
1403
|
+
const tenantId = resolveTenantId3(client, options?.tenantId);
|
|
1404
|
+
return await client.put(
|
|
1405
|
+
`/dashboards/forks/${forkId}`,
|
|
1406
|
+
input,
|
|
1407
|
+
tenantId,
|
|
1408
|
+
options?.userId,
|
|
1409
|
+
options?.scopes,
|
|
1410
|
+
signal
|
|
1411
|
+
);
|
|
1412
|
+
}
|
|
1413
|
+
async function rollbackFork(client, forkId, tenantId, options, signal) {
|
|
1414
|
+
return await client.post(
|
|
1415
|
+
`/dashboards/forks/${forkId}/rollback`,
|
|
1416
|
+
{ tenant_id: tenantId },
|
|
1417
|
+
tenantId,
|
|
1418
|
+
options?.userId,
|
|
1419
|
+
options?.scopes,
|
|
1420
|
+
signal
|
|
1421
|
+
);
|
|
1422
|
+
}
|
|
1423
|
+
async function deleteFork(client, forkId, tenantId, options, signal) {
|
|
1424
|
+
const params = new URLSearchParams();
|
|
1425
|
+
params.set("tenant_id", tenantId);
|
|
1426
|
+
await client.delete(
|
|
1427
|
+
`/dashboards/forks/${forkId}?${params.toString()}`,
|
|
1428
|
+
tenantId,
|
|
1429
|
+
options?.userId,
|
|
1430
|
+
options?.scopes,
|
|
1431
|
+
signal
|
|
1432
|
+
);
|
|
1433
|
+
}
|
|
1434
|
+
async function listForksForTenant(client, tenantId, options, signal) {
|
|
1435
|
+
return await client.get(
|
|
1436
|
+
`/dashboards/customer/${tenantId}`,
|
|
1437
|
+
tenantId,
|
|
1438
|
+
options?.userId,
|
|
1439
|
+
options?.scopes,
|
|
1440
|
+
signal
|
|
1441
|
+
);
|
|
1442
|
+
}
|
|
1443
|
+
|
|
1172
1444
|
// src/routes/ingest.ts
|
|
1173
1445
|
import crypto2 from "crypto";
|
|
1174
1446
|
async function syncSchema(client, queryEngine, databaseName, options, signal) {
|
|
1175
|
-
const tenantId =
|
|
1447
|
+
const tenantId = resolveTenantId4(client, options.tenantId);
|
|
1176
1448
|
const adapter = queryEngine.getDatabase(databaseName);
|
|
1177
1449
|
const metadata = queryEngine.getDatabaseMetadata(databaseName);
|
|
1178
1450
|
const introspection = await adapter.introspect(
|
|
@@ -1194,7 +1466,7 @@ async function syncSchema(client, queryEngine, databaseName, options, signal) {
|
|
|
1194
1466
|
);
|
|
1195
1467
|
return response;
|
|
1196
1468
|
}
|
|
1197
|
-
function
|
|
1469
|
+
function resolveTenantId4(client, tenantId) {
|
|
1198
1470
|
const resolved = tenantId ?? client.getDefaultTenantId();
|
|
1199
1471
|
if (!resolved) {
|
|
1200
1472
|
throw new Error(
|
|
@@ -1236,7 +1508,7 @@ import crypto4 from "crypto";
|
|
|
1236
1508
|
// src/routes/query.ts
|
|
1237
1509
|
import crypto3 from "crypto";
|
|
1238
1510
|
async function ask(client, queryEngine, question, options, signal) {
|
|
1239
|
-
const tenantId =
|
|
1511
|
+
const tenantId = resolveTenantId5(client, options.tenantId);
|
|
1240
1512
|
const sessionId = crypto3.randomUUID();
|
|
1241
1513
|
const querypanelSessionId = options.querypanelSessionId ?? sessionId;
|
|
1242
1514
|
const maxRetry = options.maxRetry ?? 0;
|
|
@@ -1391,7 +1663,7 @@ async function ask(client, queryEngine, question, options, signal) {
|
|
|
1391
1663
|
}
|
|
1392
1664
|
throw new Error("Unexpected error in ask retry loop");
|
|
1393
1665
|
}
|
|
1394
|
-
function
|
|
1666
|
+
function resolveTenantId5(client, tenantId) {
|
|
1395
1667
|
const resolved = tenantId ?? client.getDefaultTenantId();
|
|
1396
1668
|
if (!resolved) {
|
|
1397
1669
|
throw new Error(
|
|
@@ -1547,7 +1819,7 @@ function stripVizSpecOnlyHints(hints) {
|
|
|
1547
1819
|
const { kind: _kind, ...rest } = hints;
|
|
1548
1820
|
return rest;
|
|
1549
1821
|
}
|
|
1550
|
-
function
|
|
1822
|
+
function resolveTenantId6(client, tenantId) {
|
|
1551
1823
|
const resolved = tenantId ?? client.getDefaultTenantId();
|
|
1552
1824
|
if (!resolved) {
|
|
1553
1825
|
throw new Error(
|
|
@@ -1557,7 +1829,7 @@ function resolveTenantId5(client, tenantId) {
|
|
|
1557
1829
|
return resolved;
|
|
1558
1830
|
}
|
|
1559
1831
|
async function modifyChart(client, queryEngine, input, options, signal) {
|
|
1560
|
-
const tenantId =
|
|
1832
|
+
const tenantId = resolveTenantId6(client, options?.tenantId);
|
|
1561
1833
|
const sessionId = crypto4.randomUUID();
|
|
1562
1834
|
const querypanelSessionId = options?.querypanelSessionId ?? sessionId;
|
|
1563
1835
|
const hasQuerypanelSessionContext = !!options?.querypanelSessionId;
|
|
@@ -1725,7 +1997,7 @@ async function modifyChart(client, queryEngine, input, options, signal) {
|
|
|
1725
1997
|
|
|
1726
1998
|
// src/routes/sessions.ts
|
|
1727
1999
|
async function listSessions(client, options, signal) {
|
|
1728
|
-
const tenantId =
|
|
2000
|
+
const tenantId = resolveTenantId7(client, options?.tenantId);
|
|
1729
2001
|
const params = new URLSearchParams();
|
|
1730
2002
|
if (options?.pagination?.page)
|
|
1731
2003
|
params.set("page", `${options.pagination.page}`);
|
|
@@ -1748,7 +2020,7 @@ async function listSessions(client, options, signal) {
|
|
|
1748
2020
|
);
|
|
1749
2021
|
}
|
|
1750
2022
|
async function getSession(client, sessionId, options, signal) {
|
|
1751
|
-
const tenantId =
|
|
2023
|
+
const tenantId = resolveTenantId7(client, options?.tenantId);
|
|
1752
2024
|
const params = new URLSearchParams();
|
|
1753
2025
|
if (options?.includeTurns !== void 0) {
|
|
1754
2026
|
params.set("include_turns", `${options.includeTurns}`);
|
|
@@ -1762,7 +2034,7 @@ async function getSession(client, sessionId, options, signal) {
|
|
|
1762
2034
|
);
|
|
1763
2035
|
}
|
|
1764
2036
|
async function updateSession(client, sessionId, body, options, signal) {
|
|
1765
|
-
const tenantId =
|
|
2037
|
+
const tenantId = resolveTenantId7(client, options?.tenantId);
|
|
1766
2038
|
return await client.patch(
|
|
1767
2039
|
`/sessions/${encodeURIComponent(sessionId)}`,
|
|
1768
2040
|
body,
|
|
@@ -1773,7 +2045,7 @@ async function updateSession(client, sessionId, body, options, signal) {
|
|
|
1773
2045
|
);
|
|
1774
2046
|
}
|
|
1775
2047
|
async function deleteSession(client, sessionId, options, signal) {
|
|
1776
|
-
const tenantId =
|
|
2048
|
+
const tenantId = resolveTenantId7(client, options?.tenantId);
|
|
1777
2049
|
await client.delete(
|
|
1778
2050
|
`/sessions/${encodeURIComponent(sessionId)}`,
|
|
1779
2051
|
tenantId,
|
|
@@ -1782,7 +2054,7 @@ async function deleteSession(client, sessionId, options, signal) {
|
|
|
1782
2054
|
signal
|
|
1783
2055
|
);
|
|
1784
2056
|
}
|
|
1785
|
-
function
|
|
2057
|
+
function resolveTenantId7(client, tenantId) {
|
|
1786
2058
|
const resolved = tenantId ?? client.getDefaultTenantId();
|
|
1787
2059
|
if (!resolved) {
|
|
1788
2060
|
throw new Error(
|
|
@@ -1795,7 +2067,7 @@ function resolveTenantId6(client, tenantId) {
|
|
|
1795
2067
|
// src/routes/vizspec.ts
|
|
1796
2068
|
import crypto5 from "crypto";
|
|
1797
2069
|
async function generateVizSpec(client, input, options, signal) {
|
|
1798
|
-
const tenantId =
|
|
2070
|
+
const tenantId = resolveTenantId8(client, options?.tenantId);
|
|
1799
2071
|
const sessionId = crypto5.randomUUID();
|
|
1800
2072
|
const response = await client.post(
|
|
1801
2073
|
"/vizspec",
|
|
@@ -1817,7 +2089,7 @@ async function generateVizSpec(client, input, options, signal) {
|
|
|
1817
2089
|
);
|
|
1818
2090
|
return response;
|
|
1819
2091
|
}
|
|
1820
|
-
function
|
|
2092
|
+
function resolveTenantId8(client, tenantId) {
|
|
1821
2093
|
const resolved = tenantId ?? client.getDefaultTenantId();
|
|
1822
2094
|
if (!resolved) {
|
|
1823
2095
|
throw new Error(
|
|
@@ -1828,13 +2100,62 @@ function resolveTenantId7(client, tenantId) {
|
|
|
1828
2100
|
}
|
|
1829
2101
|
|
|
1830
2102
|
// src/index.ts
|
|
1831
|
-
var QueryPanelSdkAPI = class {
|
|
2103
|
+
var QueryPanelSdkAPI = class _QueryPanelSdkAPI {
|
|
1832
2104
|
client;
|
|
1833
2105
|
queryEngine;
|
|
1834
2106
|
constructor(baseUrl, privateKey, organizationId, options) {
|
|
1835
|
-
|
|
2107
|
+
if (options?.api) {
|
|
2108
|
+
this.client = options.api;
|
|
2109
|
+
} else {
|
|
2110
|
+
if (!baseUrl) throw new Error("Base URL is required");
|
|
2111
|
+
if (!privateKey) throw new Error("Private key is required");
|
|
2112
|
+
if (!organizationId) throw new Error("Organization ID is required");
|
|
2113
|
+
this.client = new ApiClient(baseUrl, privateKey, organizationId, {
|
|
2114
|
+
defaultTenantId: options?.defaultTenantId,
|
|
2115
|
+
additionalHeaders: options?.additionalHeaders,
|
|
2116
|
+
fetch: options?.fetch
|
|
2117
|
+
});
|
|
2118
|
+
}
|
|
2119
|
+
if (!organizationId) throw new Error("Organization ID is required");
|
|
1836
2120
|
this.queryEngine = new QueryEngine();
|
|
1837
2121
|
}
|
|
2122
|
+
/**
|
|
2123
|
+
* Create an SDK instance that uses a request callback instead of HTTP.
|
|
2124
|
+
* Use this when calling the SDK from within your own API so that "API" calls
|
|
2125
|
+
* are handled in-process (e.g. by invoking querypanel-sdk services directly)
|
|
2126
|
+
* and do not cause recursion.
|
|
2127
|
+
*
|
|
2128
|
+
* @param organizationId - Organization identifier
|
|
2129
|
+
* @param requestHandler - Callback invoked for each logical API request (method, path, body, tenantId, etc.)
|
|
2130
|
+
* @param options - Optional defaultTenantId
|
|
2131
|
+
* @returns QueryPanelSdkAPI instance; attach databases and call ask(), syncSchema(), etc. as usual
|
|
2132
|
+
*
|
|
2133
|
+
* @example
|
|
2134
|
+
* ```ts
|
|
2135
|
+
* const qp = QueryPanelSdkAPI.withCallbacks(
|
|
2136
|
+
* process.env.ORGANIZATION_ID!,
|
|
2137
|
+
* async (opts) => {
|
|
2138
|
+
* // Call your in-process services (e.g. querypanel-sdk logic) instead of HTTP
|
|
2139
|
+
* if (opts.path === '/query' || opts.path === '/v2/query') {
|
|
2140
|
+
* const result = await yourSqlGenerator.generate(opts.body, opts.tenantId);
|
|
2141
|
+
* return { data: result, headers: new Headers({ 'x-querypanel-session-id': result.sessionId }) };
|
|
2142
|
+
* }
|
|
2143
|
+
* if (opts.path === '/chart') return { data: await yourChartService.generate(opts.body) };
|
|
2144
|
+
* // ... other paths
|
|
2145
|
+
* return { data: await yourProxy(opts) };
|
|
2146
|
+
* },
|
|
2147
|
+
* { defaultTenantId: process.env.DEFAULT_TENANT_ID }
|
|
2148
|
+
* );
|
|
2149
|
+
* qp.attachPostgres('db', createClient, { tenantFieldName: 'tenant_id' });
|
|
2150
|
+
* const result = await qp.ask('Top 10 orders', { tenantId: 't1', database: 'db' });
|
|
2151
|
+
* ```
|
|
2152
|
+
*/
|
|
2153
|
+
static withCallbacks(organizationId, requestHandler, options) {
|
|
2154
|
+
const api = new CallbackApiClient(requestHandler, {
|
|
2155
|
+
defaultTenantId: options?.defaultTenantId
|
|
2156
|
+
});
|
|
2157
|
+
return new _QueryPanelSdkAPI("", "", organizationId, { api });
|
|
2158
|
+
}
|
|
1838
2159
|
// Database attachment methods
|
|
1839
2160
|
attachClickhouse(name, clientFn, options) {
|
|
1840
2161
|
const adapter = new ClickHouseAdapter(clientFn, options);
|
|
@@ -1948,6 +2269,48 @@ var QueryPanelSdkAPI = class {
|
|
|
1948
2269
|
signal
|
|
1949
2270
|
);
|
|
1950
2271
|
}
|
|
2272
|
+
// Embedded dashboard / JWT
|
|
2273
|
+
/**
|
|
2274
|
+
* Creates a JWT for the given tenant (and optional userId, scopes).
|
|
2275
|
+
* Use this when you need to pass a token to the embed (e.g. frontend or demo).
|
|
2276
|
+
* Only available when using the HTTP client (ApiClient); not available when using withCallbacks.
|
|
2277
|
+
*/
|
|
2278
|
+
async createJwt(options) {
|
|
2279
|
+
const tenantId = options.tenantId?.trim();
|
|
2280
|
+
if (!tenantId) {
|
|
2281
|
+
throw new Error("tenantId is required");
|
|
2282
|
+
}
|
|
2283
|
+
if (!(this.client instanceof ApiClient)) {
|
|
2284
|
+
throw new Error(
|
|
2285
|
+
"createJwt is not available when using withCallbacks. Use the SDK with baseUrl + privateKey to create JWTs."
|
|
2286
|
+
);
|
|
2287
|
+
}
|
|
2288
|
+
return await this.client.createJwt(
|
|
2289
|
+
tenantId,
|
|
2290
|
+
options.userId,
|
|
2291
|
+
options.scopes
|
|
2292
|
+
);
|
|
2293
|
+
}
|
|
2294
|
+
/**
|
|
2295
|
+
* Runs SQL against an attached database with tenant isolation applied.
|
|
2296
|
+
* Used by embed run-sql (e.g. dashboard chart execution). Requires a database
|
|
2297
|
+
* to be attached (e.g. via attachPostgres) and options.tenantId.
|
|
2298
|
+
*/
|
|
2299
|
+
async runSqlForDashboard(input, options) {
|
|
2300
|
+
const tenantId = options.tenantId?.trim();
|
|
2301
|
+
if (!tenantId) {
|
|
2302
|
+
throw new Error("tenantId is required");
|
|
2303
|
+
}
|
|
2304
|
+
const databaseName = input.database ?? "db";
|
|
2305
|
+
const params = input.params ?? {};
|
|
2306
|
+
const result = await this.queryEngine.validateAndExecute(
|
|
2307
|
+
input.sql,
|
|
2308
|
+
params,
|
|
2309
|
+
databaseName,
|
|
2310
|
+
tenantId
|
|
2311
|
+
);
|
|
2312
|
+
return { rows: result.rows, fields: result.fields };
|
|
2313
|
+
}
|
|
1951
2314
|
// VizSpec generation
|
|
1952
2315
|
/**
|
|
1953
2316
|
* Generates a VizSpec visualization specification from query results.
|
|
@@ -2391,8 +2754,296 @@ var QueryPanelSdkAPI = class {
|
|
|
2391
2754
|
async deleteActiveChart(id, options, signal) {
|
|
2392
2755
|
await deleteActiveChart(this.client, id, options, signal);
|
|
2393
2756
|
}
|
|
2757
|
+
// Dashboard CRUD operations
|
|
2758
|
+
/**
|
|
2759
|
+
* Creates a new dashboard with BlockNote content.
|
|
2760
|
+
*
|
|
2761
|
+
* @param body - Dashboard configuration including name and BlockNote content
|
|
2762
|
+
* @param options - Tenant, user, and scope options
|
|
2763
|
+
* @param signal - Optional AbortSignal for cancellation
|
|
2764
|
+
* @returns Created dashboard
|
|
2765
|
+
*
|
|
2766
|
+
* @example
|
|
2767
|
+
* ```typescript
|
|
2768
|
+
* const dashboard = await qp.createDashboard({
|
|
2769
|
+
* name: "Sales Dashboard",
|
|
2770
|
+
* description: "Monthly sales metrics",
|
|
2771
|
+
* content_json: blockNoteContent,
|
|
2772
|
+
* editor_type: "blocknote",
|
|
2773
|
+
* }, { tenantId: "tenant_123" });
|
|
2774
|
+
* ```
|
|
2775
|
+
*/
|
|
2776
|
+
async createDashboard(body, options, signal) {
|
|
2777
|
+
return await createDashboard(
|
|
2778
|
+
this.client,
|
|
2779
|
+
body,
|
|
2780
|
+
options,
|
|
2781
|
+
signal
|
|
2782
|
+
);
|
|
2783
|
+
}
|
|
2784
|
+
/**
|
|
2785
|
+
* Lists dashboards with pagination and filtering.
|
|
2786
|
+
*
|
|
2787
|
+
* @param options - Filtering and pagination options
|
|
2788
|
+
* @param signal - Optional AbortSignal for cancellation
|
|
2789
|
+
* @returns Paginated list of dashboards
|
|
2790
|
+
*
|
|
2791
|
+
* @example
|
|
2792
|
+
* ```typescript
|
|
2793
|
+
* const dashboards = await qp.listDashboards({
|
|
2794
|
+
* tenantId: "tenant_123",
|
|
2795
|
+
* status: "deployed",
|
|
2796
|
+
* pagination: { page: 1, limit: 10 },
|
|
2797
|
+
* });
|
|
2798
|
+
* ```
|
|
2799
|
+
*/
|
|
2800
|
+
async listDashboards(options, signal) {
|
|
2801
|
+
return await listDashboards(this.client, options, signal);
|
|
2802
|
+
}
|
|
2803
|
+
/**
|
|
2804
|
+
* Gets a dashboard by ID.
|
|
2805
|
+
*
|
|
2806
|
+
* @param id - Dashboard ID
|
|
2807
|
+
* @param options - Tenant, user, and scope options
|
|
2808
|
+
* @param signal - Optional AbortSignal for cancellation
|
|
2809
|
+
* @returns Dashboard details
|
|
2810
|
+
*
|
|
2811
|
+
* @example
|
|
2812
|
+
* ```typescript
|
|
2813
|
+
* const dashboard = await qp.getDashboard("dash_123", {
|
|
2814
|
+
* tenantId: "tenant_123",
|
|
2815
|
+
* });
|
|
2816
|
+
* ```
|
|
2817
|
+
*/
|
|
2818
|
+
async getDashboard(id, options, signal) {
|
|
2819
|
+
return await getDashboard(
|
|
2820
|
+
this.client,
|
|
2821
|
+
id,
|
|
2822
|
+
options,
|
|
2823
|
+
signal
|
|
2824
|
+
);
|
|
2825
|
+
}
|
|
2826
|
+
/**
|
|
2827
|
+
* Gets a dashboard for a specific tenant.
|
|
2828
|
+
* Returns customer fork if exists, otherwise returns the original dashboard.
|
|
2829
|
+
*
|
|
2830
|
+
* @param id - Dashboard ID
|
|
2831
|
+
* @param tenantId - Tenant ID to check for fork
|
|
2832
|
+
* @param options - Additional auth options
|
|
2833
|
+
* @param signal - Optional AbortSignal for cancellation
|
|
2834
|
+
* @returns Dashboard (fork if exists, original otherwise)
|
|
2835
|
+
*
|
|
2836
|
+
* @example
|
|
2837
|
+
* ```typescript
|
|
2838
|
+
* const dashboard = await qp.getDashboardForTenant(
|
|
2839
|
+
* "dash_123",
|
|
2840
|
+
* "tenant_456",
|
|
2841
|
+
* );
|
|
2842
|
+
* ```
|
|
2843
|
+
*/
|
|
2844
|
+
async getDashboardForTenant(id, tenantId, options, signal) {
|
|
2845
|
+
return await getDashboardForTenant(
|
|
2846
|
+
this.client,
|
|
2847
|
+
id,
|
|
2848
|
+
tenantId,
|
|
2849
|
+
options,
|
|
2850
|
+
signal
|
|
2851
|
+
);
|
|
2852
|
+
}
|
|
2853
|
+
/**
|
|
2854
|
+
* Updates a dashboard.
|
|
2855
|
+
*
|
|
2856
|
+
* @param id - Dashboard ID to update
|
|
2857
|
+
* @param body - Fields to update
|
|
2858
|
+
* @param options - Tenant, user, and scope options
|
|
2859
|
+
* @param signal - Optional AbortSignal for cancellation
|
|
2860
|
+
* @returns Updated dashboard
|
|
2861
|
+
*
|
|
2862
|
+
* @example
|
|
2863
|
+
* ```typescript
|
|
2864
|
+
* const updated = await qp.updateDashboard("dash_123", {
|
|
2865
|
+
* name: "Updated Dashboard",
|
|
2866
|
+
* content_json: newBlockNoteContent,
|
|
2867
|
+
* }, { tenantId: "tenant_123" });
|
|
2868
|
+
* ```
|
|
2869
|
+
*/
|
|
2870
|
+
async updateDashboard(id, body, options, signal) {
|
|
2871
|
+
return await updateDashboard(
|
|
2872
|
+
this.client,
|
|
2873
|
+
id,
|
|
2874
|
+
body,
|
|
2875
|
+
options,
|
|
2876
|
+
signal
|
|
2877
|
+
);
|
|
2878
|
+
}
|
|
2879
|
+
/**
|
|
2880
|
+
* Updates dashboard status (deploy/undeploy).
|
|
2881
|
+
*
|
|
2882
|
+
* @param id - Dashboard ID
|
|
2883
|
+
* @param status - New status
|
|
2884
|
+
* @param options - Tenant, user, and scope options
|
|
2885
|
+
* @param signal - Optional AbortSignal for cancellation
|
|
2886
|
+
* @returns Updated dashboard
|
|
2887
|
+
*
|
|
2888
|
+
* @example
|
|
2889
|
+
* ```typescript
|
|
2890
|
+
* const deployed = await qp.updateDashboardStatus(
|
|
2891
|
+
* "dash_123",
|
|
2892
|
+
* "deployed",
|
|
2893
|
+
* { tenantId: "tenant_123" },
|
|
2894
|
+
* );
|
|
2895
|
+
* ```
|
|
2896
|
+
*/
|
|
2897
|
+
async updateDashboardStatus(id, status, options, signal) {
|
|
2898
|
+
return await updateDashboardStatus(
|
|
2899
|
+
this.client,
|
|
2900
|
+
id,
|
|
2901
|
+
status,
|
|
2902
|
+
options,
|
|
2903
|
+
signal
|
|
2904
|
+
);
|
|
2905
|
+
}
|
|
2906
|
+
/**
|
|
2907
|
+
* Deletes a dashboard.
|
|
2908
|
+
*
|
|
2909
|
+
* @param id - Dashboard ID to delete
|
|
2910
|
+
* @param options - Tenant, user, and scope options
|
|
2911
|
+
* @param signal - Optional AbortSignal for cancellation
|
|
2912
|
+
*
|
|
2913
|
+
* @example
|
|
2914
|
+
* ```typescript
|
|
2915
|
+
* await qp.deleteDashboard("dash_123", { tenantId: "tenant_123" });
|
|
2916
|
+
* ```
|
|
2917
|
+
*/
|
|
2918
|
+
async deleteDashboard(id, options, signal) {
|
|
2919
|
+
await deleteDashboard(this.client, id, options, signal);
|
|
2920
|
+
}
|
|
2921
|
+
// Dashboard Fork operations (Customer Customization)
|
|
2922
|
+
/**
|
|
2923
|
+
* Forks a dashboard for customer customization (copy-on-write).
|
|
2924
|
+
*
|
|
2925
|
+
* Creates a full copy of the dashboard that the customer can edit independently.
|
|
2926
|
+
* The original dashboard remains unchanged.
|
|
2927
|
+
*
|
|
2928
|
+
* @param id - Dashboard ID to fork
|
|
2929
|
+
* @param input - Fork configuration with tenant_id
|
|
2930
|
+
* @param options - Additional auth options
|
|
2931
|
+
* @param signal - Optional AbortSignal for cancellation
|
|
2932
|
+
* @returns Forked dashboard
|
|
2933
|
+
*
|
|
2934
|
+
* @example
|
|
2935
|
+
* ```typescript
|
|
2936
|
+
* const fork = await qp.forkDashboard("dash_123", {
|
|
2937
|
+
* tenant_id: "tenant_456",
|
|
2938
|
+
* name: "Customer's Custom Dashboard",
|
|
2939
|
+
* });
|
|
2940
|
+
* ```
|
|
2941
|
+
*/
|
|
2942
|
+
async forkDashboard(id, input, options, signal) {
|
|
2943
|
+
return await forkDashboard(
|
|
2944
|
+
this.client,
|
|
2945
|
+
id,
|
|
2946
|
+
input,
|
|
2947
|
+
options,
|
|
2948
|
+
signal
|
|
2949
|
+
);
|
|
2950
|
+
}
|
|
2951
|
+
/**
|
|
2952
|
+
* Updates a customer fork.
|
|
2953
|
+
*
|
|
2954
|
+
* @param forkId - Fork ID to update
|
|
2955
|
+
* @param input - Update data including tenant_id
|
|
2956
|
+
* @param options - Additional auth options
|
|
2957
|
+
* @param signal - Optional AbortSignal for cancellation
|
|
2958
|
+
* @returns Updated fork
|
|
2959
|
+
*
|
|
2960
|
+
* @example
|
|
2961
|
+
* ```typescript
|
|
2962
|
+
* const updated = await qp.updateFork("fork_123", {
|
|
2963
|
+
* tenant_id: "tenant_456",
|
|
2964
|
+
* content_json: newBlockNoteContent,
|
|
2965
|
+
* });
|
|
2966
|
+
* ```
|
|
2967
|
+
*/
|
|
2968
|
+
async updateFork(forkId, input, options, signal) {
|
|
2969
|
+
return await updateFork(
|
|
2970
|
+
this.client,
|
|
2971
|
+
forkId,
|
|
2972
|
+
input,
|
|
2973
|
+
options,
|
|
2974
|
+
signal
|
|
2975
|
+
);
|
|
2976
|
+
}
|
|
2977
|
+
/**
|
|
2978
|
+
* Rollbacks a fork to the original dashboard.
|
|
2979
|
+
* This deletes the fork and the customer will see the original again.
|
|
2980
|
+
*
|
|
2981
|
+
* @param forkId - Fork ID to rollback
|
|
2982
|
+
* @param tenantId - Tenant ID
|
|
2983
|
+
* @param options - Additional auth options
|
|
2984
|
+
* @param signal - Optional AbortSignal for cancellation
|
|
2985
|
+
* @returns Original dashboard
|
|
2986
|
+
*
|
|
2987
|
+
* @example
|
|
2988
|
+
* ```typescript
|
|
2989
|
+
* const original = await qp.rollbackFork("fork_123", "tenant_456");
|
|
2990
|
+
* ```
|
|
2991
|
+
*/
|
|
2992
|
+
async rollbackFork(forkId, tenantId, options, signal) {
|
|
2993
|
+
return await rollbackFork(
|
|
2994
|
+
this.client,
|
|
2995
|
+
forkId,
|
|
2996
|
+
tenantId,
|
|
2997
|
+
options,
|
|
2998
|
+
signal
|
|
2999
|
+
);
|
|
3000
|
+
}
|
|
3001
|
+
/**
|
|
3002
|
+
* Deletes a customer fork.
|
|
3003
|
+
*
|
|
3004
|
+
* @param forkId - Fork ID to delete
|
|
3005
|
+
* @param tenantId - Tenant ID
|
|
3006
|
+
* @param options - Additional auth options
|
|
3007
|
+
* @param signal - Optional AbortSignal for cancellation
|
|
3008
|
+
*
|
|
3009
|
+
* @example
|
|
3010
|
+
* ```typescript
|
|
3011
|
+
* await qp.deleteFork("fork_123", "tenant_456");
|
|
3012
|
+
* ```
|
|
3013
|
+
*/
|
|
3014
|
+
async deleteFork(forkId, tenantId, options, signal) {
|
|
3015
|
+
await deleteFork(
|
|
3016
|
+
this.client,
|
|
3017
|
+
forkId,
|
|
3018
|
+
tenantId,
|
|
3019
|
+
options,
|
|
3020
|
+
signal
|
|
3021
|
+
);
|
|
3022
|
+
}
|
|
3023
|
+
/**
|
|
3024
|
+
* Lists all customer forks for a tenant.
|
|
3025
|
+
*
|
|
3026
|
+
* @param tenantId - Tenant ID
|
|
3027
|
+
* @param options - Additional auth options
|
|
3028
|
+
* @param signal - Optional AbortSignal for cancellation
|
|
3029
|
+
* @returns Array of forks
|
|
3030
|
+
*
|
|
3031
|
+
* @example
|
|
3032
|
+
* ```typescript
|
|
3033
|
+
* const forks = await qp.listForksForTenant("tenant_456");
|
|
3034
|
+
* ```
|
|
3035
|
+
*/
|
|
3036
|
+
async listForksForTenant(tenantId, options, signal) {
|
|
3037
|
+
return await listForksForTenant(
|
|
3038
|
+
this.client,
|
|
3039
|
+
tenantId,
|
|
3040
|
+
options,
|
|
3041
|
+
signal
|
|
3042
|
+
);
|
|
3043
|
+
}
|
|
2394
3044
|
};
|
|
2395
3045
|
export {
|
|
3046
|
+
CallbackApiClient,
|
|
2396
3047
|
ClickHouseAdapter,
|
|
2397
3048
|
PostgresAdapter,
|
|
2398
3049
|
QueryErrorCode,
|