yamchart 0.9.2 → 0.9.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (82) hide show
  1. package/dist/{advisor-SK2EPAAY.js → advisor-SC64RTZO.js} +11 -11
  2. package/dist/agent-TZZHNDPK.js +8 -0
  3. package/dist/{chunk-4P5UHWYK.js → chunk-7CD6UQAV.js} +102 -2
  4. package/dist/chunk-7CD6UQAV.js.map +1 -0
  5. package/dist/chunk-7D4SUZUM.js +38 -0
  6. package/dist/{chunk-EHM6AMMA.js → chunk-EAQXUGP6.js} +65 -2
  7. package/dist/chunk-EAQXUGP6.js.map +1 -0
  8. package/dist/{chunk-UDKODFOE.js → chunk-H4L3FNLS.js} +16 -6
  9. package/dist/chunk-H4L3FNLS.js.map +1 -0
  10. package/dist/{chunk-OI3EGXVE.js → chunk-NXQ6ZO3V.js} +19 -4
  11. package/dist/chunk-NXQ6ZO3V.js.map +1 -0
  12. package/dist/{chunk-65G5DBRO.js → chunk-RM6MNDVF.js} +35 -5
  13. package/dist/chunk-RM6MNDVF.js.map +1 -0
  14. package/dist/{chunk-EHYYYKRW.js → chunk-RMIDEBHD.js} +4 -4
  15. package/dist/{chunk-CWAWATL4.js → chunk-S7YQXEKM.js} +159 -2
  16. package/dist/chunk-S7YQXEKM.js.map +1 -0
  17. package/dist/{chunk-ZA6AOQVZ.js → chunk-ZMJPRNOA.js} +2 -2
  18. package/dist/{compare-ZN6RUOOQ.js → compare-RQFCEZIK.js} +2 -2
  19. package/dist/{connection-utils-MCJBJEDQ.js → connection-utils-C4FQGBW6.js} +5 -5
  20. package/dist/{describe-XJ5GXYUE.js → describe-X75C2VDU.js} +7 -7
  21. package/dist/{dev-PLBVJXT4.js → dev-7YLRQ6SA.js} +27994 -13330
  22. package/dist/dev-7YLRQ6SA.js.map +1 -0
  23. package/dist/{dist-VNX77VV5.js → dist-JMLAZUL7.js} +9 -3
  24. package/dist/{dist-7CRX2GIR.js → dist-MNXSMGV6.js} +3 -3
  25. package/dist/{dist-OCECEAXB.js → dist-MX5K2ABB.js} +3 -3
  26. package/dist/{dist-JH7OL7U4.js → dist-NGQG7Z4G.js} +7 -3
  27. package/dist/{generate-KNER36CB.js → generate-B7FAWVIQ.js} +2 -2
  28. package/dist/index.js +33 -33
  29. package/dist/{init-GVBYCLJT.js → init-SECXKD5G.js} +2 -2
  30. package/dist/{lineage-T5NRHHZN.js → lineage-HYO4RKZT.js} +2 -2
  31. package/dist/{query-2RB75CRI.js → query-QNRDS74I.js} +5 -5
  32. package/dist/{reset-password-IZQTDTU7.js → reset-password-HDCLH7PZ.js} +3 -3
  33. package/dist/{rewrite-database-FDJIXKZ2.js → rewrite-database-BOA4QPUR.js} +2 -2
  34. package/dist/{sample-3UAL7MVU.js → sample-SKLHBZBU.js} +5 -5
  35. package/dist/{search-ODC4S575.js → search-4KMETZVX.js} +7 -7
  36. package/dist/{semantic-RAP3S5PQ.js → semantic-6WKELH5V.js} +2 -2
  37. package/dist/source-resolver-R7WBIL7M.js +18 -0
  38. package/dist/{sync-dbt-22QQKT3A.js → sync-dbt-72GVO75P.js} +2 -2
  39. package/dist/{sync-warehouse-QMCT5B4G.js → sync-warehouse-UWRNUXE7.js} +41 -15
  40. package/dist/sync-warehouse-UWRNUXE7.js.map +1 -0
  41. package/dist/{tables-QWHUCBRH.js → tables-V65QUGHK.js} +7 -7
  42. package/dist/templates/default/docs/yamchart-reference.md +74 -9
  43. package/dist/{test-KX2GETNF.js → test-UE5OWG3E.js} +5 -5
  44. package/dist/{update-WMATDZTO.js → update-HWCJNQRP.js} +2 -2
  45. package/package.json +9 -3
  46. package/dist/agent-KWKPAYT2.js +0 -8
  47. package/dist/chunk-4P5UHWYK.js.map +0 -1
  48. package/dist/chunk-65G5DBRO.js.map +0 -1
  49. package/dist/chunk-CWAWATL4.js.map +0 -1
  50. package/dist/chunk-DGUM43GV.js +0 -11
  51. package/dist/chunk-EHM6AMMA.js.map +0 -1
  52. package/dist/chunk-OI3EGXVE.js.map +0 -1
  53. package/dist/chunk-UDKODFOE.js.map +0 -1
  54. package/dist/dev-PLBVJXT4.js.map +0 -1
  55. package/dist/source-resolver-6QBBNW3P.js +0 -18
  56. package/dist/sync-warehouse-QMCT5B4G.js.map +0 -1
  57. /package/dist/{advisor-SK2EPAAY.js.map → advisor-SC64RTZO.js.map} +0 -0
  58. /package/dist/{agent-KWKPAYT2.js.map → agent-TZZHNDPK.js.map} +0 -0
  59. /package/dist/{chunk-DGUM43GV.js.map → chunk-7D4SUZUM.js.map} +0 -0
  60. /package/dist/{chunk-EHYYYKRW.js.map → chunk-RMIDEBHD.js.map} +0 -0
  61. /package/dist/{chunk-ZA6AOQVZ.js.map → chunk-ZMJPRNOA.js.map} +0 -0
  62. /package/dist/{compare-ZN6RUOOQ.js.map → compare-RQFCEZIK.js.map} +0 -0
  63. /package/dist/{connection-utils-MCJBJEDQ.js.map → connection-utils-C4FQGBW6.js.map} +0 -0
  64. /package/dist/{describe-XJ5GXYUE.js.map → describe-X75C2VDU.js.map} +0 -0
  65. /package/dist/{dist-JH7OL7U4.js.map → dist-JMLAZUL7.js.map} +0 -0
  66. /package/dist/{dist-7CRX2GIR.js.map → dist-MNXSMGV6.js.map} +0 -0
  67. /package/dist/{dist-OCECEAXB.js.map → dist-MX5K2ABB.js.map} +0 -0
  68. /package/dist/{dist-VNX77VV5.js.map → dist-NGQG7Z4G.js.map} +0 -0
  69. /package/dist/{generate-KNER36CB.js.map → generate-B7FAWVIQ.js.map} +0 -0
  70. /package/dist/{init-GVBYCLJT.js.map → init-SECXKD5G.js.map} +0 -0
  71. /package/dist/{lineage-T5NRHHZN.js.map → lineage-HYO4RKZT.js.map} +0 -0
  72. /package/dist/{query-2RB75CRI.js.map → query-QNRDS74I.js.map} +0 -0
  73. /package/dist/{reset-password-IZQTDTU7.js.map → reset-password-HDCLH7PZ.js.map} +0 -0
  74. /package/dist/{rewrite-database-FDJIXKZ2.js.map → rewrite-database-BOA4QPUR.js.map} +0 -0
  75. /package/dist/{sample-3UAL7MVU.js.map → sample-SKLHBZBU.js.map} +0 -0
  76. /package/dist/{search-ODC4S575.js.map → search-4KMETZVX.js.map} +0 -0
  77. /package/dist/{semantic-RAP3S5PQ.js.map → semantic-6WKELH5V.js.map} +0 -0
  78. /package/dist/{source-resolver-6QBBNW3P.js.map → source-resolver-R7WBIL7M.js.map} +0 -0
  79. /package/dist/{sync-dbt-22QQKT3A.js.map → sync-dbt-72GVO75P.js.map} +0 -0
  80. /package/dist/{tables-QWHUCBRH.js.map → tables-V65QUGHK.js.map} +0 -0
  81. /package/dist/{test-KX2GETNF.js.map → test-UE5OWG3E.js.map} +0 -0
  82. /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-OI3EGXVE.js";
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-65G5DBRO.js";
14
- import "./chunk-CWAWATL4.js";
13
+ import "./chunk-RM6MNDVF.js";
14
+ import "./chunk-S7YQXEKM.js";
15
15
  import "./chunk-UND73EOB.js";
16
- import "./chunk-DGUM43GV.js";
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-VNX77VV5.js");
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-7CRX2GIR.js");
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-7CRX2GIR.js");
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-7CRX2GIR.js");
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-7CRX2GIR.js");
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-7CRX2GIR.js");
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-SK2EPAAY.js.map
382
+ //# sourceMappingURL=advisor-SC64RTZO.js.map
@@ -0,0 +1,8 @@
1
+ import {
2
+ StreamingChatAgent
3
+ } from "./chunk-ZMJPRNOA.js";
4
+ import "./chunk-7D4SUZUM.js";
5
+ export {
6
+ StreamingChatAgent
7
+ };
8
+ //# sourceMappingURL=agent-TZZHNDPK.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-4P5UHWYK.js.map
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-EHM6AMMA.js.map
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-EHM6AMMA.js";
8
+ } from "./chunk-EAQXUGP6.js";
9
9
  import {
10
10
  createConnector,
11
11
  resolveConnection
12
- } from "./chunk-OI3EGXVE.js";
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 query = getDescribeQuery(connection.type, resolved.tableName);
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 query = getTablesQuery(connection.type, options);
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(connection.type, keyword);
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-UDKODFOE.js.map
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":"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","names":["readFile","access","join","join","access","readFile"]}