@querypanel/node-sdk 1.0.43 → 1.0.45
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/README.md +48 -0
- package/dist/index.cjs +310 -37
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +261 -10
- package/dist/index.d.ts +261 -10
- package/dist/index.js +308 -37
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -80,6 +80,54 @@ console.table(response.rows);
|
|
|
80
80
|
console.log(response.chart.vegaLiteSpec);
|
|
81
81
|
```
|
|
82
82
|
|
|
83
|
+
## Session History & Context-Aware Queries
|
|
84
|
+
|
|
85
|
+
The SDK can link related questions into a session so follow-ups like “filter that to Europe” use prior context. The backend generates a QueryPanel session ID for every query and returns it in the response so you can reuse it.
|
|
86
|
+
|
|
87
|
+
```ts
|
|
88
|
+
const first = await qp.ask("Revenue by country", {
|
|
89
|
+
tenantId: "tenant_123",
|
|
90
|
+
database: "analytics",
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
const querypanelSessionId = first.querypanelSessionId;
|
|
94
|
+
|
|
95
|
+
const followUp = await qp.ask("Now filter that to Europe", {
|
|
96
|
+
tenantId: "tenant_123",
|
|
97
|
+
database: "analytics",
|
|
98
|
+
querypanelSessionId, // same QueryPanel session keeps context
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
console.log(followUp.sql);
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
### Managing Session History
|
|
105
|
+
|
|
106
|
+
```ts
|
|
107
|
+
// List sessions
|
|
108
|
+
const sessions = await qp.listSessions({
|
|
109
|
+
tenantId: "tenant_123",
|
|
110
|
+
pagination: { page: 1, limit: 20 },
|
|
111
|
+
sortBy: "updated_at",
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
// Get a session with its turns
|
|
115
|
+
const session = await qp.getSession("session_abc123", {
|
|
116
|
+
tenantId: "tenant_123",
|
|
117
|
+
includeTurns: true,
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
// Update session title
|
|
121
|
+
await qp.updateSession(
|
|
122
|
+
"session_abc123",
|
|
123
|
+
{ title: "Q4 Revenue Analysis" },
|
|
124
|
+
{ tenantId: "tenant_123" },
|
|
125
|
+
);
|
|
126
|
+
|
|
127
|
+
// Delete a session
|
|
128
|
+
await qp.deleteSession("session_abc123", { tenantId: "tenant_123" });
|
|
129
|
+
```
|
|
130
|
+
|
|
83
131
|
## Saving & Managing Charts
|
|
84
132
|
|
|
85
133
|
The SDK allows you to save generated charts to the QueryPanel system.
|
package/dist/index.cjs
CHANGED
|
@@ -32,7 +32,9 @@ var index_exports = {};
|
|
|
32
32
|
__export(index_exports, {
|
|
33
33
|
ClickHouseAdapter: () => ClickHouseAdapter,
|
|
34
34
|
PostgresAdapter: () => PostgresAdapter,
|
|
35
|
+
QueryErrorCode: () => QueryErrorCode,
|
|
35
36
|
QueryPanelSdkAPI: () => QueryPanelSdkAPI,
|
|
37
|
+
QueryPipelineError: () => QueryPipelineError,
|
|
36
38
|
anonymizeResults: () => anonymizeResults
|
|
37
39
|
});
|
|
38
40
|
module.exports = __toCommonJS(index_exports);
|
|
@@ -626,6 +628,22 @@ var ApiClient = class {
|
|
|
626
628
|
signal
|
|
627
629
|
});
|
|
628
630
|
}
|
|
631
|
+
async postWithHeaders(path, body, tenantId, userId, scopes, signal, sessionId) {
|
|
632
|
+
const response = await this.fetchImpl(`${this.baseUrl}${path}`, {
|
|
633
|
+
method: "POST",
|
|
634
|
+
headers: await this.buildHeaders(
|
|
635
|
+
tenantId,
|
|
636
|
+
userId,
|
|
637
|
+
scopes,
|
|
638
|
+
true,
|
|
639
|
+
sessionId
|
|
640
|
+
),
|
|
641
|
+
body: JSON.stringify(body ?? {}),
|
|
642
|
+
signal
|
|
643
|
+
});
|
|
644
|
+
const data = await this.parseResponse(response);
|
|
645
|
+
return { data, headers: response.headers };
|
|
646
|
+
}
|
|
629
647
|
async put(path, body, tenantId, userId, scopes, signal, sessionId) {
|
|
630
648
|
return await this.request(path, {
|
|
631
649
|
method: "PUT",
|
|
@@ -640,6 +658,20 @@ var ApiClient = class {
|
|
|
640
658
|
signal
|
|
641
659
|
});
|
|
642
660
|
}
|
|
661
|
+
async patch(path, body, tenantId, userId, scopes, signal, sessionId) {
|
|
662
|
+
return await this.request(path, {
|
|
663
|
+
method: "PATCH",
|
|
664
|
+
headers: await this.buildHeaders(
|
|
665
|
+
tenantId,
|
|
666
|
+
userId,
|
|
667
|
+
scopes,
|
|
668
|
+
true,
|
|
669
|
+
sessionId
|
|
670
|
+
),
|
|
671
|
+
body: JSON.stringify(body ?? {}),
|
|
672
|
+
signal
|
|
673
|
+
});
|
|
674
|
+
}
|
|
643
675
|
async delete(path, tenantId, userId, scopes, signal, sessionId) {
|
|
644
676
|
return await this.request(path, {
|
|
645
677
|
method: "DELETE",
|
|
@@ -655,6 +687,9 @@ var ApiClient = class {
|
|
|
655
687
|
}
|
|
656
688
|
async request(path, init) {
|
|
657
689
|
const response = await this.fetchImpl(`${this.baseUrl}${path}`, init);
|
|
690
|
+
return await this.parseResponse(response);
|
|
691
|
+
}
|
|
692
|
+
async parseResponse(response) {
|
|
658
693
|
const text = await response.text();
|
|
659
694
|
let json;
|
|
660
695
|
try {
|
|
@@ -881,6 +916,57 @@ var QueryEngine = class {
|
|
|
881
916
|
}
|
|
882
917
|
};
|
|
883
918
|
|
|
919
|
+
// src/errors.ts
|
|
920
|
+
var QueryErrorCode = {
|
|
921
|
+
// Moderation errors
|
|
922
|
+
MODERATION_FAILED: "MODERATION_FAILED",
|
|
923
|
+
// Guardrail errors
|
|
924
|
+
RELEVANCE_CHECK_FAILED: "RELEVANCE_CHECK_FAILED",
|
|
925
|
+
SECURITY_CHECK_FAILED: "SECURITY_CHECK_FAILED",
|
|
926
|
+
// SQL generation errors
|
|
927
|
+
SQL_GENERATION_FAILED: "SQL_GENERATION_FAILED",
|
|
928
|
+
// SQL validation errors
|
|
929
|
+
SQL_VALIDATION_FAILED: "SQL_VALIDATION_FAILED",
|
|
930
|
+
// Context retrieval errors
|
|
931
|
+
CONTEXT_RETRIEVAL_FAILED: "CONTEXT_RETRIEVAL_FAILED",
|
|
932
|
+
// General errors
|
|
933
|
+
INTERNAL_ERROR: "INTERNAL_ERROR",
|
|
934
|
+
AUTHENTICATION_REQUIRED: "AUTHENTICATION_REQUIRED",
|
|
935
|
+
VALIDATION_ERROR: "VALIDATION_ERROR"
|
|
936
|
+
};
|
|
937
|
+
var QueryPipelineError = class extends Error {
|
|
938
|
+
constructor(message, code, details) {
|
|
939
|
+
super(message);
|
|
940
|
+
this.code = code;
|
|
941
|
+
this.details = details;
|
|
942
|
+
this.name = "QueryPipelineError";
|
|
943
|
+
}
|
|
944
|
+
/**
|
|
945
|
+
* Check if this is a moderation error
|
|
946
|
+
*/
|
|
947
|
+
isModeration() {
|
|
948
|
+
return this.code === QueryErrorCode.MODERATION_FAILED;
|
|
949
|
+
}
|
|
950
|
+
/**
|
|
951
|
+
* Check if this is a relevance error (question not related to database)
|
|
952
|
+
*/
|
|
953
|
+
isRelevanceError() {
|
|
954
|
+
return this.code === QueryErrorCode.RELEVANCE_CHECK_FAILED;
|
|
955
|
+
}
|
|
956
|
+
/**
|
|
957
|
+
* Check if this is a security error (SQL injection, prompt injection, etc.)
|
|
958
|
+
*/
|
|
959
|
+
isSecurityError() {
|
|
960
|
+
return this.code === QueryErrorCode.SECURITY_CHECK_FAILED;
|
|
961
|
+
}
|
|
962
|
+
/**
|
|
963
|
+
* Check if this is any guardrail error (relevance or security)
|
|
964
|
+
*/
|
|
965
|
+
isGuardrailError() {
|
|
966
|
+
return this.isRelevanceError() || this.isSecurityError();
|
|
967
|
+
}
|
|
968
|
+
};
|
|
969
|
+
|
|
884
970
|
// src/routes/charts.ts
|
|
885
971
|
async function createChart(client, body, options, signal) {
|
|
886
972
|
const tenantId = resolveTenantId(client, options?.tenantId);
|
|
@@ -917,15 +1003,10 @@ async function listCharts(client, queryEngine, options, signal) {
|
|
|
917
1003
|
);
|
|
918
1004
|
if (options?.includeData) {
|
|
919
1005
|
response.data = await Promise.all(
|
|
920
|
-
response.data.map(async (chart) =>
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
data: {
|
|
925
|
-
values: await executeChartQuery(queryEngine, chart, tenantId)
|
|
926
|
-
}
|
|
927
|
-
}
|
|
928
|
-
}))
|
|
1006
|
+
response.data.map(async (chart) => {
|
|
1007
|
+
const rows = await executeChartQuery(queryEngine, chart, tenantId);
|
|
1008
|
+
return hydrateChartWithData(chart, rows);
|
|
1009
|
+
})
|
|
929
1010
|
);
|
|
930
1011
|
}
|
|
931
1012
|
return response;
|
|
@@ -939,15 +1020,8 @@ async function getChart(client, queryEngine, id, options, signal) {
|
|
|
939
1020
|
options?.scopes,
|
|
940
1021
|
signal
|
|
941
1022
|
);
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
vega_lite_spec: {
|
|
945
|
-
...chart.vega_lite_spec,
|
|
946
|
-
data: {
|
|
947
|
-
values: await executeChartQuery(queryEngine, chart, tenantId)
|
|
948
|
-
}
|
|
949
|
-
}
|
|
950
|
-
};
|
|
1023
|
+
const rows = await executeChartQuery(queryEngine, chart, tenantId);
|
|
1024
|
+
return hydrateChartWithData(chart, rows);
|
|
951
1025
|
}
|
|
952
1026
|
async function updateChart(client, id, body, options, signal) {
|
|
953
1027
|
const tenantId = resolveTenantId(client, options?.tenantId);
|
|
@@ -998,6 +1072,31 @@ async function executeChartQuery(queryEngine, chart, tenantId) {
|
|
|
998
1072
|
return [];
|
|
999
1073
|
}
|
|
1000
1074
|
}
|
|
1075
|
+
function hydrateChartWithData(chart, rows) {
|
|
1076
|
+
const spec = chart.vega_lite_spec;
|
|
1077
|
+
if (chart.spec_type === "vizspec") {
|
|
1078
|
+
const existingData = spec.data ?? {};
|
|
1079
|
+
return {
|
|
1080
|
+
...chart,
|
|
1081
|
+
vega_lite_spec: {
|
|
1082
|
+
...spec,
|
|
1083
|
+
data: {
|
|
1084
|
+
...existingData,
|
|
1085
|
+
values: rows
|
|
1086
|
+
}
|
|
1087
|
+
}
|
|
1088
|
+
};
|
|
1089
|
+
}
|
|
1090
|
+
return {
|
|
1091
|
+
...chart,
|
|
1092
|
+
vega_lite_spec: {
|
|
1093
|
+
...spec,
|
|
1094
|
+
data: {
|
|
1095
|
+
values: rows
|
|
1096
|
+
}
|
|
1097
|
+
}
|
|
1098
|
+
};
|
|
1099
|
+
}
|
|
1001
1100
|
|
|
1002
1101
|
// src/routes/active-charts.ts
|
|
1003
1102
|
async function createActiveChart(client, body, options, signal) {
|
|
@@ -1172,6 +1271,7 @@ var import_node_crypto3 = __toESM(require("crypto"), 1);
|
|
|
1172
1271
|
async function ask(client, queryEngine, question, options, signal) {
|
|
1173
1272
|
const tenantId = resolveTenantId4(client, options.tenantId);
|
|
1174
1273
|
const sessionId = import_node_crypto3.default.randomUUID();
|
|
1274
|
+
const querypanelSessionId = options.querypanelSessionId ?? sessionId;
|
|
1175
1275
|
const maxRetry = options.maxRetry ?? 0;
|
|
1176
1276
|
let attempt = 0;
|
|
1177
1277
|
let lastError = options.lastError;
|
|
@@ -1188,10 +1288,11 @@ async function ask(client, queryEngine, question, options, signal) {
|
|
|
1188
1288
|
enforceTenantIsolation: metadata.enforceTenantIsolation
|
|
1189
1289
|
};
|
|
1190
1290
|
}
|
|
1191
|
-
const queryResponse = await client.
|
|
1291
|
+
const queryResponse = await client.postWithHeaders(
|
|
1192
1292
|
"/query",
|
|
1193
1293
|
{
|
|
1194
1294
|
question,
|
|
1295
|
+
...querypanelSessionId ? { session_id: querypanelSessionId } : {},
|
|
1195
1296
|
...lastError ? { last_error: lastError } : {},
|
|
1196
1297
|
...previousSql ? { previous_sql: previousSql } : {},
|
|
1197
1298
|
...options.maxRetry ? { max_retry: options.maxRetry } : {},
|
|
@@ -1205,17 +1306,30 @@ async function ask(client, queryEngine, question, options, signal) {
|
|
|
1205
1306
|
signal,
|
|
1206
1307
|
sessionId
|
|
1207
1308
|
);
|
|
1208
|
-
const
|
|
1309
|
+
const responseSessionId = queryResponse.headers.get("x-querypanel-session-id") ?? querypanelSessionId;
|
|
1310
|
+
if (!queryResponse.data.success) {
|
|
1311
|
+
throw new QueryPipelineError(
|
|
1312
|
+
queryResponse.data.error || "Query generation failed",
|
|
1313
|
+
queryResponse.data.code || "INTERNAL_ERROR",
|
|
1314
|
+
queryResponse.data.details
|
|
1315
|
+
);
|
|
1316
|
+
}
|
|
1317
|
+
const sql = queryResponse.data.sql;
|
|
1318
|
+
const dialect = queryResponse.data.dialect;
|
|
1319
|
+
if (!sql || !dialect) {
|
|
1320
|
+
throw new Error("Query response missing required SQL or dialect");
|
|
1321
|
+
}
|
|
1322
|
+
const dbName = queryResponse.data.database ?? options.database ?? queryEngine.getDefaultDatabase();
|
|
1209
1323
|
if (!dbName) {
|
|
1210
1324
|
throw new Error(
|
|
1211
1325
|
"No database attached. Call attachPostgres/attachClickhouse first."
|
|
1212
1326
|
);
|
|
1213
1327
|
}
|
|
1214
|
-
const paramMetadata = Array.isArray(queryResponse.params) ? queryResponse.params : [];
|
|
1328
|
+
const paramMetadata = Array.isArray(queryResponse.data.params) ? queryResponse.data.params : [];
|
|
1215
1329
|
const paramValues = queryEngine.mapGeneratedParams(paramMetadata);
|
|
1216
1330
|
try {
|
|
1217
1331
|
const execution = await queryEngine.validateAndExecute(
|
|
1218
|
-
|
|
1332
|
+
sql,
|
|
1219
1333
|
paramValues,
|
|
1220
1334
|
dbName,
|
|
1221
1335
|
tenantId
|
|
@@ -1232,12 +1346,12 @@ async function ask(client, queryEngine, question, options, signal) {
|
|
|
1232
1346
|
"/vizspec",
|
|
1233
1347
|
{
|
|
1234
1348
|
question,
|
|
1235
|
-
sql
|
|
1236
|
-
rationale: queryResponse.rationale,
|
|
1349
|
+
sql,
|
|
1350
|
+
rationale: queryResponse.data.rationale,
|
|
1237
1351
|
fields: execution.fields,
|
|
1238
1352
|
rows: anonymizeResults(rows),
|
|
1239
1353
|
max_retries: options.chartMaxRetries ?? 3,
|
|
1240
|
-
query_id: queryResponse.queryId
|
|
1354
|
+
query_id: queryResponse.data.queryId
|
|
1241
1355
|
},
|
|
1242
1356
|
tenantId,
|
|
1243
1357
|
options.userId,
|
|
@@ -1255,12 +1369,12 @@ async function ask(client, queryEngine, question, options, signal) {
|
|
|
1255
1369
|
"/chart",
|
|
1256
1370
|
{
|
|
1257
1371
|
question,
|
|
1258
|
-
sql
|
|
1259
|
-
rationale: queryResponse.rationale,
|
|
1372
|
+
sql,
|
|
1373
|
+
rationale: queryResponse.data.rationale,
|
|
1260
1374
|
fields: execution.fields,
|
|
1261
1375
|
rows: anonymizeResults(rows),
|
|
1262
1376
|
max_retries: options.chartMaxRetries ?? 3,
|
|
1263
|
-
query_id: queryResponse.queryId
|
|
1377
|
+
query_id: queryResponse.data.queryId
|
|
1264
1378
|
},
|
|
1265
1379
|
tenantId,
|
|
1266
1380
|
options.userId,
|
|
@@ -1279,18 +1393,19 @@ async function ask(client, queryEngine, question, options, signal) {
|
|
|
1279
1393
|
}
|
|
1280
1394
|
}
|
|
1281
1395
|
return {
|
|
1282
|
-
sql
|
|
1396
|
+
sql,
|
|
1283
1397
|
params: paramValues,
|
|
1284
1398
|
paramMetadata,
|
|
1285
|
-
rationale: queryResponse.rationale,
|
|
1286
|
-
dialect
|
|
1287
|
-
queryId: queryResponse.queryId,
|
|
1399
|
+
rationale: queryResponse.data.rationale,
|
|
1400
|
+
dialect,
|
|
1401
|
+
queryId: queryResponse.data.queryId,
|
|
1288
1402
|
rows,
|
|
1289
1403
|
fields: execution.fields,
|
|
1290
1404
|
chart,
|
|
1291
|
-
context: queryResponse.context,
|
|
1405
|
+
context: queryResponse.data.context,
|
|
1292
1406
|
attempts: attempt + 1,
|
|
1293
|
-
target_db: dbName
|
|
1407
|
+
target_db: dbName,
|
|
1408
|
+
querypanelSessionId: responseSessionId ?? void 0
|
|
1294
1409
|
};
|
|
1295
1410
|
} catch (error) {
|
|
1296
1411
|
attempt++;
|
|
@@ -1298,7 +1413,7 @@ async function ask(client, queryEngine, question, options, signal) {
|
|
|
1298
1413
|
throw error;
|
|
1299
1414
|
}
|
|
1300
1415
|
lastError = error instanceof Error ? error.message : String(error);
|
|
1301
|
-
previousSql = queryResponse.sql;
|
|
1416
|
+
previousSql = queryResponse.data.sql ?? previousSql;
|
|
1302
1417
|
console.warn(
|
|
1303
1418
|
`SQL execution failed (attempt ${attempt}/${maxRetry + 1}): ${lastError}. Retrying...`
|
|
1304
1419
|
);
|
|
@@ -1533,10 +1648,79 @@ async function modifyChart(client, queryEngine, input, options, signal) {
|
|
|
1533
1648
|
};
|
|
1534
1649
|
}
|
|
1535
1650
|
|
|
1651
|
+
// src/routes/sessions.ts
|
|
1652
|
+
async function listSessions(client, options, signal) {
|
|
1653
|
+
const tenantId = resolveTenantId6(client, options?.tenantId);
|
|
1654
|
+
const params = new URLSearchParams();
|
|
1655
|
+
if (options?.pagination?.page)
|
|
1656
|
+
params.set("page", `${options.pagination.page}`);
|
|
1657
|
+
if (options?.pagination?.limit)
|
|
1658
|
+
params.set("limit", `${options.pagination.limit}`);
|
|
1659
|
+
if (options?.sortBy) params.set("sort_by", options.sortBy);
|
|
1660
|
+
if (options?.sortDir) params.set("sort_dir", options.sortDir);
|
|
1661
|
+
if (options?.title) params.set("title", options.title);
|
|
1662
|
+
if (options?.userFilter) params.set("user_id", options.userFilter);
|
|
1663
|
+
if (options?.createdFrom) params.set("created_from", options.createdFrom);
|
|
1664
|
+
if (options?.createdTo) params.set("created_to", options.createdTo);
|
|
1665
|
+
if (options?.updatedFrom) params.set("updated_from", options.updatedFrom);
|
|
1666
|
+
if (options?.updatedTo) params.set("updated_to", options.updatedTo);
|
|
1667
|
+
return await client.get(
|
|
1668
|
+
`/sessions${params.toString() ? `?${params.toString()}` : ""}`,
|
|
1669
|
+
tenantId,
|
|
1670
|
+
options?.userId,
|
|
1671
|
+
options?.scopes,
|
|
1672
|
+
signal
|
|
1673
|
+
);
|
|
1674
|
+
}
|
|
1675
|
+
async function getSession(client, sessionId, options, signal) {
|
|
1676
|
+
const tenantId = resolveTenantId6(client, options?.tenantId);
|
|
1677
|
+
const params = new URLSearchParams();
|
|
1678
|
+
if (options?.includeTurns !== void 0) {
|
|
1679
|
+
params.set("include_turns", `${options.includeTurns}`);
|
|
1680
|
+
}
|
|
1681
|
+
return await client.get(
|
|
1682
|
+
`/sessions/${encodeURIComponent(sessionId)}${params.toString() ? `?${params.toString()}` : ""}`,
|
|
1683
|
+
tenantId,
|
|
1684
|
+
options?.userId,
|
|
1685
|
+
options?.scopes,
|
|
1686
|
+
signal
|
|
1687
|
+
);
|
|
1688
|
+
}
|
|
1689
|
+
async function updateSession(client, sessionId, body, options, signal) {
|
|
1690
|
+
const tenantId = resolveTenantId6(client, options?.tenantId);
|
|
1691
|
+
return await client.patch(
|
|
1692
|
+
`/sessions/${encodeURIComponent(sessionId)}`,
|
|
1693
|
+
body,
|
|
1694
|
+
tenantId,
|
|
1695
|
+
options?.userId,
|
|
1696
|
+
options?.scopes,
|
|
1697
|
+
signal
|
|
1698
|
+
);
|
|
1699
|
+
}
|
|
1700
|
+
async function deleteSession(client, sessionId, options, signal) {
|
|
1701
|
+
const tenantId = resolveTenantId6(client, options?.tenantId);
|
|
1702
|
+
await client.delete(
|
|
1703
|
+
`/sessions/${encodeURIComponent(sessionId)}`,
|
|
1704
|
+
tenantId,
|
|
1705
|
+
options?.userId,
|
|
1706
|
+
options?.scopes,
|
|
1707
|
+
signal
|
|
1708
|
+
);
|
|
1709
|
+
}
|
|
1710
|
+
function resolveTenantId6(client, tenantId) {
|
|
1711
|
+
const resolved = tenantId ?? client.getDefaultTenantId();
|
|
1712
|
+
if (!resolved) {
|
|
1713
|
+
throw new Error(
|
|
1714
|
+
"tenantId is required. Provide it per request or via defaultTenantId option."
|
|
1715
|
+
);
|
|
1716
|
+
}
|
|
1717
|
+
return resolved;
|
|
1718
|
+
}
|
|
1719
|
+
|
|
1536
1720
|
// src/routes/vizspec.ts
|
|
1537
1721
|
var import_node_crypto5 = __toESM(require("crypto"), 1);
|
|
1538
1722
|
async function generateVizSpec(client, input, options, signal) {
|
|
1539
|
-
const tenantId =
|
|
1723
|
+
const tenantId = resolveTenantId7(client, options?.tenantId);
|
|
1540
1724
|
const sessionId = import_node_crypto5.default.randomUUID();
|
|
1541
1725
|
const response = await client.post(
|
|
1542
1726
|
"/vizspec",
|
|
@@ -1557,7 +1741,7 @@ async function generateVizSpec(client, input, options, signal) {
|
|
|
1557
1741
|
);
|
|
1558
1742
|
return response;
|
|
1559
1743
|
}
|
|
1560
|
-
function
|
|
1744
|
+
function resolveTenantId7(client, tenantId) {
|
|
1561
1745
|
const resolved = tenantId ?? client.getDefaultTenantId();
|
|
1562
1746
|
if (!resolved) {
|
|
1563
1747
|
throw new Error(
|
|
@@ -1670,6 +1854,7 @@ var QueryPanelSdkAPI = class {
|
|
|
1670
1854
|
* console.log(result.sql); // Generated SQL
|
|
1671
1855
|
* console.log(result.rows); // Query results
|
|
1672
1856
|
* console.log(result.chart); // Vega-Lite chart spec
|
|
1857
|
+
* console.log(result.querypanelSessionId); // Use for follow-ups
|
|
1673
1858
|
*
|
|
1674
1859
|
* // With automatic SQL repair on failure
|
|
1675
1860
|
* const result = await qp.ask("Show monthly trends", {
|
|
@@ -1845,6 +2030,92 @@ var QueryPanelSdkAPI = class {
|
|
|
1845
2030
|
signal
|
|
1846
2031
|
);
|
|
1847
2032
|
}
|
|
2033
|
+
// Session history CRUD operations
|
|
2034
|
+
/**
|
|
2035
|
+
* Lists query sessions with pagination and filtering.
|
|
2036
|
+
*
|
|
2037
|
+
* @param options - Filtering, pagination, and sort options
|
|
2038
|
+
* @param signal - Optional AbortSignal for cancellation
|
|
2039
|
+
* @returns Paginated list of sessions
|
|
2040
|
+
*
|
|
2041
|
+
* @example
|
|
2042
|
+
* ```typescript
|
|
2043
|
+
* const sessions = await qp.listSessions({
|
|
2044
|
+
* tenantId: "tenant_123",
|
|
2045
|
+
* pagination: { page: 1, limit: 20 },
|
|
2046
|
+
* sortBy: "updated_at",
|
|
2047
|
+
* });
|
|
2048
|
+
* ```
|
|
2049
|
+
*/
|
|
2050
|
+
async listSessions(options, signal) {
|
|
2051
|
+
return await listSessions(this.client, options, signal);
|
|
2052
|
+
}
|
|
2053
|
+
/**
|
|
2054
|
+
* Retrieves a session by session_id with optional turn history.
|
|
2055
|
+
*
|
|
2056
|
+
* @param sessionId - QueryPanel session identifier used in ask()
|
|
2057
|
+
* @param options - Tenant, user, scopes, and includeTurns flag
|
|
2058
|
+
* @param signal - Optional AbortSignal for cancellation
|
|
2059
|
+
* @returns Session metadata with optional turns
|
|
2060
|
+
*
|
|
2061
|
+
* @example
|
|
2062
|
+
* ```typescript
|
|
2063
|
+
* const session = await qp.getSession("session_123", {
|
|
2064
|
+
* tenantId: "tenant_123",
|
|
2065
|
+
* includeTurns: true,
|
|
2066
|
+
* });
|
|
2067
|
+
* ```
|
|
2068
|
+
*/
|
|
2069
|
+
async getSession(sessionId, options, signal) {
|
|
2070
|
+
return await getSession(
|
|
2071
|
+
this.client,
|
|
2072
|
+
sessionId,
|
|
2073
|
+
options,
|
|
2074
|
+
signal
|
|
2075
|
+
);
|
|
2076
|
+
}
|
|
2077
|
+
/**
|
|
2078
|
+
* Updates session metadata (title).
|
|
2079
|
+
*
|
|
2080
|
+
* @param sessionId - QueryPanel session identifier to update
|
|
2081
|
+
* @param body - Fields to update
|
|
2082
|
+
* @param options - Tenant, user, and scope options
|
|
2083
|
+
* @param signal - Optional AbortSignal for cancellation
|
|
2084
|
+
* @returns Updated session
|
|
2085
|
+
*
|
|
2086
|
+
* @example
|
|
2087
|
+
* ```typescript
|
|
2088
|
+
* const updated = await qp.updateSession(
|
|
2089
|
+
* "session_123",
|
|
2090
|
+
* { title: "Q4 Revenue Analysis" },
|
|
2091
|
+
* { tenantId: "tenant_123" },
|
|
2092
|
+
* );
|
|
2093
|
+
* ```
|
|
2094
|
+
*/
|
|
2095
|
+
async updateSession(sessionId, body, options, signal) {
|
|
2096
|
+
return await updateSession(
|
|
2097
|
+
this.client,
|
|
2098
|
+
sessionId,
|
|
2099
|
+
body,
|
|
2100
|
+
options,
|
|
2101
|
+
signal
|
|
2102
|
+
);
|
|
2103
|
+
}
|
|
2104
|
+
/**
|
|
2105
|
+
* Deletes a session and its turn history.
|
|
2106
|
+
*
|
|
2107
|
+
* @param sessionId - QueryPanel session identifier to delete
|
|
2108
|
+
* @param options - Tenant, user, and scope options
|
|
2109
|
+
* @param signal - Optional AbortSignal for cancellation
|
|
2110
|
+
*
|
|
2111
|
+
* @example
|
|
2112
|
+
* ```typescript
|
|
2113
|
+
* await qp.deleteSession("session_123", { tenantId: "tenant_123" });
|
|
2114
|
+
* ```
|
|
2115
|
+
*/
|
|
2116
|
+
async deleteSession(sessionId, options, signal) {
|
|
2117
|
+
await deleteSession(this.client, sessionId, options, signal);
|
|
2118
|
+
}
|
|
1848
2119
|
/**
|
|
1849
2120
|
* Retrieves a single chart by ID with live data.
|
|
1850
2121
|
*
|
|
@@ -2049,7 +2320,9 @@ var QueryPanelSdkAPI = class {
|
|
|
2049
2320
|
0 && (module.exports = {
|
|
2050
2321
|
ClickHouseAdapter,
|
|
2051
2322
|
PostgresAdapter,
|
|
2323
|
+
QueryErrorCode,
|
|
2052
2324
|
QueryPanelSdkAPI,
|
|
2325
|
+
QueryPipelineError,
|
|
2053
2326
|
anonymizeResults
|
|
2054
2327
|
});
|
|
2055
2328
|
//# sourceMappingURL=index.cjs.map
|