@querypanel/node-sdk 1.3.0 → 1.3.1
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 +1 -1
- package/dist/index.cjs +86 -45
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +12 -13
- package/dist/index.d.ts +12 -13
- package/dist/index.js +86 -45
- package/dist/index.js.map +1 -1
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -544,7 +544,7 @@ Every request is signed with `RS256` using the private key you pass to the const
|
|
|
544
544
|
|
|
545
545
|
- HTTP errors propagate as thrown `Error` instances that include `status` (and `details` when available).
|
|
546
546
|
- `syncSchema` automatically skips embedding if the schema hasn't changed (drift detection). Use `syncSchema(..., { forceReindex: true })` to force updates.
|
|
547
|
-
- `ask()` raises immediately for guardrail/moderation errors because `/query` responds with 4xx/5xx.
|
|
547
|
+
- `ask()` raises immediately for guardrail/moderation errors because `/v2/query` responds with 4xx/5xx. `pipeline: "v1"` is not accepted.
|
|
548
548
|
|
|
549
549
|
### Automatic SQL repair and retry
|
|
550
550
|
|
package/dist/index.cjs
CHANGED
|
@@ -61,6 +61,13 @@ var BigQueryAdapter = class {
|
|
|
61
61
|
);
|
|
62
62
|
}
|
|
63
63
|
}
|
|
64
|
+
clientFn;
|
|
65
|
+
projectId;
|
|
66
|
+
datasetProjectId;
|
|
67
|
+
defaultDataset;
|
|
68
|
+
databaseName;
|
|
69
|
+
kind;
|
|
70
|
+
allowedTables;
|
|
64
71
|
async execute(sql, params) {
|
|
65
72
|
if (this.allowedTables) {
|
|
66
73
|
this.validateQueryTables(sql);
|
|
@@ -291,6 +298,11 @@ var ClickHouseAdapter = class {
|
|
|
291
298
|
this.allowedTables = normalizeTableFilter2(options.allowedTables);
|
|
292
299
|
}
|
|
293
300
|
}
|
|
301
|
+
clientFn;
|
|
302
|
+
databaseName;
|
|
303
|
+
defaultFormat;
|
|
304
|
+
kind;
|
|
305
|
+
allowedTables;
|
|
294
306
|
async execute(sql, params) {
|
|
295
307
|
if (this.allowedTables) {
|
|
296
308
|
this.validateQueryTables(sql);
|
|
@@ -544,6 +556,11 @@ var PostgresAdapter = class {
|
|
|
544
556
|
);
|
|
545
557
|
}
|
|
546
558
|
}
|
|
559
|
+
clientFn;
|
|
560
|
+
databaseName;
|
|
561
|
+
defaultSchema;
|
|
562
|
+
kind;
|
|
563
|
+
allowedTables;
|
|
547
564
|
async execute(sql, params) {
|
|
548
565
|
if (this.allowedTables) {
|
|
549
566
|
this.validateQueryTables(sql);
|
|
@@ -852,6 +869,9 @@ var QueryPipelineError = class extends Error {
|
|
|
852
869
|
this.status = status;
|
|
853
870
|
this.name = "QueryPipelineError";
|
|
854
871
|
}
|
|
872
|
+
code;
|
|
873
|
+
details;
|
|
874
|
+
status;
|
|
855
875
|
/**
|
|
856
876
|
* Check if this is a moderation error
|
|
857
877
|
*/
|
|
@@ -904,8 +924,14 @@ var QueryPipelineError = class extends Error {
|
|
|
904
924
|
|
|
905
925
|
// src/core/client.ts
|
|
906
926
|
var ApiClient = class {
|
|
927
|
+
baseUrl;
|
|
928
|
+
privateKey;
|
|
929
|
+
organizationId;
|
|
930
|
+
defaultTenantId;
|
|
931
|
+
additionalHeaders;
|
|
932
|
+
fetchImpl;
|
|
933
|
+
cryptoKey = null;
|
|
907
934
|
constructor(baseUrl, privateKey, organizationId, options) {
|
|
908
|
-
this.cryptoKey = null;
|
|
909
935
|
if (!baseUrl) {
|
|
910
936
|
throw new Error("Base URL is required");
|
|
911
937
|
}
|
|
@@ -1159,6 +1185,8 @@ var ApiClient = class {
|
|
|
1159
1185
|
|
|
1160
1186
|
// src/core/callback-client.ts
|
|
1161
1187
|
var CallbackApiClient = class {
|
|
1188
|
+
requestHandler;
|
|
1189
|
+
defaultTenantId;
|
|
1162
1190
|
constructor(requestHandler, options) {
|
|
1163
1191
|
this.requestHandler = requestHandler;
|
|
1164
1192
|
this.defaultTenantId = options?.defaultTenantId;
|
|
@@ -1301,10 +1329,9 @@ function normalizeSqlParamsInput(params) {
|
|
|
1301
1329
|
|
|
1302
1330
|
// src/core/query-engine.ts
|
|
1303
1331
|
var QueryEngine = class {
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
}
|
|
1332
|
+
databases = /* @__PURE__ */ new Map();
|
|
1333
|
+
databaseMetadata = /* @__PURE__ */ new Map();
|
|
1334
|
+
defaultDatabase;
|
|
1308
1335
|
attachDatabase(name, adapter, metadata) {
|
|
1309
1336
|
this.databases.set(name, adapter);
|
|
1310
1337
|
this.databaseMetadata.set(name, metadata);
|
|
@@ -1990,7 +2017,13 @@ var import_node_crypto4 = __toESM(require("crypto"), 1);
|
|
|
1990
2017
|
// src/routes/query.ts
|
|
1991
2018
|
var import_node_crypto3 = __toESM(require("crypto"), 1);
|
|
1992
2019
|
function resolveQueryPipeline(pipeline) {
|
|
1993
|
-
|
|
2020
|
+
const requested = pipeline;
|
|
2021
|
+
if (requested != null && requested !== "v2") {
|
|
2022
|
+
throw new Error(
|
|
2023
|
+
`Query pipeline "${requested}" was removed. ask() and modifyChart() always use POST /v2/query.`
|
|
2024
|
+
);
|
|
2025
|
+
}
|
|
2026
|
+
return "v2";
|
|
1994
2027
|
}
|
|
1995
2028
|
async function ask(client, queryEngine, question, options, signal) {
|
|
1996
2029
|
const tenantId = resolveTenantId5(client, options.tenantId);
|
|
@@ -2000,8 +2033,9 @@ async function ask(client, queryEngine, question, options, signal) {
|
|
|
2000
2033
|
let attempt = 0;
|
|
2001
2034
|
let lastError = options.lastError;
|
|
2002
2035
|
let previousSql = options.previousSql;
|
|
2003
|
-
|
|
2004
|
-
|
|
2036
|
+
let parentQueryId;
|
|
2037
|
+
resolveQueryPipeline(options.pipeline);
|
|
2038
|
+
const queryEndpoint = "/v2/query";
|
|
2005
2039
|
while (attempt <= maxRetry) {
|
|
2006
2040
|
const databaseName = options.database ?? queryEngine.getDefaultDatabase();
|
|
2007
2041
|
const metadata = databaseName ? queryEngine.getDatabaseMetadata(databaseName) : void 0;
|
|
@@ -2031,7 +2065,8 @@ async function ask(client, queryEngine, question, options, signal) {
|
|
|
2031
2065
|
...databaseName ? { database: databaseName } : {},
|
|
2032
2066
|
...metadata?.dialect ? { dialect: metadata.dialect } : {},
|
|
2033
2067
|
...options.model?.trim() ? { model: options.model.trim() } : {},
|
|
2034
|
-
...
|
|
2068
|
+
...options.systemPrompt?.trim() ? { system_prompt: options.systemPrompt.trim() } : {},
|
|
2069
|
+
...parentQueryId ? { parent_query_id: parentQueryId } : {},
|
|
2035
2070
|
debug: options.debug ?? false
|
|
2036
2071
|
},
|
|
2037
2072
|
tenantId,
|
|
@@ -2053,6 +2088,9 @@ async function ask(client, queryEngine, question, options, signal) {
|
|
|
2053
2088
|
if (!sql || !dialect) {
|
|
2054
2089
|
throw new Error("Query response missing required SQL or dialect");
|
|
2055
2090
|
}
|
|
2091
|
+
if (queryResponse.data.queryId) {
|
|
2092
|
+
parentQueryId = queryResponse.data.queryId;
|
|
2093
|
+
}
|
|
2056
2094
|
const dbName = queryResponse.data.database ?? options.database ?? queryEngine.getDefaultDatabase();
|
|
2057
2095
|
if (!dbName) {
|
|
2058
2096
|
throw new Error(
|
|
@@ -2212,35 +2250,35 @@ async function resolveQuery(client, queryEngine, queryId, options, signal) {
|
|
|
2212
2250
|
dialect: response.dialect
|
|
2213
2251
|
};
|
|
2214
2252
|
}
|
|
2253
|
+
async function markQueryExecuted(client, queryId, options, signal) {
|
|
2254
|
+
try {
|
|
2255
|
+
await client.post(
|
|
2256
|
+
`/v2/queries/${encodeURIComponent(queryId)}/executed`,
|
|
2257
|
+
{},
|
|
2258
|
+
options.tenantId,
|
|
2259
|
+
options.userId,
|
|
2260
|
+
options.scopes,
|
|
2261
|
+
signal
|
|
2262
|
+
);
|
|
2263
|
+
} catch {
|
|
2264
|
+
}
|
|
2265
|
+
}
|
|
2215
2266
|
|
|
2216
2267
|
// src/routes/modify.ts
|
|
2217
|
-
function buildModifiedQuestion(originalQuestion, modifications,
|
|
2268
|
+
function buildModifiedQuestion(originalQuestion, modifications, hasSessionContext = false) {
|
|
2218
2269
|
const hints = [];
|
|
2219
2270
|
if (modifications.timeGranularity) {
|
|
2220
2271
|
hints.push(`group results by ${modifications.timeGranularity}`);
|
|
2221
2272
|
}
|
|
2222
2273
|
if (modifications.dateRange) {
|
|
2223
|
-
|
|
2224
|
-
|
|
2225
|
-
|
|
2226
|
-
|
|
2227
|
-
|
|
2228
|
-
|
|
2229
|
-
|
|
2230
|
-
|
|
2231
|
-
hints.push(`change end date to ${to}`);
|
|
2232
|
-
}
|
|
2233
|
-
} else {
|
|
2234
|
-
const parts = [];
|
|
2235
|
-
if (modifications.dateRange.from) {
|
|
2236
|
-
parts.push(`from ${modifications.dateRange.from}`);
|
|
2237
|
-
}
|
|
2238
|
-
if (modifications.dateRange.to) {
|
|
2239
|
-
parts.push(`to ${modifications.dateRange.to}`);
|
|
2240
|
-
}
|
|
2241
|
-
if (parts.length > 0) {
|
|
2242
|
-
hints.push(`filter date range ${parts.join(" ")}`);
|
|
2243
|
-
}
|
|
2274
|
+
const from = normalizeDateInput(modifications.dateRange.from);
|
|
2275
|
+
const to = normalizeDateInput(modifications.dateRange.to);
|
|
2276
|
+
if (from && to) {
|
|
2277
|
+
hints.push(`change date range to ${from} through ${to}`);
|
|
2278
|
+
} else if (from) {
|
|
2279
|
+
hints.push(`change start date to ${from}`);
|
|
2280
|
+
} else if (to) {
|
|
2281
|
+
hints.push(`change end date to ${to}`);
|
|
2244
2282
|
}
|
|
2245
2283
|
}
|
|
2246
2284
|
if (modifications.additionalInstructions) {
|
|
@@ -2249,7 +2287,7 @@ function buildModifiedQuestion(originalQuestion, modifications, pipeline, hasSes
|
|
|
2249
2287
|
if (hints.length === 0) {
|
|
2250
2288
|
return originalQuestion;
|
|
2251
2289
|
}
|
|
2252
|
-
if (
|
|
2290
|
+
if (hasSessionContext) {
|
|
2253
2291
|
return hints.join(", ");
|
|
2254
2292
|
}
|
|
2255
2293
|
return `${originalQuestion} (${hints.join(", ")})`;
|
|
@@ -2365,8 +2403,8 @@ async function modifyChart(client, queryEngine, input, options, signal) {
|
|
|
2365
2403
|
const hasSqlMods = !!input.sqlModifications;
|
|
2366
2404
|
const hasVizMods = !!input.vizModifications;
|
|
2367
2405
|
const hasCustomSql = !!input.sqlModifications?.customSql;
|
|
2368
|
-
|
|
2369
|
-
const queryEndpoint =
|
|
2406
|
+
resolveQueryPipeline(options?.pipeline);
|
|
2407
|
+
const queryEndpoint = "/v2/query";
|
|
2370
2408
|
let currentSql = input.sql;
|
|
2371
2409
|
let finalParams = input.params ?? {};
|
|
2372
2410
|
let paramMetadata = [];
|
|
@@ -2422,12 +2460,9 @@ async function modifyChart(client, queryEngine, input, options, signal) {
|
|
|
2422
2460
|
const modifiedQuestion = buildModifiedQuestion(
|
|
2423
2461
|
input.question,
|
|
2424
2462
|
input.sqlModifications,
|
|
2425
|
-
pipeline,
|
|
2426
2463
|
hasQuerypanelSessionContext
|
|
2427
2464
|
);
|
|
2428
|
-
|
|
2429
|
-
finalQuestion = modifiedQuestion;
|
|
2430
|
-
}
|
|
2465
|
+
finalQuestion = modifiedQuestion;
|
|
2431
2466
|
const queryResponse = await client.post(
|
|
2432
2467
|
queryEndpoint,
|
|
2433
2468
|
{
|
|
@@ -2449,13 +2484,11 @@ async function modifyChart(client, queryEngine, input, options, signal) {
|
|
|
2449
2484
|
finalSql = queryResponse.sql;
|
|
2450
2485
|
paramMetadata = Array.isArray(queryResponse.params) ? queryResponse.params : [];
|
|
2451
2486
|
finalParams = queryEngine.mapGeneratedParams(paramMetadata);
|
|
2452
|
-
|
|
2453
|
-
|
|
2454
|
-
|
|
2455
|
-
|
|
2456
|
-
|
|
2457
|
-
);
|
|
2458
|
-
}
|
|
2487
|
+
applyDateRangeOverrides(
|
|
2488
|
+
input.sqlModifications?.dateRange,
|
|
2489
|
+
finalParams,
|
|
2490
|
+
paramMetadata
|
|
2491
|
+
);
|
|
2459
2492
|
rationale = queryResponse.rationale;
|
|
2460
2493
|
queryId = queryResponse.queryId;
|
|
2461
2494
|
sqlChanged = finalSql !== currentSql;
|
|
@@ -2673,6 +2706,9 @@ function resolveAttachEnforceTenantIsolation(tenantFieldName, enforceTenantIsola
|
|
|
2673
2706
|
return tenantFieldName ? true : void 0;
|
|
2674
2707
|
}
|
|
2675
2708
|
var QueryPanelSdkAPI = class _QueryPanelSdkAPI {
|
|
2709
|
+
client;
|
|
2710
|
+
queryEngine;
|
|
2711
|
+
supportedChartTypes;
|
|
2676
2712
|
/**
|
|
2677
2713
|
* @param workspaceId - Workspace UUID (same value as your org in the dashboard). Passed to the API as JWT claim `organizationId`.
|
|
2678
2714
|
*/
|
|
@@ -2924,6 +2960,11 @@ var QueryPanelSdkAPI = class _QueryPanelSdkAPI {
|
|
|
2924
2960
|
databaseName,
|
|
2925
2961
|
tenantId
|
|
2926
2962
|
);
|
|
2963
|
+
if (input.queryId) {
|
|
2964
|
+
await markQueryExecuted(this.client, input.queryId, {
|
|
2965
|
+
tenantId
|
|
2966
|
+
});
|
|
2967
|
+
}
|
|
2927
2968
|
return { rows: result.rows, fields: result.fields };
|
|
2928
2969
|
}
|
|
2929
2970
|
// VizSpec generation
|