@askdb/core 1.0.0-beta.41 → 1.0.0-beta.43
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 +44 -4
- package/dist/ask.d.ts +129 -2
- package/dist/ask.d.ts.map +1 -1
- package/dist/ask.js +391 -15
- package/dist/ask.js.map +1 -1
- package/dist/errors.d.ts +87 -2
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +29 -0
- package/dist/errors.js.map +1 -1
- package/dist/index.d.ts +8 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -2
- package/dist/index.js.map +1 -1
- package/dist/logging/log-events.d.ts +13 -0
- package/dist/logging/log-events.d.ts.map +1 -1
- package/dist/logging/log-events.js +13 -0
- package/dist/logging/log-events.js.map +1 -1
- package/dist/schema/v2/index.d.ts +1 -1
- package/dist/schema/v2/index.d.ts.map +1 -1
- package/dist/schema/v2/loader.d.ts +9 -1
- package/dist/schema/v2/loader.d.ts.map +1 -1
- package/dist/schema/v2/loader.js +171 -49
- package/dist/schema/v2/loader.js.map +1 -1
- package/dist/schema/v2/normalized.d.ts +33 -0
- package/dist/schema/v2/normalized.d.ts.map +1 -1
- package/dist/schema/v2/parser.d.ts +9 -0
- package/dist/schema/v2/parser.d.ts.map +1 -1
- package/dist/schema/v2/parser.js +18 -2
- package/dist/schema/v2/parser.js.map +1 -1
- package/dist/schema/v2/tenant-policy-loader.d.ts.map +1 -1
- package/dist/schema/v2/tenant-policy-loader.js +7 -3
- package/dist/schema/v2/tenant-policy-loader.js.map +1 -1
- package/dist/schema/v2/tenant-policy.d.ts +28 -21
- package/dist/schema/v2/tenant-policy.d.ts.map +1 -1
- package/dist/schema/v2/tenant-policy.js +67 -11
- package/dist/schema/v2/tenant-policy.js.map +1 -1
- package/dist/sql/bind.d.ts +102 -0
- package/dist/sql/bind.d.ts.map +1 -0
- package/dist/sql/bind.js +422 -0
- package/dist/sql/bind.js.map +1 -0
- package/dist/sql/dialect-spec.d.ts +24 -1
- package/dist/sql/dialect-spec.d.ts.map +1 -1
- package/dist/sql/dialect-spec.js +82 -3
- package/dist/sql/dialect-spec.js.map +1 -1
- package/dist/sql/extract-sql.d.ts +8 -1
- package/dist/sql/extract-sql.d.ts.map +1 -1
- package/dist/sql/extract-sql.js +27 -4
- package/dist/sql/extract-sql.js.map +1 -1
- package/dist/sql/generate.d.ts +22 -0
- package/dist/sql/generate.d.ts.map +1 -1
- package/dist/sql/generate.js +92 -16
- package/dist/sql/generate.js.map +1 -1
- package/dist/sql/index.d.ts +4 -2
- package/dist/sql/index.d.ts.map +1 -1
- package/dist/sql/index.js +4 -2
- package/dist/sql/index.js.map +1 -1
- package/dist/sql/lexer.d.ts +114 -0
- package/dist/sql/lexer.d.ts.map +1 -0
- package/dist/sql/lexer.js +397 -0
- package/dist/sql/lexer.js.map +1 -0
- package/dist/sql/parameter-manifest.d.ts +34 -0
- package/dist/sql/parameter-manifest.d.ts.map +1 -0
- package/dist/sql/parameter-manifest.js +150 -0
- package/dist/sql/parameter-manifest.js.map +1 -0
- package/dist/sql/prompt.d.ts +7 -1
- package/dist/sql/prompt.d.ts.map +1 -1
- package/dist/sql/prompt.js +24 -1
- package/dist/sql/prompt.js.map +1 -1
- package/dist/sql/sensitive-guardrail.d.ts +62 -0
- package/dist/sql/sensitive-guardrail.d.ts.map +1 -0
- package/dist/sql/sensitive-guardrail.js +876 -0
- package/dist/sql/sensitive-guardrail.js.map +1 -0
- package/dist/sql/tenant-guardrail.d.ts +70 -8
- package/dist/sql/tenant-guardrail.d.ts.map +1 -1
- package/dist/sql/tenant-guardrail.js +799 -52
- package/dist/sql/tenant-guardrail.js.map +1 -1
- package/dist/sql/tenant-hierarchy.d.ts +19 -0
- package/dist/sql/tenant-hierarchy.d.ts.map +1 -0
- package/dist/sql/tenant-hierarchy.js +53 -0
- package/dist/sql/tenant-hierarchy.js.map +1 -0
- package/dist/sql/tenant-placeholders.d.ts +60 -9
- package/dist/sql/tenant-placeholders.d.ts.map +1 -1
- package/dist/sql/tenant-placeholders.js +237 -63
- package/dist/sql/tenant-placeholders.js.map +1 -1
- package/dist/sql/tenant-prompt.d.ts +4 -0
- package/dist/sql/tenant-prompt.d.ts.map +1 -1
- package/dist/sql/tenant-prompt.js +79 -11
- package/dist/sql/tenant-prompt.js.map +1 -1
- package/dist/sql/tenant-scope-validate.d.ts +3 -1
- package/dist/sql/tenant-scope-validate.d.ts.map +1 -1
- package/dist/sql/tenant-scope-validate.js +5 -2
- package/dist/sql/tenant-scope-validate.js.map +1 -1
- package/dist/sql/validate.d.ts +24 -4
- package/dist/sql/validate.d.ts.map +1 -1
- package/dist/sql/validate.js +123 -83
- package/dist/sql/validate.js.map +1 -1
- package/package.json +9 -7
- package/dist/exec/postgres.d.ts +0 -6
- package/dist/exec/postgres.d.ts.map +0 -1
- package/dist/exec/postgres.js +0 -30
- package/dist/exec/postgres.js.map +0 -1
- package/dist/modes/post-execute-log.d.ts +0 -9
- package/dist/modes/post-execute-log.d.ts.map +0 -1
- package/dist/modes/post-execute-log.js +0 -26
- package/dist/modes/post-execute-log.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"extract-sql.d.ts","sourceRoot":"","sources":["../../src/sql/extract-sql.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"extract-sql.d.ts","sourceRoot":"","sources":["../../src/sql/extract-sql.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAe3D;AAED;;;GAGG;AACH,wBAAgB,8BAA8B,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAQ9E"}
|
package/dist/sql/extract-sql.js
CHANGED
|
@@ -1,12 +1,35 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Prefer
|
|
2
|
+
* Prefer an explicitly `sql`-tagged fence; fall back to an untagged fence.
|
|
3
|
+
* Never return a fence tagged with anything else (e.g. `json`, `sql-unbound`).
|
|
4
|
+
* Keep single-block and bare-prose behavior identical to the pre-parameterize path.
|
|
3
5
|
*/
|
|
4
6
|
export function extractSqlFromModelText(raw) {
|
|
5
7
|
const text = raw.trim();
|
|
6
|
-
const
|
|
7
|
-
if (
|
|
8
|
-
return
|
|
8
|
+
const sqlTagged = /```sql(?![\w-])\s*([\s\S]*?)```/im.exec(text);
|
|
9
|
+
if (sqlTagged?.[1]) {
|
|
10
|
+
return sqlTagged[1].trim();
|
|
11
|
+
}
|
|
12
|
+
const untagged = /```(?![a-zA-Z])\s*([\s\S]*?)```/m.exec(text);
|
|
13
|
+
if (untagged?.[1]) {
|
|
14
|
+
return untagged[1].trim();
|
|
15
|
+
}
|
|
16
|
+
// A reply that only has non-sql tagged fences (json, sql-unbound, …) has no SQL.
|
|
17
|
+
if (/```[a-zA-Z][\w-]*/.test(text)) {
|
|
18
|
+
return "";
|
|
9
19
|
}
|
|
10
20
|
return text.trim();
|
|
11
21
|
}
|
|
22
|
+
/**
|
|
23
|
+
* Extract the ```sql-unbound fence from model text, if present.
|
|
24
|
+
* Returns undefined when the fence is missing or empty.
|
|
25
|
+
*/
|
|
26
|
+
export function extractUnboundSqlFromModelText(raw) {
|
|
27
|
+
const text = raw.trim();
|
|
28
|
+
const fence = /```sql-unbound\s*([\s\S]*?)```/im.exec(text);
|
|
29
|
+
if (fence?.[1]) {
|
|
30
|
+
const unbound = fence[1].trim();
|
|
31
|
+
return unbound.length > 0 ? unbound : undefined;
|
|
32
|
+
}
|
|
33
|
+
return undefined;
|
|
34
|
+
}
|
|
12
35
|
//# sourceMappingURL=extract-sql.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"extract-sql.js","sourceRoot":"","sources":["../../src/sql/extract-sql.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"extract-sql.js","sourceRoot":"","sources":["../../src/sql/extract-sql.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,MAAM,UAAU,uBAAuB,CAAC,GAAW;IACjD,MAAM,IAAI,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC;IACxB,MAAM,SAAS,GAAG,mCAAmC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACjE,IAAI,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACnB,OAAO,SAAS,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IAC7B,CAAC;IACD,MAAM,QAAQ,GAAG,kCAAkC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC/D,IAAI,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAClB,OAAO,QAAQ,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IAC5B,CAAC;IACD,iFAAiF;IACjF,IAAI,mBAAmB,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;QACnC,OAAO,EAAE,CAAC;IACZ,CAAC;IACD,OAAO,IAAI,CAAC,IAAI,EAAE,CAAC;AACrB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,8BAA8B,CAAC,GAAW;IACxD,MAAM,IAAI,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC;IACxB,MAAM,KAAK,GAAG,kCAAkC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC5D,IAAI,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACf,MAAM,OAAO,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QAChC,OAAO,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC;IAClD,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC"}
|
package/dist/sql/generate.d.ts
CHANGED
|
@@ -4,6 +4,7 @@ import type { AskDbLogger } from "../logging/askdb-logger.js";
|
|
|
4
4
|
import type { AnyNormalizedSchema } from "../schema/types.js";
|
|
5
5
|
import type { NormalizedTenantPolicy, TenantScope } from "../schema/v2/tenant-policy.js";
|
|
6
6
|
import type { DialectSpec } from "./dialect-spec.js";
|
|
7
|
+
import { type ParameterManifest } from "./parameter-manifest.js";
|
|
7
8
|
import { type TenantGuardrailResult } from "./tenant-guardrail.js";
|
|
8
9
|
import { type SelectGuardrailExplain } from "./validate.js";
|
|
9
10
|
export type GenerateSqlDeps = {
|
|
@@ -36,6 +37,11 @@ export type GenerateSqlDeps = {
|
|
|
36
37
|
* are unaffected.
|
|
37
38
|
*/
|
|
38
39
|
providerOptions?: Record<string, unknown>;
|
|
40
|
+
/**
|
|
41
|
+
* When true, ask the model for unbound SQL + parameter manifest and return
|
|
42
|
+
* them as optional extras when valid. Forwarded from ask(); default decided there.
|
|
43
|
+
*/
|
|
44
|
+
parameterize?: boolean;
|
|
39
45
|
};
|
|
40
46
|
/** Result of NL→SQL generation (always includes `sql`; `explain` when {@link GenerateSqlDeps.explain}). */
|
|
41
47
|
export type GenerateSelectSqlResult = {
|
|
@@ -48,11 +54,27 @@ export type GenerateSelectSqlResult = {
|
|
|
48
54
|
completionTokens: number | null;
|
|
49
55
|
totalTokens: number | null;
|
|
50
56
|
};
|
|
57
|
+
/** Named-placeholder SQL from the ```sql-unbound fence, when parameterize succeeded. */
|
|
58
|
+
unboundNamedSql?: string;
|
|
59
|
+
/** Validated parameter manifest, when parameterize succeeded. */
|
|
60
|
+
parameterManifest?: ParameterManifest;
|
|
51
61
|
};
|
|
52
62
|
/**
|
|
53
63
|
* Dialect-parameterized NL→SQL generator. Validates inputs, builds the user/system
|
|
54
64
|
* prompt with the dialect's syntax brief, calls the model, extracts the fenced SQL,
|
|
55
65
|
* and runs the shared read-only validator (plus any dialect-specific `extraValidate`).
|
|
66
|
+
*
|
|
67
|
+
* When `deps.tenantPolicy` and `deps.tenantScope` are supplied, the tenant guardrail
|
|
68
|
+
* runs on the returned `sql` (and on `unboundNamedSql` when that is returned too);
|
|
69
|
+
* `strict` policies throw `TenantGuardrailError`. Tenant placeholders are left in
|
|
70
|
+
* place — `ask()` substitutes them and re-checks the final SQL.
|
|
56
71
|
*/
|
|
57
72
|
export declare function generateSelectSql(dialect: DialectSpec, question: string, schema: AnyNormalizedSchema, model: AskDbLanguageModel, deps?: GenerateSqlDeps): Promise<GenerateSelectSqlResult>;
|
|
73
|
+
/**
|
|
74
|
+
* Internal entry used by `ask()`: identical to {@link generateSelectSql} but skips the
|
|
75
|
+
* tenant guardrail, because `ask()` runs it once on the final SQL — after tenant
|
|
76
|
+
* placeholder substitution and the unbound/bound consistency check. Not exported
|
|
77
|
+
* from the package index.
|
|
78
|
+
*/
|
|
79
|
+
export declare function generateSelectSqlWithoutTenantGuardrail(dialect: DialectSpec, question: string, schema: AnyNormalizedSchema, model: AskDbLanguageModel, deps?: GenerateSqlDeps): Promise<GenerateSelectSqlResult>;
|
|
58
80
|
//# sourceMappingURL=generate.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"generate.d.ts","sourceRoot":"","sources":["../../src/sql/generate.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,IAAI,mBAAmB,EAAE,MAAM,IAAI,CAAC;AACzD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AAGzD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAC;AAE9D,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAC9D,OAAO,KAAK,EAAE,sBAAsB,EAAE,WAAW,EAAE,MAAM,+BAA+B,CAAC;AACzF,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"generate.d.ts","sourceRoot":"","sources":["../../src/sql/generate.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,IAAI,mBAAmB,EAAE,MAAM,IAAI,CAAC;AACzD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AAGzD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAC;AAE9D,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAC9D,OAAO,KAAK,EAAE,sBAAsB,EAAE,WAAW,EAAE,MAAM,+BAA+B,CAAC;AACzF,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAErD,OAAO,EAGL,KAAK,iBAAiB,EACvB,MAAM,yBAAyB,CAAC;AAGjC,OAAO,EAA2B,KAAK,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AAC5F,OAAO,EAGL,KAAK,sBAAsB,EAC5B,MAAM,eAAe,CAAC;AAEvB,MAAM,MAAM,eAAe,GAAG;IAC5B,YAAY,CAAC,EAAE,OAAO,mBAAmB,CAAC;IAC1C,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,qGAAqG;IACrG,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB;;;OAGG;IACH,yCAAyC,CAAC,EAAE,OAAO,CAAC;IACpD;;;;;OAKG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,+EAA+E;IAC/E,YAAY,CAAC,EAAE,sBAAsB,CAAC;IACtC,kEAAkE;IAClE,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B;;;;;;;OAOG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC1C;;;OAGG;IACH,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB,CAAC;AAEF,2GAA2G;AAC3G,MAAM,MAAM,uBAAuB,GAAG;IACpC,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,CAAC,EAAE,sBAAsB,CAAC;IACjC,eAAe,CAAC,EAAE,qBAAqB,CAAC;IACxC,iGAAiG;IACjG,KAAK,CAAC,EAAE;QAAE,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,WAAW,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,CAAC;IACrG,wFAAwF;IACxF,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,iEAAiE;IACjE,iBAAiB,CAAC,EAAE,iBAAiB,CAAC;CACvC,CAAC;AAEF;;;;;;;;;GASG;AACH,wBAAsB,iBAAiB,CACrC,OAAO,EAAE,WAAW,EACpB,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,mBAAmB,EAC3B,KAAK,EAAE,kBAAkB,EACzB,IAAI,GAAE,eAAoB,GACzB,OAAO,CAAC,uBAAuB,CAAC,CAElC;AAED;;;;;GAKG;AACH,wBAAsB,uCAAuC,CAC3D,OAAO,EAAE,WAAW,EACpB,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,mBAAmB,EAC3B,KAAK,EAAE,kBAAkB,EACzB,IAAI,GAAE,eAAoB,GACzB,OAAO,CAAC,uBAAuB,CAAC,CAElC"}
|
package/dist/sql/generate.js
CHANGED
|
@@ -1,17 +1,35 @@
|
|
|
1
1
|
import { generateText as defaultGenerateText } from "ai";
|
|
2
2
|
import { SqlGenerationError } from "../errors.js";
|
|
3
3
|
import { AskDbLogEvent } from "../logging/log-events.js";
|
|
4
|
-
import { extractSqlFromModelText } from "./extract-sql.js";
|
|
4
|
+
import { extractSqlFromModelText, extractUnboundSqlFromModelText } from "./extract-sql.js";
|
|
5
|
+
import { crossValidateManifestAgainstSql, parseParameterManifest, } from "./parameter-manifest.js";
|
|
5
6
|
import { buildNlToSqlSystemPrompt, buildNlToSqlUserPrompt } from "./prompt.js";
|
|
6
7
|
import { assertNlToSqlInputs, nlToSqlAmbiguityNotes } from "./schema-question-precheck.js";
|
|
7
|
-
import {
|
|
8
|
+
import { enforceTenantGuardrails } from "./tenant-guardrail.js";
|
|
8
9
|
import { buildSelectGuardrailExplanation, validateSelectSql, } from "./validate.js";
|
|
9
10
|
/**
|
|
10
11
|
* Dialect-parameterized NL→SQL generator. Validates inputs, builds the user/system
|
|
11
12
|
* prompt with the dialect's syntax brief, calls the model, extracts the fenced SQL,
|
|
12
13
|
* and runs the shared read-only validator (plus any dialect-specific `extraValidate`).
|
|
14
|
+
*
|
|
15
|
+
* When `deps.tenantPolicy` and `deps.tenantScope` are supplied, the tenant guardrail
|
|
16
|
+
* runs on the returned `sql` (and on `unboundNamedSql` when that is returned too);
|
|
17
|
+
* `strict` policies throw `TenantGuardrailError`. Tenant placeholders are left in
|
|
18
|
+
* place — `ask()` substitutes them and re-checks the final SQL.
|
|
13
19
|
*/
|
|
14
20
|
export async function generateSelectSql(dialect, question, schema, model, deps = {}) {
|
|
21
|
+
return runGenerateSelectSql(dialect, question, schema, model, deps, true);
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Internal entry used by `ask()`: identical to {@link generateSelectSql} but skips the
|
|
25
|
+
* tenant guardrail, because `ask()` runs it once on the final SQL — after tenant
|
|
26
|
+
* placeholder substitution and the unbound/bound consistency check. Not exported
|
|
27
|
+
* from the package index.
|
|
28
|
+
*/
|
|
29
|
+
export async function generateSelectSqlWithoutTenantGuardrail(dialect, question, schema, model, deps = {}) {
|
|
30
|
+
return runGenerateSelectSql(dialect, question, schema, model, deps, false);
|
|
31
|
+
}
|
|
32
|
+
async function runGenerateSelectSql(dialect, question, schema, model, deps, runTenantGuardrail) {
|
|
15
33
|
assertNlToSqlInputs(schema, question);
|
|
16
34
|
const ambiguityNotes = nlToSqlAmbiguityNotes(question, schema);
|
|
17
35
|
const generateText = deps.generateText ?? defaultGenerateText;
|
|
@@ -19,6 +37,7 @@ export async function generateSelectSql(dialect, question, schema, model, deps =
|
|
|
19
37
|
const nlToSqlSchemaOptions = deps.omitSensitiveIdentifiersFromNlToSqlPrompt === true
|
|
20
38
|
? { omitSensitiveIdentifiersFromPrompt: true }
|
|
21
39
|
: undefined;
|
|
40
|
+
const parameterize = deps.parameterize === true;
|
|
22
41
|
logger?.info({
|
|
23
42
|
event: AskDbLogEvent.PipelineGenerateStart,
|
|
24
43
|
questionLength: question.length,
|
|
@@ -31,7 +50,7 @@ export async function generateSelectSql(dialect, question, schema, model, deps =
|
|
|
31
50
|
const result = await generateText({
|
|
32
51
|
model,
|
|
33
52
|
instructions: buildNlToSqlSystemPrompt(dialect),
|
|
34
|
-
prompt: buildNlToSqlUserPrompt(dialect, question, schema, ambiguityNotes, logger, nlToSqlSchemaOptions, deps.prebuiltDdl, deps.tenantPolicy, deps.tenantScope),
|
|
53
|
+
prompt: buildNlToSqlUserPrompt(dialect, question, schema, ambiguityNotes, logger, nlToSqlSchemaOptions, deps.prebuiltDdl, deps.tenantPolicy, deps.tenantScope, parameterize || undefined),
|
|
35
54
|
temperature: 0,
|
|
36
55
|
// Cast: AskDB's public `providerOptions` type is a plain opaque bag
|
|
37
56
|
// (`Record<string, unknown>`) so callers don't need AI SDK JSON types.
|
|
@@ -59,20 +78,21 @@ export async function generateSelectSql(dialect, question, schema, model, deps =
|
|
|
59
78
|
}
|
|
60
79
|
const extracted = extractSqlFromModelText(text);
|
|
61
80
|
const sql = validateSelectSql(dialect, extracted);
|
|
62
|
-
//
|
|
81
|
+
// Optional parameterized extras — any failure clears them (never throws).
|
|
82
|
+
let unboundNamedSql;
|
|
83
|
+
let parameterManifest;
|
|
84
|
+
if (parameterize) {
|
|
85
|
+
const extras = tryParseParameterizedExtras(text, dialect, logger);
|
|
86
|
+
unboundNamedSql = extras.unboundNamedSql;
|
|
87
|
+
parameterManifest = extras.parameterManifest;
|
|
88
|
+
}
|
|
89
|
+
// Tenant guardrail: check every SQL form this function returns — the bound
|
|
90
|
+
// `sql` callers execute, plus the unbound form when it is returned too. Never
|
|
91
|
+
// check only the unbound form: both blocks come from the model and can
|
|
92
|
+
// disagree (e.g. a scoped unbound block next to an unscoped bound one).
|
|
63
93
|
let tenantGuardrail;
|
|
64
|
-
if (deps.tenantPolicy && deps.tenantScope) {
|
|
65
|
-
tenantGuardrail =
|
|
66
|
-
if (tenantGuardrail.passed) {
|
|
67
|
-
logger?.info({ event: AskDbLogEvent.TenantGuardrailPassed }, "tenant guardrail validation passed");
|
|
68
|
-
}
|
|
69
|
-
else {
|
|
70
|
-
logger?.info({
|
|
71
|
-
event: AskDbLogEvent.TenantGuardrailFailed,
|
|
72
|
-
warningCount: tenantGuardrail.warnings.length,
|
|
73
|
-
enforcement: deps.tenantPolicy.enforcement,
|
|
74
|
-
}, "tenant guardrail validation found issues");
|
|
75
|
-
}
|
|
94
|
+
if (runTenantGuardrail && deps.tenantPolicy && deps.tenantScope) {
|
|
95
|
+
tenantGuardrail = enforceTenantGuardrails([sql, unboundNamedSql], deps.tenantPolicy, deps.tenantScope, logger, undefined, dialect);
|
|
76
96
|
}
|
|
77
97
|
const explain = deps.explain ? buildSelectGuardrailExplanation(sql) : undefined;
|
|
78
98
|
logger?.info({
|
|
@@ -86,6 +106,10 @@ export async function generateSelectSql(dialect, question, schema, model, deps =
|
|
|
86
106
|
out.tenantGuardrail = tenantGuardrail;
|
|
87
107
|
if (usage !== undefined)
|
|
88
108
|
out.usage = usage;
|
|
109
|
+
if (unboundNamedSql !== undefined)
|
|
110
|
+
out.unboundNamedSql = unboundNamedSql;
|
|
111
|
+
if (parameterManifest !== undefined)
|
|
112
|
+
out.parameterManifest = parameterManifest;
|
|
89
113
|
return out;
|
|
90
114
|
}
|
|
91
115
|
catch (e) {
|
|
@@ -98,4 +122,56 @@ export async function generateSelectSql(dialect, question, schema, model, deps =
|
|
|
98
122
|
throw e;
|
|
99
123
|
}
|
|
100
124
|
}
|
|
125
|
+
function tryParseParameterizedExtras(text, dialect, logger) {
|
|
126
|
+
const unbound = extractUnboundSqlFromModelText(text);
|
|
127
|
+
if (!unbound) {
|
|
128
|
+
logger?.debug?.({
|
|
129
|
+
event: AskDbLogEvent.PipelineParameterized,
|
|
130
|
+
parameterCount: 0,
|
|
131
|
+
listParameterCount: 0,
|
|
132
|
+
reason: "missing_unbound",
|
|
133
|
+
}, "parameterize extras dropped");
|
|
134
|
+
return {};
|
|
135
|
+
}
|
|
136
|
+
let unboundValidated;
|
|
137
|
+
try {
|
|
138
|
+
unboundValidated = validateSelectSql(dialect, unbound);
|
|
139
|
+
}
|
|
140
|
+
catch {
|
|
141
|
+
logger?.debug?.({
|
|
142
|
+
event: AskDbLogEvent.PipelineParameterized,
|
|
143
|
+
parameterCount: 0,
|
|
144
|
+
listParameterCount: 0,
|
|
145
|
+
reason: "unbound_invalid",
|
|
146
|
+
}, "parameterize extras dropped");
|
|
147
|
+
return {};
|
|
148
|
+
}
|
|
149
|
+
const parsed = parseParameterManifest(text);
|
|
150
|
+
if (!parsed.ok) {
|
|
151
|
+
logger?.debug?.({
|
|
152
|
+
event: AskDbLogEvent.PipelineParameterized,
|
|
153
|
+
parameterCount: 0,
|
|
154
|
+
listParameterCount: 0,
|
|
155
|
+
reason: parsed.reason.toLowerCase(),
|
|
156
|
+
}, "parameterize extras dropped");
|
|
157
|
+
return {};
|
|
158
|
+
}
|
|
159
|
+
const cross = crossValidateManifestAgainstSql(unboundValidated, parsed.manifest, dialect);
|
|
160
|
+
if (!cross.ok) {
|
|
161
|
+
logger?.debug?.({
|
|
162
|
+
event: AskDbLogEvent.PipelineParameterized,
|
|
163
|
+
parameterCount: 0,
|
|
164
|
+
listParameterCount: 0,
|
|
165
|
+
reason: cross.reason.toLowerCase(),
|
|
166
|
+
}, "parameterize extras dropped");
|
|
167
|
+
return {};
|
|
168
|
+
}
|
|
169
|
+
const listParameterCount = parsed.manifest.parameters.filter((p) => p.cardinality === "many").length;
|
|
170
|
+
logger?.info({
|
|
171
|
+
event: AskDbLogEvent.PipelineParameterized,
|
|
172
|
+
parameterCount: parsed.manifest.parameters.length,
|
|
173
|
+
listParameterCount,
|
|
174
|
+
}, "parameterize extras accepted");
|
|
175
|
+
return { unboundNamedSql: unboundValidated, parameterManifest: parsed.manifest };
|
|
176
|
+
}
|
|
101
177
|
//# sourceMappingURL=generate.js.map
|
package/dist/sql/generate.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"generate.js","sourceRoot":"","sources":["../../src/sql/generate.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,IAAI,mBAAmB,EAAE,MAAM,IAAI,CAAC;AAEzD,OAAO,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAClD,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAMzD,OAAO,EAAE,uBAAuB,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"generate.js","sourceRoot":"","sources":["../../src/sql/generate.ts"],"names":[],"mappings":"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"}
|
package/dist/sql/index.d.ts
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export { extractSqlFromModelText, extractUnboundSqlFromModelText } from "./extract-sql.js";
|
|
2
|
+
export { bindPreparedQuery, escapeSqlLiteral, type QueryParameterType, type QueryParameterValue, type QueryParamSlot, type QueryParameterBinding, type PreparedQuery, type BoundQuery, } from "./bind.js";
|
|
3
|
+
export { parseParameterManifest, type ParameterManifest, type ManifestParameter, } from "./parameter-manifest.js";
|
|
2
4
|
export { generateSelectSql, type GenerateSelectSqlResult, type GenerateSqlDeps, } from "./generate.js";
|
|
3
5
|
export { validateSelectSql, buildSelectGuardrailExplanation, type SelectGuardrailExplain, } from "./validate.js";
|
|
4
6
|
export { buildNlToSqlUserPrompt, buildNlToSqlSystemPrompt, } from "./prompt.js";
|
|
5
7
|
export { assertNlToSqlInputs, nlToSqlAmbiguityNotes, } from "./schema-question-precheck.js";
|
|
6
|
-
export {
|
|
8
|
+
export { type DialectId, type DialectSpec, type BuiltInDialectId, POSTGRES_DIALECT, COCKROACHDB_DIALECT, MYSQL_DIALECT, MARIADB_DIALECT, SQLITE_DIALECT, SQLSERVER_DIALECT, BUILT_IN_DIALECTS, SUPPORTED_DIALECT_IDS, isBuiltInDialectId, getDialectSpec, } from "./dialect-spec.js";
|
|
7
9
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/sql/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/sql/index.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/sql/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,uBAAuB,EAAE,8BAA8B,EAAE,MAAM,kBAAkB,CAAC;AAC3F,OAAO,EACL,iBAAiB,EACjB,gBAAgB,EAChB,KAAK,kBAAkB,EACvB,KAAK,mBAAmB,EACxB,KAAK,cAAc,EACnB,KAAK,qBAAqB,EAC1B,KAAK,aAAa,EAClB,KAAK,UAAU,GAChB,MAAM,WAAW,CAAC;AACnB,OAAO,EACL,sBAAsB,EACtB,KAAK,iBAAiB,EACtB,KAAK,iBAAiB,GACvB,MAAM,yBAAyB,CAAC;AACjC,OAAO,EACL,iBAAiB,EACjB,KAAK,uBAAuB,EAC5B,KAAK,eAAe,GACrB,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,iBAAiB,EACjB,+BAA+B,EAC/B,KAAK,sBAAsB,GAC5B,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,sBAAsB,EACtB,wBAAwB,GACzB,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,mBAAmB,EACnB,qBAAqB,GACtB,MAAM,+BAA+B,CAAC;AACvC,OAAO,EACL,KAAK,SAAS,EACd,KAAK,WAAW,EAChB,KAAK,gBAAgB,EACrB,gBAAgB,EAChB,mBAAmB,EACnB,aAAa,EACb,eAAe,EACf,cAAc,EACd,iBAAiB,EACjB,iBAAiB,EACjB,qBAAqB,EACrB,kBAAkB,EAClB,cAAc,GACf,MAAM,mBAAmB,CAAC"}
|
package/dist/sql/index.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export { extractSqlFromModelText, extractUnboundSqlFromModelText } from "./extract-sql.js";
|
|
2
|
+
export { bindPreparedQuery, escapeSqlLiteral, } from "./bind.js";
|
|
3
|
+
export { parseParameterManifest, } from "./parameter-manifest.js";
|
|
2
4
|
export { generateSelectSql, } from "./generate.js";
|
|
3
5
|
export { validateSelectSql, buildSelectGuardrailExplanation, } from "./validate.js";
|
|
4
6
|
export { buildNlToSqlUserPrompt, buildNlToSqlSystemPrompt, } from "./prompt.js";
|
|
5
7
|
export { assertNlToSqlInputs, nlToSqlAmbiguityNotes, } from "./schema-question-precheck.js";
|
|
6
|
-
export {
|
|
8
|
+
export { POSTGRES_DIALECT, COCKROACHDB_DIALECT, MYSQL_DIALECT, MARIADB_DIALECT, SQLITE_DIALECT, SQLSERVER_DIALECT, BUILT_IN_DIALECTS, SUPPORTED_DIALECT_IDS, isBuiltInDialectId, getDialectSpec, } from "./dialect-spec.js";
|
|
7
9
|
//# sourceMappingURL=index.js.map
|
package/dist/sql/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/sql/index.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/sql/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,uBAAuB,EAAE,8BAA8B,EAAE,MAAM,kBAAkB,CAAC;AAC3F,OAAO,EACL,iBAAiB,EACjB,gBAAgB,GAOjB,MAAM,WAAW,CAAC;AACnB,OAAO,EACL,sBAAsB,GAGvB,MAAM,yBAAyB,CAAC;AACjC,OAAO,EACL,iBAAiB,GAGlB,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,iBAAiB,EACjB,+BAA+B,GAEhC,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,sBAAsB,EACtB,wBAAwB,GACzB,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,mBAAmB,EACnB,qBAAqB,GACtB,MAAM,+BAA+B,CAAC;AACvC,OAAO,EAIL,gBAAgB,EAChB,mBAAmB,EACnB,aAAa,EACb,eAAe,EACf,cAAc,EACd,iBAAiB,EACjB,iBAAiB,EACjB,qBAAqB,EACrB,kBAAkB,EAClB,cAAc,GACf,MAAM,mBAAmB,CAAC"}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dialect-aware SQL lexer shared by the read-only validator, the sensitive-identifier
|
|
3
|
+
* guardrail, and the placeholder scanner.
|
|
4
|
+
*
|
|
5
|
+
* It only splits SQL into tokens — it does not parse. Its job is to agree with the
|
|
6
|
+
* target engine about where strings, quoted identifiers, and comments begin and end,
|
|
7
|
+
* because every downstream check ("is there a second statement?", "is `DELETE` a
|
|
8
|
+
* keyword here?", "is `ssn` a column reference?") depends on that boundary. Rules per
|
|
9
|
+
* engine:
|
|
10
|
+
*
|
|
11
|
+
* | Construct | Postgres | MySQL/MariaDB | SQL Server | SQLite |
|
|
12
|
+
* |---------------------------|----------|------------------------|------------|--------|
|
|
13
|
+
* | `'…'` backslash escapes | no | yes (`backslashEscapes`) | no | no |
|
|
14
|
+
* | `E'…'` backslash escapes | yes | — | — | — |
|
|
15
|
+
* | `$tag$…$tag$` | yes | — | — | — |
|
|
16
|
+
* | `"…"` | ident | string | ident | ident |
|
|
17
|
+
* | `` `…` `` | — | ident | — | ident |
|
|
18
|
+
* | `[…]` | — | — | ident (`]]`) | ident |
|
|
19
|
+
* | `#` line comment | — | yes | — | — |
|
|
20
|
+
* | `--` line comment | yes | only before whitespace | yes | yes |
|
|
21
|
+
* | nested `/* … *\/` | yes | no (`/*! … *\/` runs) | yes | no |
|
|
22
|
+
*
|
|
23
|
+
* The lexer never throws: a string, quoted identifier, or comment that runs off the end
|
|
24
|
+
* of the input is returned with `unterminated: true` so callers can fail closed.
|
|
25
|
+
*/
|
|
26
|
+
import type { DialectSpec } from "./dialect-spec.js";
|
|
27
|
+
export type SqlLexerProfileId = "postgres" | "mysql" | "sqlserver" | "sqlite" | "generic";
|
|
28
|
+
export type SqlLexerProfile = {
|
|
29
|
+
id: SqlLexerProfileId;
|
|
30
|
+
/** `'…'` (and MySQL `"…"`) treat backslash as an escape character. */
|
|
31
|
+
backslashEscapes: boolean;
|
|
32
|
+
/** Whether `"…"` is a quoted identifier (ANSI) or a string literal (MySQL default mode). */
|
|
33
|
+
doubleQuote: "identifier" | "string";
|
|
34
|
+
backtickIdentifiers: boolean;
|
|
35
|
+
/** `[…]` quoted identifiers. `"doubled"` accepts `]]` as an escaped `]` (SQL Server). */
|
|
36
|
+
bracketIdentifiers: false | "simple" | "doubled";
|
|
37
|
+
/** Postgres `$tag$ … $tag$` strings. */
|
|
38
|
+
dollarQuotes: boolean;
|
|
39
|
+
/** Postgres `E'…'` strings with backslash escapes. */
|
|
40
|
+
escapeStrings: boolean;
|
|
41
|
+
/** MySQL `#` line comments. */
|
|
42
|
+
hashComments: boolean;
|
|
43
|
+
/** MySQL: `--` starts a comment only when followed by whitespace, a control char, or EOF. */
|
|
44
|
+
dashCommentNeedsSpace: boolean;
|
|
45
|
+
nestedBlockComments: boolean;
|
|
46
|
+
/** MySQL/MariaDB `/*! … *\/` and `/*M! … *\/`: the body is executed, so it is lexed as code. */
|
|
47
|
+
executableComments: boolean;
|
|
48
|
+
/** `@name` / `@@name` variables and parameters. Off for Postgres, where `@` is an operator. */
|
|
49
|
+
atVariables: boolean;
|
|
50
|
+
/** SQL Server `#temp` / `##temp` table names. */
|
|
51
|
+
hashIdentifiers: boolean;
|
|
52
|
+
};
|
|
53
|
+
export declare const POSTGRES_LEXER: SqlLexerProfile;
|
|
54
|
+
export declare const MYSQL_LEXER: SqlLexerProfile;
|
|
55
|
+
export declare const SQLSERVER_LEXER: SqlLexerProfile;
|
|
56
|
+
export declare const SQLITE_LEXER: SqlLexerProfile;
|
|
57
|
+
/**
|
|
58
|
+
* Dialect-agnostic profile for callers that have no dialect (the tenant placeholder
|
|
59
|
+
* path, the sensitive guardrail when no dialect is supplied). Recognizes the union of
|
|
60
|
+
* quoting forms — `'…'`, `E'…'`, `$tag$…$tag$`, `"…"`, `` `…` ``, `[…]` — with the
|
|
61
|
+
* escape rules the owning engine uses, and standard `--` / `/* *\/` comments.
|
|
62
|
+
*/
|
|
63
|
+
export declare const GENERIC_LEXER: SqlLexerProfile;
|
|
64
|
+
/** Every engine-specific profile. Used when the dialect is unknown and each reading must be safe. */
|
|
65
|
+
export declare const ENGINE_LEXER_PROFILES: readonly SqlLexerProfile[];
|
|
66
|
+
/**
|
|
67
|
+
* The lexer profile for a dialect, or `undefined` when the id is not a built-in engine
|
|
68
|
+
* family (callers should then check every profile in {@link ENGINE_LEXER_PROFILES}).
|
|
69
|
+
*
|
|
70
|
+
* `backslashEscapes` on the spec is honored: MySQL with `NO_BACKSLASH_ESCAPES` sets it
|
|
71
|
+
* to `false`; Postgres with `standard_conforming_strings = off` sets it to `true`.
|
|
72
|
+
* An unset value on a MySQL-family spec means the server default (escapes on).
|
|
73
|
+
*/
|
|
74
|
+
export declare function lexerProfileFor(dialect: Pick<DialectSpec, "id" | "backslashEscapes">): SqlLexerProfile | undefined;
|
|
75
|
+
export type SqlTokenKind =
|
|
76
|
+
/** Unquoted identifier or keyword. */
|
|
77
|
+
"word" | "quoted_identifier" | "string" | "number"
|
|
78
|
+
/** `$1`, `:name`, `@name`, `@@name`. */
|
|
79
|
+
| "parameter"
|
|
80
|
+
/** Any other single character, plus `::`. Includes `(`, `)`, `,`, `.`, `;`. */
|
|
81
|
+
| "punct" | "comment";
|
|
82
|
+
export type SqlToken = {
|
|
83
|
+
kind: SqlTokenKind;
|
|
84
|
+
/** Exact source text of the token. */
|
|
85
|
+
text: string;
|
|
86
|
+
/**
|
|
87
|
+
* `word`: the text as written. `quoted_identifier`: the unescaped name.
|
|
88
|
+
* Everything else: same as `text`.
|
|
89
|
+
*/
|
|
90
|
+
value: string;
|
|
91
|
+
/** Lower-cased `value`, for case-insensitive keyword and name matching. */
|
|
92
|
+
lower: string;
|
|
93
|
+
start: number;
|
|
94
|
+
end: number;
|
|
95
|
+
/** Opening delimiter for strings and quoted identifiers (`'`, `"`, `` ` ``, `[`, `$tag$`). */
|
|
96
|
+
quote?: string;
|
|
97
|
+
/**
|
|
98
|
+
* The closing delimiter was never found; the token runs to the end of the input. On a
|
|
99
|
+
* MySQL `/*!` opener it means the matching `*\/` never came (the body is still lexed
|
|
100
|
+
* as code after it).
|
|
101
|
+
*/
|
|
102
|
+
unterminated?: true;
|
|
103
|
+
};
|
|
104
|
+
/**
|
|
105
|
+
* Whether the `--` at `i` starts a line comment. It always does, except on MySQL/MariaDB
|
|
106
|
+
* (`needsSpace`), where it must be followed by whitespace, a control character, or the end
|
|
107
|
+
* of the statement: there `--1` is two minus signs and a number.
|
|
108
|
+
*/
|
|
109
|
+
export declare function startsDashComment(sql: string, i: number, needsSpace: boolean): boolean;
|
|
110
|
+
/** Split `sql` into tokens under `profile`. Whitespace is dropped; comments are kept. */
|
|
111
|
+
export declare function lexSql(sql: string, profile: SqlLexerProfile): SqlToken[];
|
|
112
|
+
/** True when any token ran off the end of the input. */
|
|
113
|
+
export declare function hasUnterminatedToken(tokens: readonly SqlToken[]): boolean;
|
|
114
|
+
//# sourceMappingURL=lexer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lexer.d.ts","sourceRoot":"","sources":["../../src/sql/lexer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAErD,MAAM,MAAM,iBAAiB,GAAG,UAAU,GAAG,OAAO,GAAG,WAAW,GAAG,QAAQ,GAAG,SAAS,CAAC;AAE1F,MAAM,MAAM,eAAe,GAAG;IAC5B,EAAE,EAAE,iBAAiB,CAAC;IACtB,sEAAsE;IACtE,gBAAgB,EAAE,OAAO,CAAC;IAC1B,4FAA4F;IAC5F,WAAW,EAAE,YAAY,GAAG,QAAQ,CAAC;IACrC,mBAAmB,EAAE,OAAO,CAAC;IAC7B,yFAAyF;IACzF,kBAAkB,EAAE,KAAK,GAAG,QAAQ,GAAG,SAAS,CAAC;IACjD,wCAAwC;IACxC,YAAY,EAAE,OAAO,CAAC;IACtB,sDAAsD;IACtD,aAAa,EAAE,OAAO,CAAC;IACvB,+BAA+B;IAC/B,YAAY,EAAE,OAAO,CAAC;IACtB,6FAA6F;IAC7F,qBAAqB,EAAE,OAAO,CAAC;IAC/B,mBAAmB,EAAE,OAAO,CAAC;IAC7B,gGAAgG;IAChG,kBAAkB,EAAE,OAAO,CAAC;IAC5B,+FAA+F;IAC/F,WAAW,EAAE,OAAO,CAAC;IACrB,iDAAiD;IACjD,eAAe,EAAE,OAAO,CAAC;CAC1B,CAAC;AAEF,eAAO,MAAM,cAAc,EAAE,eAc5B,CAAC;AAEF,eAAO,MAAM,WAAW,EAAE,eAczB,CAAC;AAEF,eAAO,MAAM,eAAe,EAAE,eAc7B,CAAC;AAEF,eAAO,MAAM,YAAY,EAAE,eAc1B,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,aAAa,EAAE,eAc3B,CAAC;AAEF,qGAAqG;AACrG,eAAO,MAAM,qBAAqB,EAAE,SAAS,eAAe,EAK3D,CAAC;AAEF;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAC7B,OAAO,EAAE,IAAI,CAAC,WAAW,EAAE,IAAI,GAAG,kBAAkB,CAAC,GACpD,eAAe,GAAG,SAAS,CAmB7B;AAED,MAAM,MAAM,YAAY;AACtB,sCAAsC;AACpC,MAAM,GACN,mBAAmB,GACnB,QAAQ,GACR,QAAQ;AACV,wCAAwC;GACtC,WAAW;AACb,+EAA+E;GAC7E,OAAO,GACP,SAAS,CAAC;AAEd,MAAM,MAAM,QAAQ,GAAG;IACrB,IAAI,EAAE,YAAY,CAAC;IACnB,sCAAsC;IACtC,IAAI,EAAE,MAAM,CAAC;IACb;;;OAGG;IACH,KAAK,EAAE,MAAM,CAAC;IACd,2EAA2E;IAC3E,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,8FAA8F;IAC9F,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;;OAIG;IACH,YAAY,CAAC,EAAE,IAAI,CAAC;CACrB,CAAC;AAQF;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,UAAU,EAAE,OAAO,GAAG,OAAO,CAItF;AAED,yFAAyF;AACzF,wBAAgB,MAAM,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,eAAe,GAAG,QAAQ,EAAE,CAsQxE;AAED,wDAAwD;AACxD,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,SAAS,QAAQ,EAAE,GAAG,OAAO,CAEzE"}
|