@negusdev/dbask 0.0.0-stage → 0.1.8
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/CHANGELOG.md +40 -0
- package/LICENSE +15 -0
- package/README.md +422 -2
- package/dist/ai/factory.d.ts +4 -0
- package/dist/ai/factory.d.ts.map +1 -0
- package/dist/ai/factory.js +55 -0
- package/dist/ai/factory.js.map +1 -0
- package/dist/ai/provider.d.ts +13 -0
- package/dist/ai/provider.d.ts.map +1 -0
- package/dist/ai/provider.js +2 -0
- package/dist/ai/provider.js.map +1 -0
- package/dist/ai/sdk-provider.d.ts +13 -0
- package/dist/ai/sdk-provider.d.ts.map +1 -0
- package/dist/ai/sdk-provider.js +36 -0
- package/dist/ai/sdk-provider.js.map +1 -0
- package/dist/cli-args.d.ts +26 -0
- package/dist/cli-args.d.ts.map +1 -0
- package/dist/cli-args.js +72 -0
- package/dist/cli-args.js.map +1 -0
- package/dist/cli-observer.d.ts +23 -0
- package/dist/cli-observer.d.ts.map +1 -0
- package/dist/cli-observer.js +224 -0
- package/dist/cli-observer.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +127 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/init.d.ts +2 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +247 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/validate.d.ts +31 -0
- package/dist/commands/validate.d.ts.map +1 -0
- package/dist/commands/validate.js +205 -0
- package/dist/commands/validate.js.map +1 -0
- package/dist/config/config.d.ts +42 -0
- package/dist/config/config.d.ts.map +1 -0
- package/dist/config/config.js +94 -0
- package/dist/config/config.js.map +1 -0
- package/dist/context/db-context.d.ts +12 -0
- package/dist/context/db-context.d.ts.map +1 -0
- package/dist/context/db-context.js +29 -0
- package/dist/context/db-context.js.map +1 -0
- package/dist/core/agent/agent.d.ts +57 -0
- package/dist/core/agent/agent.d.ts.map +1 -0
- package/dist/core/agent/agent.js +518 -0
- package/dist/core/agent/agent.js.map +1 -0
- package/dist/core/agent/index.d.ts +4 -0
- package/dist/core/agent/index.d.ts.map +1 -0
- package/dist/core/agent/index.js +2 -0
- package/dist/core/agent/index.js.map +1 -0
- package/dist/core/agent/observability.d.ts +19 -0
- package/dist/core/agent/observability.d.ts.map +1 -0
- package/dist/core/agent/observability.js +4 -0
- package/dist/core/agent/observability.js.map +1 -0
- package/dist/core/agent/query-plan.d.ts +68 -0
- package/dist/core/agent/query-plan.d.ts.map +1 -0
- package/dist/core/agent/query-plan.js +282 -0
- package/dist/core/agent/query-plan.js.map +1 -0
- package/dist/core/tools/describe-table.d.ts +6 -0
- package/dist/core/tools/describe-table.d.ts.map +1 -0
- package/dist/core/tools/describe-table.js +25 -0
- package/dist/core/tools/describe-table.js.map +1 -0
- package/dist/core/tools/describe-tables.d.ts +6 -0
- package/dist/core/tools/describe-tables.d.ts.map +1 -0
- package/dist/core/tools/describe-tables.js +22 -0
- package/dist/core/tools/describe-tables.js.map +1 -0
- package/dist/core/tools/execute-query.d.ts +6 -0
- package/dist/core/tools/execute-query.d.ts.map +1 -0
- package/dist/core/tools/execute-query.js +31 -0
- package/dist/core/tools/execute-query.js.map +1 -0
- package/dist/core/tools/explain-query.d.ts +10 -0
- package/dist/core/tools/explain-query.d.ts.map +1 -0
- package/dist/core/tools/explain-query.js +34 -0
- package/dist/core/tools/explain-query.js.map +1 -0
- package/dist/core/tools/get-relationships.d.ts +6 -0
- package/dist/core/tools/get-relationships.d.ts.map +1 -0
- package/dist/core/tools/get-relationships.js +23 -0
- package/dist/core/tools/get-relationships.js.map +1 -0
- package/dist/core/tools/index.d.ts +9 -0
- package/dist/core/tools/index.d.ts.map +1 -0
- package/dist/core/tools/index.js +8 -0
- package/dist/core/tools/index.js.map +1 -0
- package/dist/core/tools/list-tables.d.ts +3 -0
- package/dist/core/tools/list-tables.d.ts.map +1 -0
- package/dist/core/tools/list-tables.js +18 -0
- package/dist/core/tools/list-tables.js.map +1 -0
- package/dist/core/tools/registry.d.ts +11 -0
- package/dist/core/tools/registry.d.ts.map +1 -0
- package/dist/core/tools/registry.js +48 -0
- package/dist/core/tools/registry.js.map +1 -0
- package/dist/core/types/index.d.ts +102 -0
- package/dist/core/types/index.d.ts.map +1 -0
- package/dist/core/types/index.js +6 -0
- package/dist/core/types/index.js.map +1 -0
- package/dist/database/adapter.d.ts +3 -0
- package/dist/database/adapter.d.ts.map +1 -0
- package/dist/database/adapter.js +2 -0
- package/dist/database/adapter.js.map +1 -0
- package/dist/database/factory.d.ts +16 -0
- package/dist/database/factory.d.ts.map +1 -0
- package/dist/database/factory.js +27 -0
- package/dist/database/factory.js.map +1 -0
- package/dist/database/index.d.ts +8 -0
- package/dist/database/index.d.ts.map +1 -0
- package/dist/database/index.js +4 -0
- package/dist/database/index.js.map +1 -0
- package/dist/database/mysql/adapter.d.ts +26 -0
- package/dist/database/mysql/adapter.d.ts.map +1 -0
- package/dist/database/mysql/adapter.js +131 -0
- package/dist/database/mysql/adapter.js.map +1 -0
- package/dist/database/postgres/adapter.d.ts +60 -0
- package/dist/database/postgres/adapter.d.ts.map +1 -0
- package/dist/database/postgres/adapter.js +307 -0
- package/dist/database/postgres/adapter.js.map +1 -0
- package/dist/database/result-limits.d.ts +17 -0
- package/dist/database/result-limits.d.ts.map +1 -0
- package/dist/database/result-limits.js +26 -0
- package/dist/database/result-limits.js.map +1 -0
- package/dist/index.d.ts +20 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +13 -0
- package/dist/index.js.map +1 -0
- package/dist/safety/limits.d.ts +7 -0
- package/dist/safety/limits.d.ts.map +1 -0
- package/dist/safety/limits.js +15 -0
- package/dist/safety/limits.js.map +1 -0
- package/dist/safety/policy.d.ts +8 -0
- package/dist/safety/policy.d.ts.map +1 -0
- package/dist/safety/policy.js +11 -0
- package/dist/safety/policy.js.map +1 -0
- package/dist/safety/sql-tokenizer.d.ts +49 -0
- package/dist/safety/sql-tokenizer.d.ts.map +1 -0
- package/dist/safety/sql-tokenizer.js +240 -0
- package/dist/safety/sql-tokenizer.js.map +1 -0
- package/dist/safety/sql-validator.d.ts +34 -0
- package/dist/safety/sql-validator.d.ts.map +1 -0
- package/dist/safety/sql-validator.js +270 -0
- package/dist/safety/sql-validator.js.map +1 -0
- package/dist/schema/cache.d.ts +24 -0
- package/dist/schema/cache.d.ts.map +1 -0
- package/dist/schema/cache.js +57 -0
- package/dist/schema/cache.js.map +1 -0
- package/dist/ui/markdown.d.ts +8 -0
- package/dist/ui/markdown.d.ts.map +1 -0
- package/dist/ui/markdown.js +205 -0
- package/dist/ui/markdown.js.map +1 -0
- package/dist/ui/spinner.d.ts +32 -0
- package/dist/ui/spinner.d.ts.map +1 -0
- package/dist/ui/spinner.js +74 -0
- package/dist/ui/spinner.js.map +1 -0
- package/dist/ui/sql-highlight.d.ts +4 -0
- package/dist/ui/sql-highlight.d.ts.map +1 -0
- package/dist/ui/sql-highlight.js +28 -0
- package/dist/ui/sql-highlight.js.map +1 -0
- package/dist/ui/style.d.ts +38 -0
- package/dist/ui/style.d.ts.map +1 -0
- package/dist/ui/style.js +69 -0
- package/dist/ui/style.js.map +1 -0
- package/package.json +91 -4
- package/sql-ai.example.md +32 -0
|
@@ -0,0 +1,307 @@
|
|
|
1
|
+
import pg from 'pg';
|
|
2
|
+
import Cursor from 'pg-cursor';
|
|
3
|
+
import { limitRows } from '../result-limits.js';
|
|
4
|
+
const DEFAULT_MAX_ROWS = 500;
|
|
5
|
+
const DEFAULT_TIMEOUT_MS = 10_000;
|
|
6
|
+
const DEFAULT_MAX_RESULT_BYTES = 1_048_576;
|
|
7
|
+
// OIDs of date/time types. They are returned as the server formats them
|
|
8
|
+
// (e.g. "2026-05-11", "2026-05-11 09:51:43") rather than as JS Date objects,
|
|
9
|
+
// which keeps results timezone-independent and matches the MySQL adapter.
|
|
10
|
+
const RAW_TEXT_TYPE_OIDS = new Set([1082, 1114, 1184]); // date, timestamp, timestamptz
|
|
11
|
+
const resultTypes = {
|
|
12
|
+
getTypeParser: ((oid, format) => RAW_TEXT_TYPE_OIDS.has(oid)
|
|
13
|
+
? (value) => value
|
|
14
|
+
: pg.types.getTypeParser(oid, format)),
|
|
15
|
+
};
|
|
16
|
+
/** A table name as shown to the model: unqualified when SQL would resolve it. */
|
|
17
|
+
function displayName(schema, name, visible) {
|
|
18
|
+
return visible ? name : `${schema}.${name}`;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Splits "name", "schema.name", or quoted forms ("My Table", "Sales"."Order")
|
|
22
|
+
* into parts. Unquoted parts are kept exactly as given.
|
|
23
|
+
*/
|
|
24
|
+
function parseQualifiedName(input) {
|
|
25
|
+
const parts = [];
|
|
26
|
+
let current = '';
|
|
27
|
+
let quoted = false;
|
|
28
|
+
for (let i = 0; i < input.length; i += 1) {
|
|
29
|
+
const c = input[i];
|
|
30
|
+
if (quoted) {
|
|
31
|
+
if (c === '"' && input[i + 1] === '"') {
|
|
32
|
+
current += '"';
|
|
33
|
+
i += 1;
|
|
34
|
+
}
|
|
35
|
+
else if (c === '"') {
|
|
36
|
+
quoted = false;
|
|
37
|
+
}
|
|
38
|
+
else {
|
|
39
|
+
current += c;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
else if (c === '"') {
|
|
43
|
+
quoted = true;
|
|
44
|
+
}
|
|
45
|
+
else if (c === '.') {
|
|
46
|
+
parts.push(current);
|
|
47
|
+
current = '';
|
|
48
|
+
}
|
|
49
|
+
else {
|
|
50
|
+
current += c;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
parts.push(current);
|
|
54
|
+
return parts.map((part) => part.trim()).filter((part) => part.length > 0);
|
|
55
|
+
}
|
|
56
|
+
/** Converts values JSON.stringify would bloat or mangle. */
|
|
57
|
+
function normalizeRow(row) {
|
|
58
|
+
const out = {};
|
|
59
|
+
for (const [key, value] of Object.entries(row)) {
|
|
60
|
+
out[key] = Buffer.isBuffer(value) ? `\\x${value.toString('hex')}` : value;
|
|
61
|
+
}
|
|
62
|
+
return out;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* PostgreSQL adapter.
|
|
66
|
+
*
|
|
67
|
+
* Safety properties, independent of the SQL validator:
|
|
68
|
+
* - Every statement runs inside `BEGIN READ ONLY`, so the server refuses
|
|
69
|
+
* writes even if the connected role is allowed to make them. The
|
|
70
|
+
* transaction is always rolled back.
|
|
71
|
+
* - `statement_timeout` is set per transaction, so slow queries are cancelled
|
|
72
|
+
* by the server rather than abandoned by the client.
|
|
73
|
+
* - Queries use the extended protocol (via a cursor), so the server itself
|
|
74
|
+
* rejects multiple statements in one request.
|
|
75
|
+
* - Rows are fetched through the cursor, so at most `maxRows + 1` rows are
|
|
76
|
+
* ever transferred, however large the result is.
|
|
77
|
+
* - `standard_conforming_strings` is pinned to `on`, which the validator's
|
|
78
|
+
* tokenizer assumes.
|
|
79
|
+
*
|
|
80
|
+
* A dedicated read-only database role is still recommended.
|
|
81
|
+
*/
|
|
82
|
+
export class PostgresAdapter {
|
|
83
|
+
dialect = 'postgres';
|
|
84
|
+
pool;
|
|
85
|
+
constructor(config) {
|
|
86
|
+
const options = {
|
|
87
|
+
host: config.host,
|
|
88
|
+
port: config.port,
|
|
89
|
+
database: config.database,
|
|
90
|
+
user: config.user,
|
|
91
|
+
password: config.password,
|
|
92
|
+
max: config.connectionLimit ?? 5,
|
|
93
|
+
application_name: 'dbask',
|
|
94
|
+
connectionTimeoutMillis: 10_000,
|
|
95
|
+
idleTimeoutMillis: 30_000,
|
|
96
|
+
types: resultTypes,
|
|
97
|
+
};
|
|
98
|
+
if (config.ssl === 'require') {
|
|
99
|
+
options.ssl = { rejectUnauthorized: false };
|
|
100
|
+
}
|
|
101
|
+
else if (config.ssl === 'verify-full') {
|
|
102
|
+
options.ssl = { rejectUnauthorized: true };
|
|
103
|
+
}
|
|
104
|
+
this.pool = new pg.Pool(options);
|
|
105
|
+
// An idle connection can be dropped by the server or a proxy. Without a
|
|
106
|
+
// handler this 'error' event would crash the process; the pool discards
|
|
107
|
+
// the broken client and the next query opens a new one.
|
|
108
|
+
this.pool.on('error', () => undefined);
|
|
109
|
+
}
|
|
110
|
+
async listTables() {
|
|
111
|
+
const rows = await this.run(`
|
|
112
|
+
SELECT n.nspname AS schema_name,
|
|
113
|
+
c.relname AS table_name,
|
|
114
|
+
pg_table_is_visible(c.oid) AS visible
|
|
115
|
+
FROM pg_class c
|
|
116
|
+
JOIN pg_namespace n ON n.oid = c.relnamespace
|
|
117
|
+
WHERE c.relkind IN ('r', 'p')
|
|
118
|
+
AND NOT c.relispartition
|
|
119
|
+
AND n.nspname <> 'information_schema'
|
|
120
|
+
AND n.nspname NOT LIKE 'pg\\_%'
|
|
121
|
+
AND has_table_privilege(c.oid, 'SELECT')
|
|
122
|
+
ORDER BY n.nspname, c.relname
|
|
123
|
+
`);
|
|
124
|
+
return rows.map((row) => ({
|
|
125
|
+
name: displayName(row.schema_name, row.table_name, row.visible),
|
|
126
|
+
schema: row.schema_name,
|
|
127
|
+
}));
|
|
128
|
+
}
|
|
129
|
+
async describeTable(table) {
|
|
130
|
+
const target = await this.resolveTable(table);
|
|
131
|
+
const rows = await this.run(`
|
|
132
|
+
SELECT a.attname AS column_name,
|
|
133
|
+
format_type(a.atttypid, a.atttypmod) AS data_type,
|
|
134
|
+
NOT a.attnotnull AS nullable,
|
|
135
|
+
pg_get_expr(d.adbin, d.adrelid) AS column_default,
|
|
136
|
+
EXISTS (
|
|
137
|
+
SELECT 1 FROM pg_index i
|
|
138
|
+
WHERE i.indrelid = a.attrelid AND i.indisprimary AND a.attnum = ANY (i.indkey)
|
|
139
|
+
) AS is_primary_key,
|
|
140
|
+
(a.attidentity IN ('a', 'd')
|
|
141
|
+
OR COALESCE(pg_get_expr(d.adbin, d.adrelid), '') LIKE 'nextval(%') AS is_auto_increment
|
|
142
|
+
FROM pg_attribute a
|
|
143
|
+
LEFT JOIN pg_attrdef d ON d.adrelid = a.attrelid AND d.adnum = a.attnum
|
|
144
|
+
WHERE a.attrelid = $1::oid AND a.attnum > 0 AND NOT a.attisdropped
|
|
145
|
+
ORDER BY a.attnum
|
|
146
|
+
`, [target.oid]);
|
|
147
|
+
const columns = rows.map((row) => ({
|
|
148
|
+
name: row.column_name,
|
|
149
|
+
dataType: row.data_type,
|
|
150
|
+
nullable: row.nullable,
|
|
151
|
+
defaultValue: row.column_default,
|
|
152
|
+
isPrimaryKey: row.is_primary_key,
|
|
153
|
+
isAutoIncrement: row.is_auto_increment,
|
|
154
|
+
}));
|
|
155
|
+
return {
|
|
156
|
+
table: { name: target.display, schema: target.schema },
|
|
157
|
+
columns,
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
async getRelationships(table) {
|
|
161
|
+
const target = table ? await this.resolveTable(table) : undefined;
|
|
162
|
+
const rows = await this.run(`
|
|
163
|
+
SELECT cn.nspname AS table_schema,
|
|
164
|
+
cl.relname AS table_name,
|
|
165
|
+
a.attname AS column_name,
|
|
166
|
+
fn.nspname AS ref_schema,
|
|
167
|
+
fl.relname AS ref_table,
|
|
168
|
+
fa.attname AS ref_column,
|
|
169
|
+
c.conname AS constraint_name,
|
|
170
|
+
pg_table_is_visible(cl.oid) AS table_visible,
|
|
171
|
+
pg_table_is_visible(fl.oid) AS ref_visible
|
|
172
|
+
FROM pg_constraint c
|
|
173
|
+
JOIN pg_class cl ON cl.oid = c.conrelid
|
|
174
|
+
JOIN pg_namespace cn ON cn.oid = cl.relnamespace
|
|
175
|
+
JOIN pg_class fl ON fl.oid = c.confrelid
|
|
176
|
+
JOIN pg_namespace fn ON fn.oid = fl.relnamespace
|
|
177
|
+
CROSS JOIN LATERAL unnest(c.conkey, c.confkey) AS k(attnum, fattnum)
|
|
178
|
+
JOIN pg_attribute a ON a.attrelid = c.conrelid AND a.attnum = k.attnum
|
|
179
|
+
JOIN pg_attribute fa ON fa.attrelid = c.confrelid AND fa.attnum = k.fattnum
|
|
180
|
+
WHERE c.contype = 'f'
|
|
181
|
+
AND c.conparentid = 0
|
|
182
|
+
AND cn.nspname <> 'information_schema'
|
|
183
|
+
AND cn.nspname NOT LIKE 'pg\\_%'
|
|
184
|
+
AND has_table_privilege(cl.oid, 'SELECT')
|
|
185
|
+
AND ($1::oid IS NULL OR c.conrelid = $1::oid)
|
|
186
|
+
ORDER BY cn.nspname, cl.relname, a.attname
|
|
187
|
+
`, [target?.oid ?? null]);
|
|
188
|
+
return rows.map((row) => ({
|
|
189
|
+
table: displayName(row.table_schema, row.table_name, row.table_visible),
|
|
190
|
+
column: row.column_name,
|
|
191
|
+
referencedTable: displayName(row.ref_schema, row.ref_table, row.ref_visible),
|
|
192
|
+
referencedColumn: row.ref_column,
|
|
193
|
+
constraintName: row.constraint_name,
|
|
194
|
+
}));
|
|
195
|
+
}
|
|
196
|
+
async executeQuery(sql, options = {}) {
|
|
197
|
+
const maxRows = options.maxRows ?? DEFAULT_MAX_ROWS;
|
|
198
|
+
const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
199
|
+
const maxResultBytes = options.maxResultBytes ?? DEFAULT_MAX_RESULT_BYTES;
|
|
200
|
+
const startedAt = performance.now();
|
|
201
|
+
const fetched = await this.withReadOnlyTransaction(timeoutMs, async (client) => {
|
|
202
|
+
const cursor = client.query(new Cursor(sql, undefined, { types: resultTypes }));
|
|
203
|
+
// One extra row tells us whether the result was cut off.
|
|
204
|
+
const rows = (await cursor.read(maxRows + 1));
|
|
205
|
+
await cursor.close();
|
|
206
|
+
return rows;
|
|
207
|
+
});
|
|
208
|
+
const { rows, truncated } = limitRows(fetched.map(normalizeRow), maxRows, maxResultBytes);
|
|
209
|
+
return {
|
|
210
|
+
rows,
|
|
211
|
+
rowCount: rows.length,
|
|
212
|
+
executionTimeMs: Math.round(performance.now() - startedAt),
|
|
213
|
+
truncated,
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
async explainQuery(sql) {
|
|
217
|
+
// Plain EXPLAIN (never ANALYZE): the statement is planned, not executed.
|
|
218
|
+
const rows = await this.withReadOnlyTransaction(DEFAULT_TIMEOUT_MS, async (client) => {
|
|
219
|
+
const cursor = client.query(new Cursor(`EXPLAIN (FORMAT JSON) ${sql}`, undefined, { types: resultTypes }));
|
|
220
|
+
const result = (await cursor.read(10));
|
|
221
|
+
await cursor.close();
|
|
222
|
+
return result;
|
|
223
|
+
});
|
|
224
|
+
return {
|
|
225
|
+
sql,
|
|
226
|
+
plan: rows[0]?.['QUERY PLAN'] ?? rows,
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
async close() {
|
|
230
|
+
await this.pool.end();
|
|
231
|
+
}
|
|
232
|
+
/** Runs a fixed catalog query with bind parameters. */
|
|
233
|
+
async run(text, values = []) {
|
|
234
|
+
return this.withReadOnlyTransaction(DEFAULT_TIMEOUT_MS, async (client) => {
|
|
235
|
+
const result = await client.query(text, values);
|
|
236
|
+
return result.rows;
|
|
237
|
+
});
|
|
238
|
+
}
|
|
239
|
+
/**
|
|
240
|
+
* Resolves a name from the model ("users", "Sales.orders", "\"Order Items\"")
|
|
241
|
+
* to a table. Unqualified names resolve the way SQL would (search_path);
|
|
242
|
+
* an exact-case match wins over a lower-case one.
|
|
243
|
+
*/
|
|
244
|
+
async resolveTable(input) {
|
|
245
|
+
const parts = parseQualifiedName(input);
|
|
246
|
+
if (parts.length === 0 || parts.length > 2) {
|
|
247
|
+
throw new Error(`Table "${input}" was not found in the current database.`);
|
|
248
|
+
}
|
|
249
|
+
const name = parts[parts.length - 1];
|
|
250
|
+
const schema = parts.length === 2 ? parts[0] : null;
|
|
251
|
+
const rows = await this.run(`
|
|
252
|
+
SELECT c.oid::text AS oid,
|
|
253
|
+
n.nspname AS schema_name,
|
|
254
|
+
c.relname AS table_name,
|
|
255
|
+
pg_table_is_visible(c.oid) AS visible
|
|
256
|
+
FROM pg_class c
|
|
257
|
+
JOIN pg_namespace n ON n.oid = c.relnamespace
|
|
258
|
+
WHERE c.relkind IN ('r', 'p')
|
|
259
|
+
AND c.relname IN ($1::text, lower($1::text))
|
|
260
|
+
AND (($2::text IS NULL AND pg_table_is_visible(c.oid)) OR n.nspname IN ($2::text, lower($2::text)))
|
|
261
|
+
AND has_table_privilege(c.oid, 'SELECT')
|
|
262
|
+
`, [name, schema]);
|
|
263
|
+
const best = rows.find((row) => row.table_name === name && (schema === null || row.schema_name === schema)) ??
|
|
264
|
+
rows[0];
|
|
265
|
+
if (!best) {
|
|
266
|
+
throw new Error(`Table "${input}" was not found in the current database.`);
|
|
267
|
+
}
|
|
268
|
+
return {
|
|
269
|
+
oid: best.oid,
|
|
270
|
+
schema: best.schema_name,
|
|
271
|
+
display: displayName(best.schema_name, best.table_name, best.visible),
|
|
272
|
+
};
|
|
273
|
+
}
|
|
274
|
+
/**
|
|
275
|
+
* Runs `work` inside a READ ONLY transaction with a server-side statement
|
|
276
|
+
* timeout. The transaction is always rolled back. A connection that saw an
|
|
277
|
+
* error is discarded rather than returned to the pool.
|
|
278
|
+
*/
|
|
279
|
+
async withReadOnlyTransaction(timeoutMs, work) {
|
|
280
|
+
const client = await this.pool.connect();
|
|
281
|
+
let discard = false;
|
|
282
|
+
try {
|
|
283
|
+
await client.query('BEGIN READ ONLY');
|
|
284
|
+
await client.query({
|
|
285
|
+
text: `SELECT set_config('statement_timeout', $1, true),
|
|
286
|
+
set_config('idle_in_transaction_session_timeout', $2, true),
|
|
287
|
+
set_config('standard_conforming_strings', 'on', true)`,
|
|
288
|
+
values: [String(Math.max(1, Math.floor(timeoutMs))), String(Math.floor(timeoutMs) + 5_000)],
|
|
289
|
+
});
|
|
290
|
+
return await work(client);
|
|
291
|
+
}
|
|
292
|
+
catch (error) {
|
|
293
|
+
discard = true;
|
|
294
|
+
throw error;
|
|
295
|
+
}
|
|
296
|
+
finally {
|
|
297
|
+
try {
|
|
298
|
+
await client.query('ROLLBACK');
|
|
299
|
+
}
|
|
300
|
+
catch {
|
|
301
|
+
discard = true;
|
|
302
|
+
}
|
|
303
|
+
client.release(discard);
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
//# sourceMappingURL=adapter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"adapter.js","sourceRoot":"","sources":["../../../src/database/postgres/adapter.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared by database adapters: keeps a result within the configured row and
|
|
3
|
+
* byte limits and reports whether anything was left out.
|
|
4
|
+
*/
|
|
5
|
+
export interface LimitedRows {
|
|
6
|
+
rows: Record<string, unknown>[];
|
|
7
|
+
truncated: boolean;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* @param rows Rows fetched from the database. May contain one more row
|
|
11
|
+
* than `maxRows` so truncation can be detected without
|
|
12
|
+
* reading the whole result.
|
|
13
|
+
* @param maxRows Maximum number of rows to return.
|
|
14
|
+
* @param maxBytes Maximum size of the JSON-serialized rows.
|
|
15
|
+
*/
|
|
16
|
+
export declare function limitRows(rows: Record<string, unknown>[], maxRows: number, maxBytes: number): LimitedRows;
|
|
17
|
+
//# sourceMappingURL=result-limits.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"result-limits.d.ts","sourceRoot":"","sources":["../../src/database/result-limits.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC;IAChC,SAAS,EAAE,OAAO,CAAC;CACpB;AAED;;;;;;GAMG;AACH,wBAAgB,SAAS,CACvB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,EAC/B,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM,GACf,WAAW,CAuBb"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @param rows Rows fetched from the database. May contain one more row
|
|
3
|
+
* than `maxRows` so truncation can be detected without
|
|
4
|
+
* reading the whole result.
|
|
5
|
+
* @param maxRows Maximum number of rows to return.
|
|
6
|
+
* @param maxBytes Maximum size of the JSON-serialized rows.
|
|
7
|
+
*/
|
|
8
|
+
export function limitRows(rows, maxRows, maxBytes) {
|
|
9
|
+
let truncated = rows.length > maxRows;
|
|
10
|
+
const capped = truncated ? rows.slice(0, maxRows) : rows;
|
|
11
|
+
if (Buffer.byteLength(JSON.stringify(capped), 'utf8') <= maxBytes) {
|
|
12
|
+
return { rows: capped, truncated };
|
|
13
|
+
}
|
|
14
|
+
const kept = [];
|
|
15
|
+
let size = 2; // "[]"
|
|
16
|
+
for (const row of capped) {
|
|
17
|
+
const rowSize = Buffer.byteLength(JSON.stringify(row), 'utf8') + (kept.length > 0 ? 1 : 0);
|
|
18
|
+
if (size + rowSize > maxBytes)
|
|
19
|
+
break;
|
|
20
|
+
kept.push(row);
|
|
21
|
+
size += rowSize;
|
|
22
|
+
}
|
|
23
|
+
truncated = true;
|
|
24
|
+
return { rows: kept, truncated };
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=result-limits.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"result-limits.js","sourceRoot":"","sources":["../../src/database/result-limits.ts"],"names":[],"mappings":"AASA;;;;;;GAMG;AACH,MAAM,UAAU,SAAS,CACvB,IAA+B,EAC/B,OAAe,EACf,QAAgB;IAEhB,IAAI,SAAS,GAAG,IAAI,CAAC,MAAM,GAAG,OAAO,CAAC;IACtC,MAAM,MAAM,GAAG,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IAEzD,IAAI,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,IAAI,QAAQ,EAAE,CAAC;QAClE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC;IACrC,CAAC;IAED,MAAM,IAAI,GAA8B,EAAE,CAAC;IAC3C,IAAI,IAAI,GAAG,CAAC,CAAC,CAAC,OAAO;IAErB,KAAK,MAAM,GAAG,IAAI,MAAM,EAAE,CAAC;QACzB,MAAM,OAAO,GACX,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAE7E,IAAI,IAAI,GAAG,OAAO,GAAG,QAAQ;YAAE,MAAM;QAErC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACf,IAAI,IAAI,OAAO,CAAC;IAClB,CAAC;IAED,SAAS,GAAG,IAAI,CAAC;IACjB,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC;AACnC,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public SDK entry point for dbask.
|
|
3
|
+
*
|
|
4
|
+
* Keep this file as the supported import surface. Consumers should not need to
|
|
5
|
+
* import implementation files from internal src/ paths.
|
|
6
|
+
*/
|
|
7
|
+
export { Agent } from './core/agent/index.js';
|
|
8
|
+
export type { AgentOptions, AgentResult, PlanStats, ResponseMode, } from './core/agent/agent.js';
|
|
9
|
+
export type { StructuredQueryPlan } from './core/agent/query-plan.js';
|
|
10
|
+
export type { AgentObserver, AgentToolEvent, } from './core/agent/observability.js';
|
|
11
|
+
export type { AiProvider } from './ai/provider.js';
|
|
12
|
+
export { SdkAiProvider } from './ai/sdk-provider.js';
|
|
13
|
+
export { createAiProvider } from './ai/factory.js';
|
|
14
|
+
export { loadConfig } from './config/config.js';
|
|
15
|
+
export type { AppConfig, AiProviderName } from './config/config.js';
|
|
16
|
+
export { MySqlAdapter, PostgresAdapter, createDatabaseAdapter } from './database/index.js';
|
|
17
|
+
export type { MySqlAdapterConfig, PostgresAdapterConfig, DatabaseConnectionConfig, DatabaseAdapter, } from './database/index.js';
|
|
18
|
+
export type { ColumnInfo, DatabaseContext, ModelProvider, ModelRequest, ModelResponse, QueryExecutionOptions, QueryPlan, QueryResult, RelationshipInfo, SqlDialect, SqlSafetyPolicy, SqlToolResult, TableInfo, TableSchema, ToolContext, } from './core/types/index.js';
|
|
19
|
+
export { SchemaCache } from './schema/cache.js';
|
|
20
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,KAAK,EAAE,MAAM,uBAAuB,CAAC;AAC9C,YAAY,EACV,YAAY,EACZ,WAAW,EACX,SAAS,EACT,YAAY,GACb,MAAM,uBAAuB,CAAC;AAC/B,YAAY,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AACtE,YAAY,EACV,aAAa,EACb,cAAc,GACf,MAAM,+BAA+B,CAAC;AAEvC,YAAY,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AACnD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAEnD,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAChD,YAAY,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAEpE,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AAC3F,YAAY,EACV,kBAAkB,EAClB,qBAAqB,EACrB,wBAAwB,EACxB,eAAe,GAChB,MAAM,qBAAqB,CAAC;AAE7B,YAAY,EACV,UAAU,EACV,eAAe,EACf,aAAa,EACb,YAAY,EACZ,aAAa,EACb,qBAAqB,EACrB,SAAS,EACT,WAAW,EACX,gBAAgB,EAChB,UAAU,EACV,eAAe,EACf,aAAa,EACb,SAAS,EACT,WAAW,EACX,WAAW,GACZ,MAAM,uBAAuB,CAAC;AAE/B,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public SDK entry point for dbask.
|
|
3
|
+
*
|
|
4
|
+
* Keep this file as the supported import surface. Consumers should not need to
|
|
5
|
+
* import implementation files from internal src/ paths.
|
|
6
|
+
*/
|
|
7
|
+
export { Agent } from './core/agent/index.js';
|
|
8
|
+
export { SdkAiProvider } from './ai/sdk-provider.js';
|
|
9
|
+
export { createAiProvider } from './ai/factory.js';
|
|
10
|
+
export { loadConfig } from './config/config.js';
|
|
11
|
+
export { MySqlAdapter, PostgresAdapter, createDatabaseAdapter } from './database/index.js';
|
|
12
|
+
export { SchemaCache } from './schema/cache.js';
|
|
13
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,KAAK,EAAE,MAAM,uBAAuB,CAAC;AAc9C,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAEnD,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAGhD,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AA0B3F,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { SqlSafetyPolicy } from '../core/types/index.js';
|
|
2
|
+
/**
|
|
3
|
+
* Adds a conservative LIMIT to simple SELECT/WITH queries that do not already
|
|
4
|
+
* have one. Actual row limits should still be enforced by the database adapter.
|
|
5
|
+
*/
|
|
6
|
+
export declare function applyRowLimit(sql: string, policy: SqlSafetyPolicy): string;
|
|
7
|
+
//# sourceMappingURL=limits.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"limits.d.ts","sourceRoot":"","sources":["../../src/safety/limits.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAE9D;;;GAGG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,eAAe,GAAG,MAAM,CAY1E"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Adds a conservative LIMIT to simple SELECT/WITH queries that do not already
|
|
3
|
+
* have one. Actual row limits should still be enforced by the database adapter.
|
|
4
|
+
*/
|
|
5
|
+
export function applyRowLimit(sql, policy) {
|
|
6
|
+
const normalized = sql.trim().replace(/;\s*$/, '');
|
|
7
|
+
if (/\bLIMIT\s+\d+/i.test(normalized)) {
|
|
8
|
+
return normalized;
|
|
9
|
+
}
|
|
10
|
+
if (/^(SELECT|WITH)\b/i.test(normalized)) {
|
|
11
|
+
return `${normalized} LIMIT ${policy.maxRows}`;
|
|
12
|
+
}
|
|
13
|
+
return normalized;
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=limits.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"limits.js","sourceRoot":"","sources":["../../src/safety/limits.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,MAAM,UAAU,aAAa,CAAC,GAAW,EAAE,MAAuB;IAChE,MAAM,UAAU,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;IAEnD,IAAI,gBAAgB,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,CAAC;QACtC,OAAO,UAAU,CAAC;IACpB,CAAC;IAED,IAAI,mBAAmB,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,CAAC;QACzC,OAAO,GAAG,UAAU,UAAU,MAAM,CAAC,OAAO,EAAE,CAAC;IACjD,CAAC;IAED,OAAO,UAAU,CAAC;AACpB,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { SqlDialect, SqlSafetyPolicy } from '../core/types/index.js';
|
|
2
|
+
import { type SqlValidationResult } from './sql-validator.js';
|
|
3
|
+
export declare function validateQuery(sql: string, policy: SqlSafetyPolicy, dialect?: SqlDialect): SqlValidationResult;
|
|
4
|
+
export declare function getQueryExecutionOptions(policy: SqlSafetyPolicy): {
|
|
5
|
+
maxRows: number;
|
|
6
|
+
timeoutMs: number;
|
|
7
|
+
};
|
|
8
|
+
//# sourceMappingURL=policy.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"policy.d.ts","sourceRoot":"","sources":["../../src/safety/policy.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAC1E,OAAO,EAAe,KAAK,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAE3E,wBAAgB,aAAa,CAC3B,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,eAAe,EACvB,OAAO,GAAE,UAAoB,GAC5B,mBAAmB,CAErB;AAED,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,eAAe;IAE5D,OAAO;IACP,SAAS;EAEZ"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { validateSql } from './sql-validator.js';
|
|
2
|
+
export function validateQuery(sql, policy, dialect = 'mysql') {
|
|
3
|
+
return validateSql(sql, policy, dialect);
|
|
4
|
+
}
|
|
5
|
+
export function getQueryExecutionOptions(policy) {
|
|
6
|
+
return {
|
|
7
|
+
maxRows: policy.maxRows,
|
|
8
|
+
timeoutMs: policy.queryTimeoutMs,
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
//# sourceMappingURL=policy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"policy.js","sourceRoot":"","sources":["../../src/safety/policy.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAA4B,MAAM,oBAAoB,CAAC;AAE3E,MAAM,UAAU,aAAa,CAC3B,GAAW,EACX,MAAuB,EACvB,OAAO,GAAe,OAAO;IAE7B,OAAO,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC;AAC3C,CAAC;AAED,MAAM,UAAU,wBAAwB,CAAC,MAAuB;IAC9D,OAAO;QACL,OAAO,EAAE,MAAM,CAAC,OAAO;QACvB,SAAS,EAAE,MAAM,CAAC,cAAc;KACjC,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Minimal SQL tokenizer used by the safety validator. It understands the
|
|
3
|
+
* lexical rules of MySQL/MariaDB and PostgreSQL.
|
|
4
|
+
*
|
|
5
|
+
* It is not a full SQL parser. Its only job is to separate the parts of a
|
|
6
|
+
* statement that carry meaning (keywords, identifiers, punctuation) from the
|
|
7
|
+
* parts that do not (string literals, quoted identifiers, comments), so safety
|
|
8
|
+
* rules are applied to real SQL tokens instead of raw text. Getting the lexical
|
|
9
|
+
* rules of the *target* database exactly right matters: if this tokenizer and
|
|
10
|
+
* the server disagree about where a string or comment ends, a second statement
|
|
11
|
+
* can hide inside what the validator thinks is a literal.
|
|
12
|
+
*
|
|
13
|
+
* MySQL/MariaDB (defaults assumed):
|
|
14
|
+
* - `-- ` and `#` line comments, non-nested block comments
|
|
15
|
+
* - backslash escapes inside '...' and "..." strings (no NO_BACKSLASH_ESCAPES)
|
|
16
|
+
* - double quotes delimit strings, not identifiers (no ANSI_QUOTES)
|
|
17
|
+
* - executable comments (`/*! ... *\/`, `/*M! ... *\/`) are rejected outright
|
|
18
|
+
* because the server executes their contents
|
|
19
|
+
*
|
|
20
|
+
* PostgreSQL:
|
|
21
|
+
* - `--` line comments (no whitespace needed); `#` is an operator, not a comment
|
|
22
|
+
* - nested block comments
|
|
23
|
+
* - '...' strings only escape quotes by doubling; backslash escapes apply only
|
|
24
|
+
* to E'...' strings (the adapter pins standard_conforming_strings = on)
|
|
25
|
+
* - "..." delimits identifiers
|
|
26
|
+
* - dollar-quoted strings ($$...$$ and $tag$...$tag$)
|
|
27
|
+
* - U&'...' and U&"..." are rejected: their escapes can spell any name
|
|
28
|
+
*/
|
|
29
|
+
import type { SqlDialect } from '../core/types/index.js';
|
|
30
|
+
export type SqlTokenType = 'word' | 'string' | 'quoted-identifier' | 'punct';
|
|
31
|
+
export interface SqlToken {
|
|
32
|
+
type: SqlTokenType;
|
|
33
|
+
/** Upper-cased for words; raw text for everything else. */
|
|
34
|
+
value: string;
|
|
35
|
+
/** Offset of the first character in the original SQL. */
|
|
36
|
+
start: number;
|
|
37
|
+
/** Offset one past the last character in the original SQL. */
|
|
38
|
+
end: number;
|
|
39
|
+
}
|
|
40
|
+
export interface TokenizeResult {
|
|
41
|
+
tokens: SqlToken[];
|
|
42
|
+
error?: string;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Tokenizes SQL using the lexical rules of `dialect`. Dialects other than
|
|
46
|
+
* PostgreSQL use the MySQL rules (no other adapter exists yet).
|
|
47
|
+
*/
|
|
48
|
+
export declare function tokenizeSql(sql: string, dialect?: SqlDialect): TokenizeResult;
|
|
49
|
+
//# sourceMappingURL=sql-tokenizer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sql-tokenizer.d.ts","sourceRoot":"","sources":["../../src/safety/sql-tokenizer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAEzD,MAAM,MAAM,YAAY,GAAG,MAAM,GAAG,QAAQ,GAAG,mBAAmB,GAAG,OAAO,CAAC;AAE7E,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,YAAY,CAAC;IACnB,2DAA2D;IAC3D,KAAK,EAAE,MAAM,CAAC;IACd,yDAAyD;IACzD,KAAK,EAAE,MAAM,CAAC;IACd,8DAA8D;IAC9D,GAAG,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,QAAQ,EAAE,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAKD;;;GAGG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,GAAE,UAAoB,GAAG,cAAc,CA8OtF"}
|