yamchart 0.9.2 → 0.9.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{advisor-SK2EPAAY.js → advisor-SC64RTZO.js} +11 -11
- package/dist/agent-TZZHNDPK.js +8 -0
- package/dist/{chunk-4P5UHWYK.js → chunk-7CD6UQAV.js} +102 -2
- package/dist/chunk-7CD6UQAV.js.map +1 -0
- package/dist/chunk-7D4SUZUM.js +38 -0
- package/dist/{chunk-EHM6AMMA.js → chunk-EAQXUGP6.js} +65 -2
- package/dist/chunk-EAQXUGP6.js.map +1 -0
- package/dist/{chunk-UDKODFOE.js → chunk-H4L3FNLS.js} +16 -6
- package/dist/chunk-H4L3FNLS.js.map +1 -0
- package/dist/{chunk-OI3EGXVE.js → chunk-NXQ6ZO3V.js} +19 -4
- package/dist/chunk-NXQ6ZO3V.js.map +1 -0
- package/dist/{chunk-65G5DBRO.js → chunk-RM6MNDVF.js} +35 -5
- package/dist/chunk-RM6MNDVF.js.map +1 -0
- package/dist/{chunk-EHYYYKRW.js → chunk-RMIDEBHD.js} +4 -4
- package/dist/{chunk-CWAWATL4.js → chunk-S7YQXEKM.js} +159 -2
- package/dist/chunk-S7YQXEKM.js.map +1 -0
- package/dist/{chunk-ZA6AOQVZ.js → chunk-ZMJPRNOA.js} +2 -2
- package/dist/{compare-ZN6RUOOQ.js → compare-RQFCEZIK.js} +2 -2
- package/dist/{connection-utils-MCJBJEDQ.js → connection-utils-C4FQGBW6.js} +5 -5
- package/dist/{describe-XJ5GXYUE.js → describe-X75C2VDU.js} +7 -7
- package/dist/{dev-PLBVJXT4.js → dev-KDNXUNME.js} +27978 -13314
- package/dist/dev-KDNXUNME.js.map +1 -0
- package/dist/{dist-VNX77VV5.js → dist-JMLAZUL7.js} +9 -3
- package/dist/{dist-7CRX2GIR.js → dist-MNXSMGV6.js} +3 -3
- package/dist/{dist-OCECEAXB.js → dist-MX5K2ABB.js} +3 -3
- package/dist/{dist-JH7OL7U4.js → dist-NGQG7Z4G.js} +7 -3
- package/dist/{generate-KNER36CB.js → generate-B7FAWVIQ.js} +2 -2
- package/dist/index.js +33 -33
- package/dist/{init-GVBYCLJT.js → init-SECXKD5G.js} +2 -2
- package/dist/{lineage-T5NRHHZN.js → lineage-HYO4RKZT.js} +2 -2
- package/dist/{query-2RB75CRI.js → query-QNRDS74I.js} +5 -5
- package/dist/{reset-password-IZQTDTU7.js → reset-password-HDCLH7PZ.js} +3 -3
- package/dist/{rewrite-database-FDJIXKZ2.js → rewrite-database-BOA4QPUR.js} +2 -2
- package/dist/{sample-3UAL7MVU.js → sample-SKLHBZBU.js} +5 -5
- package/dist/{search-ODC4S575.js → search-4KMETZVX.js} +7 -7
- package/dist/{semantic-RAP3S5PQ.js → semantic-6WKELH5V.js} +2 -2
- package/dist/source-resolver-R7WBIL7M.js +18 -0
- package/dist/{sync-dbt-22QQKT3A.js → sync-dbt-72GVO75P.js} +2 -2
- package/dist/{sync-warehouse-QMCT5B4G.js → sync-warehouse-UWRNUXE7.js} +41 -15
- package/dist/sync-warehouse-UWRNUXE7.js.map +1 -0
- package/dist/{tables-QWHUCBRH.js → tables-V65QUGHK.js} +7 -7
- package/dist/templates/default/docs/yamchart-reference.md +74 -9
- package/dist/{test-KX2GETNF.js → test-UE5OWG3E.js} +5 -5
- package/dist/{update-WMATDZTO.js → update-HWCJNQRP.js} +2 -2
- package/package.json +10 -4
- package/dist/agent-KWKPAYT2.js +0 -8
- package/dist/chunk-4P5UHWYK.js.map +0 -1
- package/dist/chunk-65G5DBRO.js.map +0 -1
- package/dist/chunk-CWAWATL4.js.map +0 -1
- package/dist/chunk-DGUM43GV.js +0 -11
- package/dist/chunk-EHM6AMMA.js.map +0 -1
- package/dist/chunk-OI3EGXVE.js.map +0 -1
- package/dist/chunk-UDKODFOE.js.map +0 -1
- package/dist/dev-PLBVJXT4.js.map +0 -1
- package/dist/source-resolver-6QBBNW3P.js +0 -18
- package/dist/sync-warehouse-QMCT5B4G.js.map +0 -1
- /package/dist/{advisor-SK2EPAAY.js.map → advisor-SC64RTZO.js.map} +0 -0
- /package/dist/{agent-KWKPAYT2.js.map → agent-TZZHNDPK.js.map} +0 -0
- /package/dist/{chunk-DGUM43GV.js.map → chunk-7D4SUZUM.js.map} +0 -0
- /package/dist/{chunk-EHYYYKRW.js.map → chunk-RMIDEBHD.js.map} +0 -0
- /package/dist/{chunk-ZA6AOQVZ.js.map → chunk-ZMJPRNOA.js.map} +0 -0
- /package/dist/{compare-ZN6RUOOQ.js.map → compare-RQFCEZIK.js.map} +0 -0
- /package/dist/{connection-utils-MCJBJEDQ.js.map → connection-utils-C4FQGBW6.js.map} +0 -0
- /package/dist/{describe-XJ5GXYUE.js.map → describe-X75C2VDU.js.map} +0 -0
- /package/dist/{dist-JH7OL7U4.js.map → dist-JMLAZUL7.js.map} +0 -0
- /package/dist/{dist-7CRX2GIR.js.map → dist-MNXSMGV6.js.map} +0 -0
- /package/dist/{dist-OCECEAXB.js.map → dist-MX5K2ABB.js.map} +0 -0
- /package/dist/{dist-VNX77VV5.js.map → dist-NGQG7Z4G.js.map} +0 -0
- /package/dist/{generate-KNER36CB.js.map → generate-B7FAWVIQ.js.map} +0 -0
- /package/dist/{init-GVBYCLJT.js.map → init-SECXKD5G.js.map} +0 -0
- /package/dist/{lineage-T5NRHHZN.js.map → lineage-HYO4RKZT.js.map} +0 -0
- /package/dist/{query-2RB75CRI.js.map → query-QNRDS74I.js.map} +0 -0
- /package/dist/{reset-password-IZQTDTU7.js.map → reset-password-HDCLH7PZ.js.map} +0 -0
- /package/dist/{rewrite-database-FDJIXKZ2.js.map → rewrite-database-BOA4QPUR.js.map} +0 -0
- /package/dist/{sample-3UAL7MVU.js.map → sample-SKLHBZBU.js.map} +0 -0
- /package/dist/{search-ODC4S575.js.map → search-4KMETZVX.js.map} +0 -0
- /package/dist/{semantic-RAP3S5PQ.js.map → semantic-6WKELH5V.js.map} +0 -0
- /package/dist/{source-resolver-6QBBNW3P.js.map → source-resolver-R7WBIL7M.js.map} +0 -0
- /package/dist/{sync-dbt-22QQKT3A.js.map → sync-dbt-72GVO75P.js.map} +0 -0
- /package/dist/{tables-QWHUCBRH.js.map → tables-V65QUGHK.js.map} +0 -0
- /package/dist/{test-KX2GETNF.js.map → test-UE5OWG3E.js.map} +0 -0
- /package/dist/{update-WMATDZTO.js.map → update-HWCJNQRP.js.map} +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
createConnector,
|
|
3
3
|
resolveConnection
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-NXQ6ZO3V.js";
|
|
5
5
|
import {
|
|
6
6
|
detail,
|
|
7
7
|
error,
|
|
@@ -10,10 +10,10 @@ import {
|
|
|
10
10
|
success,
|
|
11
11
|
warning
|
|
12
12
|
} from "./chunk-HJVVHYVN.js";
|
|
13
|
-
import "./chunk-
|
|
14
|
-
import "./chunk-
|
|
13
|
+
import "./chunk-RM6MNDVF.js";
|
|
14
|
+
import "./chunk-S7YQXEKM.js";
|
|
15
15
|
import "./chunk-UND73EOB.js";
|
|
16
|
-
import "./chunk-
|
|
16
|
+
import "./chunk-7D4SUZUM.js";
|
|
17
17
|
|
|
18
18
|
// src/commands/advisor.ts
|
|
19
19
|
import { readFile, readdir, access } from "fs/promises";
|
|
@@ -44,7 +44,7 @@ async function getDbtProjectPath(projectDir, override) {
|
|
|
44
44
|
return null;
|
|
45
45
|
}
|
|
46
46
|
async function buildContext(projectDir, options) {
|
|
47
|
-
const { parseModelMetadata } = await import("./dist-
|
|
47
|
+
const { parseModelMetadata } = await import("./dist-JMLAZUL7.js");
|
|
48
48
|
const modelsDir = join(projectDir, "models");
|
|
49
49
|
const yamchartModels = [];
|
|
50
50
|
try {
|
|
@@ -140,7 +140,7 @@ async function buildContext(projectDir, options) {
|
|
|
140
140
|
};
|
|
141
141
|
if (dbtPath) {
|
|
142
142
|
try {
|
|
143
|
-
const { detectConventions, listDbtModels } = await import("./dist-
|
|
143
|
+
const { detectConventions, listDbtModels } = await import("./dist-MNXSMGV6.js");
|
|
144
144
|
const dbtProjectYml = await readFile(join(dbtPath, "dbt_project.yml"), "utf-8");
|
|
145
145
|
const dbtConfig = parseYaml(dbtProjectYml);
|
|
146
146
|
const conventions = await detectConventions(dbtPath);
|
|
@@ -236,7 +236,7 @@ async function runAdvisor(projectDir, questionOrMode, options) {
|
|
|
236
236
|
`warehouse: ${context.warehouse ? `connected (${context.warehouse.connectionType})` : "not connected"}`
|
|
237
237
|
);
|
|
238
238
|
console.log("");
|
|
239
|
-
const { AdvisorAgent, AnthropicProvider, buildModelPath } = await import("./dist-
|
|
239
|
+
const { AdvisorAgent, AnthropicProvider, buildModelPath } = await import("./dist-MNXSMGV6.js");
|
|
240
240
|
const provider = new AnthropicProvider(apiKey);
|
|
241
241
|
const agent = new AdvisorAgent(provider);
|
|
242
242
|
const isAudit = questionOrMode === "audit";
|
|
@@ -281,7 +281,7 @@ ${pc.bold(`[${i + 1}]`)} ${formatProposal(proposal, context.dbt.conventions, bui
|
|
|
281
281
|
spin2.stop();
|
|
282
282
|
console.log(result.response);
|
|
283
283
|
if (result.proposals.length > 0) {
|
|
284
|
-
const { buildModelPath: bmp } = await import("./dist-
|
|
284
|
+
const { buildModelPath: bmp } = await import("./dist-MNXSMGV6.js");
|
|
285
285
|
for (const proposal of result.proposals) {
|
|
286
286
|
console.log(
|
|
287
287
|
`
|
|
@@ -322,7 +322,7 @@ ${formatProposal(proposal, context.dbt.conventions, bmp)}`
|
|
|
322
322
|
conversationHistory.length = 0;
|
|
323
323
|
conversationHistory.push(...result.messages);
|
|
324
324
|
if (result.proposals.length > 0) {
|
|
325
|
-
const { buildModelPath: bmp } = await import("./dist-
|
|
325
|
+
const { buildModelPath: bmp } = await import("./dist-MNXSMGV6.js");
|
|
326
326
|
for (const proposal of result.proposals) {
|
|
327
327
|
console.log(
|
|
328
328
|
`
|
|
@@ -340,7 +340,7 @@ async function offerApply(context, proposals) {
|
|
|
340
340
|
return;
|
|
341
341
|
}
|
|
342
342
|
const { confirm } = await import("@inquirer/prompts");
|
|
343
|
-
const { writeDbtModel, buildModelPath, formatModelSql, updateSchemaYml } = await import("./dist-
|
|
343
|
+
const { writeDbtModel, buildModelPath, formatModelSql, updateSchemaYml } = await import("./dist-MNXSMGV6.js");
|
|
344
344
|
for (const proposal of proposals) {
|
|
345
345
|
console.log("");
|
|
346
346
|
const shouldApply = await confirm({
|
|
@@ -379,4 +379,4 @@ async function offerApply(context, proposals) {
|
|
|
379
379
|
export {
|
|
380
380
|
runAdvisor
|
|
381
381
|
};
|
|
382
|
-
//# sourceMappingURL=advisor-
|
|
382
|
+
//# sourceMappingURL=advisor-SC64RTZO.js.map
|
|
@@ -51,6 +51,40 @@ CREATE TABLE IF NOT EXISTS share_links (
|
|
|
51
51
|
expires_at TEXT,
|
|
52
52
|
is_active INTEGER NOT NULL DEFAULT 1
|
|
53
53
|
);
|
|
54
|
+
|
|
55
|
+
CREATE TABLE IF NOT EXISTS oauth_clients (
|
|
56
|
+
client_id TEXT PRIMARY KEY,
|
|
57
|
+
client_secret_hash TEXT,
|
|
58
|
+
client_name TEXT,
|
|
59
|
+
redirect_uris TEXT NOT NULL,
|
|
60
|
+
grant_types TEXT NOT NULL,
|
|
61
|
+
token_endpoint_auth_method TEXT NOT NULL DEFAULT 'none',
|
|
62
|
+
scope TEXT,
|
|
63
|
+
created_at TEXT NOT NULL,
|
|
64
|
+
client_secret_expires_at INTEGER NOT NULL DEFAULT 0
|
|
65
|
+
);
|
|
66
|
+
|
|
67
|
+
CREATE TABLE IF NOT EXISTS oauth_auth_codes (
|
|
68
|
+
code_hash TEXT PRIMARY KEY,
|
|
69
|
+
client_id TEXT NOT NULL REFERENCES oauth_clients(client_id) ON DELETE CASCADE,
|
|
70
|
+
user_id TEXT NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
|
71
|
+
redirect_uri TEXT NOT NULL,
|
|
72
|
+
code_challenge TEXT NOT NULL,
|
|
73
|
+
code_challenge_method TEXT NOT NULL,
|
|
74
|
+
scope TEXT,
|
|
75
|
+
expires_at TEXT NOT NULL,
|
|
76
|
+
created_at TEXT NOT NULL
|
|
77
|
+
);
|
|
78
|
+
|
|
79
|
+
CREATE TABLE IF NOT EXISTS oauth_tokens (
|
|
80
|
+
token_hash TEXT PRIMARY KEY,
|
|
81
|
+
token_type TEXT NOT NULL,
|
|
82
|
+
client_id TEXT NOT NULL REFERENCES oauth_clients(client_id) ON DELETE CASCADE,
|
|
83
|
+
user_id TEXT NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
|
84
|
+
scope TEXT,
|
|
85
|
+
expires_at TEXT NOT NULL,
|
|
86
|
+
created_at TEXT NOT NULL
|
|
87
|
+
);
|
|
54
88
|
`;
|
|
55
89
|
function toSafeUser(user) {
|
|
56
90
|
return {
|
|
@@ -212,6 +246,61 @@ var AuthDatabase = class {
|
|
|
212
246
|
deleteShareLink(id) {
|
|
213
247
|
this.db.prepare("DELETE FROM share_links WHERE id = ?").run(id);
|
|
214
248
|
}
|
|
249
|
+
// ---- OAuth: clients ----
|
|
250
|
+
registerOAuthClient(input) {
|
|
251
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
252
|
+
this.db.prepare(`
|
|
253
|
+
INSERT INTO oauth_clients
|
|
254
|
+
(client_id, client_secret_hash, client_name, redirect_uris, grant_types,
|
|
255
|
+
token_endpoint_auth_method, scope, created_at, client_secret_expires_at)
|
|
256
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
257
|
+
`).run(input.client_id, input.client_secret_hash, input.client_name, JSON.stringify(input.redirect_uris), JSON.stringify(input.grant_types), input.token_endpoint_auth_method, input.scope, now, input.client_secret_expires_at);
|
|
258
|
+
return this.getOAuthClient(input.client_id);
|
|
259
|
+
}
|
|
260
|
+
getOAuthClient(clientId) {
|
|
261
|
+
return this.db.prepare("SELECT * FROM oauth_clients WHERE client_id = ?").get(clientId) ?? null;
|
|
262
|
+
}
|
|
263
|
+
// ---- OAuth: authorization codes (single-use) ----
|
|
264
|
+
createAuthCode(input) {
|
|
265
|
+
this.db.prepare(`
|
|
266
|
+
INSERT INTO oauth_auth_codes
|
|
267
|
+
(code_hash, client_id, user_id, redirect_uri, code_challenge, code_challenge_method, scope, expires_at, created_at)
|
|
268
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
269
|
+
`).run(input.code_hash, input.client_id, input.user_id, input.redirect_uri, input.code_challenge, input.code_challenge_method, input.scope, input.expires_at, (/* @__PURE__ */ new Date()).toISOString());
|
|
270
|
+
}
|
|
271
|
+
/** Atomically fetch-and-delete a non-expired auth code. Returns null if missing/expired. */
|
|
272
|
+
consumeAuthCode(codeHash) {
|
|
273
|
+
const tx = this.db.transaction((hash) => {
|
|
274
|
+
const row = this.db.prepare("SELECT * FROM oauth_auth_codes WHERE code_hash = ?").get(hash);
|
|
275
|
+
this.db.prepare("DELETE FROM oauth_auth_codes WHERE code_hash = ?").run(hash);
|
|
276
|
+
if (!row)
|
|
277
|
+
return null;
|
|
278
|
+
if (new Date(row.expires_at).getTime() <= Date.now())
|
|
279
|
+
return null;
|
|
280
|
+
return row;
|
|
281
|
+
});
|
|
282
|
+
return tx(codeHash);
|
|
283
|
+
}
|
|
284
|
+
// ---- OAuth: tokens ----
|
|
285
|
+
createOAuthToken(input) {
|
|
286
|
+
this.db.prepare(`
|
|
287
|
+
INSERT INTO oauth_tokens (token_hash, token_type, client_id, user_id, scope, expires_at, created_at)
|
|
288
|
+
VALUES (?, ?, ?, ?, ?, ?, ?)
|
|
289
|
+
`).run(input.token_hash, input.token_type, input.client_id, input.user_id, input.scope, input.expires_at, (/* @__PURE__ */ new Date()).toISOString());
|
|
290
|
+
}
|
|
291
|
+
getOAuthToken(tokenHash, type) {
|
|
292
|
+
const row = this.db.prepare("SELECT * FROM oauth_tokens WHERE token_hash = ? AND token_type = ? AND expires_at > ?").get(tokenHash, type, (/* @__PURE__ */ new Date()).toISOString());
|
|
293
|
+
return row ?? null;
|
|
294
|
+
}
|
|
295
|
+
deleteOAuthToken(tokenHash) {
|
|
296
|
+
this.db.prepare("DELETE FROM oauth_tokens WHERE token_hash = ?").run(tokenHash);
|
|
297
|
+
}
|
|
298
|
+
purgeExpiredOAuth() {
|
|
299
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
300
|
+
const codes = this.db.prepare("DELETE FROM oauth_auth_codes WHERE expires_at <= ?").run(now);
|
|
301
|
+
const tokens = this.db.prepare("DELETE FROM oauth_tokens WHERE expires_at <= ?").run(now);
|
|
302
|
+
return codes.changes + tokens.changes;
|
|
303
|
+
}
|
|
215
304
|
};
|
|
216
305
|
|
|
217
306
|
// ../../packages/auth-local/dist/sessions.js
|
|
@@ -237,11 +326,22 @@ function parseTtl(ttl) {
|
|
|
237
326
|
}
|
|
238
327
|
}
|
|
239
328
|
|
|
329
|
+
// ../../packages/auth-local/dist/oauth-crypto.js
|
|
330
|
+
import { randomBytes as randomBytes3, createHash } from "crypto";
|
|
331
|
+
function generateOpaqueToken() {
|
|
332
|
+
return randomBytes3(32).toString("hex");
|
|
333
|
+
}
|
|
334
|
+
function hashToken(token) {
|
|
335
|
+
return createHash("sha256").update(token).digest("hex");
|
|
336
|
+
}
|
|
337
|
+
|
|
240
338
|
export {
|
|
241
339
|
hashPassword,
|
|
242
340
|
verifyPassword,
|
|
243
341
|
AuthDatabase,
|
|
244
342
|
generateSessionToken,
|
|
245
|
-
parseTtl
|
|
343
|
+
parseTtl,
|
|
344
|
+
generateOpaqueToken,
|
|
345
|
+
hashToken
|
|
246
346
|
};
|
|
247
|
-
//# sourceMappingURL=chunk-
|
|
347
|
+
//# sourceMappingURL=chunk-7CD6UQAV.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../packages/auth-local/src/passwords.ts","../../../packages/auth-local/src/database.ts","../../../packages/auth-local/src/sessions.ts","../../../packages/auth-local/src/oauth-crypto.ts"],"sourcesContent":["import bcrypt from 'bcryptjs';\n\nconst SALT_ROUNDS = 12;\n\nexport async function hashPassword(password: string): Promise<string> {\n return bcrypt.hash(password, SALT_ROUNDS);\n}\n\nexport async function verifyPassword(password: string, hash: string): Promise<boolean> {\n return bcrypt.compare(password, hash);\n}\n","import Database from 'better-sqlite3';\nimport { randomBytes } from 'crypto';\nimport { v4 as uuidv4 } from 'uuid';\nimport type { LocalUser, SafeUser, Role, Provider, Session, ShareLink, CreateShareLinkInput } from './types.js';\nimport type {\n OAuthClient, RegisterOAuthClientInput,\n OAuthAuthCode, CreateAuthCodeInput,\n OAuthToken, OAuthTokenType, CreateOAuthTokenInput,\n} from './oauth-types.js';\n\nconst SCHEMA_SQL = `\nCREATE TABLE IF NOT EXISTS users (\n id TEXT PRIMARY KEY,\n email TEXT UNIQUE NOT NULL,\n name TEXT NOT NULL,\n password_hash TEXT,\n role TEXT NOT NULL DEFAULT 'viewer',\n provider TEXT NOT NULL DEFAULT 'local',\n external_id TEXT,\n created_at TEXT NOT NULL,\n updated_at TEXT NOT NULL,\n UNIQUE(provider, external_id)\n);\n\nCREATE TABLE IF NOT EXISTS sessions (\n id TEXT PRIMARY KEY,\n user_id TEXT NOT NULL REFERENCES users(id) ON DELETE CASCADE,\n expires_at TEXT NOT NULL,\n created_at TEXT NOT NULL\n);\n\nCREATE TABLE IF NOT EXISTS password_reset_tokens (\n id TEXT PRIMARY KEY,\n user_id TEXT NOT NULL REFERENCES users(id) ON DELETE CASCADE,\n token TEXT UNIQUE NOT NULL,\n expires_at TEXT NOT NULL,\n used INTEGER NOT NULL DEFAULT 0\n);\n\nCREATE TABLE IF NOT EXISTS share_links (\n id TEXT PRIMARY KEY,\n token TEXT UNIQUE NOT NULL,\n resource_type TEXT NOT NULL,\n resource_name TEXT NOT NULL,\n created_by TEXT NOT NULL,\n created_at TEXT NOT NULL,\n expires_at TEXT,\n is_active INTEGER NOT NULL DEFAULT 1\n);\n\nCREATE TABLE IF NOT EXISTS oauth_clients (\n client_id TEXT PRIMARY KEY,\n client_secret_hash TEXT,\n client_name TEXT,\n redirect_uris TEXT NOT NULL,\n grant_types TEXT NOT NULL,\n token_endpoint_auth_method TEXT NOT NULL DEFAULT 'none',\n scope TEXT,\n created_at TEXT NOT NULL,\n client_secret_expires_at INTEGER NOT NULL DEFAULT 0\n);\n\nCREATE TABLE IF NOT EXISTS oauth_auth_codes (\n code_hash TEXT PRIMARY KEY,\n client_id TEXT NOT NULL REFERENCES oauth_clients(client_id) ON DELETE CASCADE,\n user_id TEXT NOT NULL REFERENCES users(id) ON DELETE CASCADE,\n redirect_uri TEXT NOT NULL,\n code_challenge TEXT NOT NULL,\n code_challenge_method TEXT NOT NULL,\n scope TEXT,\n expires_at TEXT NOT NULL,\n created_at TEXT NOT NULL\n);\n\nCREATE TABLE IF NOT EXISTS oauth_tokens (\n token_hash TEXT PRIMARY KEY,\n token_type TEXT NOT NULL,\n client_id TEXT NOT NULL REFERENCES oauth_clients(client_id) ON DELETE CASCADE,\n user_id TEXT NOT NULL REFERENCES users(id) ON DELETE CASCADE,\n scope TEXT,\n expires_at TEXT NOT NULL,\n created_at TEXT NOT NULL\n);\n`;\n\nexport interface CreateUserInput {\n email: string;\n name: string;\n password_hash: string | null;\n role: Role;\n provider?: Provider;\n external_id?: string | null;\n}\n\nexport interface UpdateUserInput {\n name?: string;\n role?: Role;\n password_hash?: string;\n}\n\nfunction toSafeUser(user: LocalUser): SafeUser {\n return {\n id: user.id,\n email: user.email,\n name: user.name,\n role: user.role,\n provider: user.provider,\n attributes: user.attributes,\n created_at: user.created_at,\n updated_at: user.updated_at,\n };\n}\n\nexport class AuthDatabase {\n private db: Database.Database;\n\n constructor(dbPath: string) {\n this.db = new Database(dbPath);\n this.db.pragma('journal_mode = WAL');\n this.db.pragma('foreign_keys = ON');\n this.db.exec(SCHEMA_SQL);\n\n // Migrate: add attributes column if missing\n try {\n this.db.prepare(\"SELECT attributes FROM users LIMIT 0\").get();\n } catch {\n this.db.exec(\"ALTER TABLE users ADD COLUMN attributes TEXT NOT NULL DEFAULT '{}'\");\n }\n }\n\n close(): void {\n this.db.close();\n }\n\n needsSetup(): boolean {\n return this.getUserCount() === 0;\n }\n\n getUserCount(): number {\n const row = this.db.prepare('SELECT COUNT(*) as count FROM users').get() as { count: number };\n return row.count;\n }\n\n private getAdminCount(): number {\n const row = this.db.prepare(\"SELECT COUNT(*) as count FROM users WHERE role = 'admin'\").get() as { count: number };\n return row.count;\n }\n\n createUser(input: CreateUserInput): SafeUser {\n const id = uuidv4();\n const now = new Date().toISOString();\n\n this.db.prepare(`\n INSERT INTO users (id, email, name, password_hash, role, provider, external_id, created_at, updated_at)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)\n `).run(\n id,\n input.email,\n input.name,\n input.password_hash,\n input.role,\n input.provider ?? 'local',\n input.external_id ?? null,\n now,\n now,\n );\n\n return this.getUserById(id)! as SafeUser;\n }\n\n getUserById(id: string): LocalUser | null {\n return (this.db.prepare('SELECT * FROM users WHERE id = ?').get(id) as LocalUser) ?? null;\n }\n\n getUserByEmail(email: string): LocalUser | null {\n return (this.db.prepare('SELECT * FROM users WHERE email = ?').get(email) as LocalUser) ?? null;\n }\n\n listUsers(): SafeUser[] {\n const users = this.db.prepare('SELECT * FROM users ORDER BY created_at ASC').all() as LocalUser[];\n return users.map(toSafeUser);\n }\n\n updateUser(id: string, input: UpdateUserInput): void {\n // Guard: prevent changing last admin's role\n if (input.role && input.role !== 'admin') {\n const user = this.getUserById(id);\n if (user && user.role === 'admin' && this.getAdminCount() === 1) {\n throw new Error('Cannot change role of last admin user');\n }\n }\n\n const sets: string[] = [];\n const values: unknown[] = [];\n\n if (input.name !== undefined) { sets.push('name = ?'); values.push(input.name); }\n if (input.role !== undefined) { sets.push('role = ?'); values.push(input.role); }\n if (input.password_hash !== undefined) { sets.push('password_hash = ?'); values.push(input.password_hash); }\n\n if (sets.length === 0) return;\n\n sets.push('updated_at = ?');\n values.push(new Date().toISOString());\n values.push(id);\n\n this.db.prepare(`UPDATE users SET ${sets.join(', ')} WHERE id = ?`).run(...values);\n }\n\n deleteUser(id: string): void {\n const user = this.getUserById(id);\n if (user && user.role === 'admin' && this.getAdminCount() === 1) {\n throw new Error('Cannot delete last admin user');\n }\n this.db.prepare('DELETE FROM users WHERE id = ?').run(id);\n }\n\n createSession(token: string, userId: string, ttlMs: number): void {\n const now = new Date();\n const expiresAt = new Date(now.getTime() + ttlMs);\n\n this.db.prepare(`\n INSERT INTO sessions (id, user_id, expires_at, created_at)\n VALUES (?, ?, ?, ?)\n `).run(token, userId, expiresAt.toISOString(), now.toISOString());\n }\n\n validateSession(token: string): Session | null {\n const session = this.db.prepare(\n 'SELECT * FROM sessions WHERE id = ? AND expires_at > ?'\n ).get(token, new Date().toISOString()) as Session | undefined;\n\n return session ?? null;\n }\n\n deleteSession(token: string): void {\n this.db.prepare('DELETE FROM sessions WHERE id = ?').run(token);\n }\n\n deleteUserSessions(userId: string): void {\n this.db.prepare('DELETE FROM sessions WHERE user_id = ?').run(userId);\n }\n\n purgeExpiredSessions(): number {\n const result = this.db.prepare(\n 'DELETE FROM sessions WHERE expires_at <= ?'\n ).run(new Date().toISOString());\n return result.changes;\n }\n\n getUserByProviderAndExternalId(provider: string, externalId: string): LocalUser | null {\n return (this.db.prepare(\n 'SELECT * FROM users WHERE provider = ? AND external_id = ?'\n ).get(provider, externalId) as LocalUser) ?? null;\n }\n\n // --- User Attributes ---\n\n getUserAttributes(id: string): Record<string, string> {\n const row = this.db.prepare('SELECT attributes FROM users WHERE id = ?').get(id) as { attributes: string } | undefined;\n if (!row) return {};\n try {\n return JSON.parse(row.attributes);\n } catch {\n return {};\n }\n }\n\n updateUserAttributes(id: string, attributes: Record<string, string>): void {\n this.db.prepare('UPDATE users SET attributes = ?, updated_at = ? WHERE id = ?')\n .run(JSON.stringify(attributes), new Date().toISOString(), id);\n }\n\n // --- Share Links ---\n\n createShareLink(input: CreateShareLinkInput): ShareLink {\n const id = uuidv4();\n const token = randomBytes(32).toString('hex');\n const now = new Date().toISOString();\n\n this.db.prepare(`\n INSERT INTO share_links (id, token, resource_type, resource_name, created_by, created_at, expires_at, is_active)\n VALUES (?, ?, ?, ?, ?, ?, ?, 1)\n `).run(id, token, input.resourceType, input.resourceName, input.createdBy, now, input.expiresAt ?? null);\n\n return this.db.prepare('SELECT * FROM share_links WHERE id = ?').get(id) as ShareLink;\n }\n\n getShareLinkByToken(token: string): ShareLink | null {\n const now = new Date().toISOString();\n const link = this.db.prepare(\n 'SELECT * FROM share_links WHERE token = ? AND is_active = 1 AND (expires_at IS NULL OR expires_at > ?)'\n ).get(token, now) as ShareLink | undefined;\n return link ?? null;\n }\n\n listShareLinks(createdBy?: string): ShareLink[] {\n if (createdBy) {\n return this.db.prepare(\n 'SELECT * FROM share_links WHERE created_by = ? AND is_active = 1 ORDER BY created_at DESC'\n ).all(createdBy) as ShareLink[];\n }\n return this.db.prepare(\n 'SELECT * FROM share_links WHERE is_active = 1 ORDER BY created_at DESC'\n ).all() as ShareLink[];\n }\n\n revokeShareLink(id: string): void {\n this.db.prepare('UPDATE share_links SET is_active = 0 WHERE id = ?').run(id);\n }\n\n deleteShareLink(id: string): void {\n this.db.prepare('DELETE FROM share_links WHERE id = ?').run(id);\n }\n\n // ---- OAuth: clients ----\n registerOAuthClient(input: RegisterOAuthClientInput): OAuthClient {\n const now = new Date().toISOString();\n this.db.prepare(`\n INSERT INTO oauth_clients\n (client_id, client_secret_hash, client_name, redirect_uris, grant_types,\n token_endpoint_auth_method, scope, created_at, client_secret_expires_at)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)\n `).run(\n input.client_id,\n input.client_secret_hash,\n input.client_name,\n JSON.stringify(input.redirect_uris),\n JSON.stringify(input.grant_types),\n input.token_endpoint_auth_method,\n input.scope,\n now,\n input.client_secret_expires_at,\n );\n return this.getOAuthClient(input.client_id)!;\n }\n\n getOAuthClient(clientId: string): OAuthClient | null {\n return (this.db.prepare('SELECT * FROM oauth_clients WHERE client_id = ?').get(clientId) as OAuthClient) ?? null;\n }\n\n // ---- OAuth: authorization codes (single-use) ----\n createAuthCode(input: CreateAuthCodeInput): void {\n this.db.prepare(`\n INSERT INTO oauth_auth_codes\n (code_hash, client_id, user_id, redirect_uri, code_challenge, code_challenge_method, scope, expires_at, created_at)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)\n `).run(\n input.code_hash, input.client_id, input.user_id, input.redirect_uri,\n input.code_challenge, input.code_challenge_method, input.scope,\n input.expires_at, new Date().toISOString(),\n );\n }\n\n /** Atomically fetch-and-delete a non-expired auth code. Returns null if missing/expired. */\n consumeAuthCode(codeHash: string): OAuthAuthCode | null {\n const tx = this.db.transaction((hash: string) => {\n const row = this.db.prepare(\n 'SELECT * FROM oauth_auth_codes WHERE code_hash = ?'\n ).get(hash) as OAuthAuthCode | undefined;\n this.db.prepare('DELETE FROM oauth_auth_codes WHERE code_hash = ?').run(hash);\n if (!row) return null;\n if (new Date(row.expires_at).getTime() <= Date.now()) return null;\n return row;\n });\n return tx(codeHash);\n }\n\n // ---- OAuth: tokens ----\n createOAuthToken(input: CreateOAuthTokenInput): void {\n this.db.prepare(`\n INSERT INTO oauth_tokens (token_hash, token_type, client_id, user_id, scope, expires_at, created_at)\n VALUES (?, ?, ?, ?, ?, ?, ?)\n `).run(\n input.token_hash, input.token_type, input.client_id, input.user_id,\n input.scope, input.expires_at, new Date().toISOString(),\n );\n }\n\n getOAuthToken(tokenHash: string, type: OAuthTokenType): OAuthToken | null {\n const row = this.db.prepare(\n 'SELECT * FROM oauth_tokens WHERE token_hash = ? AND token_type = ? AND expires_at > ?'\n ).get(tokenHash, type, new Date().toISOString()) as OAuthToken | undefined;\n return row ?? null;\n }\n\n deleteOAuthToken(tokenHash: string): void {\n this.db.prepare('DELETE FROM oauth_tokens WHERE token_hash = ?').run(tokenHash);\n }\n\n purgeExpiredOAuth(): number {\n const now = new Date().toISOString();\n const codes = this.db.prepare('DELETE FROM oauth_auth_codes WHERE expires_at <= ?').run(now);\n const tokens = this.db.prepare('DELETE FROM oauth_tokens WHERE expires_at <= ?').run(now);\n return codes.changes + tokens.changes;\n }\n}\n","import { randomBytes } from 'crypto';\n\nexport function generateSessionToken(): string {\n return randomBytes(32).toString('hex');\n}\n\nconst DEFAULT_TTL_MS = 30 * 24 * 60 * 60 * 1000; // 30 days\n\nexport function parseTtl(ttl: string): number {\n const match = ttl.match(/^(\\d+)(d|h|m)$/);\n if (!match || !match[1] || !match[2]) return DEFAULT_TTL_MS;\n\n const value = parseInt(match[1], 10);\n switch (match[2]) {\n case 'd': return value * 24 * 60 * 60 * 1000;\n case 'h': return value * 60 * 60 * 1000;\n case 'm': return value * 60 * 1000;\n default: return DEFAULT_TTL_MS;\n }\n}\n","import { randomBytes, createHash } from 'node:crypto';\n\n/** A 256-bit opaque token, hex-encoded. */\nexport function generateOpaqueToken(): string {\n return randomBytes(32).toString('hex');\n}\n\n/** SHA-256 of a token, hex — what we store at rest so a DB leak yields no usable tokens. */\nexport function hashToken(token: string): string {\n return createHash('sha256').update(token).digest('hex');\n}\n"],"mappings":"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","names":["randomBytes","randomBytes"]}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
var __create = Object.create;
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
6
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
+
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
8
|
+
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
9
|
+
}) : x)(function(x) {
|
|
10
|
+
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
11
|
+
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
12
|
+
});
|
|
13
|
+
var __commonJS = (cb, mod) => function __require2() {
|
|
14
|
+
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
|
|
15
|
+
};
|
|
16
|
+
var __copyProps = (to, from, except, desc) => {
|
|
17
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
18
|
+
for (let key of __getOwnPropNames(from))
|
|
19
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
20
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
21
|
+
}
|
|
22
|
+
return to;
|
|
23
|
+
};
|
|
24
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
25
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
26
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
27
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
28
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
29
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
30
|
+
mod
|
|
31
|
+
));
|
|
32
|
+
|
|
33
|
+
export {
|
|
34
|
+
__require,
|
|
35
|
+
__commonJS,
|
|
36
|
+
__toESM
|
|
37
|
+
};
|
|
38
|
+
//# sourceMappingURL=chunk-7D4SUZUM.js.map
|
|
@@ -78,6 +78,18 @@ function getTablesQuery(type, options) {
|
|
|
78
78
|
}))
|
|
79
79
|
};
|
|
80
80
|
}
|
|
81
|
+
case "bigquery": {
|
|
82
|
+
const dataset = options?.schema;
|
|
83
|
+
if (!dataset) throw new Error("BigQuery introspection requires a dataset. Pass --schema <dataset> (or set config.dataset).");
|
|
84
|
+
return {
|
|
85
|
+
sql: `SELECT table_schema, table_name, table_type FROM \`${dataset}.INFORMATION_SCHEMA.TABLES\``,
|
|
86
|
+
normalize: (rows) => rows.map((row) => ({
|
|
87
|
+
schema: String(row.table_schema),
|
|
88
|
+
name: String(row.table_name),
|
|
89
|
+
type: normalizeTableType(String(row.table_type))
|
|
90
|
+
}))
|
|
91
|
+
};
|
|
92
|
+
}
|
|
81
93
|
default:
|
|
82
94
|
throw new Error(`Unsupported database type: ${type}`);
|
|
83
95
|
}
|
|
@@ -150,11 +162,25 @@ function getDescribeQuery(type, table) {
|
|
|
150
162
|
}))
|
|
151
163
|
};
|
|
152
164
|
}
|
|
165
|
+
case "bigquery": {
|
|
166
|
+
const parts = table.split(".");
|
|
167
|
+
const bareTable = parts[parts.length - 1];
|
|
168
|
+
const dataset = parts.length > 1 ? parts.slice(0, -1).join(".") : void 0;
|
|
169
|
+
if (!dataset) throw new Error("BigQuery describe requires a dataset-qualified table, e.g. analytics.orders.");
|
|
170
|
+
return {
|
|
171
|
+
sql: `SELECT column_name, data_type, is_nullable FROM \`${dataset}.INFORMATION_SCHEMA.COLUMNS\` WHERE table_name = '${escapeSqlValue(bareTable)}' ORDER BY ordinal_position`,
|
|
172
|
+
normalize: (rows) => rows.map((row) => ({
|
|
173
|
+
name: String(row.column_name),
|
|
174
|
+
type: String(row.data_type),
|
|
175
|
+
nullable: String(row.is_nullable)
|
|
176
|
+
}))
|
|
177
|
+
};
|
|
178
|
+
}
|
|
153
179
|
default:
|
|
154
180
|
throw new Error(`Unsupported database type: ${type}`);
|
|
155
181
|
}
|
|
156
182
|
}
|
|
157
|
-
function getSearchQuery(type, keyword) {
|
|
183
|
+
function getSearchQuery(type, keyword, options) {
|
|
158
184
|
const escaped = escapeSqlValue(keyword);
|
|
159
185
|
switch (type) {
|
|
160
186
|
case "duckdb":
|
|
@@ -237,6 +263,29 @@ function getSearchQuery(type, keyword) {
|
|
|
237
263
|
}))
|
|
238
264
|
};
|
|
239
265
|
}
|
|
266
|
+
case "bigquery": {
|
|
267
|
+
const dataset = options?.schema;
|
|
268
|
+
if (!dataset) throw new Error("BigQuery search requires a dataset. Pass --schema <dataset> (or set config.dataset).");
|
|
269
|
+
const needle = escapeSqlValue(keyword.toLowerCase());
|
|
270
|
+
const sql = [
|
|
271
|
+
`SELECT 'table' AS match_type, table_schema, table_name, NULL AS column_name, NULL AS data_type`,
|
|
272
|
+
`FROM \`${dataset}.INFORMATION_SCHEMA.TABLES\` WHERE LOWER(table_name) LIKE '%${needle}%'`,
|
|
273
|
+
`UNION ALL`,
|
|
274
|
+
`SELECT 'column' AS match_type, table_schema, table_name, column_name, data_type`,
|
|
275
|
+
`FROM \`${dataset}.INFORMATION_SCHEMA.COLUMNS\` WHERE LOWER(column_name) LIKE '%${needle}%'`,
|
|
276
|
+
`ORDER BY match_type, table_schema, table_name`
|
|
277
|
+
].join(" ");
|
|
278
|
+
return {
|
|
279
|
+
sql,
|
|
280
|
+
normalize: (rows) => rows.map((row) => ({
|
|
281
|
+
type: String(row.match_type),
|
|
282
|
+
schema: String(row.table_schema),
|
|
283
|
+
table: String(row.table_name),
|
|
284
|
+
...row.column_name ? { column: String(row.column_name) } : {},
|
|
285
|
+
...row.data_type ? { columnType: String(row.data_type) } : {}
|
|
286
|
+
}))
|
|
287
|
+
};
|
|
288
|
+
}
|
|
240
289
|
default:
|
|
241
290
|
throw new Error(`Unsupported database type: ${type}`);
|
|
242
291
|
}
|
|
@@ -312,6 +361,20 @@ function getColumnsQuery(type, options) {
|
|
|
312
361
|
throw new Error(
|
|
313
362
|
"SQLite does not support bulk column queries. Use getDescribeQuery per table."
|
|
314
363
|
);
|
|
364
|
+
case "bigquery": {
|
|
365
|
+
const dataset = options?.schema;
|
|
366
|
+
if (!dataset) throw new Error("BigQuery introspection requires a dataset. Pass --schema <dataset> (or set config.dataset).");
|
|
367
|
+
return {
|
|
368
|
+
sql: `SELECT table_schema, table_name, column_name, data_type, is_nullable FROM \`${dataset}.INFORMATION_SCHEMA.COLUMNS\` ORDER BY table_name, ordinal_position`,
|
|
369
|
+
normalize: (rows) => rows.map((row) => ({
|
|
370
|
+
schema: String(row.table_schema),
|
|
371
|
+
table: String(row.table_name),
|
|
372
|
+
name: String(row.column_name),
|
|
373
|
+
type: String(row.data_type),
|
|
374
|
+
nullable: String(row.is_nullable)
|
|
375
|
+
}))
|
|
376
|
+
};
|
|
377
|
+
}
|
|
315
378
|
default:
|
|
316
379
|
throw new Error(`Unsupported database type: ${type}`);
|
|
317
380
|
}
|
|
@@ -323,4 +386,4 @@ export {
|
|
|
323
386
|
getSearchQuery,
|
|
324
387
|
getColumnsQuery
|
|
325
388
|
};
|
|
326
|
-
//# sourceMappingURL=chunk-
|
|
389
|
+
//# sourceMappingURL=chunk-EAQXUGP6.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/commands/introspection.ts"],"sourcesContent":["/**\n * Per-engine SQL generation and result normalization for database introspection.\n *\n * Pure logic — no I/O, no connectors. Generates SQL strings and provides\n * normalize functions to transform raw query results into consistent shapes.\n */\n\nexport interface NormalizedTable {\n schema: string;\n name: string;\n type: string;\n}\n\nexport interface NormalizedColumn {\n name: string;\n type: string;\n nullable: string;\n}\n\nexport interface SearchResult {\n type: 'table' | 'column';\n schema: string;\n table: string;\n column?: string;\n columnType?: string;\n}\n\nexport interface TablesQuery {\n sql: string;\n normalize: (rows: Record<string, unknown>[]) => NormalizedTable[];\n}\n\nexport interface DescribeQuery {\n sql: string;\n normalize: (rows: Record<string, unknown>[]) => NormalizedColumn[];\n}\n\nexport interface SearchQuery {\n sql: string;\n normalize: (rows: Record<string, unknown>[]) => SearchResult[];\n}\n\nexport interface NormalizedColumnWithTable {\n schema: string;\n table: string;\n name: string;\n type: string;\n nullable: string;\n}\n\nexport interface ColumnsQuery {\n sql: string;\n normalize: (rows: Record<string, unknown>[]) => NormalizedColumnWithTable[];\n}\n\n/**\n * Escape a SQL string literal value by doubling single quotes.\n */\nfunction escapeSqlValue(value: string): string {\n return value.replace(/'/g, \"''\");\n}\n\n/**\n * Normalize table_type values: 'BASE TABLE' -> 'TABLE', everything else uppercased.\n */\nfunction normalizeTableType(tableType: string): string {\n const upper = tableType.toUpperCase();\n if (upper === 'BASE TABLE') return 'TABLE';\n return upper;\n}\n\n/**\n * Helper to read a property from a row, trying lowercase first then uppercase.\n * MySQL drivers may return column names in either case.\n */\nfunction getField(row: Record<string, unknown>, lowercase: string, uppercase: string): unknown {\n if (lowercase in row) return row[lowercase];\n if (uppercase in row) return row[uppercase];\n return undefined;\n}\n\n/**\n * Generate a SQL query to list tables/views and a normalizer for the results.\n *\n * Supported types: duckdb, postgres, mysql, snowflake, sqlite.\n */\nexport function getTablesQuery(\n type: string,\n options?: { schema?: string; database?: string },\n): TablesQuery {\n switch (type) {\n case 'duckdb':\n case 'postgres': {\n const conditions = [\n \"table_schema NOT IN ('information_schema', 'pg_catalog')\",\n ];\n if (options?.schema) {\n conditions.push(`table_schema = '${escapeSqlValue(options.schema)}'`);\n }\n const sql = `SELECT table_schema, table_name, table_type FROM information_schema.tables WHERE ${conditions.join(' AND ')}`;\n return {\n sql,\n normalize: (rows) =>\n rows.map((row) => ({\n schema: String(row.table_schema),\n name: String(row.table_name),\n type: normalizeTableType(String(row.table_type)),\n })),\n };\n }\n\n case 'mysql': {\n let sql = 'SELECT table_schema, table_name, table_type FROM information_schema.tables';\n if (options?.schema) {\n sql += ` WHERE table_schema = '${escapeSqlValue(options.schema)}'`;\n }\n return {\n sql,\n normalize: (rows) =>\n rows.map((row) => ({\n schema: String(getField(row, 'table_schema', 'TABLE_SCHEMA')),\n name: String(getField(row, 'table_name', 'TABLE_NAME')),\n type: normalizeTableType(String(getField(row, 'table_type', 'TABLE_TYPE'))),\n })),\n };\n }\n\n case 'snowflake': {\n const conditions: string[] = [];\n if (options?.schema) {\n conditions.push(`TABLE_SCHEMA = '${escapeSqlValue(options.schema)}'`);\n }\n if (options?.database) {\n conditions.push(`TABLE_CATALOG = '${escapeSqlValue(options.database)}'`);\n }\n let sql = 'SELECT TABLE_SCHEMA, TABLE_NAME, TABLE_TYPE FROM INFORMATION_SCHEMA.TABLES';\n if (conditions.length > 0) {\n sql += ` WHERE ${conditions.join(' AND ')}`;\n }\n return {\n sql,\n normalize: (rows) =>\n rows.map((row) => ({\n schema: String(row.TABLE_SCHEMA),\n name: String(row.TABLE_NAME),\n type: normalizeTableType(String(row.TABLE_TYPE)),\n })),\n };\n }\n\n case 'sqlite': {\n const sql = \"SELECT name, type FROM sqlite_master WHERE type IN ('table', 'view') AND name NOT LIKE 'sqlite_%'\";\n return {\n sql,\n normalize: (rows) =>\n rows.map((row) => ({\n schema: '',\n name: String(row.name),\n type: String(row.type).toUpperCase(),\n })),\n };\n }\n\n case 'bigquery': {\n const dataset = options?.schema;\n if (!dataset) throw new Error('BigQuery introspection requires a dataset. Pass --schema <dataset> (or set config.dataset).');\n return {\n sql: `SELECT table_schema, table_name, table_type FROM \\`${dataset}.INFORMATION_SCHEMA.TABLES\\``,\n normalize: (rows) =>\n rows.map((row) => ({\n schema: String(row.table_schema),\n name: String(row.table_name),\n type: normalizeTableType(String(row.table_type)),\n })),\n };\n }\n\n default:\n throw new Error(`Unsupported database type: ${type}`);\n }\n}\n\n/**\n * Generate a SQL query to describe a table's columns and a normalizer for the results.\n *\n * Supported types: duckdb, postgres, mysql, snowflake, sqlite.\n * Accepts schema-qualified names (e.g. 'public.orders', 'ANALYTICS.PUBLIC.ORDERS').\n */\nexport function getDescribeQuery(type: string, table: string): DescribeQuery {\n switch (type) {\n case 'duckdb': {\n return {\n sql: `DESCRIBE ${table}`,\n normalize: (rows) =>\n rows.map((row) => ({\n name: String(row.column_name),\n type: String(row.column_type),\n nullable: String(row.null),\n })),\n };\n }\n\n case 'postgres': {\n const parts = table.split('.');\n const tableName = parts.length > 1 ? parts[parts.length - 1]! : table;\n const schemaName = parts.length > 1 ? parts[0]! : null;\n\n const conditions = [`table_name = '${escapeSqlValue(tableName)}'`];\n if (schemaName) {\n conditions.push(`table_schema = '${escapeSqlValue(schemaName)}'`);\n }\n\n const sql = `SELECT column_name, data_type, is_nullable FROM information_schema.columns WHERE ${conditions.join(' AND ')} ORDER BY ordinal_position`;\n return {\n sql,\n normalize: (rows) =>\n rows.map((row) => ({\n name: String(row.column_name),\n type: String(row.data_type),\n nullable: String(row.is_nullable),\n })),\n };\n }\n\n case 'mysql': {\n const parts = table.split('.');\n const tableName = parts.length > 1 ? parts[parts.length - 1]! : table;\n const schemaName = parts.length > 1 ? parts[0]! : null;\n\n const conditions = [`table_name = '${escapeSqlValue(tableName)}'`];\n if (schemaName) {\n conditions.push(`table_schema = '${escapeSqlValue(schemaName)}'`);\n }\n\n const sql = `SELECT column_name, column_type, is_nullable FROM information_schema.columns WHERE ${conditions.join(' AND ')} ORDER BY ordinal_position`;\n return {\n sql,\n normalize: (rows) =>\n rows.map((row) => ({\n name: String(getField(row, 'column_name', 'COLUMN_NAME')),\n type: String(getField(row, 'column_type', 'COLUMN_TYPE')),\n nullable: String(getField(row, 'is_nullable', 'IS_NULLABLE')),\n })),\n };\n }\n\n case 'snowflake': {\n return {\n sql: `DESCRIBE TABLE ${table}`,\n normalize: (rows) =>\n rows.map((row) => ({\n name: String(row.name),\n type: String(row.type),\n nullable: String(row['null?']) === 'Y' ? 'YES' : 'NO',\n })),\n };\n }\n\n case 'sqlite': {\n return {\n sql: `PRAGMA table_info(${table})`,\n normalize: (rows) =>\n rows.map((row) => ({\n name: String(row.name),\n type: String(row.type),\n nullable: Number(row.notnull) === 1 ? 'NO' : 'YES',\n })),\n };\n }\n\n case 'bigquery': {\n const parts = table.split('.');\n const bareTable = parts[parts.length - 1];\n const dataset = parts.length > 1 ? parts.slice(0, -1).join('.') : undefined;\n if (!dataset) throw new Error('BigQuery describe requires a dataset-qualified table, e.g. analytics.orders.');\n return {\n sql: `SELECT column_name, data_type, is_nullable FROM \\`${dataset}.INFORMATION_SCHEMA.COLUMNS\\` WHERE table_name = '${escapeSqlValue(bareTable!)}' ORDER BY ordinal_position`,\n normalize: (rows) =>\n rows.map((row) => ({\n name: String(row.column_name),\n type: String(row.data_type),\n nullable: String(row.is_nullable),\n })),\n };\n }\n\n default:\n throw new Error(`Unsupported database type: ${type}`);\n }\n}\n\n/**\n * Generate a SQL query to search for tables and columns matching a keyword.\n *\n * Supported types: duckdb, postgres, mysql, snowflake, sqlite.\n */\nexport function getSearchQuery(\n type: string,\n keyword: string,\n options?: { schema?: string; database?: string },\n): SearchQuery {\n const escaped = escapeSqlValue(keyword);\n\n switch (type) {\n case 'duckdb':\n case 'postgres': {\n const sql = [\n `SELECT 'table' AS match_type, table_schema, table_name, NULL AS column_name, NULL AS data_type`,\n `FROM information_schema.tables`,\n `WHERE table_schema NOT IN ('information_schema', 'pg_catalog')`,\n `AND table_name ILIKE '%${escaped}%'`,\n `UNION ALL`,\n `SELECT 'column' AS match_type, table_schema, table_name, column_name, data_type`,\n `FROM information_schema.columns`,\n `WHERE table_schema NOT IN ('information_schema', 'pg_catalog')`,\n `AND column_name ILIKE '%${escaped}%'`,\n `ORDER BY match_type, table_schema, table_name`,\n ].join(' ');\n\n return {\n sql,\n normalize: (rows) =>\n rows.map((row) => ({\n type: String(row.match_type) as 'table' | 'column',\n schema: String(row.table_schema),\n table: String(row.table_name),\n ...(row.column_name ? { column: String(row.column_name) } : {}),\n ...(row.data_type ? { columnType: String(row.data_type) } : {}),\n })),\n };\n }\n\n case 'mysql': {\n const sql = [\n `SELECT 'table' AS match_type, table_schema, table_name, NULL AS column_name, NULL AS data_type`,\n `FROM information_schema.tables`,\n `WHERE table_name LIKE '%${escaped}%'`,\n `UNION ALL`,\n `SELECT 'column' AS match_type, table_schema, table_name, column_name, data_type`,\n `FROM information_schema.columns`,\n `WHERE column_name LIKE '%${escaped}%'`,\n `ORDER BY match_type, table_schema, table_name`,\n ].join(' ');\n\n return {\n sql,\n normalize: (rows) =>\n rows.map((row) => ({\n type: String(getField(row, 'match_type', 'MATCH_TYPE')) as 'table' | 'column',\n schema: String(getField(row, 'table_schema', 'TABLE_SCHEMA')),\n table: String(getField(row, 'table_name', 'TABLE_NAME')),\n ...(getField(row, 'column_name', 'COLUMN_NAME')\n ? { column: String(getField(row, 'column_name', 'COLUMN_NAME')) }\n : {}),\n ...(getField(row, 'data_type', 'DATA_TYPE')\n ? { columnType: String(getField(row, 'data_type', 'DATA_TYPE')) }\n : {}),\n })),\n };\n }\n\n case 'snowflake': {\n const sql = [\n `SELECT 'table' AS MATCH_TYPE, TABLE_SCHEMA, TABLE_NAME, NULL AS COLUMN_NAME, NULL AS DATA_TYPE`,\n `FROM INFORMATION_SCHEMA.TABLES`,\n `WHERE TABLE_NAME ILIKE '%${escaped}%'`,\n `UNION ALL`,\n `SELECT 'column' AS MATCH_TYPE, TABLE_SCHEMA, TABLE_NAME, COLUMN_NAME, DATA_TYPE`,\n `FROM INFORMATION_SCHEMA.COLUMNS`,\n `WHERE COLUMN_NAME ILIKE '%${escaped}%'`,\n `ORDER BY MATCH_TYPE, TABLE_SCHEMA, TABLE_NAME`,\n ].join(' ');\n\n return {\n sql,\n normalize: (rows) =>\n rows.map((row) => ({\n type: String(row.MATCH_TYPE) as 'table' | 'column',\n schema: String(row.TABLE_SCHEMA),\n table: String(row.TABLE_NAME),\n ...(row.COLUMN_NAME ? { column: String(row.COLUMN_NAME) } : {}),\n ...(row.DATA_TYPE ? { columnType: String(row.DATA_TYPE) } : {}),\n })),\n };\n }\n\n case 'sqlite': {\n const sql = `SELECT name FROM sqlite_master WHERE type IN ('table', 'view') AND name NOT LIKE 'sqlite_%' AND name LIKE '%${escaped}%'`;\n\n return {\n sql,\n normalize: (rows) =>\n rows.map((row) => ({\n type: 'table' as const,\n schema: '',\n table: String(row.name),\n })),\n };\n }\n\n case 'bigquery': {\n const dataset = options?.schema;\n if (!dataset) throw new Error('BigQuery search requires a dataset. Pass --schema <dataset> (or set config.dataset).');\n const needle = escapeSqlValue(keyword.toLowerCase());\n const sql = [\n `SELECT 'table' AS match_type, table_schema, table_name, NULL AS column_name, NULL AS data_type`,\n `FROM \\`${dataset}.INFORMATION_SCHEMA.TABLES\\` WHERE LOWER(table_name) LIKE '%${needle}%'`,\n `UNION ALL`,\n `SELECT 'column' AS match_type, table_schema, table_name, column_name, data_type`,\n `FROM \\`${dataset}.INFORMATION_SCHEMA.COLUMNS\\` WHERE LOWER(column_name) LIKE '%${needle}%'`,\n `ORDER BY match_type, table_schema, table_name`,\n ].join(' ');\n return {\n sql,\n normalize: (rows) =>\n rows.map((row) => ({\n type: String(row.match_type) as 'table' | 'column',\n schema: String(row.table_schema),\n table: String(row.table_name),\n ...(row.column_name ? { column: String(row.column_name) } : {}),\n ...(row.data_type ? { columnType: String(row.data_type) } : {}),\n })),\n };\n }\n\n default:\n throw new Error(`Unsupported database type: ${type}`);\n }\n}\n\n/**\n * Generate a SQL query to fetch ALL columns across all tables in a single bulk query,\n * and a normalizer for the results.\n *\n * Supported types: duckdb, postgres, mysql, snowflake.\n * SQLite is not supported (no information_schema); use getDescribeQuery per table.\n */\nexport function getColumnsQuery(\n type: string,\n options?: { schema?: string; database?: string },\n): ColumnsQuery {\n switch (type) {\n case 'duckdb':\n case 'postgres': {\n const conditions = [\n \"table_schema NOT IN ('information_schema', 'pg_catalog')\",\n ];\n if (options?.schema) {\n conditions.push(`table_schema = '${escapeSqlValue(options.schema)}'`);\n }\n const sql = `SELECT table_schema, table_name, column_name, data_type, is_nullable FROM information_schema.columns WHERE ${conditions.join(' AND ')} ORDER BY table_schema, table_name, ordinal_position`;\n return {\n sql,\n normalize: (rows) =>\n rows.map((row) => ({\n schema: String(row.table_schema),\n table: String(row.table_name),\n name: String(row.column_name),\n type: String(row.data_type),\n nullable: String(row.is_nullable),\n })),\n };\n }\n\n case 'mysql': {\n const conditions: string[] = [];\n if (options?.schema) {\n conditions.push(`table_schema = '${escapeSqlValue(options.schema)}'`);\n }\n let sql = 'SELECT table_schema, table_name, column_name, column_type, is_nullable FROM information_schema.columns';\n if (conditions.length > 0) {\n sql += ` WHERE ${conditions.join(' AND ')}`;\n }\n sql += ' ORDER BY table_schema, table_name, ordinal_position';\n return {\n sql,\n normalize: (rows) =>\n rows.map((row) => ({\n schema: String(getField(row, 'table_schema', 'TABLE_SCHEMA')),\n table: String(getField(row, 'table_name', 'TABLE_NAME')),\n name: String(getField(row, 'column_name', 'COLUMN_NAME')),\n type: String(getField(row, 'column_type', 'COLUMN_TYPE')),\n nullable: String(getField(row, 'is_nullable', 'IS_NULLABLE')),\n })),\n };\n }\n\n case 'snowflake': {\n const conditions: string[] = [];\n if (options?.schema) {\n conditions.push(`TABLE_SCHEMA = '${escapeSqlValue(options.schema)}'`);\n }\n if (options?.database) {\n conditions.push(`TABLE_CATALOG = '${escapeSqlValue(options.database)}'`);\n }\n let sql = 'SELECT TABLE_SCHEMA, TABLE_NAME, COLUMN_NAME, DATA_TYPE, IS_NULLABLE FROM INFORMATION_SCHEMA.COLUMNS';\n if (conditions.length > 0) {\n sql += ` WHERE ${conditions.join(' AND ')}`;\n }\n sql += ' ORDER BY TABLE_SCHEMA, TABLE_NAME, ORDINAL_POSITION';\n return {\n sql,\n normalize: (rows) =>\n rows.map((row) => ({\n schema: String(row.TABLE_SCHEMA),\n table: String(row.TABLE_NAME),\n name: String(row.COLUMN_NAME),\n type: String(row.DATA_TYPE),\n nullable: String(row.IS_NULLABLE),\n })),\n };\n }\n\n case 'sqlite':\n throw new Error(\n 'SQLite does not support bulk column queries. Use getDescribeQuery per table.',\n );\n\n case 'bigquery': {\n const dataset = options?.schema;\n if (!dataset) throw new Error('BigQuery introspection requires a dataset. Pass --schema <dataset> (or set config.dataset).');\n return {\n sql: `SELECT table_schema, table_name, column_name, data_type, is_nullable FROM \\`${dataset}.INFORMATION_SCHEMA.COLUMNS\\` ORDER BY table_name, ordinal_position`,\n normalize: (rows) =>\n rows.map((row) => ({\n schema: String(row.table_schema),\n table: String(row.table_name),\n name: String(row.column_name),\n type: String(row.data_type),\n nullable: String(row.is_nullable),\n })),\n };\n }\n\n default:\n throw new Error(`Unsupported database type: ${type}`);\n }\n}\n"],"mappings":"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","names":[]}
|
|
@@ -5,11 +5,11 @@ import {
|
|
|
5
5
|
getDescribeQuery,
|
|
6
6
|
getSearchQuery,
|
|
7
7
|
getTablesQuery
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-EAQXUGP6.js";
|
|
9
9
|
import {
|
|
10
10
|
createConnector,
|
|
11
11
|
resolveConnection
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-NXQ6ZO3V.js";
|
|
13
13
|
|
|
14
14
|
// src/commands/source-resolver.ts
|
|
15
15
|
import { readFile as readFile2, access as access2 } from "fs/promises";
|
|
@@ -75,6 +75,9 @@ async function scanModels(projectDir) {
|
|
|
75
75
|
}
|
|
76
76
|
|
|
77
77
|
// src/commands/source-resolver.ts
|
|
78
|
+
function bigqueryDataset(connection) {
|
|
79
|
+
return connection.type === "bigquery" ? connection.config.dataset : void 0;
|
|
80
|
+
}
|
|
78
81
|
async function loadCatalog(projectDir) {
|
|
79
82
|
try {
|
|
80
83
|
const catalogPath = join2(projectDir, ".yamchart", "catalog.json");
|
|
@@ -129,7 +132,9 @@ async function describeFromDb(projectDir, table, connectionName) {
|
|
|
129
132
|
const connector = createConnector(connection, projectDir);
|
|
130
133
|
try {
|
|
131
134
|
await connector.connect();
|
|
132
|
-
const
|
|
135
|
+
const ds = bigqueryDataset(connection);
|
|
136
|
+
const tableForDescribe = connection.type === "bigquery" && ds && !resolved.tableName.includes(".") ? `${ds}.${resolved.tableName}` : resolved.tableName;
|
|
137
|
+
const query = getDescribeQuery(connection.type, tableForDescribe);
|
|
133
138
|
const startTime = performance.now();
|
|
134
139
|
const result = await connector.execute(query.sql);
|
|
135
140
|
const durationMs = performance.now() - startTime;
|
|
@@ -213,7 +218,8 @@ async function tablesFromDb(projectDir, connectionName, options) {
|
|
|
213
218
|
const connector = createConnector(connection, projectDir);
|
|
214
219
|
try {
|
|
215
220
|
await connector.connect();
|
|
216
|
-
const
|
|
221
|
+
const effectiveOptions = connection.type === "bigquery" ? { ...options, schema: options?.schema ?? bigqueryDataset(connection) } : options;
|
|
222
|
+
const query = getTablesQuery(connection.type, effectiveOptions);
|
|
217
223
|
const start = performance.now();
|
|
218
224
|
const result = await connector.execute(query.sql);
|
|
219
225
|
const tables = query.normalize(result.rows);
|
|
@@ -281,7 +287,11 @@ async function searchFromDb(projectDir, keyword, connectionName) {
|
|
|
281
287
|
const connector = createConnector(connection, projectDir);
|
|
282
288
|
try {
|
|
283
289
|
await connector.connect();
|
|
284
|
-
const query = getSearchQuery(
|
|
290
|
+
const query = getSearchQuery(
|
|
291
|
+
connection.type,
|
|
292
|
+
keyword,
|
|
293
|
+
connection.type === "bigquery" ? { schema: bigqueryDataset(connection) } : void 0
|
|
294
|
+
);
|
|
285
295
|
const startTime = performance.now();
|
|
286
296
|
const result = await connector.execute(query.sql);
|
|
287
297
|
const durationMs = performance.now() - startTime;
|
|
@@ -359,4 +369,4 @@ export {
|
|
|
359
369
|
resolveTablesSource,
|
|
360
370
|
resolveSearchSource
|
|
361
371
|
};
|
|
362
|
-
//# sourceMappingURL=chunk-
|
|
372
|
+
//# sourceMappingURL=chunk-H4L3FNLS.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/commands/source-resolver.ts","../src/commands/model-parser.ts"],"sourcesContent":["import { readFile, access } from 'fs/promises';\nimport { join } from 'path';\nimport { performance } from 'node:perf_hooks';\nimport type { NormalizedColumn, NormalizedTable, SearchResult } from './introspection.js';\nimport { getDescribeQuery, getTablesQuery, getSearchQuery } from './introspection.js';\nimport { resolveConnection, createConnector } from './connection-utils.js';\nimport { scanModels } from './model-parser.js';\nimport { resolveTableName } from './model-resolver.js';\nimport type { BigQueryConnection, Connection } from '@yamchart/schema';\n\nexport type SourceType = 'auto' | 'catalog' | 'model' | 'db';\n\n/** BigQuery introspection is dataset-scoped; default the dataset from the connection config. */\nfunction bigqueryDataset(connection: Connection): string | undefined {\n return connection.type === 'bigquery' ? (connection as BigQueryConnection).config.dataset : undefined;\n}\n\ninterface CatalogColumn {\n name: string;\n data_type: string;\n description?: string;\n}\n\ninterface CatalogModel {\n name: string;\n table?: string;\n columns?: CatalogColumn[];\n source?: string;\n dependsOn?: string[];\n}\n\ninterface CatalogFile {\n models?: CatalogModel[];\n}\n\nexport interface DescribeSourceResult {\n source: 'catalog' | 'model' | 'db';\n table: string;\n columns: NormalizedColumn[];\n connectionName?: string;\n connectionType?: string;\n durationMs: number;\n resolvedFrom?: string;\n}\n\nexport interface TablesSourceResult {\n source: 'catalog' | 'model' | 'db';\n tables: NormalizedTable[];\n connectionName?: string;\n connectionType?: string;\n durationMs: number;\n}\n\nexport interface SearchSourceResult {\n source: 'catalog' | 'model' | 'db';\n keyword: string;\n results: SearchResult[];\n connectionName?: string;\n connectionType?: string;\n durationMs: number;\n}\n\nasync function loadCatalog(projectDir: string): Promise<CatalogFile | null> {\n try {\n const catalogPath = join(projectDir, '.yamchart', 'catalog.json');\n await access(catalogPath);\n const content = await readFile(catalogPath, 'utf-8');\n return JSON.parse(content) as CatalogFile;\n } catch {\n return null;\n }\n}\n\nfunction findCatalogModel(catalog: CatalogFile, tableName: string): CatalogModel | undefined {\n return catalog.models?.find(\n (m) => m.name.toLowerCase() === tableName.toLowerCase(),\n );\n}\n\nfunction catalogColumnsToNormalized(columns: CatalogColumn[]): NormalizedColumn[] {\n return columns.map((c) => ({\n name: c.name,\n type: c.data_type,\n nullable: 'YES',\n }));\n}\n\n// --- DESCRIBE ---\n\nasync function describeFromCatalog(\n projectDir: string,\n table: string,\n): Promise<DescribeSourceResult | null> {\n const catalog = await loadCatalog(projectDir);\n if (!catalog) return null;\n\n const model = findCatalogModel(catalog, table);\n if (!model?.columns?.length) return null;\n\n return {\n source: 'catalog',\n table: model.table || table,\n columns: catalogColumnsToNormalized(model.columns),\n durationMs: 0,\n ...(model.table ? { resolvedFrom: table } : {}),\n };\n}\n\nasync function describeFromModel(\n projectDir: string,\n table: string,\n): Promise<DescribeSourceResult | null> {\n const models = await scanModels(projectDir);\n const match = models.find(\n (m) => m.name.toLowerCase() === table.toLowerCase(),\n );\n if (!match || match.columns.length === 0) return null;\n\n return {\n source: 'model',\n table: match.name,\n columns: match.columns,\n durationMs: 0,\n };\n}\n\nasync function describeFromDb(\n projectDir: string,\n table: string,\n connectionName?: string,\n): Promise<DescribeSourceResult> {\n const resolved = await resolveTableName(projectDir, table);\n const connection = await resolveConnection(projectDir, connectionName);\n const connector = createConnector(connection, projectDir);\n\n try {\n await connector.connect();\n // BigQuery describe needs a dataset-qualified table; default the dataset from config.\n const ds = bigqueryDataset(connection);\n const tableForDescribe = connection.type === 'bigquery' && ds && !resolved.tableName.includes('.')\n ? `${ds}.${resolved.tableName}`\n : resolved.tableName;\n const query = getDescribeQuery(connection.type, tableForDescribe);\n const startTime = performance.now();\n const result = await connector.execute(query.sql);\n const durationMs = performance.now() - startTime;\n const columns = query.normalize(result.rows as Record<string, unknown>[]);\n\n return {\n source: 'db',\n table: resolved.tableName,\n columns,\n connectionName: connection.name,\n connectionType: connection.type,\n durationMs,\n ...(resolved.source === 'catalog' ? { resolvedFrom: table } : {}),\n };\n } finally {\n await connector.disconnect();\n }\n}\n\nexport async function resolveDescribeSource(\n projectDir: string,\n table: string,\n source: SourceType,\n connectionName?: string,\n): Promise<DescribeSourceResult> {\n switch (source) {\n case 'catalog': {\n const catalog = await loadCatalog(projectDir);\n if (!catalog) throw new Error('No catalog found. Run `yamchart sync-dbt` or `yamchart sync-warehouse` to populate it.');\n const model = findCatalogModel(catalog, table);\n if (!model) throw new Error(`Table \"${table}\" not found in catalog.`);\n if (!model.columns?.length) throw new Error(`Catalog has no column metadata for \"${table}\". Run sync to populate.`);\n return {\n source: 'catalog',\n table: model.table || table,\n columns: catalogColumnsToNormalized(model.columns),\n durationMs: 0,\n ...(model.table ? { resolvedFrom: table } : {}),\n };\n }\n\n case 'model': {\n const models = await scanModels(projectDir);\n const match = models.find((m) => m.name.toLowerCase() === table.toLowerCase());\n if (!match) throw new Error(`No model found matching \"${table}\". Check your models/ directory.`);\n return {\n source: 'model',\n table: match.name,\n columns: match.columns,\n durationMs: 0,\n };\n }\n\n case 'db':\n return describeFromDb(projectDir, table, connectionName);\n\n case 'auto': {\n const catalogResult = await describeFromCatalog(projectDir, table);\n if (catalogResult) return catalogResult;\n\n const modelResult = await describeFromModel(projectDir, table);\n if (modelResult) return modelResult;\n\n return describeFromDb(projectDir, table, connectionName);\n }\n }\n}\n\n// --- TABLES ---\n\nasync function tablesFromCatalog(projectDir: string): Promise<TablesSourceResult | null> {\n const catalog = await loadCatalog(projectDir);\n if (!catalog?.models?.length) return null;\n\n const tables: NormalizedTable[] = catalog.models.map((m) => {\n const parts = (m.table || m.name).split('.');\n return {\n schema: parts.length > 1 ? parts.slice(0, -1).join('.') : '',\n name: parts[parts.length - 1],\n type: m.source === 'dbt-source' ? 'SOURCE' : 'TABLE',\n };\n });\n\n return { source: 'catalog', tables, durationMs: 0 };\n}\n\nasync function tablesFromModel(projectDir: string): Promise<TablesSourceResult | null> {\n const models = await scanModels(projectDir);\n if (models.length === 0) return null;\n\n const tables: NormalizedTable[] = models.map((m) => ({\n schema: '',\n name: m.name,\n type: 'MODEL',\n }));\n\n return { source: 'model', tables, durationMs: 0 };\n}\n\nasync function tablesFromDb(\n projectDir: string,\n connectionName?: string,\n options?: { schema?: string; database?: string },\n): Promise<TablesSourceResult> {\n const connection = await resolveConnection(projectDir, connectionName);\n const connector = createConnector(connection, projectDir);\n\n try {\n await connector.connect();\n const effectiveOptions = connection.type === 'bigquery'\n ? { ...options, schema: options?.schema ?? bigqueryDataset(connection) }\n : options;\n const query = getTablesQuery(connection.type, effectiveOptions);\n const start = performance.now();\n const result = await connector.execute(query.sql);\n const tables = query.normalize(result.rows);\n const durationMs = Math.round((performance.now() - start) * 100) / 100;\n\n return {\n source: 'db',\n tables,\n connectionName: connection.name,\n connectionType: connection.type,\n durationMs,\n };\n } finally {\n await connector.disconnect();\n }\n}\n\nexport async function resolveTablesSource(\n projectDir: string,\n source: SourceType,\n connectionName?: string,\n options?: { schema?: string; database?: string },\n): Promise<TablesSourceResult> {\n switch (source) {\n case 'catalog': {\n const catalog = await loadCatalog(projectDir);\n if (!catalog) throw new Error('No catalog found. Run `yamchart sync-dbt` or `yamchart sync-warehouse` to populate it.');\n const result = await tablesFromCatalog(projectDir);\n return result || { source: 'catalog', tables: [], durationMs: 0 };\n }\n\n case 'model': {\n const result = await tablesFromModel(projectDir);\n return result || { source: 'model', tables: [], durationMs: 0 };\n }\n\n case 'db':\n return tablesFromDb(projectDir, connectionName, options);\n\n case 'auto': {\n const catalogResult = await tablesFromCatalog(projectDir);\n if (catalogResult) return catalogResult;\n\n const modelResult = await tablesFromModel(projectDir);\n if (modelResult) return modelResult;\n\n return tablesFromDb(projectDir, connectionName, options);\n }\n }\n}\n\n// --- SEARCH ---\n\nfunction searchCatalog(catalog: CatalogFile, keyword: string): SearchResult[] {\n const results: SearchResult[] = [];\n const lower = keyword.toLowerCase();\n\n for (const model of catalog.models || []) {\n const tableParts = (model.table || model.name).split('.');\n const schema = tableParts.length > 1 ? tableParts.slice(0, -1).join('.') : '';\n const tableName = tableParts[tableParts.length - 1];\n\n if (model.name.toLowerCase().includes(lower) || tableName.toLowerCase().includes(lower)) {\n results.push({ type: 'table', schema, table: model.name });\n }\n\n for (const col of model.columns || []) {\n if (col.name.toLowerCase().includes(lower)) {\n results.push({\n type: 'column',\n schema,\n table: model.name,\n column: col.name,\n columnType: col.data_type,\n });\n }\n }\n }\n\n return results;\n}\n\nasync function searchFromDb(\n projectDir: string,\n keyword: string,\n connectionName?: string,\n): Promise<SearchSourceResult> {\n const connection = await resolveConnection(projectDir, connectionName);\n const connector = createConnector(connection, projectDir);\n\n try {\n await connector.connect();\n const query = getSearchQuery(\n connection.type,\n keyword,\n connection.type === 'bigquery' ? { schema: bigqueryDataset(connection) } : undefined,\n );\n const startTime = performance.now();\n const result = await connector.execute(query.sql);\n const durationMs = performance.now() - startTime;\n const results = query.normalize(result.rows as Record<string, unknown>[]);\n\n return {\n source: 'db',\n keyword,\n results,\n connectionName: connection.name,\n connectionType: connection.type,\n durationMs,\n };\n } finally {\n await connector.disconnect();\n }\n}\n\nexport async function resolveSearchSource(\n projectDir: string,\n keyword: string,\n source: SourceType,\n connectionName?: string,\n): Promise<SearchSourceResult> {\n switch (source) {\n case 'catalog': {\n const catalog = await loadCatalog(projectDir);\n if (!catalog) throw new Error('No catalog found. Run `yamchart sync-dbt` or `yamchart sync-warehouse` to populate it.');\n return { source: 'catalog', keyword, results: searchCatalog(catalog, keyword), durationMs: 0 };\n }\n\n case 'model': {\n const models = await scanModels(projectDir);\n const lower = keyword.toLowerCase();\n const results: SearchResult[] = [];\n\n for (const model of models) {\n if (model.name.toLowerCase().includes(lower)) {\n results.push({ type: 'table', schema: '', table: model.name });\n }\n for (const col of model.columns) {\n if (col.name.toLowerCase().includes(lower)) {\n results.push({ type: 'column', schema: '', table: model.name, column: col.name, columnType: col.type });\n }\n }\n }\n\n return { source: 'model', keyword, results, durationMs: 0 };\n }\n\n case 'db':\n return searchFromDb(projectDir, keyword, connectionName);\n\n case 'auto': {\n const catalog = await loadCatalog(projectDir);\n if (catalog?.models?.length) {\n const results = searchCatalog(catalog, keyword);\n if (results.length > 0) {\n return { source: 'catalog', keyword, results, durationMs: 0 };\n }\n }\n\n const models = await scanModels(projectDir);\n if (models.length > 0) {\n const lower = keyword.toLowerCase();\n const results: SearchResult[] = [];\n for (const model of models) {\n if (model.name.toLowerCase().includes(lower)) {\n results.push({ type: 'table', schema: '', table: model.name });\n }\n for (const col of model.columns) {\n if (col.name.toLowerCase().includes(lower)) {\n results.push({ type: 'column', schema: '', table: model.name, column: col.name, columnType: col.type });\n }\n }\n }\n if (results.length > 0) {\n return { source: 'model', keyword, results, durationMs: 0 };\n }\n }\n\n return searchFromDb(projectDir, keyword, connectionName);\n }\n }\n}\n","import { readFile, readdir, access } from 'fs/promises';\nimport { join, extname } from 'path';\nimport type { NormalizedColumn } from './introspection.js';\n\nexport interface ParsedModel {\n name: string;\n description?: string;\n columns: NormalizedColumn[];\n}\n\n/**\n * Parse @name, @description, and @returns from a SQL model file's content.\n * Returns null if no @name annotation is found.\n */\nexport function parseModelReturns(sql: string): ParsedModel | null {\n const nameMatch = sql.match(/--\\s*@name:\\s*(.+)/);\n if (!nameMatch?.[1]) return null;\n\n const name = nameMatch[1].trim();\n\n const descMatch = sql.match(/--\\s*@description:\\s*(.+)/);\n const description = descMatch?.[1]?.trim();\n\n const columns: NormalizedColumn[] = [];\n\n // Find @returns: block and parse each -- - name: type line\n const returnsMatch = sql.match(/--\\s*@returns:\\s*\\n((?:\\s*--\\s+-\\s+.+\\n?)*)/);\n if (returnsMatch?.[1]) {\n const lines = returnsMatch[1].split('\\n');\n for (const line of lines) {\n const colMatch = line.match(/--\\s+-\\s+(\\w+)(?:\\s*:\\s*(\\w+))?/);\n if (colMatch?.[1]) {\n columns.push({\n name: colMatch[1],\n type: colMatch[2] || 'unknown',\n nullable: 'YES',\n });\n }\n }\n }\n\n return { name, description, columns };\n}\n\n/**\n * Recursively find all .sql files in a directory.\n */\nasync function findSqlFiles(dir: string): Promise<string[]> {\n const files: string[] = [];\n const entries = await readdir(dir, { withFileTypes: true });\n\n for (const entry of entries) {\n const fullPath = join(dir, entry.name);\n if (entry.isDirectory()) {\n files.push(...await findSqlFiles(fullPath));\n } else if (extname(entry.name) === '.sql') {\n files.push(fullPath);\n }\n }\n\n return files;\n}\n\n/**\n * Scan models/ directory for SQL files, parse @name and @returns annotations.\n * Returns array of ParsedModel for files that have @name.\n */\nexport async function scanModels(projectDir: string): Promise<ParsedModel[]> {\n const modelsDir = join(projectDir, 'models');\n\n try {\n await access(modelsDir);\n } catch {\n return [];\n }\n\n const sqlFiles = await findSqlFiles(modelsDir);\n const models: ParsedModel[] = [];\n\n for (const filePath of sqlFiles) {\n const content = await readFile(filePath, 'utf-8');\n const parsed = parseModelReturns(content);\n if (parsed) {\n models.push(parsed);\n }\n }\n\n return models;\n}\n"],"mappings":";;;;;;;;;;;;;;AAAA,SAAS,YAAAA,WAAU,UAAAC,eAAc;AACjC,SAAS,QAAAC,aAAY;AACrB,SAAS,mBAAmB;;;ACF5B,SAAS,UAAU,SAAS,cAAc;AAC1C,SAAS,MAAM,eAAe;AAavB,SAAS,kBAAkB,KAAiC;AACjE,QAAM,YAAY,IAAI,MAAM,oBAAoB;AAChD,MAAI,CAAC,YAAY,CAAC,EAAG,QAAO;AAE5B,QAAM,OAAO,UAAU,CAAC,EAAE,KAAK;AAE/B,QAAM,YAAY,IAAI,MAAM,2BAA2B;AACvD,QAAM,cAAc,YAAY,CAAC,GAAG,KAAK;AAEzC,QAAM,UAA8B,CAAC;AAGrC,QAAM,eAAe,IAAI,MAAM,6CAA6C;AAC5E,MAAI,eAAe,CAAC,GAAG;AACrB,UAAM,QAAQ,aAAa,CAAC,EAAE,MAAM,IAAI;AACxC,eAAW,QAAQ,OAAO;AACxB,YAAM,WAAW,KAAK,MAAM,iCAAiC;AAC7D,UAAI,WAAW,CAAC,GAAG;AACjB,gBAAQ,KAAK;AAAA,UACX,MAAM,SAAS,CAAC;AAAA,UAChB,MAAM,SAAS,CAAC,KAAK;AAAA,UACrB,UAAU;AAAA,QACZ,CAAC;AAAA,MACH;AAAA,IACF;AAAA,EACF;AAEA,SAAO,EAAE,MAAM,aAAa,QAAQ;AACtC;AAKA,eAAe,aAAa,KAAgC;AAC1D,QAAM,QAAkB,CAAC;AACzB,QAAM,UAAU,MAAM,QAAQ,KAAK,EAAE,eAAe,KAAK,CAAC;AAE1D,aAAW,SAAS,SAAS;AAC3B,UAAM,WAAW,KAAK,KAAK,MAAM,IAAI;AACrC,QAAI,MAAM,YAAY,GAAG;AACvB,YAAM,KAAK,GAAG,MAAM,aAAa,QAAQ,CAAC;AAAA,IAC5C,WAAW,QAAQ,MAAM,IAAI,MAAM,QAAQ;AACzC,YAAM,KAAK,QAAQ;AAAA,IACrB;AAAA,EACF;AAEA,SAAO;AACT;AAMA,eAAsB,WAAW,YAA4C;AAC3E,QAAM,YAAY,KAAK,YAAY,QAAQ;AAE3C,MAAI;AACF,UAAM,OAAO,SAAS;AAAA,EACxB,QAAQ;AACN,WAAO,CAAC;AAAA,EACV;AAEA,QAAM,WAAW,MAAM,aAAa,SAAS;AAC7C,QAAM,SAAwB,CAAC;AAE/B,aAAW,YAAY,UAAU;AAC/B,UAAM,UAAU,MAAM,SAAS,UAAU,OAAO;AAChD,UAAM,SAAS,kBAAkB,OAAO;AACxC,QAAI,QAAQ;AACV,aAAO,KAAK,MAAM;AAAA,IACpB;AAAA,EACF;AAEA,SAAO;AACT;;;AD3EA,SAAS,gBAAgB,YAA4C;AACnE,SAAO,WAAW,SAAS,aAAc,WAAkC,OAAO,UAAU;AAC9F;AA+CA,eAAe,YAAY,YAAiD;AAC1E,MAAI;AACF,UAAM,cAAcC,MAAK,YAAY,aAAa,cAAc;AAChE,UAAMC,QAAO,WAAW;AACxB,UAAM,UAAU,MAAMC,UAAS,aAAa,OAAO;AACnD,WAAO,KAAK,MAAM,OAAO;AAAA,EAC3B,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,SAAS,iBAAiB,SAAsB,WAA6C;AAC3F,SAAO,QAAQ,QAAQ;AAAA,IACrB,CAAC,MAAM,EAAE,KAAK,YAAY,MAAM,UAAU,YAAY;AAAA,EACxD;AACF;AAEA,SAAS,2BAA2B,SAA8C;AAChF,SAAO,QAAQ,IAAI,CAAC,OAAO;AAAA,IACzB,MAAM,EAAE;AAAA,IACR,MAAM,EAAE;AAAA,IACR,UAAU;AAAA,EACZ,EAAE;AACJ;AAIA,eAAe,oBACb,YACA,OACsC;AACtC,QAAM,UAAU,MAAM,YAAY,UAAU;AAC5C,MAAI,CAAC,QAAS,QAAO;AAErB,QAAM,QAAQ,iBAAiB,SAAS,KAAK;AAC7C,MAAI,CAAC,OAAO,SAAS,OAAQ,QAAO;AAEpC,SAAO;AAAA,IACL,QAAQ;AAAA,IACR,OAAO,MAAM,SAAS;AAAA,IACtB,SAAS,2BAA2B,MAAM,OAAO;AAAA,IACjD,YAAY;AAAA,IACZ,GAAI,MAAM,QAAQ,EAAE,cAAc,MAAM,IAAI,CAAC;AAAA,EAC/C;AACF;AAEA,eAAe,kBACb,YACA,OACsC;AACtC,QAAM,SAAS,MAAM,WAAW,UAAU;AAC1C,QAAM,QAAQ,OAAO;AAAA,IACnB,CAAC,MAAM,EAAE,KAAK,YAAY,MAAM,MAAM,YAAY;AAAA,EACpD;AACA,MAAI,CAAC,SAAS,MAAM,QAAQ,WAAW,EAAG,QAAO;AAEjD,SAAO;AAAA,IACL,QAAQ;AAAA,IACR,OAAO,MAAM;AAAA,IACb,SAAS,MAAM;AAAA,IACf,YAAY;AAAA,EACd;AACF;AAEA,eAAe,eACb,YACA,OACA,gBAC+B;AAC/B,QAAM,WAAW,MAAM,iBAAiB,YAAY,KAAK;AACzD,QAAM,aAAa,MAAM,kBAAkB,YAAY,cAAc;AACrE,QAAM,YAAY,gBAAgB,YAAY,UAAU;AAExD,MAAI;AACF,UAAM,UAAU,QAAQ;AAExB,UAAM,KAAK,gBAAgB,UAAU;AACrC,UAAM,mBAAmB,WAAW,SAAS,cAAc,MAAM,CAAC,SAAS,UAAU,SAAS,GAAG,IAC7F,GAAG,EAAE,IAAI,SAAS,SAAS,KAC3B,SAAS;AACb,UAAM,QAAQ,iBAAiB,WAAW,MAAM,gBAAgB;AAChE,UAAM,YAAY,YAAY,IAAI;AAClC,UAAM,SAAS,MAAM,UAAU,QAAQ,MAAM,GAAG;AAChD,UAAM,aAAa,YAAY,IAAI,IAAI;AACvC,UAAM,UAAU,MAAM,UAAU,OAAO,IAAiC;AAExE,WAAO;AAAA,MACL,QAAQ;AAAA,MACR,OAAO,SAAS;AAAA,MAChB;AAAA,MACA,gBAAgB,WAAW;AAAA,MAC3B,gBAAgB,WAAW;AAAA,MAC3B;AAAA,MACA,GAAI,SAAS,WAAW,YAAY,EAAE,cAAc,MAAM,IAAI,CAAC;AAAA,IACjE;AAAA,EACF,UAAE;AACA,UAAM,UAAU,WAAW;AAAA,EAC7B;AACF;AAEA,eAAsB,sBACpB,YACA,OACA,QACA,gBAC+B;AAC/B,UAAQ,QAAQ;AAAA,IACd,KAAK,WAAW;AACd,YAAM,UAAU,MAAM,YAAY,UAAU;AAC5C,UAAI,CAAC,QAAS,OAAM,IAAI,MAAM,wFAAwF;AACtH,YAAM,QAAQ,iBAAiB,SAAS,KAAK;AAC7C,UAAI,CAAC,MAAO,OAAM,IAAI,MAAM,UAAU,KAAK,yBAAyB;AACpE,UAAI,CAAC,MAAM,SAAS,OAAQ,OAAM,IAAI,MAAM,uCAAuC,KAAK,0BAA0B;AAClH,aAAO;AAAA,QACL,QAAQ;AAAA,QACR,OAAO,MAAM,SAAS;AAAA,QACtB,SAAS,2BAA2B,MAAM,OAAO;AAAA,QACjD,YAAY;AAAA,QACZ,GAAI,MAAM,QAAQ,EAAE,cAAc,MAAM,IAAI,CAAC;AAAA,MAC/C;AAAA,IACF;AAAA,IAEA,KAAK,SAAS;AACZ,YAAM,SAAS,MAAM,WAAW,UAAU;AAC1C,YAAM,QAAQ,OAAO,KAAK,CAAC,MAAM,EAAE,KAAK,YAAY,MAAM,MAAM,YAAY,CAAC;AAC7E,UAAI,CAAC,MAAO,OAAM,IAAI,MAAM,4BAA4B,KAAK,kCAAkC;AAC/F,aAAO;AAAA,QACL,QAAQ;AAAA,QACR,OAAO,MAAM;AAAA,QACb,SAAS,MAAM;AAAA,QACf,YAAY;AAAA,MACd;AAAA,IACF;AAAA,IAEA,KAAK;AACH,aAAO,eAAe,YAAY,OAAO,cAAc;AAAA,IAEzD,KAAK,QAAQ;AACX,YAAM,gBAAgB,MAAM,oBAAoB,YAAY,KAAK;AACjE,UAAI,cAAe,QAAO;AAE1B,YAAM,cAAc,MAAM,kBAAkB,YAAY,KAAK;AAC7D,UAAI,YAAa,QAAO;AAExB,aAAO,eAAe,YAAY,OAAO,cAAc;AAAA,IACzD;AAAA,EACF;AACF;AAIA,eAAe,kBAAkB,YAAwD;AACvF,QAAM,UAAU,MAAM,YAAY,UAAU;AAC5C,MAAI,CAAC,SAAS,QAAQ,OAAQ,QAAO;AAErC,QAAM,SAA4B,QAAQ,OAAO,IAAI,CAAC,MAAM;AAC1D,UAAM,SAAS,EAAE,SAAS,EAAE,MAAM,MAAM,GAAG;AAC3C,WAAO;AAAA,MACL,QAAQ,MAAM,SAAS,IAAI,MAAM,MAAM,GAAG,EAAE,EAAE,KAAK,GAAG,IAAI;AAAA,MAC1D,MAAM,MAAM,MAAM,SAAS,CAAC;AAAA,MAC5B,MAAM,EAAE,WAAW,eAAe,WAAW;AAAA,IAC/C;AAAA,EACF,CAAC;AAED,SAAO,EAAE,QAAQ,WAAW,QAAQ,YAAY,EAAE;AACpD;AAEA,eAAe,gBAAgB,YAAwD;AACrF,QAAM,SAAS,MAAM,WAAW,UAAU;AAC1C,MAAI,OAAO,WAAW,EAAG,QAAO;AAEhC,QAAM,SAA4B,OAAO,IAAI,CAAC,OAAO;AAAA,IACnD,QAAQ;AAAA,IACR,MAAM,EAAE;AAAA,IACR,MAAM;AAAA,EACR,EAAE;AAEF,SAAO,EAAE,QAAQ,SAAS,QAAQ,YAAY,EAAE;AAClD;AAEA,eAAe,aACb,YACA,gBACA,SAC6B;AAC7B,QAAM,aAAa,MAAM,kBAAkB,YAAY,cAAc;AACrE,QAAM,YAAY,gBAAgB,YAAY,UAAU;AAExD,MAAI;AACF,UAAM,UAAU,QAAQ;AACxB,UAAM,mBAAmB,WAAW,SAAS,aACzC,EAAE,GAAG,SAAS,QAAQ,SAAS,UAAU,gBAAgB,UAAU,EAAE,IACrE;AACJ,UAAM,QAAQ,eAAe,WAAW,MAAM,gBAAgB;AAC9D,UAAM,QAAQ,YAAY,IAAI;AAC9B,UAAM,SAAS,MAAM,UAAU,QAAQ,MAAM,GAAG;AAChD,UAAM,SAAS,MAAM,UAAU,OAAO,IAAI;AAC1C,UAAM,aAAa,KAAK,OAAO,YAAY,IAAI,IAAI,SAAS,GAAG,IAAI;AAEnE,WAAO;AAAA,MACL,QAAQ;AAAA,MACR;AAAA,MACA,gBAAgB,WAAW;AAAA,MAC3B,gBAAgB,WAAW;AAAA,MAC3B;AAAA,IACF;AAAA,EACF,UAAE;AACA,UAAM,UAAU,WAAW;AAAA,EAC7B;AACF;AAEA,eAAsB,oBACpB,YACA,QACA,gBACA,SAC6B;AAC7B,UAAQ,QAAQ;AAAA,IACd,KAAK,WAAW;AACd,YAAM,UAAU,MAAM,YAAY,UAAU;AAC5C,UAAI,CAAC,QAAS,OAAM,IAAI,MAAM,wFAAwF;AACtH,YAAM,SAAS,MAAM,kBAAkB,UAAU;AACjD,aAAO,UAAU,EAAE,QAAQ,WAAW,QAAQ,CAAC,GAAG,YAAY,EAAE;AAAA,IAClE;AAAA,IAEA,KAAK,SAAS;AACZ,YAAM,SAAS,MAAM,gBAAgB,UAAU;AAC/C,aAAO,UAAU,EAAE,QAAQ,SAAS,QAAQ,CAAC,GAAG,YAAY,EAAE;AAAA,IAChE;AAAA,IAEA,KAAK;AACH,aAAO,aAAa,YAAY,gBAAgB,OAAO;AAAA,IAEzD,KAAK,QAAQ;AACX,YAAM,gBAAgB,MAAM,kBAAkB,UAAU;AACxD,UAAI,cAAe,QAAO;AAE1B,YAAM,cAAc,MAAM,gBAAgB,UAAU;AACpD,UAAI,YAAa,QAAO;AAExB,aAAO,aAAa,YAAY,gBAAgB,OAAO;AAAA,IACzD;AAAA,EACF;AACF;AAIA,SAAS,cAAc,SAAsB,SAAiC;AAC5E,QAAM,UAA0B,CAAC;AACjC,QAAM,QAAQ,QAAQ,YAAY;AAElC,aAAW,SAAS,QAAQ,UAAU,CAAC,GAAG;AACxC,UAAM,cAAc,MAAM,SAAS,MAAM,MAAM,MAAM,GAAG;AACxD,UAAM,SAAS,WAAW,SAAS,IAAI,WAAW,MAAM,GAAG,EAAE,EAAE,KAAK,GAAG,IAAI;AAC3E,UAAM,YAAY,WAAW,WAAW,SAAS,CAAC;AAElD,QAAI,MAAM,KAAK,YAAY,EAAE,SAAS,KAAK,KAAK,UAAU,YAAY,EAAE,SAAS,KAAK,GAAG;AACvF,cAAQ,KAAK,EAAE,MAAM,SAAS,QAAQ,OAAO,MAAM,KAAK,CAAC;AAAA,IAC3D;AAEA,eAAW,OAAO,MAAM,WAAW,CAAC,GAAG;AACrC,UAAI,IAAI,KAAK,YAAY,EAAE,SAAS,KAAK,GAAG;AAC1C,gBAAQ,KAAK;AAAA,UACX,MAAM;AAAA,UACN;AAAA,UACA,OAAO,MAAM;AAAA,UACb,QAAQ,IAAI;AAAA,UACZ,YAAY,IAAI;AAAA,QAClB,CAAC;AAAA,MACH;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;AAEA,eAAe,aACb,YACA,SACA,gBAC6B;AAC7B,QAAM,aAAa,MAAM,kBAAkB,YAAY,cAAc;AACrE,QAAM,YAAY,gBAAgB,YAAY,UAAU;AAExD,MAAI;AACF,UAAM,UAAU,QAAQ;AACxB,UAAM,QAAQ;AAAA,MACZ,WAAW;AAAA,MACX;AAAA,MACA,WAAW,SAAS,aAAa,EAAE,QAAQ,gBAAgB,UAAU,EAAE,IAAI;AAAA,IAC7E;AACA,UAAM,YAAY,YAAY,IAAI;AAClC,UAAM,SAAS,MAAM,UAAU,QAAQ,MAAM,GAAG;AAChD,UAAM,aAAa,YAAY,IAAI,IAAI;AACvC,UAAM,UAAU,MAAM,UAAU,OAAO,IAAiC;AAExE,WAAO;AAAA,MACL,QAAQ;AAAA,MACR;AAAA,MACA;AAAA,MACA,gBAAgB,WAAW;AAAA,MAC3B,gBAAgB,WAAW;AAAA,MAC3B;AAAA,IACF;AAAA,EACF,UAAE;AACA,UAAM,UAAU,WAAW;AAAA,EAC7B;AACF;AAEA,eAAsB,oBACpB,YACA,SACA,QACA,gBAC6B;AAC7B,UAAQ,QAAQ;AAAA,IACd,KAAK,WAAW;AACd,YAAM,UAAU,MAAM,YAAY,UAAU;AAC5C,UAAI,CAAC,QAAS,OAAM,IAAI,MAAM,wFAAwF;AACtH,aAAO,EAAE,QAAQ,WAAW,SAAS,SAAS,cAAc,SAAS,OAAO,GAAG,YAAY,EAAE;AAAA,IAC/F;AAAA,IAEA,KAAK,SAAS;AACZ,YAAM,SAAS,MAAM,WAAW,UAAU;AAC1C,YAAM,QAAQ,QAAQ,YAAY;AAClC,YAAM,UAA0B,CAAC;AAEjC,iBAAW,SAAS,QAAQ;AAC1B,YAAI,MAAM,KAAK,YAAY,EAAE,SAAS,KAAK,GAAG;AAC5C,kBAAQ,KAAK,EAAE,MAAM,SAAS,QAAQ,IAAI,OAAO,MAAM,KAAK,CAAC;AAAA,QAC/D;AACA,mBAAW,OAAO,MAAM,SAAS;AAC/B,cAAI,IAAI,KAAK,YAAY,EAAE,SAAS,KAAK,GAAG;AAC1C,oBAAQ,KAAK,EAAE,MAAM,UAAU,QAAQ,IAAI,OAAO,MAAM,MAAM,QAAQ,IAAI,MAAM,YAAY,IAAI,KAAK,CAAC;AAAA,UACxG;AAAA,QACF;AAAA,MACF;AAEA,aAAO,EAAE,QAAQ,SAAS,SAAS,SAAS,YAAY,EAAE;AAAA,IAC5D;AAAA,IAEA,KAAK;AACH,aAAO,aAAa,YAAY,SAAS,cAAc;AAAA,IAEzD,KAAK,QAAQ;AACX,YAAM,UAAU,MAAM,YAAY,UAAU;AAC5C,UAAI,SAAS,QAAQ,QAAQ;AAC3B,cAAM,UAAU,cAAc,SAAS,OAAO;AAC9C,YAAI,QAAQ,SAAS,GAAG;AACtB,iBAAO,EAAE,QAAQ,WAAW,SAAS,SAAS,YAAY,EAAE;AAAA,QAC9D;AAAA,MACF;AAEA,YAAM,SAAS,MAAM,WAAW,UAAU;AAC1C,UAAI,OAAO,SAAS,GAAG;AACrB,cAAM,QAAQ,QAAQ,YAAY;AAClC,cAAM,UAA0B,CAAC;AACjC,mBAAW,SAAS,QAAQ;AAC1B,cAAI,MAAM,KAAK,YAAY,EAAE,SAAS,KAAK,GAAG;AAC5C,oBAAQ,KAAK,EAAE,MAAM,SAAS,QAAQ,IAAI,OAAO,MAAM,KAAK,CAAC;AAAA,UAC/D;AACA,qBAAW,OAAO,MAAM,SAAS;AAC/B,gBAAI,IAAI,KAAK,YAAY,EAAE,SAAS,KAAK,GAAG;AAC1C,sBAAQ,KAAK,EAAE,MAAM,UAAU,QAAQ,IAAI,OAAO,MAAM,MAAM,QAAQ,IAAI,MAAM,YAAY,IAAI,KAAK,CAAC;AAAA,YACxG;AAAA,UACF;AAAA,QACF;AACA,YAAI,QAAQ,SAAS,GAAG;AACtB,iBAAO,EAAE,QAAQ,SAAS,SAAS,SAAS,YAAY,EAAE;AAAA,QAC5D;AAAA,MACF;AAEA,aAAO,aAAa,YAAY,SAAS,cAAc;AAAA,IACzD;AAAA,EACF;AACF;","names":["readFile","access","join","join","access","readFile"]}
|