@querypanel/node-sdk 1.2.8 → 1.2.10

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 CHANGED
@@ -749,6 +749,118 @@ function sanitize2(value) {
749
749
 
750
750
  // src/core/client.ts
751
751
  var import_node_crypto = __toESM(require("crypto"), 1);
752
+
753
+ // src/errors.ts
754
+ var QueryErrorCode = {
755
+ // Moderation errors
756
+ MODERATION_FAILED: "MODERATION_FAILED",
757
+ // Guardrail errors
758
+ RELEVANCE_CHECK_FAILED: "RELEVANCE_CHECK_FAILED",
759
+ SECURITY_CHECK_FAILED: "SECURITY_CHECK_FAILED",
760
+ // SQL generation errors
761
+ SQL_GENERATION_FAILED: "SQL_GENERATION_FAILED",
762
+ // SQL validation errors
763
+ SQL_VALIDATION_FAILED: "SQL_VALIDATION_FAILED",
764
+ // Context retrieval errors
765
+ CONTEXT_RETRIEVAL_FAILED: "CONTEXT_RETRIEVAL_FAILED",
766
+ // Clarification errors (v2)
767
+ CLARIFICATION_NEEDED: "CLARIFICATION_NEEDED",
768
+ // Bring-your-own-key / provider errors
769
+ AI_PROVIDER_AUTH_FAILED: "AI_PROVIDER_AUTH_FAILED",
770
+ AI_PROVIDER_RATE_LIMITED: "AI_PROVIDER_RATE_LIMITED",
771
+ AI_PROVIDER_UNAVAILABLE: "AI_PROVIDER_UNAVAILABLE",
772
+ // General errors
773
+ INTERNAL_ERROR: "INTERNAL_ERROR",
774
+ AUTHENTICATION_REQUIRED: "AUTHENTICATION_REQUIRED",
775
+ VALIDATION_ERROR: "VALIDATION_ERROR"
776
+ };
777
+ function isQueryErrorCode(code) {
778
+ return typeof code === "string" && Object.values(QueryErrorCode).includes(code);
779
+ }
780
+ function isAiProviderErrorCode(code) {
781
+ return code === QueryErrorCode.AI_PROVIDER_AUTH_FAILED || code === QueryErrorCode.AI_PROVIDER_RATE_LIMITED || code === QueryErrorCode.AI_PROVIDER_UNAVAILABLE;
782
+ }
783
+ function isAiProviderPipelineError(error) {
784
+ if (error instanceof QueryPipelineError) {
785
+ return isAiProviderErrorCode(error.code);
786
+ }
787
+ if (error && typeof error === "object" && "code" in error) {
788
+ return isAiProviderErrorCode(error.code);
789
+ }
790
+ return false;
791
+ }
792
+ function throwIfGenerationErrorResponse(response) {
793
+ if (!response || typeof response !== "object") {
794
+ return;
795
+ }
796
+ const record = response;
797
+ if (typeof record.error !== "string") {
798
+ return;
799
+ }
800
+ if (isQueryErrorCode(record.code)) {
801
+ throw new QueryPipelineError(record.error, record.code);
802
+ }
803
+ throw new Error(record.error);
804
+ }
805
+ var QueryPipelineError = class extends Error {
806
+ constructor(message, code, details, status) {
807
+ super(message);
808
+ this.code = code;
809
+ this.details = details;
810
+ this.status = status;
811
+ this.name = "QueryPipelineError";
812
+ }
813
+ /**
814
+ * Check if this is a moderation error
815
+ */
816
+ isModeration() {
817
+ return this.code === QueryErrorCode.MODERATION_FAILED;
818
+ }
819
+ /**
820
+ * Check if this is a relevance error (question not related to database)
821
+ */
822
+ isRelevanceError() {
823
+ return this.code === QueryErrorCode.RELEVANCE_CHECK_FAILED;
824
+ }
825
+ /**
826
+ * Check if this is a security error (SQL injection, prompt injection, etc.)
827
+ */
828
+ isSecurityError() {
829
+ return this.code === QueryErrorCode.SECURITY_CHECK_FAILED;
830
+ }
831
+ /**
832
+ * Check if this is any guardrail error (relevance or security)
833
+ */
834
+ isGuardrailError() {
835
+ return this.isRelevanceError() || this.isSecurityError();
836
+ }
837
+ /**
838
+ * Check if this is a clarification needed error (v2 pipeline)
839
+ */
840
+ isClarificationNeeded() {
841
+ return this.code === QueryErrorCode.CLARIFICATION_NEEDED;
842
+ }
843
+ /**
844
+ * Check if this is a BYOK / provider credential error
845
+ */
846
+ isAiProviderAuthError() {
847
+ return this.code === QueryErrorCode.AI_PROVIDER_AUTH_FAILED;
848
+ }
849
+ /**
850
+ * Check if this is a BYOK / provider rate-limit error
851
+ */
852
+ isAiProviderRateLimited() {
853
+ return this.code === QueryErrorCode.AI_PROVIDER_RATE_LIMITED;
854
+ }
855
+ /**
856
+ * Check if this is any BYOK / provider error (auth, rate limit, or unavailable)
857
+ */
858
+ isAiProviderError() {
859
+ return isAiProviderErrorCode(this.code);
860
+ }
861
+ };
862
+
863
+ // src/core/client.ts
752
864
  var ApiClient = class {
753
865
  constructor(baseUrl, privateKey, organizationId, options) {
754
866
  this.cryptoKey = null;
@@ -880,10 +992,18 @@ var ApiClient = class {
880
992
  json = void 0;
881
993
  }
882
994
  if (!response.ok) {
883
- const error = new Error(
884
- json?.error || response.statusText || "Request failed"
885
- );
995
+ const message = json?.error || response.statusText || "Request failed";
996
+ if (isQueryErrorCode(json?.code)) {
997
+ throw new QueryPipelineError(
998
+ message,
999
+ json.code,
1000
+ json?.details,
1001
+ response.status
1002
+ );
1003
+ }
1004
+ const error = new Error(message);
886
1005
  error.status = response.status;
1006
+ if (json?.code) error.code = json.code;
887
1007
  if (json?.details) error.details = json.details;
888
1008
  throw error;
889
1009
  }
@@ -1212,65 +1332,6 @@ var QueryEngine = class {
1212
1332
  }
1213
1333
  };
1214
1334
 
1215
- // src/errors.ts
1216
- var QueryErrorCode = {
1217
- // Moderation errors
1218
- MODERATION_FAILED: "MODERATION_FAILED",
1219
- // Guardrail errors
1220
- RELEVANCE_CHECK_FAILED: "RELEVANCE_CHECK_FAILED",
1221
- SECURITY_CHECK_FAILED: "SECURITY_CHECK_FAILED",
1222
- // SQL generation errors
1223
- SQL_GENERATION_FAILED: "SQL_GENERATION_FAILED",
1224
- // SQL validation errors
1225
- SQL_VALIDATION_FAILED: "SQL_VALIDATION_FAILED",
1226
- // Context retrieval errors
1227
- CONTEXT_RETRIEVAL_FAILED: "CONTEXT_RETRIEVAL_FAILED",
1228
- // Clarification errors (v2)
1229
- CLARIFICATION_NEEDED: "CLARIFICATION_NEEDED",
1230
- // General errors
1231
- INTERNAL_ERROR: "INTERNAL_ERROR",
1232
- AUTHENTICATION_REQUIRED: "AUTHENTICATION_REQUIRED",
1233
- VALIDATION_ERROR: "VALIDATION_ERROR"
1234
- };
1235
- var QueryPipelineError = class extends Error {
1236
- constructor(message, code, details) {
1237
- super(message);
1238
- this.code = code;
1239
- this.details = details;
1240
- this.name = "QueryPipelineError";
1241
- }
1242
- /**
1243
- * Check if this is a moderation error
1244
- */
1245
- isModeration() {
1246
- return this.code === QueryErrorCode.MODERATION_FAILED;
1247
- }
1248
- /**
1249
- * Check if this is a relevance error (question not related to database)
1250
- */
1251
- isRelevanceError() {
1252
- return this.code === QueryErrorCode.RELEVANCE_CHECK_FAILED;
1253
- }
1254
- /**
1255
- * Check if this is a security error (SQL injection, prompt injection, etc.)
1256
- */
1257
- isSecurityError() {
1258
- return this.code === QueryErrorCode.SECURITY_CHECK_FAILED;
1259
- }
1260
- /**
1261
- * Check if this is any guardrail error (relevance or security)
1262
- */
1263
- isGuardrailError() {
1264
- return this.isRelevanceError() || this.isSecurityError();
1265
- }
1266
- /**
1267
- * Check if this is a clarification needed error (v2 pipeline)
1268
- */
1269
- isClarificationNeeded() {
1270
- return this.code === QueryErrorCode.CLARIFICATION_NEEDED;
1271
- }
1272
- };
1273
-
1274
1335
  // src/routes/charts.ts
1275
1336
  async function createChart(client, body, options, signal) {
1276
1337
  const tenantId = resolveTenantId(client, options?.tenantId);
@@ -1907,60 +1968,60 @@ async function ask(client, queryEngine, question, options, signal) {
1907
1968
  specType: chartType,
1908
1969
  notes: rows.length === 0 ? "Query returned no rows." : null
1909
1970
  };
1910
- if (rows.length > 0) {
1911
- if (chartType === "vizspec") {
1912
- const vizspecResponse = await client.post(
1913
- "/vizspec",
1914
- {
1915
- question,
1916
- sql,
1917
- rationale: queryResponse.data.rationale,
1918
- fields: execution.fields,
1919
- rows: anonymizeResults(rows),
1920
- max_retries: options.chartMaxRetries ?? 3,
1921
- query_id: queryResponse.data.queryId,
1922
- ...options.supportedChartTypes?.length ? {
1923
- supported_chart_types: options.supportedChartTypes
1924
- } : {}
1925
- },
1926
- tenantId,
1927
- options.userId,
1928
- options.scopes,
1929
- signal,
1930
- sessionId
1931
- );
1932
- chart = {
1933
- vizSpec: vizspecResponse.spec,
1934
- specType: "vizspec",
1935
- notes: vizspecResponse.notes
1936
- };
1937
- } else {
1938
- const chartResponse = await client.post(
1939
- "/chart",
1940
- {
1941
- question,
1942
- sql,
1943
- rationale: queryResponse.data.rationale,
1944
- fields: execution.fields,
1945
- rows: anonymizeResults(rows),
1946
- max_retries: options.chartMaxRetries ?? 3,
1947
- query_id: queryResponse.data.queryId
1948
- },
1949
- tenantId,
1950
- options.userId,
1951
- options.scopes,
1952
- signal,
1953
- sessionId
1954
- );
1955
- chart = {
1956
- vegaLiteSpec: chartResponse.chart ? {
1957
- ...chartResponse.chart,
1958
- data: { values: rows }
1959
- } : null,
1960
- specType: "vega-lite",
1961
- notes: chartResponse.notes
1962
- };
1963
- }
1971
+ if (chartType === "vizspec") {
1972
+ const vizspecResponse = await client.post(
1973
+ "/vizspec",
1974
+ {
1975
+ question,
1976
+ sql,
1977
+ rationale: queryResponse.data.rationale,
1978
+ fields: execution.fields,
1979
+ rows: anonymizeResults(rows),
1980
+ max_retries: options.chartMaxRetries ?? 3,
1981
+ query_id: queryResponse.data.queryId,
1982
+ ...options.supportedChartTypes?.length ? {
1983
+ supported_chart_types: options.supportedChartTypes
1984
+ } : {}
1985
+ },
1986
+ tenantId,
1987
+ options.userId,
1988
+ options.scopes,
1989
+ signal,
1990
+ sessionId
1991
+ );
1992
+ throwIfGenerationErrorResponse(vizspecResponse);
1993
+ chart = {
1994
+ vizSpec: vizspecResponse.spec,
1995
+ specType: "vizspec",
1996
+ notes: rows.length === 0 ? vizspecResponse.notes ?? "Query returned no rows." : vizspecResponse.notes
1997
+ };
1998
+ } else {
1999
+ const chartResponse = await client.post(
2000
+ "/chart",
2001
+ {
2002
+ question,
2003
+ sql,
2004
+ rationale: queryResponse.data.rationale,
2005
+ fields: execution.fields,
2006
+ rows: anonymizeResults(rows),
2007
+ max_retries: options.chartMaxRetries ?? 3,
2008
+ query_id: queryResponse.data.queryId
2009
+ },
2010
+ tenantId,
2011
+ options.userId,
2012
+ options.scopes,
2013
+ signal,
2014
+ sessionId
2015
+ );
2016
+ throwIfGenerationErrorResponse(chartResponse);
2017
+ chart = {
2018
+ vegaLiteSpec: chartResponse.chart ? {
2019
+ ...chartResponse.chart,
2020
+ data: { values: rows }
2021
+ } : null,
2022
+ specType: "vega-lite",
2023
+ notes: rows.length === 0 ? chartResponse.notes ?? "Query returned no rows." : chartResponse.notes
2024
+ };
1964
2025
  }
1965
2026
  return {
1966
2027
  sql,
@@ -1980,6 +2041,13 @@ async function ask(client, queryEngine, question, options, signal) {
1980
2041
  trace: queryResponse.data.trace
1981
2042
  };
1982
2043
  } catch (error) {
2044
+ if (isAiProviderPipelineError(error)) {
2045
+ if (error instanceof QueryPipelineError) {
2046
+ throw error;
2047
+ }
2048
+ const providerError = error;
2049
+ throw new QueryPipelineError(providerError.message, providerError.code);
2050
+ }
1983
2051
  attempt++;
1984
2052
  if (attempt > maxRetry) {
1985
2053
  throw error;
@@ -2253,64 +2321,64 @@ async function modifyChart(client, queryEngine, input, options, signal) {
2253
2321
  specType: chartType,
2254
2322
  notes: rows.length === 0 ? "Query returned no rows." : null
2255
2323
  };
2256
- if (rows.length > 0) {
2257
- const vizHints = hasVizMods ? buildVizHints(input.vizModifications) : {};
2258
- const vizHintsForChart = chartType === "vizspec" ? vizHints : stripVizSpecOnlyHints(vizHints);
2259
- if (chartType === "vizspec") {
2260
- const vizspecResponse = await client.post(
2261
- "/vizspec",
2262
- {
2263
- question: finalQuestion,
2264
- sql: finalSql,
2265
- rationale,
2266
- fields: execution.fields,
2267
- rows: anonymizeResults(rows),
2268
- max_retries: options?.chartMaxRetries ?? 3,
2269
- query_id: queryId,
2270
- // Include viz hints for the chart generator
2271
- ...hasVizMods ? { encoding_hints: vizHintsForChart } : {},
2272
- ...options?.supportedChartTypes?.length ? { supported_chart_types: options.supportedChartTypes } : {}
2273
- },
2274
- tenantId,
2275
- options?.userId,
2276
- options?.scopes,
2277
- signal,
2278
- sessionId
2279
- );
2280
- chart = {
2281
- vizSpec: vizspecResponse.spec,
2282
- specType: "vizspec",
2283
- notes: vizspecResponse.notes
2284
- };
2285
- } else {
2286
- const chartResponse = await client.post(
2287
- "/chart",
2288
- {
2289
- question: finalQuestion,
2290
- sql: finalSql,
2291
- rationale,
2292
- fields: execution.fields,
2293
- rows: anonymizeResults(rows),
2294
- max_retries: options?.chartMaxRetries ?? 3,
2295
- query_id: queryId,
2296
- // Include viz hints for the chart generator
2297
- ...hasVizMods ? { encoding_hints: vizHintsForChart } : {}
2298
- },
2299
- tenantId,
2300
- options?.userId,
2301
- options?.scopes,
2302
- signal,
2303
- sessionId
2304
- );
2305
- chart = {
2306
- vegaLiteSpec: chartResponse.chart ? {
2307
- ...chartResponse.chart,
2308
- data: { values: rows }
2309
- } : null,
2310
- specType: "vega-lite",
2311
- notes: chartResponse.notes
2312
- };
2313
- }
2324
+ const vizHints = hasVizMods ? buildVizHints(input.vizModifications) : {};
2325
+ const vizHintsForChart = chartType === "vizspec" ? vizHints : stripVizSpecOnlyHints(vizHints);
2326
+ if (chartType === "vizspec") {
2327
+ const vizspecResponse = await client.post(
2328
+ "/vizspec",
2329
+ {
2330
+ question: finalQuestion,
2331
+ sql: finalSql,
2332
+ rationale,
2333
+ fields: execution.fields,
2334
+ rows: anonymizeResults(rows),
2335
+ max_retries: options?.chartMaxRetries ?? 3,
2336
+ query_id: queryId,
2337
+ // Include viz hints for the chart generator
2338
+ ...hasVizMods ? { encoding_hints: vizHintsForChart } : {},
2339
+ ...options?.supportedChartTypes?.length ? { supported_chart_types: options.supportedChartTypes } : {}
2340
+ },
2341
+ tenantId,
2342
+ options?.userId,
2343
+ options?.scopes,
2344
+ signal,
2345
+ sessionId
2346
+ );
2347
+ throwIfGenerationErrorResponse(vizspecResponse);
2348
+ chart = {
2349
+ vizSpec: vizspecResponse.spec,
2350
+ specType: "vizspec",
2351
+ notes: rows.length === 0 ? vizspecResponse.notes ?? "Query returned no rows." : vizspecResponse.notes
2352
+ };
2353
+ } else {
2354
+ const chartResponse = await client.post(
2355
+ "/chart",
2356
+ {
2357
+ question: finalQuestion,
2358
+ sql: finalSql,
2359
+ rationale,
2360
+ fields: execution.fields,
2361
+ rows: anonymizeResults(rows),
2362
+ max_retries: options?.chartMaxRetries ?? 3,
2363
+ query_id: queryId,
2364
+ // Include viz hints for the chart generator
2365
+ ...hasVizMods ? { encoding_hints: vizHintsForChart } : {}
2366
+ },
2367
+ tenantId,
2368
+ options?.userId,
2369
+ options?.scopes,
2370
+ signal,
2371
+ sessionId
2372
+ );
2373
+ throwIfGenerationErrorResponse(chartResponse);
2374
+ chart = {
2375
+ vegaLiteSpec: chartResponse.chart ? {
2376
+ ...chartResponse.chart,
2377
+ data: { values: rows }
2378
+ } : null,
2379
+ specType: "vega-lite",
2380
+ notes: rows.length === 0 ? chartResponse.notes ?? "Query returned no rows." : chartResponse.notes
2381
+ };
2314
2382
  }
2315
2383
  return {
2316
2384
  sql: finalSql,