@querypanel/node-sdk 1.2.9 → 1.3.0-beta.0
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 +265 -102
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +31 -8
- package/dist/index.d.ts +31 -8
- package/dist/index.js +262 -101
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -220,11 +220,8 @@ declare class PostgresAdapter implements DatabaseAdapter {
|
|
|
220
220
|
execute(sql: string, params?: Record<string, string | number | boolean | string[] | number[]>): Promise<DatabaseExecutionResult>;
|
|
221
221
|
private validateQueryTables;
|
|
222
222
|
/**
|
|
223
|
-
* Convert params to positional array for PostgreSQL.
|
|
224
|
-
*
|
|
225
|
-
* When the record has numeric keys ("1", "2", "3") — e.g. from mapGeneratedParams —
|
|
226
|
-
* use only those in order so placeholder order matches SQL. Otherwise fall back to
|
|
227
|
-
* named keys in alphabetical order for backward compatibility.
|
|
223
|
+
* Convert params to positional array for PostgreSQL ($1, $2, …).
|
|
224
|
+
* Values must align with v2 generation order via numeric keys from mapGeneratedParams.
|
|
228
225
|
*/
|
|
229
226
|
private convertNamedToPositionalParams;
|
|
230
227
|
validate(sql: string, params?: Record<string, string | number | boolean | string[] | number[]>): Promise<void>;
|
|
@@ -288,6 +285,9 @@ declare const QueryErrorCode: {
|
|
|
288
285
|
readonly SQL_VALIDATION_FAILED: "SQL_VALIDATION_FAILED";
|
|
289
286
|
readonly CONTEXT_RETRIEVAL_FAILED: "CONTEXT_RETRIEVAL_FAILED";
|
|
290
287
|
readonly CLARIFICATION_NEEDED: "CLARIFICATION_NEEDED";
|
|
288
|
+
readonly AI_PROVIDER_AUTH_FAILED: "AI_PROVIDER_AUTH_FAILED";
|
|
289
|
+
readonly AI_PROVIDER_RATE_LIMITED: "AI_PROVIDER_RATE_LIMITED";
|
|
290
|
+
readonly AI_PROVIDER_UNAVAILABLE: "AI_PROVIDER_UNAVAILABLE";
|
|
291
291
|
readonly INTERNAL_ERROR: "INTERNAL_ERROR";
|
|
292
292
|
readonly AUTHENTICATION_REQUIRED: "AUTHENTICATION_REQUIRED";
|
|
293
293
|
readonly VALIDATION_ERROR: "VALIDATION_ERROR";
|
|
@@ -299,7 +299,8 @@ type QueryErrorCode = (typeof QueryErrorCode)[keyof typeof QueryErrorCode];
|
|
|
299
299
|
declare class QueryPipelineError extends Error {
|
|
300
300
|
readonly code: QueryErrorCode;
|
|
301
301
|
readonly details?: Record<string, unknown> | undefined;
|
|
302
|
-
|
|
302
|
+
readonly status?: number | undefined;
|
|
303
|
+
constructor(message: string, code: QueryErrorCode, details?: Record<string, unknown> | undefined, status?: number | undefined);
|
|
303
304
|
/**
|
|
304
305
|
* Check if this is a moderation error
|
|
305
306
|
*/
|
|
@@ -320,6 +321,18 @@ declare class QueryPipelineError extends Error {
|
|
|
320
321
|
* Check if this is a clarification needed error (v2 pipeline)
|
|
321
322
|
*/
|
|
322
323
|
isClarificationNeeded(): boolean;
|
|
324
|
+
/**
|
|
325
|
+
* Check if this is a BYOK / provider credential error
|
|
326
|
+
*/
|
|
327
|
+
isAiProviderAuthError(): boolean;
|
|
328
|
+
/**
|
|
329
|
+
* Check if this is a BYOK / provider rate-limit error
|
|
330
|
+
*/
|
|
331
|
+
isAiProviderRateLimited(): boolean;
|
|
332
|
+
/**
|
|
333
|
+
* Check if this is any BYOK / provider error (auth, rate limit, or unavailable)
|
|
334
|
+
*/
|
|
335
|
+
isAiProviderError(): boolean;
|
|
323
336
|
}
|
|
324
337
|
|
|
325
338
|
type ParamValue = string | number | boolean | string[] | number[];
|
|
@@ -717,7 +730,7 @@ interface AskOptions {
|
|
|
717
730
|
*/
|
|
718
731
|
pipeline?: "v1" | "v2";
|
|
719
732
|
/**
|
|
720
|
-
* Optional
|
|
733
|
+
* Optional model id for v2 SQL generation (e.g. OpenAI or `gemini-*` when the API uses Gemini). Omit for server default.
|
|
721
734
|
*/
|
|
722
735
|
model?: string;
|
|
723
736
|
/**
|
|
@@ -1122,6 +1135,16 @@ declare class CallbackApiClient implements IQueryPanelApi {
|
|
|
1122
1135
|
delete<T = void>(path: string, tenantId: string, userId?: string, scopes?: string[], signal?: AbortSignal, sessionId?: string): Promise<T>;
|
|
1123
1136
|
}
|
|
1124
1137
|
|
|
1138
|
+
/**
|
|
1139
|
+
* Maps v2-style param metadata (array order = $1, $2, $3 in SQL) to a ParamRecord.
|
|
1140
|
+
* Numeric keys preserve placeholder order for PostgreSQL; named keys support tenant lookups.
|
|
1141
|
+
*/
|
|
1142
|
+
declare function mapGeneratedParams(params: Array<Record<string, unknown>>): ParamRecord;
|
|
1143
|
+
/**
|
|
1144
|
+
* Normalizes run-sql / dashboard request params into a ParamRecord.
|
|
1145
|
+
*/
|
|
1146
|
+
declare function normalizeSqlParamsInput(params: unknown[] | Record<string, unknown> | null | undefined): ParamRecord;
|
|
1147
|
+
|
|
1125
1148
|
/** Options when constructing the SDK with HTTP (default) or with a custom API implementation. */
|
|
1126
1149
|
interface QueryPanelSdkAPIOptions {
|
|
1127
1150
|
defaultTenantId?: string;
|
|
@@ -1934,4 +1957,4 @@ declare class QueryPanelSdkAPI {
|
|
|
1934
1957
|
}, signal?: AbortSignal): Promise<SdkDashboard[]>;
|
|
1935
1958
|
}
|
|
1936
1959
|
|
|
1937
|
-
export { ALL_VIZ_CHART_TYPES, type ActiveChartBulkGetResponse, type ActiveChartCreateInput, type ActiveChartListOptions, type ActiveChartUpdateInput, type AggregateOp, type AskOptions, type AskResponse, type AxisField, type AxisFieldInput, BigQueryAdapter, type BigQueryAdapterOptions, type BigQueryClientFn, type BigQueryQueryRequest, type BigQueryQueryResult, CallbackApiClient, type ChartBulkGetResponse, type ChartCreateInput, type ChartEncoding, type ChartEnvelope, type ChartListAllOptions, type ChartListOptions, type ChartModifyInput, type ChartModifyOptions, type ChartModifyResponse, type ChartSpec, type ChartType, type ChartUpdateInput, ClickHouseAdapter, type ClickHouseAdapterOptions, type ClickHouseClientFn, type ContextDocument, type DashboardCreateInput, type DashboardForkInput, type DashboardForkUpdateInput, type DashboardListOptions, type DashboardUpdateInput, type DatabaseAdapter, type DatabaseDialect, type DateRangeInput, type EncodingHints, type FieldRef, type FieldRefInput, type FieldType, type IQueryPanelApi, type IngestResponse, type IntentResult, type MetricEncoding, type MetricField, type MetricSpec, type PaginatedResponse$1 as PaginatedResponse, type PaginationInfo$1 as PaginationInfo, type PaginationQuery$1 as PaginationQuery, type ParamRecord, type ParamValue, type PipelineTrace, PostgresAdapter, type PostgresAdapterOptions, type PostgresClientFn, QueryErrorCode, QueryErrorCode as QueryErrorCodeType, QueryPanelSdkAPI, type QueryPanelSdkAPIOptions, QueryPipelineError, type RequestHandler, type RequestHandlerOptions, type RequestHandlerResult, type SchemaIntrospection, type SchemaSyncOptions, type SdkActiveChart, type SdkChart, type SdkDashboard, type SdkSession, type SdkSessionTurn, type SessionGetOptions, type SessionListOptions, type SessionUpdateInput, type SqlModifications, type StackingMode, type TableColumn, type TableEncoding, type TableSpec, type TimeUnit, type ValueFormat, type VizModifications, type VizSpec, type VizSpecGenerateInput, type VizSpecGenerateOptions, type VizSpecGeneratorInput, type VizSpecKind, type VizSpecResponse, type VizSpecResult, anonymizeResults };
|
|
1960
|
+
export { ALL_VIZ_CHART_TYPES, type ActiveChartBulkGetResponse, type ActiveChartCreateInput, type ActiveChartListOptions, type ActiveChartUpdateInput, type AggregateOp, type AskOptions, type AskResponse, type AxisField, type AxisFieldInput, BigQueryAdapter, type BigQueryAdapterOptions, type BigQueryClientFn, type BigQueryQueryRequest, type BigQueryQueryResult, CallbackApiClient, type ChartBulkGetResponse, type ChartCreateInput, type ChartEncoding, type ChartEnvelope, type ChartListAllOptions, type ChartListOptions, type ChartModifyInput, type ChartModifyOptions, type ChartModifyResponse, type ChartSpec, type ChartType, type ChartUpdateInput, ClickHouseAdapter, type ClickHouseAdapterOptions, type ClickHouseClientFn, type ContextDocument, type DashboardCreateInput, type DashboardForkInput, type DashboardForkUpdateInput, type DashboardListOptions, type DashboardUpdateInput, type DatabaseAdapter, type DatabaseDialect, type DateRangeInput, type EncodingHints, type FieldRef, type FieldRefInput, type FieldType, type IQueryPanelApi, type IngestResponse, type IntentResult, type MetricEncoding, type MetricField, type MetricSpec, type PaginatedResponse$1 as PaginatedResponse, type PaginationInfo$1 as PaginationInfo, type PaginationQuery$1 as PaginationQuery, type ParamRecord, type ParamValue, type PipelineTrace, PostgresAdapter, type PostgresAdapterOptions, type PostgresClientFn, QueryErrorCode, QueryErrorCode as QueryErrorCodeType, QueryPanelSdkAPI, type QueryPanelSdkAPIOptions, QueryPipelineError, type RequestHandler, type RequestHandlerOptions, type RequestHandlerResult, type SchemaIntrospection, type SchemaSyncOptions, type SdkActiveChart, type SdkChart, type SdkDashboard, type SdkSession, type SdkSessionTurn, type SessionGetOptions, type SessionListOptions, type SessionUpdateInput, type SqlModifications, type StackingMode, type TableColumn, type TableEncoding, type TableSpec, type TimeUnit, type ValueFormat, type VizModifications, type VizSpec, type VizSpecGenerateInput, type VizSpecGenerateOptions, type VizSpecGeneratorInput, type VizSpecKind, type VizSpecResponse, type VizSpecResult, anonymizeResults, mapGeneratedParams, normalizeSqlParamsInput };
|
package/dist/index.d.ts
CHANGED
|
@@ -220,11 +220,8 @@ declare class PostgresAdapter implements DatabaseAdapter {
|
|
|
220
220
|
execute(sql: string, params?: Record<string, string | number | boolean | string[] | number[]>): Promise<DatabaseExecutionResult>;
|
|
221
221
|
private validateQueryTables;
|
|
222
222
|
/**
|
|
223
|
-
* Convert params to positional array for PostgreSQL.
|
|
224
|
-
*
|
|
225
|
-
* When the record has numeric keys ("1", "2", "3") — e.g. from mapGeneratedParams —
|
|
226
|
-
* use only those in order so placeholder order matches SQL. Otherwise fall back to
|
|
227
|
-
* named keys in alphabetical order for backward compatibility.
|
|
223
|
+
* Convert params to positional array for PostgreSQL ($1, $2, …).
|
|
224
|
+
* Values must align with v2 generation order via numeric keys from mapGeneratedParams.
|
|
228
225
|
*/
|
|
229
226
|
private convertNamedToPositionalParams;
|
|
230
227
|
validate(sql: string, params?: Record<string, string | number | boolean | string[] | number[]>): Promise<void>;
|
|
@@ -288,6 +285,9 @@ declare const QueryErrorCode: {
|
|
|
288
285
|
readonly SQL_VALIDATION_FAILED: "SQL_VALIDATION_FAILED";
|
|
289
286
|
readonly CONTEXT_RETRIEVAL_FAILED: "CONTEXT_RETRIEVAL_FAILED";
|
|
290
287
|
readonly CLARIFICATION_NEEDED: "CLARIFICATION_NEEDED";
|
|
288
|
+
readonly AI_PROVIDER_AUTH_FAILED: "AI_PROVIDER_AUTH_FAILED";
|
|
289
|
+
readonly AI_PROVIDER_RATE_LIMITED: "AI_PROVIDER_RATE_LIMITED";
|
|
290
|
+
readonly AI_PROVIDER_UNAVAILABLE: "AI_PROVIDER_UNAVAILABLE";
|
|
291
291
|
readonly INTERNAL_ERROR: "INTERNAL_ERROR";
|
|
292
292
|
readonly AUTHENTICATION_REQUIRED: "AUTHENTICATION_REQUIRED";
|
|
293
293
|
readonly VALIDATION_ERROR: "VALIDATION_ERROR";
|
|
@@ -299,7 +299,8 @@ type QueryErrorCode = (typeof QueryErrorCode)[keyof typeof QueryErrorCode];
|
|
|
299
299
|
declare class QueryPipelineError extends Error {
|
|
300
300
|
readonly code: QueryErrorCode;
|
|
301
301
|
readonly details?: Record<string, unknown> | undefined;
|
|
302
|
-
|
|
302
|
+
readonly status?: number | undefined;
|
|
303
|
+
constructor(message: string, code: QueryErrorCode, details?: Record<string, unknown> | undefined, status?: number | undefined);
|
|
303
304
|
/**
|
|
304
305
|
* Check if this is a moderation error
|
|
305
306
|
*/
|
|
@@ -320,6 +321,18 @@ declare class QueryPipelineError extends Error {
|
|
|
320
321
|
* Check if this is a clarification needed error (v2 pipeline)
|
|
321
322
|
*/
|
|
322
323
|
isClarificationNeeded(): boolean;
|
|
324
|
+
/**
|
|
325
|
+
* Check if this is a BYOK / provider credential error
|
|
326
|
+
*/
|
|
327
|
+
isAiProviderAuthError(): boolean;
|
|
328
|
+
/**
|
|
329
|
+
* Check if this is a BYOK / provider rate-limit error
|
|
330
|
+
*/
|
|
331
|
+
isAiProviderRateLimited(): boolean;
|
|
332
|
+
/**
|
|
333
|
+
* Check if this is any BYOK / provider error (auth, rate limit, or unavailable)
|
|
334
|
+
*/
|
|
335
|
+
isAiProviderError(): boolean;
|
|
323
336
|
}
|
|
324
337
|
|
|
325
338
|
type ParamValue = string | number | boolean | string[] | number[];
|
|
@@ -717,7 +730,7 @@ interface AskOptions {
|
|
|
717
730
|
*/
|
|
718
731
|
pipeline?: "v1" | "v2";
|
|
719
732
|
/**
|
|
720
|
-
* Optional
|
|
733
|
+
* Optional model id for v2 SQL generation (e.g. OpenAI or `gemini-*` when the API uses Gemini). Omit for server default.
|
|
721
734
|
*/
|
|
722
735
|
model?: string;
|
|
723
736
|
/**
|
|
@@ -1122,6 +1135,16 @@ declare class CallbackApiClient implements IQueryPanelApi {
|
|
|
1122
1135
|
delete<T = void>(path: string, tenantId: string, userId?: string, scopes?: string[], signal?: AbortSignal, sessionId?: string): Promise<T>;
|
|
1123
1136
|
}
|
|
1124
1137
|
|
|
1138
|
+
/**
|
|
1139
|
+
* Maps v2-style param metadata (array order = $1, $2, $3 in SQL) to a ParamRecord.
|
|
1140
|
+
* Numeric keys preserve placeholder order for PostgreSQL; named keys support tenant lookups.
|
|
1141
|
+
*/
|
|
1142
|
+
declare function mapGeneratedParams(params: Array<Record<string, unknown>>): ParamRecord;
|
|
1143
|
+
/**
|
|
1144
|
+
* Normalizes run-sql / dashboard request params into a ParamRecord.
|
|
1145
|
+
*/
|
|
1146
|
+
declare function normalizeSqlParamsInput(params: unknown[] | Record<string, unknown> | null | undefined): ParamRecord;
|
|
1147
|
+
|
|
1125
1148
|
/** Options when constructing the SDK with HTTP (default) or with a custom API implementation. */
|
|
1126
1149
|
interface QueryPanelSdkAPIOptions {
|
|
1127
1150
|
defaultTenantId?: string;
|
|
@@ -1934,4 +1957,4 @@ declare class QueryPanelSdkAPI {
|
|
|
1934
1957
|
}, signal?: AbortSignal): Promise<SdkDashboard[]>;
|
|
1935
1958
|
}
|
|
1936
1959
|
|
|
1937
|
-
export { ALL_VIZ_CHART_TYPES, type ActiveChartBulkGetResponse, type ActiveChartCreateInput, type ActiveChartListOptions, type ActiveChartUpdateInput, type AggregateOp, type AskOptions, type AskResponse, type AxisField, type AxisFieldInput, BigQueryAdapter, type BigQueryAdapterOptions, type BigQueryClientFn, type BigQueryQueryRequest, type BigQueryQueryResult, CallbackApiClient, type ChartBulkGetResponse, type ChartCreateInput, type ChartEncoding, type ChartEnvelope, type ChartListAllOptions, type ChartListOptions, type ChartModifyInput, type ChartModifyOptions, type ChartModifyResponse, type ChartSpec, type ChartType, type ChartUpdateInput, ClickHouseAdapter, type ClickHouseAdapterOptions, type ClickHouseClientFn, type ContextDocument, type DashboardCreateInput, type DashboardForkInput, type DashboardForkUpdateInput, type DashboardListOptions, type DashboardUpdateInput, type DatabaseAdapter, type DatabaseDialect, type DateRangeInput, type EncodingHints, type FieldRef, type FieldRefInput, type FieldType, type IQueryPanelApi, type IngestResponse, type IntentResult, type MetricEncoding, type MetricField, type MetricSpec, type PaginatedResponse$1 as PaginatedResponse, type PaginationInfo$1 as PaginationInfo, type PaginationQuery$1 as PaginationQuery, type ParamRecord, type ParamValue, type PipelineTrace, PostgresAdapter, type PostgresAdapterOptions, type PostgresClientFn, QueryErrorCode, QueryErrorCode as QueryErrorCodeType, QueryPanelSdkAPI, type QueryPanelSdkAPIOptions, QueryPipelineError, type RequestHandler, type RequestHandlerOptions, type RequestHandlerResult, type SchemaIntrospection, type SchemaSyncOptions, type SdkActiveChart, type SdkChart, type SdkDashboard, type SdkSession, type SdkSessionTurn, type SessionGetOptions, type SessionListOptions, type SessionUpdateInput, type SqlModifications, type StackingMode, type TableColumn, type TableEncoding, type TableSpec, type TimeUnit, type ValueFormat, type VizModifications, type VizSpec, type VizSpecGenerateInput, type VizSpecGenerateOptions, type VizSpecGeneratorInput, type VizSpecKind, type VizSpecResponse, type VizSpecResult, anonymizeResults };
|
|
1960
|
+
export { ALL_VIZ_CHART_TYPES, type ActiveChartBulkGetResponse, type ActiveChartCreateInput, type ActiveChartListOptions, type ActiveChartUpdateInput, type AggregateOp, type AskOptions, type AskResponse, type AxisField, type AxisFieldInput, BigQueryAdapter, type BigQueryAdapterOptions, type BigQueryClientFn, type BigQueryQueryRequest, type BigQueryQueryResult, CallbackApiClient, type ChartBulkGetResponse, type ChartCreateInput, type ChartEncoding, type ChartEnvelope, type ChartListAllOptions, type ChartListOptions, type ChartModifyInput, type ChartModifyOptions, type ChartModifyResponse, type ChartSpec, type ChartType, type ChartUpdateInput, ClickHouseAdapter, type ClickHouseAdapterOptions, type ClickHouseClientFn, type ContextDocument, type DashboardCreateInput, type DashboardForkInput, type DashboardForkUpdateInput, type DashboardListOptions, type DashboardUpdateInput, type DatabaseAdapter, type DatabaseDialect, type DateRangeInput, type EncodingHints, type FieldRef, type FieldRefInput, type FieldType, type IQueryPanelApi, type IngestResponse, type IntentResult, type MetricEncoding, type MetricField, type MetricSpec, type PaginatedResponse$1 as PaginatedResponse, type PaginationInfo$1 as PaginationInfo, type PaginationQuery$1 as PaginationQuery, type ParamRecord, type ParamValue, type PipelineTrace, PostgresAdapter, type PostgresAdapterOptions, type PostgresClientFn, QueryErrorCode, QueryErrorCode as QueryErrorCodeType, QueryPanelSdkAPI, type QueryPanelSdkAPIOptions, QueryPipelineError, type RequestHandler, type RequestHandlerOptions, type RequestHandlerResult, type SchemaIntrospection, type SchemaSyncOptions, type SdkActiveChart, type SdkChart, type SdkDashboard, type SdkSession, type SdkSessionTurn, type SessionGetOptions, type SessionListOptions, type SessionUpdateInput, type SqlModifications, type StackingMode, type TableColumn, type TableEncoding, type TableSpec, type TimeUnit, type ValueFormat, type VizModifications, type VizSpec, type VizSpecGenerateInput, type VizSpecGenerateOptions, type VizSpecGeneratorInput, type VizSpecKind, type VizSpecResponse, type VizSpecResult, anonymizeResults, mapGeneratedParams, normalizeSqlParamsInput };
|
package/dist/index.js
CHANGED
|
@@ -453,6 +453,37 @@ function toNumber(value) {
|
|
|
453
453
|
}
|
|
454
454
|
|
|
455
455
|
// src/adapters/postgres.ts
|
|
456
|
+
function maxPostgresPlaceholderIndex(sql) {
|
|
457
|
+
let max = 0;
|
|
458
|
+
for (const match of sql.matchAll(/\$(\d+)\b/g)) {
|
|
459
|
+
const index = Number.parseInt(match[1], 10);
|
|
460
|
+
if (Number.isFinite(index) && index > max) {
|
|
461
|
+
max = index;
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
return max;
|
|
465
|
+
}
|
|
466
|
+
function filterParamsForPostgresSql(sql, params) {
|
|
467
|
+
if (!params || Object.keys(params).length === 0) {
|
|
468
|
+
return void 0;
|
|
469
|
+
}
|
|
470
|
+
const placeholderCount = maxPostgresPlaceholderIndex(sql);
|
|
471
|
+
if (placeholderCount === 0) {
|
|
472
|
+
return void 0;
|
|
473
|
+
}
|
|
474
|
+
const hasNumericKeys = Object.keys(params).some((key) => /^\d+$/.test(key));
|
|
475
|
+
if (hasNumericKeys) {
|
|
476
|
+
const filtered = {};
|
|
477
|
+
for (let index = 1; index <= placeholderCount; index += 1) {
|
|
478
|
+
const key = String(index);
|
|
479
|
+
if (key in params) {
|
|
480
|
+
filtered[key] = params[key];
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
return Object.keys(filtered).length > 0 ? filtered : void 0;
|
|
484
|
+
}
|
|
485
|
+
return params;
|
|
486
|
+
}
|
|
456
487
|
var PostgresAdapter = class {
|
|
457
488
|
constructor(clientFn, options = {}) {
|
|
458
489
|
this.clientFn = clientFn;
|
|
@@ -470,9 +501,10 @@ var PostgresAdapter = class {
|
|
|
470
501
|
if (this.allowedTables) {
|
|
471
502
|
this.validateQueryTables(sql);
|
|
472
503
|
}
|
|
504
|
+
const boundParams = filterParamsForPostgresSql(sql, params);
|
|
473
505
|
let paramArray;
|
|
474
|
-
if (
|
|
475
|
-
paramArray = this.convertNamedToPositionalParams(
|
|
506
|
+
if (boundParams) {
|
|
507
|
+
paramArray = this.convertNamedToPositionalParams(sql, boundParams);
|
|
476
508
|
}
|
|
477
509
|
const result = await this.clientFn(sql, paramArray);
|
|
478
510
|
const fields = result.fields.map((f) => f.name);
|
|
@@ -502,36 +534,43 @@ var PostgresAdapter = class {
|
|
|
502
534
|
}
|
|
503
535
|
}
|
|
504
536
|
/**
|
|
505
|
-
* Convert params to positional array for PostgreSQL.
|
|
506
|
-
*
|
|
507
|
-
* When the record has numeric keys ("1", "2", "3") — e.g. from mapGeneratedParams —
|
|
508
|
-
* use only those in order so placeholder order matches SQL. Otherwise fall back to
|
|
509
|
-
* named keys in alphabetical order for backward compatibility.
|
|
537
|
+
* Convert params to positional array for PostgreSQL ($1, $2, …).
|
|
538
|
+
* Values must align with v2 generation order via numeric keys from mapGeneratedParams.
|
|
510
539
|
*/
|
|
511
|
-
convertNamedToPositionalParams(params) {
|
|
512
|
-
const
|
|
513
|
-
if (
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
540
|
+
convertNamedToPositionalParams(sql, params) {
|
|
541
|
+
const placeholderCount = maxPostgresPlaceholderIndex(sql);
|
|
542
|
+
if (placeholderCount === 0) {
|
|
543
|
+
return [];
|
|
544
|
+
}
|
|
545
|
+
const positionalParams = [];
|
|
546
|
+
for (let index = 1; index <= placeholderCount; index += 1) {
|
|
547
|
+
const key = String(index);
|
|
548
|
+
let val = params[key];
|
|
549
|
+
if (val === void 0 && placeholderCount === 1) {
|
|
550
|
+
const namedKeys = Object.keys(params).filter((k) => !/^\d+$/.test(k));
|
|
551
|
+
if (namedKeys.length === 1) {
|
|
552
|
+
val = params[namedKeys[0]];
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
if (val === void 0) {
|
|
556
|
+
throw new Error(`Missing value for PostgreSQL parameter $${index}`);
|
|
557
|
+
}
|
|
558
|
+
if (typeof val === "string") {
|
|
559
|
+
const match = val.match(/^<([a-zA-Z0-9_]+)>$/);
|
|
560
|
+
const namedKey = match?.[1];
|
|
561
|
+
if (namedKey && namedKey in params) {
|
|
562
|
+
val = params[namedKey];
|
|
523
563
|
}
|
|
524
|
-
positionalParams.push(val);
|
|
525
564
|
}
|
|
526
|
-
|
|
565
|
+
positionalParams.push(val);
|
|
527
566
|
}
|
|
528
|
-
|
|
529
|
-
return namedKeys.map((key) => params[key]);
|
|
567
|
+
return positionalParams;
|
|
530
568
|
}
|
|
531
569
|
async validate(sql, params) {
|
|
570
|
+
const boundParams = filterParamsForPostgresSql(sql, params);
|
|
532
571
|
let paramArray;
|
|
533
|
-
if (
|
|
534
|
-
paramArray = this.convertNamedToPositionalParams(
|
|
572
|
+
if (boundParams) {
|
|
573
|
+
paramArray = this.convertNamedToPositionalParams(sql, boundParams);
|
|
535
574
|
}
|
|
536
575
|
await this.clientFn(`EXPLAIN ${sql}`, paramArray);
|
|
537
576
|
}
|
|
@@ -705,6 +744,118 @@ function sanitize2(value) {
|
|
|
705
744
|
|
|
706
745
|
// src/core/client.ts
|
|
707
746
|
import crypto from "crypto";
|
|
747
|
+
|
|
748
|
+
// src/errors.ts
|
|
749
|
+
var QueryErrorCode = {
|
|
750
|
+
// Moderation errors
|
|
751
|
+
MODERATION_FAILED: "MODERATION_FAILED",
|
|
752
|
+
// Guardrail errors
|
|
753
|
+
RELEVANCE_CHECK_FAILED: "RELEVANCE_CHECK_FAILED",
|
|
754
|
+
SECURITY_CHECK_FAILED: "SECURITY_CHECK_FAILED",
|
|
755
|
+
// SQL generation errors
|
|
756
|
+
SQL_GENERATION_FAILED: "SQL_GENERATION_FAILED",
|
|
757
|
+
// SQL validation errors
|
|
758
|
+
SQL_VALIDATION_FAILED: "SQL_VALIDATION_FAILED",
|
|
759
|
+
// Context retrieval errors
|
|
760
|
+
CONTEXT_RETRIEVAL_FAILED: "CONTEXT_RETRIEVAL_FAILED",
|
|
761
|
+
// Clarification errors (v2)
|
|
762
|
+
CLARIFICATION_NEEDED: "CLARIFICATION_NEEDED",
|
|
763
|
+
// Bring-your-own-key / provider errors
|
|
764
|
+
AI_PROVIDER_AUTH_FAILED: "AI_PROVIDER_AUTH_FAILED",
|
|
765
|
+
AI_PROVIDER_RATE_LIMITED: "AI_PROVIDER_RATE_LIMITED",
|
|
766
|
+
AI_PROVIDER_UNAVAILABLE: "AI_PROVIDER_UNAVAILABLE",
|
|
767
|
+
// General errors
|
|
768
|
+
INTERNAL_ERROR: "INTERNAL_ERROR",
|
|
769
|
+
AUTHENTICATION_REQUIRED: "AUTHENTICATION_REQUIRED",
|
|
770
|
+
VALIDATION_ERROR: "VALIDATION_ERROR"
|
|
771
|
+
};
|
|
772
|
+
function isQueryErrorCode(code) {
|
|
773
|
+
return typeof code === "string" && Object.values(QueryErrorCode).includes(code);
|
|
774
|
+
}
|
|
775
|
+
function isAiProviderErrorCode(code) {
|
|
776
|
+
return code === QueryErrorCode.AI_PROVIDER_AUTH_FAILED || code === QueryErrorCode.AI_PROVIDER_RATE_LIMITED || code === QueryErrorCode.AI_PROVIDER_UNAVAILABLE;
|
|
777
|
+
}
|
|
778
|
+
function isAiProviderPipelineError(error) {
|
|
779
|
+
if (error instanceof QueryPipelineError) {
|
|
780
|
+
return isAiProviderErrorCode(error.code);
|
|
781
|
+
}
|
|
782
|
+
if (error && typeof error === "object" && "code" in error) {
|
|
783
|
+
return isAiProviderErrorCode(error.code);
|
|
784
|
+
}
|
|
785
|
+
return false;
|
|
786
|
+
}
|
|
787
|
+
function throwIfGenerationErrorResponse(response) {
|
|
788
|
+
if (!response || typeof response !== "object") {
|
|
789
|
+
return;
|
|
790
|
+
}
|
|
791
|
+
const record = response;
|
|
792
|
+
if (typeof record.error !== "string") {
|
|
793
|
+
return;
|
|
794
|
+
}
|
|
795
|
+
if (isQueryErrorCode(record.code)) {
|
|
796
|
+
throw new QueryPipelineError(record.error, record.code);
|
|
797
|
+
}
|
|
798
|
+
throw new Error(record.error);
|
|
799
|
+
}
|
|
800
|
+
var QueryPipelineError = class extends Error {
|
|
801
|
+
constructor(message, code, details, status) {
|
|
802
|
+
super(message);
|
|
803
|
+
this.code = code;
|
|
804
|
+
this.details = details;
|
|
805
|
+
this.status = status;
|
|
806
|
+
this.name = "QueryPipelineError";
|
|
807
|
+
}
|
|
808
|
+
/**
|
|
809
|
+
* Check if this is a moderation error
|
|
810
|
+
*/
|
|
811
|
+
isModeration() {
|
|
812
|
+
return this.code === QueryErrorCode.MODERATION_FAILED;
|
|
813
|
+
}
|
|
814
|
+
/**
|
|
815
|
+
* Check if this is a relevance error (question not related to database)
|
|
816
|
+
*/
|
|
817
|
+
isRelevanceError() {
|
|
818
|
+
return this.code === QueryErrorCode.RELEVANCE_CHECK_FAILED;
|
|
819
|
+
}
|
|
820
|
+
/**
|
|
821
|
+
* Check if this is a security error (SQL injection, prompt injection, etc.)
|
|
822
|
+
*/
|
|
823
|
+
isSecurityError() {
|
|
824
|
+
return this.code === QueryErrorCode.SECURITY_CHECK_FAILED;
|
|
825
|
+
}
|
|
826
|
+
/**
|
|
827
|
+
* Check if this is any guardrail error (relevance or security)
|
|
828
|
+
*/
|
|
829
|
+
isGuardrailError() {
|
|
830
|
+
return this.isRelevanceError() || this.isSecurityError();
|
|
831
|
+
}
|
|
832
|
+
/**
|
|
833
|
+
* Check if this is a clarification needed error (v2 pipeline)
|
|
834
|
+
*/
|
|
835
|
+
isClarificationNeeded() {
|
|
836
|
+
return this.code === QueryErrorCode.CLARIFICATION_NEEDED;
|
|
837
|
+
}
|
|
838
|
+
/**
|
|
839
|
+
* Check if this is a BYOK / provider credential error
|
|
840
|
+
*/
|
|
841
|
+
isAiProviderAuthError() {
|
|
842
|
+
return this.code === QueryErrorCode.AI_PROVIDER_AUTH_FAILED;
|
|
843
|
+
}
|
|
844
|
+
/**
|
|
845
|
+
* Check if this is a BYOK / provider rate-limit error
|
|
846
|
+
*/
|
|
847
|
+
isAiProviderRateLimited() {
|
|
848
|
+
return this.code === QueryErrorCode.AI_PROVIDER_RATE_LIMITED;
|
|
849
|
+
}
|
|
850
|
+
/**
|
|
851
|
+
* Check if this is any BYOK / provider error (auth, rate limit, or unavailable)
|
|
852
|
+
*/
|
|
853
|
+
isAiProviderError() {
|
|
854
|
+
return isAiProviderErrorCode(this.code);
|
|
855
|
+
}
|
|
856
|
+
};
|
|
857
|
+
|
|
858
|
+
// src/core/client.ts
|
|
708
859
|
var ApiClient = class {
|
|
709
860
|
constructor(baseUrl, privateKey, organizationId, options) {
|
|
710
861
|
this.cryptoKey = null;
|
|
@@ -836,10 +987,18 @@ var ApiClient = class {
|
|
|
836
987
|
json = void 0;
|
|
837
988
|
}
|
|
838
989
|
if (!response.ok) {
|
|
839
|
-
const
|
|
840
|
-
|
|
841
|
-
|
|
990
|
+
const message = json?.error || response.statusText || "Request failed";
|
|
991
|
+
if (isQueryErrorCode(json?.code)) {
|
|
992
|
+
throw new QueryPipelineError(
|
|
993
|
+
message,
|
|
994
|
+
json.code,
|
|
995
|
+
json?.details,
|
|
996
|
+
response.status
|
|
997
|
+
);
|
|
998
|
+
}
|
|
999
|
+
const error = new Error(message);
|
|
842
1000
|
error.status = response.status;
|
|
1001
|
+
if (json?.code) error.code = json.code;
|
|
843
1002
|
if (json?.details) error.details = json.details;
|
|
844
1003
|
throw error;
|
|
845
1004
|
}
|
|
@@ -1054,6 +1213,45 @@ var CallbackApiClient = class {
|
|
|
1054
1213
|
}
|
|
1055
1214
|
};
|
|
1056
1215
|
|
|
1216
|
+
// src/core/map-generated-params.ts
|
|
1217
|
+
function mapGeneratedParams(params) {
|
|
1218
|
+
const record = {};
|
|
1219
|
+
params.forEach((param, index) => {
|
|
1220
|
+
const value = param.value;
|
|
1221
|
+
if (value === void 0) {
|
|
1222
|
+
return;
|
|
1223
|
+
}
|
|
1224
|
+
record[String(index + 1)] = value;
|
|
1225
|
+
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);
|
|
1226
|
+
const key = nameCandidate.replace(/[{}:$]/g, "").trim();
|
|
1227
|
+
record[key] = value;
|
|
1228
|
+
});
|
|
1229
|
+
return record;
|
|
1230
|
+
}
|
|
1231
|
+
function normalizeSqlParamsInput(params) {
|
|
1232
|
+
if (params == null) {
|
|
1233
|
+
return {};
|
|
1234
|
+
}
|
|
1235
|
+
if (Array.isArray(params)) {
|
|
1236
|
+
if (params.length === 0) {
|
|
1237
|
+
return {};
|
|
1238
|
+
}
|
|
1239
|
+
const first = params[0];
|
|
1240
|
+
if (first && typeof first === "object" && "value" in first) {
|
|
1241
|
+
return mapGeneratedParams(params);
|
|
1242
|
+
}
|
|
1243
|
+
const positional = {};
|
|
1244
|
+
params.forEach((value, index) => {
|
|
1245
|
+
positional[String(index + 1)] = value;
|
|
1246
|
+
});
|
|
1247
|
+
return positional;
|
|
1248
|
+
}
|
|
1249
|
+
if (typeof params === "object") {
|
|
1250
|
+
return params;
|
|
1251
|
+
}
|
|
1252
|
+
return {};
|
|
1253
|
+
}
|
|
1254
|
+
|
|
1057
1255
|
// src/core/query-engine.ts
|
|
1058
1256
|
var QueryEngine = class {
|
|
1059
1257
|
constructor() {
|
|
@@ -1124,18 +1322,7 @@ var QueryEngine = class {
|
|
|
1124
1322
|
* - Named keys remain for tenant isolation / other lookups.
|
|
1125
1323
|
*/
|
|
1126
1324
|
mapGeneratedParams(params) {
|
|
1127
|
-
|
|
1128
|
-
params.forEach((param, index) => {
|
|
1129
|
-
const value = param.value;
|
|
1130
|
-
if (value === void 0) {
|
|
1131
|
-
return;
|
|
1132
|
-
}
|
|
1133
|
-
record[String(index + 1)] = value;
|
|
1134
|
-
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);
|
|
1135
|
-
const key = nameCandidate.replace(/[{}:$]/g, "").trim();
|
|
1136
|
-
record[key] = value;
|
|
1137
|
-
});
|
|
1138
|
-
return record;
|
|
1325
|
+
return mapGeneratedParams(params);
|
|
1139
1326
|
}
|
|
1140
1327
|
ensureTenantIsolation(sql, params, metadata, tenantId) {
|
|
1141
1328
|
if (!metadata.tenantFieldName || metadata.enforceTenantIsolation === false) {
|
|
@@ -1155,8 +1342,10 @@ var QueryEngine = class {
|
|
|
1155
1342
|
params[tenantField] = tenantId;
|
|
1156
1343
|
tenantPredicate = `${tenantField} = @${tenantField}`;
|
|
1157
1344
|
} else {
|
|
1158
|
-
const
|
|
1159
|
-
|
|
1345
|
+
const paramIndex = this.nextPostgresPlaceholderIndex(sql, params);
|
|
1346
|
+
params[String(paramIndex)] = tenantId;
|
|
1347
|
+
params[tenantField] = tenantId;
|
|
1348
|
+
tenantPredicate = `${tenantField} = $${paramIndex}`;
|
|
1160
1349
|
}
|
|
1161
1350
|
if (/\bwhere\b/i.test(sql)) {
|
|
1162
1351
|
return sql.replace(
|
|
@@ -1166,64 +1355,22 @@ var QueryEngine = class {
|
|
|
1166
1355
|
}
|
|
1167
1356
|
return `${sql} WHERE ${tenantPredicate}`;
|
|
1168
1357
|
}
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
CLARIFICATION_NEEDED: "CLARIFICATION_NEEDED",
|
|
1186
|
-
// General errors
|
|
1187
|
-
INTERNAL_ERROR: "INTERNAL_ERROR",
|
|
1188
|
-
AUTHENTICATION_REQUIRED: "AUTHENTICATION_REQUIRED",
|
|
1189
|
-
VALIDATION_ERROR: "VALIDATION_ERROR"
|
|
1190
|
-
};
|
|
1191
|
-
var QueryPipelineError = class extends Error {
|
|
1192
|
-
constructor(message, code, details) {
|
|
1193
|
-
super(message);
|
|
1194
|
-
this.code = code;
|
|
1195
|
-
this.details = details;
|
|
1196
|
-
this.name = "QueryPipelineError";
|
|
1197
|
-
}
|
|
1198
|
-
/**
|
|
1199
|
-
* Check if this is a moderation error
|
|
1200
|
-
*/
|
|
1201
|
-
isModeration() {
|
|
1202
|
-
return this.code === QueryErrorCode.MODERATION_FAILED;
|
|
1203
|
-
}
|
|
1204
|
-
/**
|
|
1205
|
-
* Check if this is a relevance error (question not related to database)
|
|
1206
|
-
*/
|
|
1207
|
-
isRelevanceError() {
|
|
1208
|
-
return this.code === QueryErrorCode.RELEVANCE_CHECK_FAILED;
|
|
1209
|
-
}
|
|
1210
|
-
/**
|
|
1211
|
-
* Check if this is a security error (SQL injection, prompt injection, etc.)
|
|
1212
|
-
*/
|
|
1213
|
-
isSecurityError() {
|
|
1214
|
-
return this.code === QueryErrorCode.SECURITY_CHECK_FAILED;
|
|
1215
|
-
}
|
|
1216
|
-
/**
|
|
1217
|
-
* Check if this is any guardrail error (relevance or security)
|
|
1218
|
-
*/
|
|
1219
|
-
isGuardrailError() {
|
|
1220
|
-
return this.isRelevanceError() || this.isSecurityError();
|
|
1221
|
-
}
|
|
1222
|
-
/**
|
|
1223
|
-
* Check if this is a clarification needed error (v2 pipeline)
|
|
1224
|
-
*/
|
|
1225
|
-
isClarificationNeeded() {
|
|
1226
|
-
return this.code === QueryErrorCode.CLARIFICATION_NEEDED;
|
|
1358
|
+
nextPostgresPlaceholderIndex(sql, params) {
|
|
1359
|
+
let max = 0;
|
|
1360
|
+
for (const match of sql.matchAll(/\$(\d+)\b/g)) {
|
|
1361
|
+
const index = Number.parseInt(match[1], 10);
|
|
1362
|
+
if (Number.isFinite(index) && index > max) {
|
|
1363
|
+
max = index;
|
|
1364
|
+
}
|
|
1365
|
+
}
|
|
1366
|
+
if (max > 0) {
|
|
1367
|
+
return max + 1;
|
|
1368
|
+
}
|
|
1369
|
+
const numericKeys = Object.keys(params).filter((key) => /^\d+$/.test(key)).map((key) => Number.parseInt(key, 10)).filter((index) => Number.isFinite(index));
|
|
1370
|
+
if (numericKeys.length > 0) {
|
|
1371
|
+
return Math.max(...numericKeys) + 1;
|
|
1372
|
+
}
|
|
1373
|
+
return 1;
|
|
1227
1374
|
}
|
|
1228
1375
|
};
|
|
1229
1376
|
|
|
@@ -1759,6 +1906,7 @@ function resolveTenantId4(client, tenantId) {
|
|
|
1759
1906
|
function buildSchemaRequest(databaseName, adapter, introspection, metadata) {
|
|
1760
1907
|
const dialect = adapter.getDialect();
|
|
1761
1908
|
const tables = introspection.tables.map((table) => ({
|
|
1909
|
+
schema_name: table.schema,
|
|
1762
1910
|
table_name: table.name,
|
|
1763
1911
|
description: table.comment ?? `Table ${table.name}`,
|
|
1764
1912
|
columns: table.columns.map((column) => ({
|
|
@@ -1884,6 +2032,7 @@ async function ask(client, queryEngine, question, options, signal) {
|
|
|
1884
2032
|
signal,
|
|
1885
2033
|
sessionId
|
|
1886
2034
|
);
|
|
2035
|
+
throwIfGenerationErrorResponse(vizspecResponse);
|
|
1887
2036
|
chart = {
|
|
1888
2037
|
vizSpec: vizspecResponse.spec,
|
|
1889
2038
|
specType: "vizspec",
|
|
@@ -1907,6 +2056,7 @@ async function ask(client, queryEngine, question, options, signal) {
|
|
|
1907
2056
|
signal,
|
|
1908
2057
|
sessionId
|
|
1909
2058
|
);
|
|
2059
|
+
throwIfGenerationErrorResponse(chartResponse);
|
|
1910
2060
|
chart = {
|
|
1911
2061
|
vegaLiteSpec: chartResponse.chart ? {
|
|
1912
2062
|
...chartResponse.chart,
|
|
@@ -1934,6 +2084,13 @@ async function ask(client, queryEngine, question, options, signal) {
|
|
|
1934
2084
|
trace: queryResponse.data.trace
|
|
1935
2085
|
};
|
|
1936
2086
|
} catch (error) {
|
|
2087
|
+
if (isAiProviderPipelineError(error)) {
|
|
2088
|
+
if (error instanceof QueryPipelineError) {
|
|
2089
|
+
throw error;
|
|
2090
|
+
}
|
|
2091
|
+
const providerError = error;
|
|
2092
|
+
throw new QueryPipelineError(providerError.message, providerError.code);
|
|
2093
|
+
}
|
|
1937
2094
|
attempt++;
|
|
1938
2095
|
if (attempt > maxRetry) {
|
|
1939
2096
|
throw error;
|
|
@@ -2230,6 +2387,7 @@ async function modifyChart(client, queryEngine, input, options, signal) {
|
|
|
2230
2387
|
signal,
|
|
2231
2388
|
sessionId
|
|
2232
2389
|
);
|
|
2390
|
+
throwIfGenerationErrorResponse(vizspecResponse);
|
|
2233
2391
|
chart = {
|
|
2234
2392
|
vizSpec: vizspecResponse.spec,
|
|
2235
2393
|
specType: "vizspec",
|
|
@@ -2255,6 +2413,7 @@ async function modifyChart(client, queryEngine, input, options, signal) {
|
|
|
2255
2413
|
signal,
|
|
2256
2414
|
sessionId
|
|
2257
2415
|
);
|
|
2416
|
+
throwIfGenerationErrorResponse(chartResponse);
|
|
2258
2417
|
chart = {
|
|
2259
2418
|
vegaLiteSpec: chartResponse.chart ? {
|
|
2260
2419
|
...chartResponse.chart,
|
|
@@ -3423,6 +3582,8 @@ export {
|
|
|
3423
3582
|
QueryErrorCode,
|
|
3424
3583
|
QueryPanelSdkAPI,
|
|
3425
3584
|
QueryPipelineError,
|
|
3426
|
-
anonymizeResults
|
|
3585
|
+
anonymizeResults,
|
|
3586
|
+
mapGeneratedParams,
|
|
3587
|
+
normalizeSqlParamsInput
|
|
3427
3588
|
};
|
|
3428
3589
|
//# sourceMappingURL=index.js.map
|