@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.
Files changed (105) hide show
  1. package/README.md +44 -4
  2. package/dist/ask.d.ts +129 -2
  3. package/dist/ask.d.ts.map +1 -1
  4. package/dist/ask.js +391 -15
  5. package/dist/ask.js.map +1 -1
  6. package/dist/errors.d.ts +87 -2
  7. package/dist/errors.d.ts.map +1 -1
  8. package/dist/errors.js +29 -0
  9. package/dist/errors.js.map +1 -1
  10. package/dist/index.d.ts +8 -5
  11. package/dist/index.d.ts.map +1 -1
  12. package/dist/index.js +5 -2
  13. package/dist/index.js.map +1 -1
  14. package/dist/logging/log-events.d.ts +13 -0
  15. package/dist/logging/log-events.d.ts.map +1 -1
  16. package/dist/logging/log-events.js +13 -0
  17. package/dist/logging/log-events.js.map +1 -1
  18. package/dist/schema/v2/index.d.ts +1 -1
  19. package/dist/schema/v2/index.d.ts.map +1 -1
  20. package/dist/schema/v2/loader.d.ts +9 -1
  21. package/dist/schema/v2/loader.d.ts.map +1 -1
  22. package/dist/schema/v2/loader.js +171 -49
  23. package/dist/schema/v2/loader.js.map +1 -1
  24. package/dist/schema/v2/normalized.d.ts +33 -0
  25. package/dist/schema/v2/normalized.d.ts.map +1 -1
  26. package/dist/schema/v2/parser.d.ts +9 -0
  27. package/dist/schema/v2/parser.d.ts.map +1 -1
  28. package/dist/schema/v2/parser.js +18 -2
  29. package/dist/schema/v2/parser.js.map +1 -1
  30. package/dist/schema/v2/tenant-policy-loader.d.ts.map +1 -1
  31. package/dist/schema/v2/tenant-policy-loader.js +7 -3
  32. package/dist/schema/v2/tenant-policy-loader.js.map +1 -1
  33. package/dist/schema/v2/tenant-policy.d.ts +28 -21
  34. package/dist/schema/v2/tenant-policy.d.ts.map +1 -1
  35. package/dist/schema/v2/tenant-policy.js +67 -11
  36. package/dist/schema/v2/tenant-policy.js.map +1 -1
  37. package/dist/sql/bind.d.ts +102 -0
  38. package/dist/sql/bind.d.ts.map +1 -0
  39. package/dist/sql/bind.js +422 -0
  40. package/dist/sql/bind.js.map +1 -0
  41. package/dist/sql/dialect-spec.d.ts +24 -1
  42. package/dist/sql/dialect-spec.d.ts.map +1 -1
  43. package/dist/sql/dialect-spec.js +82 -3
  44. package/dist/sql/dialect-spec.js.map +1 -1
  45. package/dist/sql/extract-sql.d.ts +8 -1
  46. package/dist/sql/extract-sql.d.ts.map +1 -1
  47. package/dist/sql/extract-sql.js +27 -4
  48. package/dist/sql/extract-sql.js.map +1 -1
  49. package/dist/sql/generate.d.ts +22 -0
  50. package/dist/sql/generate.d.ts.map +1 -1
  51. package/dist/sql/generate.js +92 -16
  52. package/dist/sql/generate.js.map +1 -1
  53. package/dist/sql/index.d.ts +4 -2
  54. package/dist/sql/index.d.ts.map +1 -1
  55. package/dist/sql/index.js +4 -2
  56. package/dist/sql/index.js.map +1 -1
  57. package/dist/sql/lexer.d.ts +114 -0
  58. package/dist/sql/lexer.d.ts.map +1 -0
  59. package/dist/sql/lexer.js +397 -0
  60. package/dist/sql/lexer.js.map +1 -0
  61. package/dist/sql/parameter-manifest.d.ts +34 -0
  62. package/dist/sql/parameter-manifest.d.ts.map +1 -0
  63. package/dist/sql/parameter-manifest.js +150 -0
  64. package/dist/sql/parameter-manifest.js.map +1 -0
  65. package/dist/sql/prompt.d.ts +7 -1
  66. package/dist/sql/prompt.d.ts.map +1 -1
  67. package/dist/sql/prompt.js +24 -1
  68. package/dist/sql/prompt.js.map +1 -1
  69. package/dist/sql/sensitive-guardrail.d.ts +62 -0
  70. package/dist/sql/sensitive-guardrail.d.ts.map +1 -0
  71. package/dist/sql/sensitive-guardrail.js +876 -0
  72. package/dist/sql/sensitive-guardrail.js.map +1 -0
  73. package/dist/sql/tenant-guardrail.d.ts +70 -8
  74. package/dist/sql/tenant-guardrail.d.ts.map +1 -1
  75. package/dist/sql/tenant-guardrail.js +799 -52
  76. package/dist/sql/tenant-guardrail.js.map +1 -1
  77. package/dist/sql/tenant-hierarchy.d.ts +19 -0
  78. package/dist/sql/tenant-hierarchy.d.ts.map +1 -0
  79. package/dist/sql/tenant-hierarchy.js +53 -0
  80. package/dist/sql/tenant-hierarchy.js.map +1 -0
  81. package/dist/sql/tenant-placeholders.d.ts +60 -9
  82. package/dist/sql/tenant-placeholders.d.ts.map +1 -1
  83. package/dist/sql/tenant-placeholders.js +237 -63
  84. package/dist/sql/tenant-placeholders.js.map +1 -1
  85. package/dist/sql/tenant-prompt.d.ts +4 -0
  86. package/dist/sql/tenant-prompt.d.ts.map +1 -1
  87. package/dist/sql/tenant-prompt.js +79 -11
  88. package/dist/sql/tenant-prompt.js.map +1 -1
  89. package/dist/sql/tenant-scope-validate.d.ts +3 -1
  90. package/dist/sql/tenant-scope-validate.d.ts.map +1 -1
  91. package/dist/sql/tenant-scope-validate.js +5 -2
  92. package/dist/sql/tenant-scope-validate.js.map +1 -1
  93. package/dist/sql/validate.d.ts +24 -4
  94. package/dist/sql/validate.d.ts.map +1 -1
  95. package/dist/sql/validate.js +123 -83
  96. package/dist/sql/validate.js.map +1 -1
  97. package/package.json +9 -7
  98. package/dist/exec/postgres.d.ts +0 -6
  99. package/dist/exec/postgres.d.ts.map +0 -1
  100. package/dist/exec/postgres.js +0 -30
  101. package/dist/exec/postgres.js.map +0 -1
  102. package/dist/modes/post-execute-log.d.ts +0 -9
  103. package/dist/modes/post-execute-log.d.ts.map +0 -1
  104. package/dist/modes/post-execute-log.js +0 -26
  105. package/dist/modes/post-execute-log.js.map +0 -1
@@ -0,0 +1,422 @@
1
+ import { QueryParameterError, } from "../errors.js";
2
+ import { BUILT_IN_DIALECTS, } from "./dialect-spec.js";
3
+ import { GENERIC_LEXER, lexSql, lexerProfileFor } from "./lexer.js";
4
+ import { validateSelectSql } from "./validate.js";
5
+ /**
6
+ * Split SQL into contiguous code / quoted / comment regions using the shared lexer
7
+ * (`lexer.ts`). With a dialect, strings, quoted identifiers, and comments follow that
8
+ * engine's rules (Postgres `E'…'` and exact-tag `$tag$…$tag$`, MySQL backslash escapes
9
+ * and `#` comments, SQL Server `[…]`, …). Without one, the generic profile recognizes
10
+ * the union of quoting forms. An unterminated quote or comment runs to the end.
11
+ */
12
+ export function tokenizeSqlSpans(sql, dialect) {
13
+ const profile = (dialect && lexerProfileFor(dialect)) ?? GENERIC_LEXER;
14
+ const spans = [];
15
+ let codeStart = 0;
16
+ const pushCode = (end) => {
17
+ if (end > codeStart)
18
+ spans.push({ kind: "code", start: codeStart, end });
19
+ };
20
+ for (const token of lexSql(sql, profile)) {
21
+ const kind = token.kind === "string" || token.kind === "quoted_identifier"
22
+ ? "quoted"
23
+ : token.kind === "comment"
24
+ ? "comment"
25
+ : undefined;
26
+ if (!kind)
27
+ continue;
28
+ pushCode(token.start);
29
+ spans.push({ kind, start: token.start, end: token.end });
30
+ codeStart = token.end;
31
+ }
32
+ pushCode(sql.length);
33
+ return spans;
34
+ }
35
+ // `(?<!:)` keeps the type in a `value::type` cast from reading as a `:type` placeholder.
36
+ const PLACEHOLDER_TOKEN_RE = /(?<!:):([a-z][a-z0-9_]*)/g;
37
+ /**
38
+ * Find `:name` placeholders only in code regions, in source order.
39
+ * A quoted `':name'` or a commented-out `-- :name` is invisible by construction.
40
+ */
41
+ export function scanPlaceholders(sql, dialect) {
42
+ const spans = tokenizeSqlSpans(sql, dialect);
43
+ const out = [];
44
+ for (const span of spans) {
45
+ if (span.kind !== "code")
46
+ continue;
47
+ const segment = sql.slice(span.start, span.end);
48
+ PLACEHOLDER_TOKEN_RE.lastIndex = 0;
49
+ let m;
50
+ while ((m = PLACEHOLDER_TOKEN_RE.exec(segment)) !== null) {
51
+ const name = m[1];
52
+ const start = span.start + m.index;
53
+ const end = start + m[0].length;
54
+ out.push({ name, placeholder: m[0], start, end });
55
+ }
56
+ }
57
+ return out;
58
+ }
59
+ /**
60
+ * `:tenant_<root>_ids` placeholders in code regions. Pass the dialect so strings and
61
+ * comments are recognized the way the target engine reads them (MySQL backslash
62
+ * escapes and `#` comments, Postgres nested block comments, …); without one the
63
+ * generic profile is used.
64
+ */
65
+ export function scanTenantPlaceholders(sql, dialect) {
66
+ return scanPlaceholders(sql, dialect).filter((p) => /^tenant_[a-z0-9_]+_ids$/.test(p.name));
67
+ }
68
+ // ---------------------------------------------------------------------------
69
+ // List-context validation
70
+ // ---------------------------------------------------------------------------
71
+ /**
72
+ * A `many` placeholder must be the sole expression inside `IN (...)` / `NOT IN (...)`,
73
+ * or the sole argument of `= ANY(...)` on array dialects.
74
+ */
75
+ export function isValidListContext(sql, occurrence, listBinding) {
76
+ const before = sql.slice(0, occurrence.start);
77
+ const after = sql.slice(occurrence.end);
78
+ const inBefore = /(?:NOT\s+)?IN\s*\(\s*$/i.exec(before);
79
+ if (inBefore) {
80
+ return /^\s*\)/.test(after);
81
+ }
82
+ if (listBinding === "array") {
83
+ const anyBefore = /=\s*ANY\s*\(\s*$/i.exec(before);
84
+ if (anyBefore) {
85
+ return /^\s*\)/.test(after);
86
+ }
87
+ }
88
+ return false;
89
+ }
90
+ /** Detect whether an occurrence sits inside IN ( … ) and return the span of `IN (` … `)`. */
91
+ function inListSpan(sql, occ) {
92
+ const before = sql.slice(0, occ.start);
93
+ const after = sql.slice(occ.end);
94
+ const inBefore = /(?:NOT\s+)?IN\s*\(\s*$/i.exec(before);
95
+ if (!inBefore || !/^\s*\)/.test(after))
96
+ return undefined;
97
+ const closeMatch = /^\s*\)/.exec(after);
98
+ return {
99
+ start: occ.start - inBefore[0].length,
100
+ end: occ.end + closeMatch[0].length,
101
+ isNot: /^NOT\s+/i.test(inBefore[0]),
102
+ };
103
+ }
104
+ function anySpan(sql, occ) {
105
+ const before = sql.slice(0, occ.start);
106
+ const after = sql.slice(occ.end);
107
+ const anyBefore = /=\s*ANY\s*\(\s*$/i.exec(before);
108
+ if (!anyBefore || !/^\s*\)/.test(after))
109
+ return undefined;
110
+ const closeMatch = /^\s*\)/.exec(after);
111
+ return {
112
+ start: occ.start - anyBefore[0].length,
113
+ end: occ.end + closeMatch[0].length,
114
+ };
115
+ }
116
+ // ---------------------------------------------------------------------------
117
+ // Dialect-aware literal escaping
118
+ // ---------------------------------------------------------------------------
119
+ const CONTROL_CHAR_RE = /[\u0000-\u001f\u007f]/;
120
+ /**
121
+ * Escape a scalar value as a SQL literal for the given dialect.
122
+ * Never includes the raw parameter value in thrown error messages.
123
+ */
124
+ export function escapeSqlLiteral(value, dialect) {
125
+ if (typeof value === "boolean") {
126
+ return value ? "TRUE" : "FALSE";
127
+ }
128
+ if (typeof value === "number") {
129
+ if (!Number.isFinite(value)) {
130
+ throw paramError("INVALID_VALUE", "Numeric parameter must be a finite number.");
131
+ }
132
+ return String(value);
133
+ }
134
+ if (CONTROL_CHAR_RE.test(value)) {
135
+ throw paramError("INVALID_VALUE", "String parameter contains a disallowed control character.");
136
+ }
137
+ let escaped = value.replace(/'/g, "''");
138
+ if (dialect?.backslashEscapes === true) {
139
+ escaped = escaped.replace(/\\/g, "\\\\");
140
+ }
141
+ return `'${escaped}'`;
142
+ }
143
+ export function escapeSqlLiteralList(values, dialect) {
144
+ return `(${values.map((v) => escapeSqlLiteral(v, dialect)).join(", ")})`;
145
+ }
146
+ /** Quote-doubling only — used when no dialect is supplied (legacy tenant path). */
147
+ export function escapeSqlLiteralLegacy(value) {
148
+ return "'" + value.replace(/'/g, "''") + "'";
149
+ }
150
+ export function markerStyleForDialect(id) {
151
+ switch (id) {
152
+ case "postgres":
153
+ case "cockroachdb":
154
+ return "dollar";
155
+ case "sqlserver":
156
+ return "atp";
157
+ case "mysql":
158
+ case "mariadb":
159
+ case "sqlite":
160
+ return "question";
161
+ }
162
+ }
163
+ export function formatMarker(style, ordinal) {
164
+ switch (style) {
165
+ case "dollar":
166
+ return `$${ordinal}`;
167
+ case "question":
168
+ return "?";
169
+ case "atp":
170
+ return `@p${ordinal}`;
171
+ }
172
+ }
173
+ function listBindingOf(spec) {
174
+ return spec.listBinding ?? "expand";
175
+ }
176
+ function nextMarker(style, counters) {
177
+ switch (style) {
178
+ case "dollar":
179
+ return formatMarker("dollar", counters.dollar++);
180
+ case "atp":
181
+ return formatMarker("atp", counters.atp++);
182
+ case "question":
183
+ return formatMarker("question", 0);
184
+ }
185
+ }
186
+ // ---------------------------------------------------------------------------
187
+ // bindPreparedQuery
188
+ // ---------------------------------------------------------------------------
189
+ function paramError(reason, message) {
190
+ return new QueryParameterError(message, reason);
191
+ }
192
+ function lookupValue(values, name, placeholder) {
193
+ if (Object.prototype.hasOwnProperty.call(values, placeholder)) {
194
+ return values[placeholder];
195
+ }
196
+ if (Object.prototype.hasOwnProperty.call(values, name)) {
197
+ return values[name];
198
+ }
199
+ return undefined;
200
+ }
201
+ function assertValueMatchesDeclaration(value, type, cardinality) {
202
+ if (cardinality === "many") {
203
+ if (!Array.isArray(value)) {
204
+ throw paramError("INVALID_VALUE", "List parameter requires a non-empty array value.");
205
+ }
206
+ if (value.length === 0) {
207
+ throw paramError("INVALID_VALUE", "List parameter requires a non-empty array value.");
208
+ }
209
+ return value.map((v) => assertScalar(v, type));
210
+ }
211
+ if (Array.isArray(value)) {
212
+ throw paramError("INVALID_VALUE", "Scalar parameter must not be an array.");
213
+ }
214
+ return assertScalar(value, type);
215
+ }
216
+ function assertScalar(value, type) {
217
+ if (value === null || value === undefined) {
218
+ throw paramError("INVALID_VALUE", "Parameter value must not be null or undefined.");
219
+ }
220
+ if (typeof value === "object") {
221
+ throw paramError("INVALID_VALUE", "Parameter value must be a string, number, or boolean.");
222
+ }
223
+ switch (type) {
224
+ case "string":
225
+ case "date":
226
+ case "datetime":
227
+ if (typeof value !== "string") {
228
+ throw paramError("INVALID_VALUE", `Parameter of type ${type} requires a string value.`);
229
+ }
230
+ if (type === "date" && !/^\d{4}-\d{2}-\d{2}$/.test(value)) {
231
+ throw paramError("INVALID_VALUE", "Date parameter must be an ISO date string (YYYY-MM-DD).");
232
+ }
233
+ if (type === "datetime" &&
234
+ !/^\d{4}-\d{2}-\d{2}([T ]\d{2}:\d{2}(:\d{2}(\.\d+)?)?(Z|[+-]\d{2}:?\d{2})?)?$/.test(value)) {
235
+ throw paramError("INVALID_VALUE", "Datetime parameter must be an ISO datetime string.");
236
+ }
237
+ return value;
238
+ case "number":
239
+ if (typeof value !== "number" || !Number.isFinite(value)) {
240
+ throw paramError("INVALID_VALUE", "Numeric parameter must be a finite number.");
241
+ }
242
+ return value;
243
+ case "boolean":
244
+ if (typeof value !== "boolean") {
245
+ throw paramError("INVALID_VALUE", "Boolean parameter requires a boolean value.");
246
+ }
247
+ return value;
248
+ }
249
+ }
250
+ /**
251
+ * Pure, synchronous binder. Substitutes placeholders with escaped literals and
252
+ * allocates dialect-correct driver markers. Does not authorize tenant IDs.
253
+ */
254
+ export function bindPreparedQuery(prepared, values) {
255
+ const spec = BUILT_IN_DIALECTS[prepared.dialect];
256
+ if (!spec) {
257
+ throw paramError("DIALECT_UNSUPPORTED", `Unknown dialect '${prepared.dialect}'.`);
258
+ }
259
+ const listBinding = listBindingOf(spec);
260
+ const style = markerStyleForDialect(prepared.dialect);
261
+ const namedSql = prepared.namedSql;
262
+ const occurrences = scanPlaceholders(namedSql, spec);
263
+ const declByName = new Map(prepared.parameters.map((p) => [p.name, p]));
264
+ for (const p of prepared.parameters) {
265
+ if (!occurrences.some((o) => o.name === p.name)) {
266
+ throw paramError("UNRESOLVED_PLACEHOLDER", `Declared parameter '${p.name}' does not appear in namedSql.`);
267
+ }
268
+ }
269
+ for (const occ of occurrences) {
270
+ if (!declByName.has(occ.name)) {
271
+ throw paramError("UNRESOLVED_PLACEHOLDER", `Placeholder '${occ.placeholder}' has no matching parameter declaration.`);
272
+ }
273
+ }
274
+ const resolvedValues = new Map();
275
+ for (const p of prepared.parameters) {
276
+ const raw = lookupValue(values, p.name, p.placeholder);
277
+ if (raw === undefined) {
278
+ throw paramError("MISSING_VALUE", `Missing value for parameter '${p.name}'.`);
279
+ }
280
+ resolvedValues.set(p.name, assertValueMatchesDeclaration(raw, p.type, p.cardinality));
281
+ }
282
+ for (const occ of occurrences) {
283
+ const decl = declByName.get(occ.name);
284
+ if (decl.cardinality === "many" && !isValidListContext(namedSql, occ, listBinding)) {
285
+ throw paramError("INVALID_LIST_CONTEXT", `List parameter '${occ.name}' must appear as the sole expression inside IN (...)` +
286
+ (listBinding === "array" ? " or = ANY(...)" : "") +
287
+ ".");
288
+ }
289
+ }
290
+ const edits = [];
291
+ const params = [];
292
+ const bindings = [];
293
+ const bindingByName = new Map();
294
+ const counters = { dollar: 1, atp: 0 };
295
+ const ensureBinding = (decl, value) => {
296
+ let binding = bindingByName.get(decl.name);
297
+ if (!binding) {
298
+ binding = {
299
+ name: decl.name,
300
+ placeholder: decl.placeholder,
301
+ type: decl.type,
302
+ cardinality: decl.cardinality,
303
+ description: decl.description,
304
+ value,
305
+ markers: [],
306
+ indices: [],
307
+ source: decl.source,
308
+ };
309
+ bindingByName.set(decl.name, binding);
310
+ bindings.push(binding);
311
+ }
312
+ return binding;
313
+ };
314
+ for (const occ of occurrences) {
315
+ const decl = declByName.get(occ.name);
316
+ const value = resolvedValues.get(occ.name);
317
+ if (decl.cardinality === "many") {
318
+ const list = value;
319
+ const listLiteral = escapeSqlLiteralList(list, spec);
320
+ const binding = ensureBinding(decl, value);
321
+ if (listBinding === "array") {
322
+ // One array-typed driver param. unboundSql uses = ANY($n); bound sql uses IN (...).
323
+ const marker = nextMarker(style, counters);
324
+ const indices = [params.length];
325
+ params.push(list);
326
+ binding.markers.push(marker);
327
+ binding.indices.push(...indices);
328
+ const inSp = inListSpan(namedSql, occ);
329
+ const anySp = anySpan(namedSql, occ);
330
+ if (inSp) {
331
+ edits.push({
332
+ start: inSp.start,
333
+ end: inSp.end,
334
+ literal: `${inSp.isNot ? "NOT " : ""}IN ${listLiteral}`,
335
+ marker: inSp.isNot ? `<> ALL(${marker})` : `= ANY(${marker})`,
336
+ });
337
+ }
338
+ else if (anySp) {
339
+ edits.push({
340
+ start: anySp.start,
341
+ end: anySp.end,
342
+ literal: `IN ${listLiteral}`,
343
+ marker: `= ANY(${marker})`,
344
+ });
345
+ }
346
+ else {
347
+ // Validated above; defensive.
348
+ edits.push({
349
+ start: occ.start,
350
+ end: occ.end,
351
+ literal: listLiteral,
352
+ marker,
353
+ });
354
+ }
355
+ }
356
+ else {
357
+ // expand: one marker / literal element per value
358
+ const markerTexts = [];
359
+ for (const item of list) {
360
+ const marker = nextMarker(style, counters);
361
+ markerTexts.push(marker);
362
+ binding.indices.push(params.length);
363
+ binding.markers.push(marker);
364
+ params.push(item);
365
+ }
366
+ const inSp = inListSpan(namedSql, occ);
367
+ if (inSp) {
368
+ // Replace only the placeholder — outer IN ( ) stays; emit bare list.
369
+ edits.push({
370
+ start: occ.start,
371
+ end: occ.end,
372
+ literal: list.map((v) => escapeSqlLiteral(v, spec)).join(", "),
373
+ marker: markerTexts.join(", "),
374
+ });
375
+ }
376
+ else {
377
+ edits.push({
378
+ start: occ.start,
379
+ end: occ.end,
380
+ literal: listLiteral,
381
+ marker: `(${markerTexts.join(", ")})`,
382
+ });
383
+ }
384
+ }
385
+ }
386
+ else {
387
+ const scalar = value;
388
+ const literal = escapeSqlLiteral(scalar, spec);
389
+ const marker = nextMarker(style, counters);
390
+ const binding = ensureBinding(decl, value);
391
+ binding.markers.push(marker);
392
+ binding.indices.push(params.length);
393
+ params.push(scalar);
394
+ edits.push({ start: occ.start, end: occ.end, literal, marker });
395
+ }
396
+ }
397
+ edits.sort((a, b) => b.start - a.start);
398
+ let sql = namedSql;
399
+ let unboundSql = namedSql;
400
+ for (const edit of edits) {
401
+ sql = sql.slice(0, edit.start) + edit.literal + sql.slice(edit.end);
402
+ unboundSql = unboundSql.slice(0, edit.start) + edit.marker + unboundSql.slice(edit.end);
403
+ }
404
+ if (scanPlaceholders(sql, spec).length > 0 || scanPlaceholders(unboundSql, spec).length > 0) {
405
+ throw paramError("UNRESOLVED_PLACEHOLDER", "One or more placeholders remain after binding.");
406
+ }
407
+ validateSelectSql(spec, sql);
408
+ validateSelectSql(spec, unboundSql);
409
+ return { sql, unboundSql, params, bindings };
410
+ }
411
+ /**
412
+ * Compare two SQL strings structurally for the parameterize consistency check.
413
+ */
414
+ export function sqlStructurallyEqual(a, b) {
415
+ const norm = (s) => s
416
+ .trim()
417
+ .replace(/;\s*$/, "")
418
+ .replace(/\s+/g, " ")
419
+ .toLowerCase();
420
+ return norm(a) === norm(b);
421
+ }
422
+ //# sourceMappingURL=bind.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bind.js","sourceRoot":"","sources":["../../src/sql/bind.ts"],"names":[],"mappings":"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"}
@@ -6,9 +6,19 @@
6
6
  * Authoring guidance:
7
7
  * - Keep `promptBrief` to one short paragraph; surfaced in the model's user prompt.
8
8
  * - `extraForbiddenKeywords` is additive on top of the dialect-agnostic read-only
9
- * denylist (`insert`, `update`, `delete`, `drop`, …) baked into `validateSelectSql`.
9
+ * denylist (`insert`, `update`, `delete`, `drop`, `into`, …) baked into
10
+ * `validateSelectSql`. Matched against unquoted keyword tokens only.
11
+ * - `blockedFunctions` lists functions with side effects (writes, file/network access,
12
+ * sleeping, session changes) that `validateSelectSql` rejects when called.
10
13
  * - `extraValidate` runs *after* the base validator passes; throw a
11
14
  * `SqlValidationError` to reject dialect-specific shapes.
15
+ * - `id` also selects how SQL is lexed (string escapes, quoting, comment syntax) — see
16
+ * `lexer.ts`. Specs that spread a built-in (`{ ...POSTGRES_DIALECT, … }`) inherit its
17
+ * denylists; a spec that overrides `extraForbiddenKeywords` / `blockedFunctions`
18
+ * replaces them.
19
+ *
20
+ * These lists are defense in depth for model-generated SQL, not a security boundary:
21
+ * execute generated SQL under a read-only database role.
12
22
  */
13
23
  /** Stable identifier for a built-in dialect. Connectors may surface this via `IntrospectionResult.provider`. */
14
24
  export type DialectId = "postgres" | "cockroachdb" | "mysql" | "mariadb" | "sqlite" | "sqlserver";
@@ -21,8 +31,21 @@ export type DialectSpec = {
21
31
  identifierQuote: '"' | '`';
22
32
  /** Extra keywords to forbid on top of the dialect-agnostic base denylist. */
23
33
  extraForbiddenKeywords?: readonly string[];
34
+ /**
35
+ * Function names `validateSelectSql` rejects when called (`name(`, including
36
+ * schema-qualified and quoted spellings). Case-insensitive.
37
+ */
38
+ blockedFunctions?: readonly string[];
24
39
  /** Optional engine-specific post-validator. Receives SQL already passing the base shape checks. */
25
40
  extraValidate?: (sql: string) => void;
41
+ /** How list-valued placeholders bind in `unboundSql`. Default "expand" when absent. */
42
+ listBinding?: "array" | "expand";
43
+ /**
44
+ * Whether backslash is an escape character inside string literals. Default false for
45
+ * escaping bound values; the validator's lexer treats an unset value on a MySQL-family
46
+ * spec as the server default (escapes on).
47
+ */
48
+ backslashEscapes?: boolean;
26
49
  };
27
50
  /** PostgreSQL — the original AskDB target. */
28
51
  export declare const POSTGRES_DIALECT: DialectSpec;
@@ -1 +1 @@
1
- {"version":3,"file":"dialect-spec.d.ts","sourceRoot":"","sources":["../../src/sql/dialect-spec.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,gHAAgH;AAChH,MAAM,MAAM,SAAS,GACjB,UAAU,GACV,aAAa,GACb,OAAO,GACP,SAAS,GACT,QAAQ,GACR,WAAW,CAAC;AAEhB,MAAM,MAAM,WAAW,GAAG;IACxB,EAAE,EAAE,SAAS,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,gEAAgE;IAChE,WAAW,EAAE,MAAM,CAAC;IACpB,6EAA6E;IAC7E,eAAe,EAAE,GAAG,GAAG,GAAG,CAAC;IAC3B,6EAA6E;IAC7E,sBAAsB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC3C,mGAAmG;IACnG,aAAa,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;CACvC,CAAC;AAEF,8CAA8C;AAC9C,eAAO,MAAM,gBAAgB,EAAE,WAQ9B,CAAC;AAEF,kFAAkF;AAClF,eAAO,MAAM,mBAAmB,EAAE,WAIjC,CAAC;AAEF,mEAAmE;AACnE,eAAO,MAAM,aAAa,EAAE,WAU3B,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,eAAe,EAAE,WAI7B,CAAC;AAEF,+EAA+E;AAC/E,eAAO,MAAM,cAAc,EAAE,WAc5B,CAAC;AAEF,oCAAoC;AACpC,eAAO,MAAM,iBAAiB,EAAE,WAc/B,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,iBAAiB;;;;;;;CAOqB,CAAC;AAEpD,MAAM,MAAM,gBAAgB,GAAG,MAAM,OAAO,iBAAiB,CAAC;AAE9D,eAAO,MAAM,qBAAqB,EAAE,SAAS,gBAAgB,EAE7B,CAAC;AAEjC,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,gBAAgB,CAE5E;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,EAAE,EAAE,gBAAgB,GAAG,WAAW,CAQhE"}
1
+ {"version":3,"file":"dialect-spec.d.ts","sourceRoot":"","sources":["../../src/sql/dialect-spec.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,gHAAgH;AAChH,MAAM,MAAM,SAAS,GACjB,UAAU,GACV,aAAa,GACb,OAAO,GACP,SAAS,GACT,QAAQ,GACR,WAAW,CAAC;AAEhB,MAAM,MAAM,WAAW,GAAG;IACxB,EAAE,EAAE,SAAS,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,gEAAgE;IAChE,WAAW,EAAE,MAAM,CAAC;IACpB,6EAA6E;IAC7E,eAAe,EAAE,GAAG,GAAG,GAAG,CAAC;IAC3B,6EAA6E;IAC7E,sBAAsB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC3C;;;OAGG;IACH,gBAAgB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACrC,mGAAmG;IACnG,aAAa,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IACtC,uFAAuF;IACvF,WAAW,CAAC,EAAE,OAAO,GAAG,QAAQ,CAAC;IACjC;;;;OAIG;IACH,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC5B,CAAC;AA8CF,8CAA8C;AAC9C,eAAO,MAAM,gBAAgB,EAAE,WAW9B,CAAC;AAEF,kFAAkF;AAClF,eAAO,MAAM,mBAAmB,EAAE,WAIjC,CAAC;AAEF,mEAAmE;AACnE,eAAO,MAAM,aAAa,EAAE,WAmB3B,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,eAAe,EAAE,WAI7B,CAAC;AAEF,+EAA+E;AAC/E,eAAO,MAAM,cAAc,EAAE,WAkB5B,CAAC;AAEF,oCAAoC;AACpC,eAAO,MAAM,iBAAiB,EAAE,WAwB/B,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,iBAAiB;;;;;;;CAOqB,CAAC;AAEpD,MAAM,MAAM,gBAAgB,GAAG,MAAM,OAAO,iBAAiB,CAAC;AAE9D,eAAO,MAAM,qBAAqB,EAAE,SAAS,gBAAgB,EAE7B,CAAC;AAEjC,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,gBAAgB,CAE5E;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,EAAE,EAAE,gBAAgB,GAAG,WAAW,CAQhE"}
@@ -6,10 +6,63 @@
6
6
  * Authoring guidance:
7
7
  * - Keep `promptBrief` to one short paragraph; surfaced in the model's user prompt.
8
8
  * - `extraForbiddenKeywords` is additive on top of the dialect-agnostic read-only
9
- * denylist (`insert`, `update`, `delete`, `drop`, …) baked into `validateSelectSql`.
9
+ * denylist (`insert`, `update`, `delete`, `drop`, `into`, …) baked into
10
+ * `validateSelectSql`. Matched against unquoted keyword tokens only.
11
+ * - `blockedFunctions` lists functions with side effects (writes, file/network access,
12
+ * sleeping, session changes) that `validateSelectSql` rejects when called.
10
13
  * - `extraValidate` runs *after* the base validator passes; throw a
11
14
  * `SqlValidationError` to reject dialect-specific shapes.
15
+ * - `id` also selects how SQL is lexed (string escapes, quoting, comment syntax) — see
16
+ * `lexer.ts`. Specs that spread a built-in (`{ ...POSTGRES_DIALECT, … }`) inherit its
17
+ * denylists; a spec that overrides `extraForbiddenKeywords` / `blockedFunctions`
18
+ * replaces them.
19
+ *
20
+ * These lists are defense in depth for model-generated SQL, not a security boundary:
21
+ * execute generated SQL under a read-only database role.
22
+ */
23
+ /**
24
+ * Postgres functions with side effects or host/file/network access. Superuser-only
25
+ * functions are listed too: the validator does not know the executing role.
12
26
  */
27
+ const POSTGRES_BLOCKED_FUNCTIONS = [
28
+ // session / server configuration and process control
29
+ "set_config", "pg_reload_conf", "pg_rotate_logfile", "pg_terminate_backend",
30
+ "pg_cancel_backend", "pg_log_backend_memory_contexts", "pg_promote",
31
+ "pg_switch_wal", "pg_create_restore_point", "pg_start_backup", "pg_stop_backup",
32
+ "pg_backup_start", "pg_backup_stop", "pg_import_system_collations",
33
+ // sleeping
34
+ "pg_sleep", "pg_sleep_for", "pg_sleep_until",
35
+ // server file system
36
+ "pg_read_file", "pg_read_binary_file", "pg_ls_dir", "pg_stat_file", "pg_ls_logdir",
37
+ "pg_ls_waldir", "pg_ls_tmpdir", "pg_ls_archive_statusdir", "pg_ls_logicalsnapdir",
38
+ "pg_ls_logicalmapdir", "pg_ls_replslotdir", "pg_file_write", "pg_file_rename",
39
+ "pg_file_unlink", "pg_file_sync",
40
+ // large objects (lo_import / lo_export touch the server file system)
41
+ "lo_import", "lo_export", "lo_unlink", "lo_create", "lo_creat", "lo_from_bytea",
42
+ "lo_put", "lo_open", "lo_write", "lowrite", "lo_truncate", "lo_truncate64",
43
+ // dblink runs SQL on another (or the same) server
44
+ "dblink", "dblink_exec", "dblink_connect", "dblink_connect_u", "dblink_open",
45
+ "dblink_send_query", "dblink_fetch", "dblink_get_result",
46
+ // replication slots, messages, notifications
47
+ "pg_create_physical_replication_slot", "pg_create_logical_replication_slot",
48
+ "pg_drop_replication_slot", "pg_copy_physical_replication_slot",
49
+ "pg_copy_logical_replication_slot", "pg_replication_slot_advance",
50
+ "pg_logical_emit_message", "pg_notify",
51
+ // advisory locks
52
+ "pg_advisory_lock", "pg_advisory_lock_shared", "pg_advisory_xact_lock",
53
+ "pg_advisory_xact_lock_shared", "pg_try_advisory_lock", "pg_try_advisory_lock_shared",
54
+ "pg_try_advisory_xact_lock", "pg_try_advisory_xact_lock_shared", "pg_advisory_unlock",
55
+ "pg_advisory_unlock_shared", "pg_advisory_unlock_all",
56
+ // statistics resets
57
+ "pg_stat_reset", "pg_stat_reset_shared", "pg_stat_reset_single_table_counters",
58
+ "pg_stat_reset_single_function_counters", "pg_stat_reset_slru",
59
+ "pg_stat_reset_replication_slot",
60
+ // sequences
61
+ "nextval", "setval",
62
+ // functions that execute a query passed as a string
63
+ "query_to_xml", "query_to_xmlschema", "query_to_xml_and_xmlschema", "cursor_to_xml",
64
+ "ts_stat",
65
+ ];
13
66
  /** PostgreSQL — the original AskDB target. */
14
67
  export const POSTGRES_DIALECT = {
15
68
  id: "postgres",
@@ -18,6 +71,9 @@ export const POSTGRES_DIALECT = {
18
71
  "Quote identifiers with double quotes when they collide with keywords or contain mixed case. " +
19
72
  'Cast with `value::type`. Use NOW(), CURRENT_DATE, date_trunc(). Concatenate with `||`.',
20
73
  identifierQuote: '"',
74
+ blockedFunctions: POSTGRES_BLOCKED_FUNCTIONS,
75
+ listBinding: "array",
76
+ backslashEscapes: false,
21
77
  };
22
78
  /** CockroachDB — PostgreSQL-wire-compatible; reuses the Postgres prompt brief. */
23
79
  export const COCKROACHDB_DIALECT = {
@@ -35,6 +91,15 @@ export const MYSQL_DIALECT = {
35
91
  "Concatenate with `CONCAT(a, b)` — `||` is logical OR in MySQL, not string concat. " +
36
92
  "Limit rows with `LIMIT n` (or `LIMIT offset, n`).",
37
93
  identifierQuote: "`",
94
+ // INTO OUTFILE / DUMPFILE are also covered by the base `into` keyword.
95
+ extraForbiddenKeywords: ["outfile", "dumpfile"],
96
+ blockedFunctions: [
97
+ "load_file", "sleep", "benchmark", "get_lock", "release_lock", "release_all_locks",
98
+ "master_pos_wait", "source_pos_wait", "wait_for_executed_gtid_set",
99
+ "wait_until_sql_thread_after_gtids", "sys_exec", "sys_eval",
100
+ ],
101
+ listBinding: "expand",
102
+ backslashEscapes: true,
38
103
  };
39
104
  /**
40
105
  * MariaDB — MySQL-protocol-compatible; the SELECT surface is functionally
@@ -60,6 +125,10 @@ export const SQLITE_DIALECT = {
60
125
  // is maintenance. None belong in a generated read-only SELECT. (`vacuum` is
61
126
  // already in the dialect-agnostic base denylist.)
62
127
  extraForbiddenKeywords: ["attach", "detach", "pragma", "reindex"],
128
+ // load_extension loads native code; readfile/writefile/edit are CLI-shell extensions.
129
+ blockedFunctions: ["load_extension", "readfile", "writefile", "edit", "fts3_tokenizer"],
130
+ listBinding: "expand",
131
+ backslashEscapes: false,
63
132
  };
64
133
  /** Microsoft SQL Server (T-SQL). */
65
134
  export const SQLSERVER_DIALECT = {
@@ -73,8 +142,18 @@ export const SQLSERVER_DIALECT = {
73
142
  "Limit rows with `SELECT TOP (n) …` or `ORDER BY … OFFSET m ROWS FETCH NEXT n ROWS ONLY` — there is no LIMIT keyword.",
74
143
  identifierQuote: '"',
75
144
  // T-SQL keywords that shouldn't appear in read-only analytics SQL. (`call`
76
- // is already in the base denylist; T-SQL uses EXEC / EXECUTE for procs.)
77
- extraForbiddenKeywords: ["exec", "execute", "merge", "openrowset", "openquery"],
145
+ // is already in the base denylist; T-SQL uses EXEC / EXECUTE for procs, which also
146
+ // covers `EXEC sp_…` / `EXEC xp_…`.) T-SQL runs a batch without semicolons —
147
+ // `SELECT 1 SHUTDOWN` is two statements — so statement-level verbs are listed here
148
+ // even though they cannot appear inside a SELECT.
149
+ extraForbiddenKeywords: [
150
+ "exec", "execute", "merge", "openrowset", "openquery", "opendatasource",
151
+ "shutdown", "kill", "backup", "restore", "dbcc", "reconfigure", "deny", "waitfor",
152
+ "bulk", "use", "set", "revert", "setuser", "checkpoint", "commit", "rollback",
153
+ "writetext", "updatetext", "disable", "enable", "receive", "send", "xp_cmdshell",
154
+ ],
155
+ listBinding: "expand",
156
+ backslashEscapes: false,
78
157
  };
79
158
  /**
80
159
  * Registry of dialect specs shipped with `@askdb/core`. Connectors that
@@ -1 +1 @@
1
- {"version":3,"file":"dialect-spec.js","sourceRoot":"","sources":["../../src/sql/dialect-spec.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAwBH,8CAA8C;AAC9C,MAAM,CAAC,MAAM,gBAAgB,GAAgB;IAC3C,EAAE,EAAE,UAAU;IACd,WAAW,EAAE,YAAY;IACzB,WAAW,EACT,8DAA8D;QAC9D,8FAA8F;QAC9F,wFAAwF;IAC1F,eAAe,EAAE,GAAG;CACrB,CAAC;AAEF,kFAAkF;AAClF,MAAM,CAAC,MAAM,mBAAmB,GAAgB;IAC9C,GAAG,gBAAgB;IACnB,EAAE,EAAE,aAAa;IACjB,WAAW,EAAE,aAAa;CAC3B,CAAC;AAEF,mEAAmE;AACnE,MAAM,CAAC,MAAM,aAAa,GAAgB;IACxC,EAAE,EAAE,OAAO;IACX,WAAW,EAAE,OAAO;IACpB,WAAW,EACT,2IAA2I;QAC3I,0EAA0E;QAC1E,gGAAgG;QAChG,oFAAoF;QACpF,mDAAmD;IACrD,eAAe,EAAE,GAAG;CACrB,CAAC;AAEF;;;;GAIG;AACH,MAAM,CAAC,MAAM,eAAe,GAAgB;IAC1C,GAAG,aAAa;IAChB,EAAE,EAAE,SAAS;IACb,WAAW,EAAE,SAAS;CACvB,CAAC;AAEF,+EAA+E;AAC/E,MAAM,CAAC,MAAM,cAAc,GAAgB;IACzC,EAAE,EAAE,QAAQ;IACZ,WAAW,EAAE,QAAQ;IACrB,WAAW,EACT,iIAAiI;QACjI,8EAA8E;QAC9E,4GAA4G;QAC5G,oFAAoF;QACpF,8GAA8G;IAChH,eAAe,EAAE,GAAG;IACpB,6EAA6E;IAC7E,4EAA4E;IAC5E,kDAAkD;IAClD,sBAAsB,EAAE,CAAC,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,SAAS,CAAC;CAClE,CAAC;AAEF,oCAAoC;AACpC,MAAM,CAAC,MAAM,iBAAiB,GAAgB;IAC5C,EAAE,EAAE,WAAW;IACf,WAAW,EAAE,sBAAsB;IACnC,WAAW,EACT,qJAAqJ;QACrJ,6DAA6D;QAC7D,6DAA6D;QAC7D,oEAAoE;QACpE,wGAAwG;QACxG,sHAAsH;IACxH,eAAe,EAAE,GAAG;IACpB,2EAA2E;IAC3E,yEAAyE;IACzE,sBAAsB,EAAE,CAAC,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,YAAY,EAAE,WAAW,CAAC;CAChF,CAAC;AAEF;;;;GAIG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG;IAC/B,QAAQ,EAAE,gBAAgB;IAC1B,WAAW,EAAE,mBAAmB;IAChC,KAAK,EAAE,aAAa;IACpB,OAAO,EAAE,eAAe;IACxB,MAAM,EAAE,cAAc;IACtB,SAAS,EAAE,iBAAiB;CACqB,CAAC;AAIpD,MAAM,CAAC,MAAM,qBAAqB,GAAgC,MAAM,CAAC,IAAI,CAC3E,iBAAiB,CACa,CAAC;AAEjC,MAAM,UAAU,kBAAkB,CAAC,KAAc;IAC/C,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,IAAI,iBAAiB,CAAC;AACjE,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,cAAc,CAAC,EAAoB;IACjD,MAAM,IAAI,GAAG,iBAAiB,CAAC,EAAE,CAAC,CAAC;IACnC,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,MAAM,IAAI,KAAK,CACb,qCAAqC,EAAE,iBAAiB,qBAAqB,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAC5F,CAAC;IACJ,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC"}
1
+ {"version":3,"file":"dialect-spec.js","sourceRoot":"","sources":["../../src/sql/dialect-spec.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAqCH;;;GAGG;AACH,MAAM,0BAA0B,GAAsB;IACpD,qDAAqD;IACrD,YAAY,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,sBAAsB;IAC3E,mBAAmB,EAAE,gCAAgC,EAAE,YAAY;IACnE,eAAe,EAAE,yBAAyB,EAAE,iBAAiB,EAAE,gBAAgB;IAC/E,iBAAiB,EAAE,gBAAgB,EAAE,6BAA6B;IAClE,WAAW;IACX,UAAU,EAAE,cAAc,EAAE,gBAAgB;IAC5C,qBAAqB;IACrB,cAAc,EAAE,qBAAqB,EAAE,WAAW,EAAE,cAAc,EAAE,cAAc;IAClF,cAAc,EAAE,cAAc,EAAE,yBAAyB,EAAE,sBAAsB;IACjF,qBAAqB,EAAE,mBAAmB,EAAE,eAAe,EAAE,gBAAgB;IAC7E,gBAAgB,EAAE,cAAc;IAChC,qEAAqE;IACrE,WAAW,EAAE,WAAW,EAAE,WAAW,EAAE,WAAW,EAAE,UAAU,EAAE,eAAe;IAC/E,QAAQ,EAAE,SAAS,EAAE,UAAU,EAAE,SAAS,EAAE,aAAa,EAAE,eAAe;IAC1E,kDAAkD;IAClD,QAAQ,EAAE,aAAa,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,aAAa;IAC5E,mBAAmB,EAAE,cAAc,EAAE,mBAAmB;IACxD,6CAA6C;IAC7C,qCAAqC,EAAE,oCAAoC;IAC3E,0BAA0B,EAAE,mCAAmC;IAC/D,kCAAkC,EAAE,6BAA6B;IACjE,yBAAyB,EAAE,WAAW;IACtC,iBAAiB;IACjB,kBAAkB,EAAE,yBAAyB,EAAE,uBAAuB;IACtE,8BAA8B,EAAE,sBAAsB,EAAE,6BAA6B;IACrF,2BAA2B,EAAE,kCAAkC,EAAE,oBAAoB;IACrF,2BAA2B,EAAE,wBAAwB;IACrD,oBAAoB;IACpB,eAAe,EAAE,sBAAsB,EAAE,qCAAqC;IAC9E,wCAAwC,EAAE,oBAAoB;IAC9D,gCAAgC;IAChC,YAAY;IACZ,SAAS,EAAE,QAAQ;IACnB,oDAAoD;IACpD,cAAc,EAAE,oBAAoB,EAAE,4BAA4B,EAAE,eAAe;IACnF,SAAS;CACV,CAAC;AAEF,8CAA8C;AAC9C,MAAM,CAAC,MAAM,gBAAgB,GAAgB;IAC3C,EAAE,EAAE,UAAU;IACd,WAAW,EAAE,YAAY;IACzB,WAAW,EACT,8DAA8D;QAC9D,8FAA8F;QAC9F,wFAAwF;IAC1F,eAAe,EAAE,GAAG;IACpB,gBAAgB,EAAE,0BAA0B;IAC5C,WAAW,EAAE,OAAO;IACpB,gBAAgB,EAAE,KAAK;CACxB,CAAC;AAEF,kFAAkF;AAClF,MAAM,CAAC,MAAM,mBAAmB,GAAgB;IAC9C,GAAG,gBAAgB;IACnB,EAAE,EAAE,aAAa;IACjB,WAAW,EAAE,aAAa;CAC3B,CAAC;AAEF,mEAAmE;AACnE,MAAM,CAAC,MAAM,aAAa,GAAgB;IACxC,EAAE,EAAE,OAAO;IACX,WAAW,EAAE,OAAO;IACpB,WAAW,EACT,2IAA2I;QAC3I,0EAA0E;QAC1E,gGAAgG;QAChG,oFAAoF;QACpF,mDAAmD;IACrD,eAAe,EAAE,GAAG;IACpB,uEAAuE;IACvE,sBAAsB,EAAE,CAAC,SAAS,EAAE,UAAU,CAAC;IAC/C,gBAAgB,EAAE;QAChB,WAAW,EAAE,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,cAAc,EAAE,mBAAmB;QAClF,iBAAiB,EAAE,iBAAiB,EAAE,4BAA4B;QAClE,mCAAmC,EAAE,UAAU,EAAE,UAAU;KAC5D;IACD,WAAW,EAAE,QAAQ;IACrB,gBAAgB,EAAE,IAAI;CACvB,CAAC;AAEF;;;;GAIG;AACH,MAAM,CAAC,MAAM,eAAe,GAAgB;IAC1C,GAAG,aAAa;IAChB,EAAE,EAAE,SAAS;IACb,WAAW,EAAE,SAAS;CACvB,CAAC;AAEF,+EAA+E;AAC/E,MAAM,CAAC,MAAM,cAAc,GAAgB;IACzC,EAAE,EAAE,QAAQ;IACZ,WAAW,EAAE,QAAQ;IACrB,WAAW,EACT,iIAAiI;QACjI,8EAA8E;QAC9E,4GAA4G;QAC5G,oFAAoF;QACpF,8GAA8G;IAChH,eAAe,EAAE,GAAG;IACpB,6EAA6E;IAC7E,4EAA4E;IAC5E,kDAAkD;IAClD,sBAAsB,EAAE,CAAC,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,SAAS,CAAC;IACjE,sFAAsF;IACtF,gBAAgB,EAAE,CAAC,gBAAgB,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,EAAE,gBAAgB,CAAC;IACvF,WAAW,EAAE,QAAQ;IACrB,gBAAgB,EAAE,KAAK;CACxB,CAAC;AAEF,oCAAoC;AACpC,MAAM,CAAC,MAAM,iBAAiB,GAAgB;IAC5C,EAAE,EAAE,WAAW;IACf,WAAW,EAAE,sBAAsB;IACnC,WAAW,EACT,qJAAqJ;QACrJ,6DAA6D;QAC7D,6DAA6D;QAC7D,oEAAoE;QACpE,wGAAwG;QACxG,sHAAsH;IACxH,eAAe,EAAE,GAAG;IACpB,2EAA2E;IAC3E,mFAAmF;IACnF,6EAA6E;IAC7E,mFAAmF;IACnF,kDAAkD;IAClD,sBAAsB,EAAE;QACtB,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,gBAAgB;QACvE,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,EAAE,SAAS;QACjF,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,YAAY,EAAE,QAAQ,EAAE,UAAU;QAC7E,WAAW,EAAE,YAAY,EAAE,SAAS,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,EAAE,aAAa;KACjF;IACD,WAAW,EAAE,QAAQ;IACrB,gBAAgB,EAAE,KAAK;CACxB,CAAC;AAEF;;;;GAIG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG;IAC/B,QAAQ,EAAE,gBAAgB;IAC1B,WAAW,EAAE,mBAAmB;IAChC,KAAK,EAAE,aAAa;IACpB,OAAO,EAAE,eAAe;IACxB,MAAM,EAAE,cAAc;IACtB,SAAS,EAAE,iBAAiB;CACqB,CAAC;AAIpD,MAAM,CAAC,MAAM,qBAAqB,GAAgC,MAAM,CAAC,IAAI,CAC3E,iBAAiB,CACa,CAAC;AAEjC,MAAM,UAAU,kBAAkB,CAAC,KAAc;IAC/C,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,IAAI,iBAAiB,CAAC;AACjE,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,cAAc,CAAC,EAAoB;IACjD,MAAM,IAAI,GAAG,iBAAiB,CAAC,EAAE,CAAC,CAAC;IACnC,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,MAAM,IAAI,KAAK,CACb,qCAAqC,EAAE,iBAAiB,qBAAqB,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAC5F,CAAC;IACJ,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC"}
@@ -1,5 +1,12 @@
1
1
  /**
2
- * Prefer fenced ```sql blocks; otherwise use trimmed prose if it resembles a single SELECT.
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 declare function extractSqlFromModelText(raw: string): string;
7
+ /**
8
+ * Extract the ```sql-unbound fence from model text, if present.
9
+ * Returns undefined when the fence is missing or empty.
10
+ */
11
+ export declare function extractUnboundSqlFromModelText(raw: string): string | undefined;
5
12
  //# sourceMappingURL=extract-sql.d.ts.map