@querypanel/node-sdk 1.0.44 → 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 +221 -23
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +218 -8
- package/dist/index.d.ts +218 -8
- package/dist/index.js +221 -23
- package/dist/index.js.map +1 -1
- package/package.json +71 -71
package/dist/index.js
CHANGED
|
@@ -587,6 +587,22 @@ var ApiClient = class {
|
|
|
587
587
|
signal
|
|
588
588
|
});
|
|
589
589
|
}
|
|
590
|
+
async postWithHeaders(path, body, tenantId, userId, scopes, signal, sessionId) {
|
|
591
|
+
const response = await this.fetchImpl(`${this.baseUrl}${path}`, {
|
|
592
|
+
method: "POST",
|
|
593
|
+
headers: await this.buildHeaders(
|
|
594
|
+
tenantId,
|
|
595
|
+
userId,
|
|
596
|
+
scopes,
|
|
597
|
+
true,
|
|
598
|
+
sessionId
|
|
599
|
+
),
|
|
600
|
+
body: JSON.stringify(body ?? {}),
|
|
601
|
+
signal
|
|
602
|
+
});
|
|
603
|
+
const data = await this.parseResponse(response);
|
|
604
|
+
return { data, headers: response.headers };
|
|
605
|
+
}
|
|
590
606
|
async put(path, body, tenantId, userId, scopes, signal, sessionId) {
|
|
591
607
|
return await this.request(path, {
|
|
592
608
|
method: "PUT",
|
|
@@ -601,6 +617,20 @@ var ApiClient = class {
|
|
|
601
617
|
signal
|
|
602
618
|
});
|
|
603
619
|
}
|
|
620
|
+
async patch(path, body, tenantId, userId, scopes, signal, sessionId) {
|
|
621
|
+
return await this.request(path, {
|
|
622
|
+
method: "PATCH",
|
|
623
|
+
headers: await this.buildHeaders(
|
|
624
|
+
tenantId,
|
|
625
|
+
userId,
|
|
626
|
+
scopes,
|
|
627
|
+
true,
|
|
628
|
+
sessionId
|
|
629
|
+
),
|
|
630
|
+
body: JSON.stringify(body ?? {}),
|
|
631
|
+
signal
|
|
632
|
+
});
|
|
633
|
+
}
|
|
604
634
|
async delete(path, tenantId, userId, scopes, signal, sessionId) {
|
|
605
635
|
return await this.request(path, {
|
|
606
636
|
method: "DELETE",
|
|
@@ -616,6 +646,9 @@ var ApiClient = class {
|
|
|
616
646
|
}
|
|
617
647
|
async request(path, init) {
|
|
618
648
|
const response = await this.fetchImpl(`${this.baseUrl}${path}`, init);
|
|
649
|
+
return await this.parseResponse(response);
|
|
650
|
+
}
|
|
651
|
+
async parseResponse(response) {
|
|
619
652
|
const text = await response.text();
|
|
620
653
|
let json;
|
|
621
654
|
try {
|
|
@@ -1197,6 +1230,7 @@ import crypto3 from "crypto";
|
|
|
1197
1230
|
async function ask(client, queryEngine, question, options, signal) {
|
|
1198
1231
|
const tenantId = resolveTenantId4(client, options.tenantId);
|
|
1199
1232
|
const sessionId = crypto3.randomUUID();
|
|
1233
|
+
const querypanelSessionId = options.querypanelSessionId ?? sessionId;
|
|
1200
1234
|
const maxRetry = options.maxRetry ?? 0;
|
|
1201
1235
|
let attempt = 0;
|
|
1202
1236
|
let lastError = options.lastError;
|
|
@@ -1213,10 +1247,11 @@ async function ask(client, queryEngine, question, options, signal) {
|
|
|
1213
1247
|
enforceTenantIsolation: metadata.enforceTenantIsolation
|
|
1214
1248
|
};
|
|
1215
1249
|
}
|
|
1216
|
-
const queryResponse = await client.
|
|
1250
|
+
const queryResponse = await client.postWithHeaders(
|
|
1217
1251
|
"/query",
|
|
1218
1252
|
{
|
|
1219
1253
|
question,
|
|
1254
|
+
...querypanelSessionId ? { session_id: querypanelSessionId } : {},
|
|
1220
1255
|
...lastError ? { last_error: lastError } : {},
|
|
1221
1256
|
...previousSql ? { previous_sql: previousSql } : {},
|
|
1222
1257
|
...options.maxRetry ? { max_retry: options.maxRetry } : {},
|
|
@@ -1230,24 +1265,30 @@ async function ask(client, queryEngine, question, options, signal) {
|
|
|
1230
1265
|
signal,
|
|
1231
1266
|
sessionId
|
|
1232
1267
|
);
|
|
1233
|
-
|
|
1268
|
+
const responseSessionId = queryResponse.headers.get("x-querypanel-session-id") ?? querypanelSessionId;
|
|
1269
|
+
if (!queryResponse.data.success) {
|
|
1234
1270
|
throw new QueryPipelineError(
|
|
1235
|
-
queryResponse.error || "Query generation failed",
|
|
1236
|
-
queryResponse.code || "INTERNAL_ERROR",
|
|
1237
|
-
queryResponse.details
|
|
1271
|
+
queryResponse.data.error || "Query generation failed",
|
|
1272
|
+
queryResponse.data.code || "INTERNAL_ERROR",
|
|
1273
|
+
queryResponse.data.details
|
|
1238
1274
|
);
|
|
1239
1275
|
}
|
|
1240
|
-
const
|
|
1276
|
+
const sql = queryResponse.data.sql;
|
|
1277
|
+
const dialect = queryResponse.data.dialect;
|
|
1278
|
+
if (!sql || !dialect) {
|
|
1279
|
+
throw new Error("Query response missing required SQL or dialect");
|
|
1280
|
+
}
|
|
1281
|
+
const dbName = queryResponse.data.database ?? options.database ?? queryEngine.getDefaultDatabase();
|
|
1241
1282
|
if (!dbName) {
|
|
1242
1283
|
throw new Error(
|
|
1243
1284
|
"No database attached. Call attachPostgres/attachClickhouse first."
|
|
1244
1285
|
);
|
|
1245
1286
|
}
|
|
1246
|
-
const paramMetadata = Array.isArray(queryResponse.params) ? queryResponse.params : [];
|
|
1287
|
+
const paramMetadata = Array.isArray(queryResponse.data.params) ? queryResponse.data.params : [];
|
|
1247
1288
|
const paramValues = queryEngine.mapGeneratedParams(paramMetadata);
|
|
1248
1289
|
try {
|
|
1249
1290
|
const execution = await queryEngine.validateAndExecute(
|
|
1250
|
-
|
|
1291
|
+
sql,
|
|
1251
1292
|
paramValues,
|
|
1252
1293
|
dbName,
|
|
1253
1294
|
tenantId
|
|
@@ -1264,12 +1305,12 @@ async function ask(client, queryEngine, question, options, signal) {
|
|
|
1264
1305
|
"/vizspec",
|
|
1265
1306
|
{
|
|
1266
1307
|
question,
|
|
1267
|
-
sql
|
|
1268
|
-
rationale: queryResponse.rationale,
|
|
1308
|
+
sql,
|
|
1309
|
+
rationale: queryResponse.data.rationale,
|
|
1269
1310
|
fields: execution.fields,
|
|
1270
1311
|
rows: anonymizeResults(rows),
|
|
1271
1312
|
max_retries: options.chartMaxRetries ?? 3,
|
|
1272
|
-
query_id: queryResponse.queryId
|
|
1313
|
+
query_id: queryResponse.data.queryId
|
|
1273
1314
|
},
|
|
1274
1315
|
tenantId,
|
|
1275
1316
|
options.userId,
|
|
@@ -1287,12 +1328,12 @@ async function ask(client, queryEngine, question, options, signal) {
|
|
|
1287
1328
|
"/chart",
|
|
1288
1329
|
{
|
|
1289
1330
|
question,
|
|
1290
|
-
sql
|
|
1291
|
-
rationale: queryResponse.rationale,
|
|
1331
|
+
sql,
|
|
1332
|
+
rationale: queryResponse.data.rationale,
|
|
1292
1333
|
fields: execution.fields,
|
|
1293
1334
|
rows: anonymizeResults(rows),
|
|
1294
1335
|
max_retries: options.chartMaxRetries ?? 3,
|
|
1295
|
-
query_id: queryResponse.queryId
|
|
1336
|
+
query_id: queryResponse.data.queryId
|
|
1296
1337
|
},
|
|
1297
1338
|
tenantId,
|
|
1298
1339
|
options.userId,
|
|
@@ -1311,18 +1352,19 @@ async function ask(client, queryEngine, question, options, signal) {
|
|
|
1311
1352
|
}
|
|
1312
1353
|
}
|
|
1313
1354
|
return {
|
|
1314
|
-
sql
|
|
1355
|
+
sql,
|
|
1315
1356
|
params: paramValues,
|
|
1316
1357
|
paramMetadata,
|
|
1317
|
-
rationale: queryResponse.rationale,
|
|
1318
|
-
dialect
|
|
1319
|
-
queryId: queryResponse.queryId,
|
|
1358
|
+
rationale: queryResponse.data.rationale,
|
|
1359
|
+
dialect,
|
|
1360
|
+
queryId: queryResponse.data.queryId,
|
|
1320
1361
|
rows,
|
|
1321
1362
|
fields: execution.fields,
|
|
1322
1363
|
chart,
|
|
1323
|
-
context: queryResponse.context,
|
|
1364
|
+
context: queryResponse.data.context,
|
|
1324
1365
|
attempts: attempt + 1,
|
|
1325
|
-
target_db: dbName
|
|
1366
|
+
target_db: dbName,
|
|
1367
|
+
querypanelSessionId: responseSessionId ?? void 0
|
|
1326
1368
|
};
|
|
1327
1369
|
} catch (error) {
|
|
1328
1370
|
attempt++;
|
|
@@ -1330,7 +1372,7 @@ async function ask(client, queryEngine, question, options, signal) {
|
|
|
1330
1372
|
throw error;
|
|
1331
1373
|
}
|
|
1332
1374
|
lastError = error instanceof Error ? error.message : String(error);
|
|
1333
|
-
previousSql = queryResponse.sql;
|
|
1375
|
+
previousSql = queryResponse.data.sql ?? previousSql;
|
|
1334
1376
|
console.warn(
|
|
1335
1377
|
`SQL execution failed (attempt ${attempt}/${maxRetry + 1}): ${lastError}. Retrying...`
|
|
1336
1378
|
);
|
|
@@ -1565,10 +1607,79 @@ async function modifyChart(client, queryEngine, input, options, signal) {
|
|
|
1565
1607
|
};
|
|
1566
1608
|
}
|
|
1567
1609
|
|
|
1610
|
+
// src/routes/sessions.ts
|
|
1611
|
+
async function listSessions(client, options, signal) {
|
|
1612
|
+
const tenantId = resolveTenantId6(client, options?.tenantId);
|
|
1613
|
+
const params = new URLSearchParams();
|
|
1614
|
+
if (options?.pagination?.page)
|
|
1615
|
+
params.set("page", `${options.pagination.page}`);
|
|
1616
|
+
if (options?.pagination?.limit)
|
|
1617
|
+
params.set("limit", `${options.pagination.limit}`);
|
|
1618
|
+
if (options?.sortBy) params.set("sort_by", options.sortBy);
|
|
1619
|
+
if (options?.sortDir) params.set("sort_dir", options.sortDir);
|
|
1620
|
+
if (options?.title) params.set("title", options.title);
|
|
1621
|
+
if (options?.userFilter) params.set("user_id", options.userFilter);
|
|
1622
|
+
if (options?.createdFrom) params.set("created_from", options.createdFrom);
|
|
1623
|
+
if (options?.createdTo) params.set("created_to", options.createdTo);
|
|
1624
|
+
if (options?.updatedFrom) params.set("updated_from", options.updatedFrom);
|
|
1625
|
+
if (options?.updatedTo) params.set("updated_to", options.updatedTo);
|
|
1626
|
+
return await client.get(
|
|
1627
|
+
`/sessions${params.toString() ? `?${params.toString()}` : ""}`,
|
|
1628
|
+
tenantId,
|
|
1629
|
+
options?.userId,
|
|
1630
|
+
options?.scopes,
|
|
1631
|
+
signal
|
|
1632
|
+
);
|
|
1633
|
+
}
|
|
1634
|
+
async function getSession(client, sessionId, options, signal) {
|
|
1635
|
+
const tenantId = resolveTenantId6(client, options?.tenantId);
|
|
1636
|
+
const params = new URLSearchParams();
|
|
1637
|
+
if (options?.includeTurns !== void 0) {
|
|
1638
|
+
params.set("include_turns", `${options.includeTurns}`);
|
|
1639
|
+
}
|
|
1640
|
+
return await client.get(
|
|
1641
|
+
`/sessions/${encodeURIComponent(sessionId)}${params.toString() ? `?${params.toString()}` : ""}`,
|
|
1642
|
+
tenantId,
|
|
1643
|
+
options?.userId,
|
|
1644
|
+
options?.scopes,
|
|
1645
|
+
signal
|
|
1646
|
+
);
|
|
1647
|
+
}
|
|
1648
|
+
async function updateSession(client, sessionId, body, options, signal) {
|
|
1649
|
+
const tenantId = resolveTenantId6(client, options?.tenantId);
|
|
1650
|
+
return await client.patch(
|
|
1651
|
+
`/sessions/${encodeURIComponent(sessionId)}`,
|
|
1652
|
+
body,
|
|
1653
|
+
tenantId,
|
|
1654
|
+
options?.userId,
|
|
1655
|
+
options?.scopes,
|
|
1656
|
+
signal
|
|
1657
|
+
);
|
|
1658
|
+
}
|
|
1659
|
+
async function deleteSession(client, sessionId, options, signal) {
|
|
1660
|
+
const tenantId = resolveTenantId6(client, options?.tenantId);
|
|
1661
|
+
await client.delete(
|
|
1662
|
+
`/sessions/${encodeURIComponent(sessionId)}`,
|
|
1663
|
+
tenantId,
|
|
1664
|
+
options?.userId,
|
|
1665
|
+
options?.scopes,
|
|
1666
|
+
signal
|
|
1667
|
+
);
|
|
1668
|
+
}
|
|
1669
|
+
function resolveTenantId6(client, tenantId) {
|
|
1670
|
+
const resolved = tenantId ?? client.getDefaultTenantId();
|
|
1671
|
+
if (!resolved) {
|
|
1672
|
+
throw new Error(
|
|
1673
|
+
"tenantId is required. Provide it per request or via defaultTenantId option."
|
|
1674
|
+
);
|
|
1675
|
+
}
|
|
1676
|
+
return resolved;
|
|
1677
|
+
}
|
|
1678
|
+
|
|
1568
1679
|
// src/routes/vizspec.ts
|
|
1569
1680
|
import crypto5 from "crypto";
|
|
1570
1681
|
async function generateVizSpec(client, input, options, signal) {
|
|
1571
|
-
const tenantId =
|
|
1682
|
+
const tenantId = resolveTenantId7(client, options?.tenantId);
|
|
1572
1683
|
const sessionId = crypto5.randomUUID();
|
|
1573
1684
|
const response = await client.post(
|
|
1574
1685
|
"/vizspec",
|
|
@@ -1589,7 +1700,7 @@ async function generateVizSpec(client, input, options, signal) {
|
|
|
1589
1700
|
);
|
|
1590
1701
|
return response;
|
|
1591
1702
|
}
|
|
1592
|
-
function
|
|
1703
|
+
function resolveTenantId7(client, tenantId) {
|
|
1593
1704
|
const resolved = tenantId ?? client.getDefaultTenantId();
|
|
1594
1705
|
if (!resolved) {
|
|
1595
1706
|
throw new Error(
|
|
@@ -1702,6 +1813,7 @@ var QueryPanelSdkAPI = class {
|
|
|
1702
1813
|
* console.log(result.sql); // Generated SQL
|
|
1703
1814
|
* console.log(result.rows); // Query results
|
|
1704
1815
|
* console.log(result.chart); // Vega-Lite chart spec
|
|
1816
|
+
* console.log(result.querypanelSessionId); // Use for follow-ups
|
|
1705
1817
|
*
|
|
1706
1818
|
* // With automatic SQL repair on failure
|
|
1707
1819
|
* const result = await qp.ask("Show monthly trends", {
|
|
@@ -1877,6 +1989,92 @@ var QueryPanelSdkAPI = class {
|
|
|
1877
1989
|
signal
|
|
1878
1990
|
);
|
|
1879
1991
|
}
|
|
1992
|
+
// Session history CRUD operations
|
|
1993
|
+
/**
|
|
1994
|
+
* Lists query sessions with pagination and filtering.
|
|
1995
|
+
*
|
|
1996
|
+
* @param options - Filtering, pagination, and sort options
|
|
1997
|
+
* @param signal - Optional AbortSignal for cancellation
|
|
1998
|
+
* @returns Paginated list of sessions
|
|
1999
|
+
*
|
|
2000
|
+
* @example
|
|
2001
|
+
* ```typescript
|
|
2002
|
+
* const sessions = await qp.listSessions({
|
|
2003
|
+
* tenantId: "tenant_123",
|
|
2004
|
+
* pagination: { page: 1, limit: 20 },
|
|
2005
|
+
* sortBy: "updated_at",
|
|
2006
|
+
* });
|
|
2007
|
+
* ```
|
|
2008
|
+
*/
|
|
2009
|
+
async listSessions(options, signal) {
|
|
2010
|
+
return await listSessions(this.client, options, signal);
|
|
2011
|
+
}
|
|
2012
|
+
/**
|
|
2013
|
+
* Retrieves a session by session_id with optional turn history.
|
|
2014
|
+
*
|
|
2015
|
+
* @param sessionId - QueryPanel session identifier used in ask()
|
|
2016
|
+
* @param options - Tenant, user, scopes, and includeTurns flag
|
|
2017
|
+
* @param signal - Optional AbortSignal for cancellation
|
|
2018
|
+
* @returns Session metadata with optional turns
|
|
2019
|
+
*
|
|
2020
|
+
* @example
|
|
2021
|
+
* ```typescript
|
|
2022
|
+
* const session = await qp.getSession("session_123", {
|
|
2023
|
+
* tenantId: "tenant_123",
|
|
2024
|
+
* includeTurns: true,
|
|
2025
|
+
* });
|
|
2026
|
+
* ```
|
|
2027
|
+
*/
|
|
2028
|
+
async getSession(sessionId, options, signal) {
|
|
2029
|
+
return await getSession(
|
|
2030
|
+
this.client,
|
|
2031
|
+
sessionId,
|
|
2032
|
+
options,
|
|
2033
|
+
signal
|
|
2034
|
+
);
|
|
2035
|
+
}
|
|
2036
|
+
/**
|
|
2037
|
+
* Updates session metadata (title).
|
|
2038
|
+
*
|
|
2039
|
+
* @param sessionId - QueryPanel session identifier to update
|
|
2040
|
+
* @param body - Fields to update
|
|
2041
|
+
* @param options - Tenant, user, and scope options
|
|
2042
|
+
* @param signal - Optional AbortSignal for cancellation
|
|
2043
|
+
* @returns Updated session
|
|
2044
|
+
*
|
|
2045
|
+
* @example
|
|
2046
|
+
* ```typescript
|
|
2047
|
+
* const updated = await qp.updateSession(
|
|
2048
|
+
* "session_123",
|
|
2049
|
+
* { title: "Q4 Revenue Analysis" },
|
|
2050
|
+
* { tenantId: "tenant_123" },
|
|
2051
|
+
* );
|
|
2052
|
+
* ```
|
|
2053
|
+
*/
|
|
2054
|
+
async updateSession(sessionId, body, options, signal) {
|
|
2055
|
+
return await updateSession(
|
|
2056
|
+
this.client,
|
|
2057
|
+
sessionId,
|
|
2058
|
+
body,
|
|
2059
|
+
options,
|
|
2060
|
+
signal
|
|
2061
|
+
);
|
|
2062
|
+
}
|
|
2063
|
+
/**
|
|
2064
|
+
* Deletes a session and its turn history.
|
|
2065
|
+
*
|
|
2066
|
+
* @param sessionId - QueryPanel session identifier to delete
|
|
2067
|
+
* @param options - Tenant, user, and scope options
|
|
2068
|
+
* @param signal - Optional AbortSignal for cancellation
|
|
2069
|
+
*
|
|
2070
|
+
* @example
|
|
2071
|
+
* ```typescript
|
|
2072
|
+
* await qp.deleteSession("session_123", { tenantId: "tenant_123" });
|
|
2073
|
+
* ```
|
|
2074
|
+
*/
|
|
2075
|
+
async deleteSession(sessionId, options, signal) {
|
|
2076
|
+
await deleteSession(this.client, sessionId, options, signal);
|
|
2077
|
+
}
|
|
1880
2078
|
/**
|
|
1881
2079
|
* Retrieves a single chart by ID with live data.
|
|
1882
2080
|
*
|