yamchart 0.10.0 → 0.10.2

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 (109) hide show
  1. package/dist/{advisor-O2BRAI4T.js → advisor-5F73GF54.js} +13 -13
  2. package/dist/{advisor-O2BRAI4T.js.map → advisor-5F73GF54.js.map} +1 -1
  3. package/dist/agent-TZZHNDPK.js +1 -0
  4. package/dist/{chunk-S2CH4HUZ.js → chunk-25ES7MGF.js} +5 -4
  5. package/dist/{chunk-QUIDZO5G.js → chunk-5CRXV5PQ.js} +23 -6
  6. package/dist/chunk-5CRXV5PQ.js.map +1 -0
  7. package/dist/chunk-7D4SUZUM.js +1 -0
  8. package/dist/chunk-7HWFVUGP.js +1239 -0
  9. package/dist/chunk-7HWFVUGP.js.map +1 -0
  10. package/dist/chunk-DZVT6PHW.js +1 -0
  11. package/dist/chunk-EAQXUGP6.js +1 -0
  12. package/dist/chunk-HJVVHYVN.js +1 -0
  13. package/dist/chunk-IVD4OP3K.js +1 -0
  14. package/dist/{chunk-5FHV22X2.js → chunk-PYVROL7Z.js} +5 -4
  15. package/dist/chunk-TZKNU5TD.js +1 -0
  16. package/dist/chunk-UOSOZT47.js +966 -0
  17. package/dist/chunk-UOSOZT47.js.map +1 -0
  18. package/dist/chunk-VJC24RKT.js +1 -0
  19. package/dist/{chunk-ZBCQNWVN.js → chunk-WVSDQNAN.js} +6 -5
  20. package/dist/chunk-WYS4ULBE.js +1 -0
  21. package/dist/{chunk-UFDQ3C7Q.js → chunk-X3UG6T3Q.js} +258 -257
  22. package/dist/chunk-X3UG6T3Q.js.map +1 -0
  23. package/dist/chunk-ZMJPRNOA.js +1 -0
  24. package/dist/compare-RQFCEZIK.js +1 -0
  25. package/dist/connection-utils-HNX3473B.js +20 -0
  26. package/dist/{describe-MEP72B56.js → describe-KDGXFPDQ.js} +8 -7
  27. package/dist/{dev-LZ4YHNDJ.js → dev-KOWFGDOP.js} +934 -128
  28. package/dist/dev-KOWFGDOP.js.map +1 -0
  29. package/dist/dev-supervisor-JXLVGEHP.js +43 -0
  30. package/dist/dev-supervisor-JXLVGEHP.js.map +1 -0
  31. package/dist/{dist-5IFWLWND.js → dist-LK3ZG74Q.js} +6 -6
  32. package/dist/dist-MIKFZKSD.js +1 -0
  33. package/dist/{dist-PPAD6KOM.js → dist-WMP7BFKP.js} +25 -2
  34. package/dist/{dist-XNCED7JW.js → dist-YB5RBWCC.js} +5 -4
  35. package/dist/generate-B7FAWVIQ.js +1 -0
  36. package/dist/index.js +66 -42
  37. package/dist/index.js.map +1 -1
  38. package/dist/{init-SECXKD5G.js → init-TJJVKMEN.js} +25 -5
  39. package/dist/init-TJJVKMEN.js.map +1 -0
  40. package/dist/lineage-HYO4RKZT.js +1 -0
  41. package/dist/public/assets/DataView-BfwnWnLH.js +9 -0
  42. package/dist/public/assets/{EventManagement-BnmeJDQl.js → EventManagement-BIkVUSCe.js} +2 -2
  43. package/dist/public/assets/ExplorePage-CeaAulqT.js +1 -0
  44. package/dist/public/assets/{LoginPage-CzaFkkjg.js → LoginPage-4WeNcdRi.js} +1 -1
  45. package/dist/public/assets/{PublicViewer-irjxqH6a.js → PublicViewer-CkW-G56D.js} +1 -1
  46. package/dist/public/assets/{SetupWizard-ConWIcmy.js → SetupWizard-CwTr3PCy.js} +1 -1
  47. package/dist/public/assets/{ShareManagement-CP4wdwLR.js → ShareManagement-DSon6CoC.js} +1 -1
  48. package/dist/public/assets/{SourceDetailView-DZS5518E.js → SourceDetailView-BA4XVKqV.js} +1 -1
  49. package/dist/public/assets/UserManagement-BWD2Ugkv.js +1 -0
  50. package/dist/public/assets/{index-C1X8RW4Z.css → index-Cb4omrVn.css} +1 -1
  51. package/dist/public/assets/{index-jlfTO7f5.js → index-iR9gLdl9.js} +41 -41
  52. package/dist/public/assets/{index.es-CgnvEWi5.js → index.es-BuEtjxhO.js} +1 -1
  53. package/dist/public/assets/{jspdf.es.min-Cw5WefMt.js → jspdf.es.min-CScx2_oK.js} +3 -3
  54. package/dist/public/index.html +2 -2
  55. package/dist/{query-2H3YOPI2.js → query-7XHKSZ5H.js} +6 -5
  56. package/dist/reset-password-YVCZKZPC.js +1 -0
  57. package/dist/rewrite-database-BOA4QPUR.js +1 -0
  58. package/dist/sample-YNSJ3I3T.js +76 -0
  59. package/dist/sample-YNSJ3I3T.js.map +1 -0
  60. package/dist/{search-IPE4ISFB.js → search-NKRXXLRS.js} +8 -7
  61. package/dist/semantic-DD7P4634.js +30 -0
  62. package/dist/semantic-NBAX4WU4.js +76 -0
  63. package/dist/semantic-NBAX4WU4.js.map +1 -0
  64. package/dist/source-resolver-7NY3KEZ2.js +19 -0
  65. package/dist/source-resolver-7NY3KEZ2.js.map +1 -0
  66. package/dist/sync-dbt-72GVO75P.js +1 -0
  67. package/dist/{sync-warehouse-26L6JDSV.js → sync-warehouse-PK7HXW7U.js} +11 -6
  68. package/dist/sync-warehouse-PK7HXW7U.js.map +1 -0
  69. package/dist/{tables-K5NAN2WK.js → tables-WQTRZSXR.js} +8 -7
  70. package/dist/templates/default/docs/yamchart-reference.md +26 -0
  71. package/dist/{test-SRHVOXZB.js → test-MKNKUR3N.js} +20 -7
  72. package/dist/test-MKNKUR3N.js.map +1 -0
  73. package/dist/update-HWCJNQRP.js +1 -0
  74. package/package.json +9 -7
  75. package/dist/chunk-FN6R2LAC.js +0 -15442
  76. package/dist/chunk-FN6R2LAC.js.map +0 -1
  77. package/dist/chunk-QJ5CPQJK.js +0 -2053
  78. package/dist/chunk-QJ5CPQJK.js.map +0 -1
  79. package/dist/chunk-QUIDZO5G.js.map +0 -1
  80. package/dist/chunk-UFDQ3C7Q.js.map +0 -1
  81. package/dist/chunk-ZIY22VO7.js +0 -1189
  82. package/dist/chunk-ZIY22VO7.js.map +0 -1
  83. package/dist/connection-utils-FEUWER5I.js +0 -19
  84. package/dist/dev-LZ4YHNDJ.js.map +0 -1
  85. package/dist/fileFromPath-7TNUU6RI.js +0 -130
  86. package/dist/fileFromPath-7TNUU6RI.js.map +0 -1
  87. package/dist/init-SECXKD5G.js.map +0 -1
  88. package/dist/public/assets/DataView-DUCz_96y.js +0 -9
  89. package/dist/public/assets/ExplorePage-kk4z9ldZ.js +0 -1
  90. package/dist/public/assets/UserManagement-AubGd9hl.js +0 -1
  91. package/dist/sample-ODUGGSFA.js +0 -41
  92. package/dist/sample-ODUGGSFA.js.map +0 -1
  93. package/dist/semantic-K3MYXXJI.js +0 -40
  94. package/dist/semantic-K3MYXXJI.js.map +0 -1
  95. package/dist/source-resolver-HZQLOODU.js +0 -18
  96. package/dist/sync-warehouse-26L6JDSV.js.map +0 -1
  97. package/dist/test-SRHVOXZB.js.map +0 -1
  98. /package/dist/{chunk-S2CH4HUZ.js.map → chunk-25ES7MGF.js.map} +0 -0
  99. /package/dist/{chunk-5FHV22X2.js.map → chunk-PYVROL7Z.js.map} +0 -0
  100. /package/dist/{chunk-ZBCQNWVN.js.map → chunk-WVSDQNAN.js.map} +0 -0
  101. /package/dist/{connection-utils-FEUWER5I.js.map → connection-utils-HNX3473B.js.map} +0 -0
  102. /package/dist/{describe-MEP72B56.js.map → describe-KDGXFPDQ.js.map} +0 -0
  103. /package/dist/{dist-5IFWLWND.js.map → dist-LK3ZG74Q.js.map} +0 -0
  104. /package/dist/{dist-PPAD6KOM.js.map → dist-WMP7BFKP.js.map} +0 -0
  105. /package/dist/{dist-XNCED7JW.js.map → dist-YB5RBWCC.js.map} +0 -0
  106. /package/dist/{query-2H3YOPI2.js.map → query-7XHKSZ5H.js.map} +0 -0
  107. /package/dist/{search-IPE4ISFB.js.map → search-NKRXXLRS.js.map} +0 -0
  108. /package/dist/{source-resolver-HZQLOODU.js.map → semantic-DD7P4634.js.map} +0 -0
  109. /package/dist/{tables-K5NAN2WK.js.map → tables-WQTRZSXR.js.map} +0 -0
@@ -1,3 +1,4 @@
1
+ import { createRequire as __yamchartCreateRequire } from 'module'; if (!globalThis.require) globalThis.require = __yamchartCreateRequire(import.meta.url);
1
2
  import {
2
3
  detail,
3
4
  error,
@@ -1,3 +1,4 @@
1
+ import { createRequire as __yamchartCreateRequire } from 'module'; if (!globalThis.require) globalThis.require = __yamchartCreateRequire(import.meta.url);
1
2
  import {
2
3
  detectDatabaseMismatch,
3
4
  extractDatabase,
@@ -0,0 +1,76 @@
1
+ import { createRequire as __yamchartCreateRequire } from 'module'; if (!globalThis.require) globalThis.require = __yamchartCreateRequire(import.meta.url);
2
+ import {
3
+ resolveTableName
4
+ } from "./chunk-VJC24RKT.js";
5
+ import {
6
+ generateCatalogJson
7
+ } from "./chunk-WYS4ULBE.js";
8
+ import {
9
+ createConnector,
10
+ resolveConnection
11
+ } from "./chunk-PYVROL7Z.js";
12
+ import "./chunk-5CRXV5PQ.js";
13
+ import "./chunk-X3UG6T3Q.js";
14
+ import "./chunk-7HWFVUGP.js";
15
+ import "./chunk-7D4SUZUM.js";
16
+
17
+ // src/commands/sample.ts
18
+ import { performance } from "perf_hooks";
19
+ import { readFile, writeFile, mkdir } from "fs/promises";
20
+ import { join } from "path";
21
+ async function persistSamplesToCatalog(projectDir, tableName, rows) {
22
+ const catalogPath = join(projectDir, ".yamchart", "catalog.json");
23
+ let catalog;
24
+ try {
25
+ const raw = await readFile(catalogPath, "utf-8");
26
+ catalog = JSON.parse(raw);
27
+ } catch {
28
+ return;
29
+ }
30
+ const tableUpper = tableName.toUpperCase();
31
+ let updated = false;
32
+ const models = catalog.models.map((model) => {
33
+ const modelTable = (model.table || "").toUpperCase();
34
+ const modelName = (model.name || "").toUpperCase();
35
+ if (modelTable === tableUpper || modelName === tableUpper) {
36
+ updated = true;
37
+ return { ...model, sampleRows: rows };
38
+ }
39
+ return model;
40
+ });
41
+ if (!updated) return;
42
+ await mkdir(join(projectDir, ".yamchart"), { recursive: true });
43
+ await writeFile(catalogPath, generateCatalogJson({ ...catalog, models }));
44
+ }
45
+ async function sampleTable(projectDir, table, options) {
46
+ const resolved = await resolveTableName(projectDir, table);
47
+ const connection = await resolveConnection(projectDir, options.connection);
48
+ const connector = createConnector(connection, projectDir);
49
+ try {
50
+ await connector.connect();
51
+ const limit = options.limit ?? 5;
52
+ const sql = `SELECT * FROM ${resolved.tableName} LIMIT ${limit}`;
53
+ const startTime = performance.now();
54
+ const result = await connector.execute(sql);
55
+ const durationMs = performance.now() - startTime;
56
+ await persistSamplesToCatalog(projectDir, resolved.tableName, result.rows);
57
+ if (resolved.source === "catalog" && table !== resolved.tableName) {
58
+ await persistSamplesToCatalog(projectDir, table, result.rows);
59
+ }
60
+ return {
61
+ ...result,
62
+ durationMs,
63
+ table: resolved.tableName,
64
+ connectionName: connection.name,
65
+ connectionType: connection.type,
66
+ ...resolved.source === "catalog" ? { resolvedFrom: table } : {}
67
+ };
68
+ } finally {
69
+ await connector.disconnect();
70
+ }
71
+ }
72
+ export {
73
+ persistSamplesToCatalog,
74
+ sampleTable
75
+ };
76
+ //# sourceMappingURL=sample-YNSJ3I3T.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/commands/sample.ts"],"sourcesContent":["import { performance } from 'node:perf_hooks';\nimport { readFile, writeFile, mkdir } from 'fs/promises';\nimport { join } from 'path';\nimport type { QueryResult } from '@yamchart/query';\nimport { resolveConnection, createConnector } from './connection-utils.js';\nimport { resolveTableName } from './model-resolver.js';\nimport type { CatalogData } from '../dbt/catalog.js';\nimport { generateCatalogJson } from '../dbt/catalog.js';\n\nexport interface SampleOptions {\n connection?: string;\n json?: boolean;\n limit?: number;\n}\n\nexport interface SampleResult extends QueryResult {\n table: string;\n connectionName: string;\n connectionType: string;\n resolvedFrom?: string;\n}\n\n/**\n * Persist sample rows for a given table into .yamchart/catalog.json.\n *\n * Finds the catalog entry whose `table` or `name` field matches\n * (case-insensitive) and writes `sampleRows` onto it. No-ops gracefully when\n * the catalog doesn't exist or no matching entry is found.\n */\nexport async function persistSamplesToCatalog(\n projectDir: string,\n tableName: string,\n rows: Record<string, unknown>[],\n): Promise<void> {\n const catalogPath = join(projectDir, '.yamchart', 'catalog.json');\n let catalog: CatalogData;\n try {\n const raw = await readFile(catalogPath, 'utf-8');\n catalog = JSON.parse(raw) as CatalogData;\n } catch {\n // No catalog yet — nothing to update\n return;\n }\n\n const tableUpper = tableName.toUpperCase();\n let updated = false;\n\n const models = catalog.models.map((model) => {\n const modelTable = (model.table || '').toUpperCase();\n const modelName = (model.name || '').toUpperCase();\n if (modelTable === tableUpper || modelName === tableUpper) {\n updated = true;\n return { ...model, sampleRows: rows };\n }\n return model;\n });\n\n if (!updated) return;\n\n await mkdir(join(projectDir, '.yamchart'), { recursive: true });\n await writeFile(catalogPath, generateCatalogJson({ ...catalog, models }));\n}\n\n/**\n * Sample rows from a table or dbt model.\n *\n * Resolves dbt model names via catalog, then runs SELECT * with a LIMIT.\n * Also persists the sample rows back to .yamchart/catalog.json when a\n * matching catalog entry exists.\n */\nexport async function sampleTable(\n projectDir: string,\n table: string,\n options: SampleOptions,\n): Promise<SampleResult> {\n const resolved = await resolveTableName(projectDir, table);\n const connection = await resolveConnection(projectDir, options.connection);\n const connector = createConnector(connection, projectDir);\n\n try {\n await connector.connect();\n\n const limit = options.limit ?? 5;\n const sql = `SELECT * FROM ${resolved.tableName} LIMIT ${limit}`;\n const startTime = performance.now();\n const result = await connector.execute(sql);\n const durationMs = performance.now() - startTime;\n\n // Persist sample rows to catalog.json under the resolved table name.\n // Also try the original model name so dbt model aliases are covered.\n await persistSamplesToCatalog(projectDir, resolved.tableName, result.rows);\n if (resolved.source === 'catalog' && table !== resolved.tableName) {\n await persistSamplesToCatalog(projectDir, table, result.rows);\n }\n\n return {\n ...result,\n durationMs,\n table: resolved.tableName,\n connectionName: connection.name,\n connectionType: connection.type,\n ...(resolved.source === 'catalog' ? { resolvedFrom: table } : {}),\n };\n } finally {\n await connector.disconnect();\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAAA,SAAS,mBAAmB;AAC5B,SAAS,UAAU,WAAW,aAAa;AAC3C,SAAS,YAAY;AA2BrB,eAAsB,wBACpB,YACA,WACA,MACe;AACf,QAAM,cAAc,KAAK,YAAY,aAAa,cAAc;AAChE,MAAI;AACJ,MAAI;AACF,UAAM,MAAM,MAAM,SAAS,aAAa,OAAO;AAC/C,cAAU,KAAK,MAAM,GAAG;AAAA,EAC1B,QAAQ;AAEN;AAAA,EACF;AAEA,QAAM,aAAa,UAAU,YAAY;AACzC,MAAI,UAAU;AAEd,QAAM,SAAS,QAAQ,OAAO,IAAI,CAAC,UAAU;AAC3C,UAAM,cAAc,MAAM,SAAS,IAAI,YAAY;AACnD,UAAM,aAAa,MAAM,QAAQ,IAAI,YAAY;AACjD,QAAI,eAAe,cAAc,cAAc,YAAY;AACzD,gBAAU;AACV,aAAO,EAAE,GAAG,OAAO,YAAY,KAAK;AAAA,IACtC;AACA,WAAO;AAAA,EACT,CAAC;AAED,MAAI,CAAC,QAAS;AAEd,QAAM,MAAM,KAAK,YAAY,WAAW,GAAG,EAAE,WAAW,KAAK,CAAC;AAC9D,QAAM,UAAU,aAAa,oBAAoB,EAAE,GAAG,SAAS,OAAO,CAAC,CAAC;AAC1E;AASA,eAAsB,YACpB,YACA,OACA,SACuB;AACvB,QAAM,WAAW,MAAM,iBAAiB,YAAY,KAAK;AACzD,QAAM,aAAa,MAAM,kBAAkB,YAAY,QAAQ,UAAU;AACzE,QAAM,YAAY,gBAAgB,YAAY,UAAU;AAExD,MAAI;AACF,UAAM,UAAU,QAAQ;AAExB,UAAM,QAAQ,QAAQ,SAAS;AAC/B,UAAM,MAAM,iBAAiB,SAAS,SAAS,UAAU,KAAK;AAC9D,UAAM,YAAY,YAAY,IAAI;AAClC,UAAM,SAAS,MAAM,UAAU,QAAQ,GAAG;AAC1C,UAAM,aAAa,YAAY,IAAI,IAAI;AAIvC,UAAM,wBAAwB,YAAY,SAAS,WAAW,OAAO,IAAI;AACzE,QAAI,SAAS,WAAW,aAAa,UAAU,SAAS,WAAW;AACjE,YAAM,wBAAwB,YAAY,OAAO,OAAO,IAAI;AAAA,IAC9D;AAEA,WAAO;AAAA,MACL,GAAG;AAAA,MACH;AAAA,MACA,OAAO,SAAS;AAAA,MAChB,gBAAgB,WAAW;AAAA,MAC3B,gBAAgB,WAAW;AAAA,MAC3B,GAAI,SAAS,WAAW,YAAY,EAAE,cAAc,MAAM,IAAI,CAAC;AAAA,IACjE;AAAA,EACF,UAAE;AACA,UAAM,UAAU,WAAW;AAAA,EAC7B;AACF;","names":[]}
@@ -1,12 +1,13 @@
1
+ import { createRequire as __yamchartCreateRequire } from 'module'; if (!globalThis.require) globalThis.require = __yamchartCreateRequire(import.meta.url);
1
2
  import {
2
3
  resolveSearchSource
3
- } from "./chunk-ZBCQNWVN.js";
4
- import "./chunk-VJC24RKT.js";
4
+ } from "./chunk-WVSDQNAN.js";
5
5
  import "./chunk-EAQXUGP6.js";
6
- import "./chunk-5FHV22X2.js";
7
- import "./chunk-QUIDZO5G.js";
8
- import "./chunk-UFDQ3C7Q.js";
9
- import "./chunk-ZIY22VO7.js";
6
+ import "./chunk-VJC24RKT.js";
7
+ import "./chunk-PYVROL7Z.js";
8
+ import "./chunk-5CRXV5PQ.js";
9
+ import "./chunk-X3UG6T3Q.js";
10
+ import "./chunk-7HWFVUGP.js";
10
11
  import "./chunk-7D4SUZUM.js";
11
12
 
12
13
  // src/commands/search.ts
@@ -25,4 +26,4 @@ async function searchDatabase(projectDir, keyword, options) {
25
26
  export {
26
27
  searchDatabase
27
28
  };
28
- //# sourceMappingURL=search-IPE4ISFB.js.map
29
+ //# sourceMappingURL=search-NKRXXLRS.js.map
@@ -0,0 +1,30 @@
1
+ import { createRequire as __yamchartCreateRequire } from 'module'; if (!globalThis.require) globalThis.require = __yamchartCreateRequire(import.meta.url);
2
+ import {
3
+ SemanticModelBuilder,
4
+ SemanticQueryCompiler,
5
+ SemanticValidationError,
6
+ buildSemanticLayer,
7
+ classifyCatalogColumns,
8
+ classifyField,
9
+ compileMetricQuery,
10
+ getDialect,
11
+ inferAggregationType,
12
+ loadSemanticDefinitions,
13
+ validateSemanticQuery
14
+ } from "./chunk-X3UG6T3Q.js";
15
+ import "./chunk-7HWFVUGP.js";
16
+ import "./chunk-7D4SUZUM.js";
17
+ export {
18
+ SemanticModelBuilder,
19
+ SemanticQueryCompiler,
20
+ SemanticValidationError,
21
+ buildSemanticLayer,
22
+ classifyCatalogColumns,
23
+ classifyField,
24
+ compileMetricQuery,
25
+ getDialect,
26
+ inferAggregationType,
27
+ loadSemanticDefinitions,
28
+ validateSemanticQuery
29
+ };
30
+ //# sourceMappingURL=semantic-DD7P4634.js.map
@@ -0,0 +1,76 @@
1
+ import { createRequire as __yamchartCreateRequire } from 'module'; if (!globalThis.require) globalThis.require = __yamchartCreateRequire(import.meta.url);
2
+ import {
3
+ SemanticModelBuilder,
4
+ SemanticQueryCompiler,
5
+ buildSemanticLayer,
6
+ compileMetricQuery
7
+ } from "./chunk-X3UG6T3Q.js";
8
+ import "./chunk-7HWFVUGP.js";
9
+ import "./chunk-7D4SUZUM.js";
10
+
11
+ // src/commands/semantic.ts
12
+ function listSemanticDefinitions(defs) {
13
+ return {
14
+ entities: defs.map((def) => {
15
+ const sourceTable = def.source.table ?? def.source.model ?? def.entity;
16
+ return {
17
+ name: def.entity,
18
+ source_table: sourceTable,
19
+ description: def.description,
20
+ measures: def.metrics.map((m) => ({ name: m.name, type: m.agg })),
21
+ dimensions: def.dimensions.map((d) => ({ name: d.name, type: d.type }))
22
+ };
23
+ })
24
+ };
25
+ }
26
+ function querySemanticDefinition(defs, input) {
27
+ const layer = buildSemanticLayer(defs);
28
+ const entity = layer.getEntity(input.entity);
29
+ if (!entity) throw new Error(`Entity '${input.entity}' not found`);
30
+ const { sql } = compileMetricQuery(
31
+ entity,
32
+ {
33
+ metrics: input.measures,
34
+ dimensions: input.dimensions.length ? input.dimensions : void 0,
35
+ filters: input.filters,
36
+ order_by: input.order_by ? { field: input.order_by.field, direction: input.order_by.direction } : void 0,
37
+ limit: input.limit
38
+ },
39
+ void 0
40
+ );
41
+ return { sql, entityName: input.entity };
42
+ }
43
+ function listSemanticEntities(catalog) {
44
+ const builder = new SemanticModelBuilder();
45
+ const model = builder.build({ catalog: { models: catalog.models } });
46
+ return {
47
+ entities: model.entities.map((e) => ({
48
+ name: e.name,
49
+ source_table: e.source_table,
50
+ description: e.description,
51
+ measures: e.measures.map((m) => ({ name: m.name, type: m.type })),
52
+ dimensions: e.dimensions.map((d) => ({ name: d.name, type: d.type }))
53
+ }))
54
+ };
55
+ }
56
+ function querySemanticEntity(catalog, input) {
57
+ const builder = new SemanticModelBuilder();
58
+ const model = builder.build({ catalog: { models: catalog.models } });
59
+ const compiler = new SemanticQueryCompiler();
60
+ const sql = compiler.compile(model, {
61
+ model: input.entity,
62
+ measures: input.measures,
63
+ dimensions: input.dimensions,
64
+ filters: input.filters,
65
+ order_by: input.order_by ? { field: input.order_by.field, direction: input.order_by.direction } : void 0,
66
+ limit: input.limit
67
+ });
68
+ return { sql, entityName: input.entity };
69
+ }
70
+ export {
71
+ listSemanticDefinitions,
72
+ listSemanticEntities,
73
+ querySemanticDefinition,
74
+ querySemanticEntity
75
+ };
76
+ //# sourceMappingURL=semantic-NBAX4WU4.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/commands/semantic.ts"],"sourcesContent":["import { SemanticModelBuilder, SemanticQueryCompiler, buildSemanticLayer, compileMetricQuery } from '@yamchart/query/semantic';\nimport type { SemanticFilter, SemanticDefinition } from '@yamchart/schema';\n\ninterface CatalogJsonData {\n models: Array<{\n name: string;\n table?: string;\n description?: string;\n source?: string;\n path?: string;\n columns?: Array<{ name: string; data_type?: string; description?: string; hints?: string[] }>;\n }>;\n}\n\nexport interface SemanticEntitySummary {\n name: string;\n source_table: string;\n description?: string;\n measures: Array<{ name: string; type: string }>;\n dimensions: Array<{ name: string; type: string }>;\n}\n\nexport interface ListResult {\n entities: SemanticEntitySummary[];\n}\n\nexport interface QueryInput {\n entity: string;\n measures: string[];\n dimensions: string[];\n filters: Array<{ dimension: string; operator: string; value: string | number | boolean | Array<string | number> }>;\n order_by?: { field: string; direction: string };\n limit: number;\n}\n\nexport interface QueryResult {\n sql: string;\n entityName: string;\n}\n\n// --- Curated semantic/*.yaml definitions ---\n\nexport function listSemanticDefinitions(defs: SemanticDefinition[]): ListResult {\n return {\n entities: defs.map((def) => {\n const sourceTable = def.source.table ?? def.source.model ?? def.entity;\n return {\n name: def.entity,\n source_table: sourceTable,\n description: def.description,\n measures: def.metrics.map((m) => ({ name: m.name, type: m.agg })),\n dimensions: def.dimensions.map((d) => ({ name: d.name, type: d.type })),\n };\n }),\n };\n}\n\nexport function querySemanticDefinition(defs: SemanticDefinition[], input: QueryInput): QueryResult {\n const layer = buildSemanticLayer(defs);\n const entity = layer.getEntity(input.entity);\n if (!entity) throw new Error(`Entity '${input.entity}' not found`);\n\n const { sql } = compileMetricQuery(\n entity,\n {\n metrics: input.measures,\n dimensions: input.dimensions.length ? input.dimensions : undefined,\n filters: input.filters as Array<{ dimension: string; operator: string; value: unknown }>,\n order_by: input.order_by\n ? { field: input.order_by.field, direction: input.order_by.direction as 'asc' | 'desc' }\n : undefined,\n limit: input.limit,\n },\n undefined,\n );\n\n return { sql, entityName: input.entity };\n}\n\n// --- Catalog-derived (auto-generated) semantic entities ---\n\nexport function listSemanticEntities(catalog: CatalogJsonData): ListResult {\n const builder = new SemanticModelBuilder();\n const model = builder.build({ catalog: { models: catalog.models } });\n\n return {\n entities: model.entities.map((e) => ({\n name: e.name,\n source_table: e.source_table,\n description: e.description,\n measures: e.measures.map((m) => ({ name: m.name, type: m.type })),\n dimensions: e.dimensions.map((d) => ({ name: d.name, type: d.type })),\n })),\n };\n}\n\nexport function querySemanticEntity(catalog: CatalogJsonData, input: QueryInput): QueryResult {\n const builder = new SemanticModelBuilder();\n const model = builder.build({ catalog: { models: catalog.models } });\n\n const compiler = new SemanticQueryCompiler();\n const sql = compiler.compile(model, {\n model: input.entity,\n measures: input.measures,\n dimensions: input.dimensions,\n filters: input.filters as SemanticFilter[],\n order_by: input.order_by ? { field: input.order_by.field, direction: input.order_by.direction as 'asc' | 'desc' } : undefined,\n limit: input.limit,\n });\n\n return { sql, entityName: input.entity };\n}\n"],"mappings":";;;;;;;;;;AA0CO,SAAS,wBAAwB,MAAwC;AAC9E,SAAO;AAAA,IACL,UAAU,KAAK,IAAI,CAAC,QAAQ;AAC1B,YAAM,cAAc,IAAI,OAAO,SAAS,IAAI,OAAO,SAAS,IAAI;AAChE,aAAO;AAAA,QACL,MAAM,IAAI;AAAA,QACV,cAAc;AAAA,QACd,aAAa,IAAI;AAAA,QACjB,UAAU,IAAI,QAAQ,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,MAAM,EAAE,IAAI,EAAE;AAAA,QAChE,YAAY,IAAI,WAAW,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,MAAM,EAAE,KAAK,EAAE;AAAA,MACxE;AAAA,IACF,CAAC;AAAA,EACH;AACF;AAEO,SAAS,wBAAwB,MAA4B,OAAgC;AAClG,QAAM,QAAQ,mBAAmB,IAAI;AACrC,QAAM,SAAS,MAAM,UAAU,MAAM,MAAM;AAC3C,MAAI,CAAC,OAAQ,OAAM,IAAI,MAAM,WAAW,MAAM,MAAM,aAAa;AAEjE,QAAM,EAAE,IAAI,IAAI;AAAA,IACd;AAAA,IACA;AAAA,MACE,SAAS,MAAM;AAAA,MACf,YAAY,MAAM,WAAW,SAAS,MAAM,aAAa;AAAA,MACzD,SAAS,MAAM;AAAA,MACf,UAAU,MAAM,WACZ,EAAE,OAAO,MAAM,SAAS,OAAO,WAAW,MAAM,SAAS,UAA4B,IACrF;AAAA,MACJ,OAAO,MAAM;AAAA,IACf;AAAA,IACA;AAAA,EACF;AAEA,SAAO,EAAE,KAAK,YAAY,MAAM,OAAO;AACzC;AAIO,SAAS,qBAAqB,SAAsC;AACzE,QAAM,UAAU,IAAI,qBAAqB;AACzC,QAAM,QAAQ,QAAQ,MAAM,EAAE,SAAS,EAAE,QAAQ,QAAQ,OAAO,EAAE,CAAC;AAEnE,SAAO;AAAA,IACL,UAAU,MAAM,SAAS,IAAI,CAAC,OAAO;AAAA,MACnC,MAAM,EAAE;AAAA,MACR,cAAc,EAAE;AAAA,MAChB,aAAa,EAAE;AAAA,MACf,UAAU,EAAE,SAAS,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,MAAM,EAAE,KAAK,EAAE;AAAA,MAChE,YAAY,EAAE,WAAW,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,MAAM,EAAE,KAAK,EAAE;AAAA,IACtE,EAAE;AAAA,EACJ;AACF;AAEO,SAAS,oBAAoB,SAA0B,OAAgC;AAC5F,QAAM,UAAU,IAAI,qBAAqB;AACzC,QAAM,QAAQ,QAAQ,MAAM,EAAE,SAAS,EAAE,QAAQ,QAAQ,OAAO,EAAE,CAAC;AAEnE,QAAM,WAAW,IAAI,sBAAsB;AAC3C,QAAM,MAAM,SAAS,QAAQ,OAAO;AAAA,IAClC,OAAO,MAAM;AAAA,IACb,UAAU,MAAM;AAAA,IAChB,YAAY,MAAM;AAAA,IAClB,SAAS,MAAM;AAAA,IACf,UAAU,MAAM,WAAW,EAAE,OAAO,MAAM,SAAS,OAAO,WAAW,MAAM,SAAS,UAA4B,IAAI;AAAA,IACpH,OAAO,MAAM;AAAA,EACf,CAAC;AAED,SAAO,EAAE,KAAK,YAAY,MAAM,OAAO;AACzC;","names":[]}
@@ -0,0 +1,19 @@
1
+ import { createRequire as __yamchartCreateRequire } from 'module'; if (!globalThis.require) globalThis.require = __yamchartCreateRequire(import.meta.url);
2
+ import {
3
+ resolveDescribeSource,
4
+ resolveSearchSource,
5
+ resolveTablesSource
6
+ } from "./chunk-WVSDQNAN.js";
7
+ import "./chunk-EAQXUGP6.js";
8
+ import "./chunk-VJC24RKT.js";
9
+ import "./chunk-PYVROL7Z.js";
10
+ import "./chunk-5CRXV5PQ.js";
11
+ import "./chunk-X3UG6T3Q.js";
12
+ import "./chunk-7HWFVUGP.js";
13
+ import "./chunk-7D4SUZUM.js";
14
+ export {
15
+ resolveDescribeSource,
16
+ resolveSearchSource,
17
+ resolveTablesSource
18
+ };
19
+ //# sourceMappingURL=source-resolver-7NY3KEZ2.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -1,3 +1,4 @@
1
+ import { createRequire as __yamchartCreateRequire } from 'module'; if (!globalThis.require) globalThis.require = __yamchartCreateRequire(import.meta.url);
1
2
  import {
2
3
  generateCatalogJson,
3
4
  generateCatalogMd
@@ -1,3 +1,4 @@
1
+ import { createRequire as __yamchartCreateRequire } from 'module'; if (!globalThis.require) globalThis.require = __yamchartCreateRequire(import.meta.url);
1
2
  import {
2
3
  getColumnsQuery,
3
4
  getDescribeQuery,
@@ -11,7 +12,7 @@ import {
11
12
  import {
12
13
  createConnector,
13
14
  resolveConnection
14
- } from "./chunk-5FHV22X2.js";
15
+ } from "./chunk-PYVROL7Z.js";
15
16
  import {
16
17
  detail,
17
18
  error,
@@ -20,9 +21,9 @@ import {
20
21
  success,
21
22
  warning
22
23
  } from "./chunk-HJVVHYVN.js";
23
- import "./chunk-QUIDZO5G.js";
24
- import "./chunk-UFDQ3C7Q.js";
25
- import "./chunk-ZIY22VO7.js";
24
+ import "./chunk-5CRXV5PQ.js";
25
+ import "./chunk-X3UG6T3Q.js";
26
+ import "./chunk-7HWFVUGP.js";
26
27
  import "./chunk-7D4SUZUM.js";
27
28
 
28
29
  // src/commands/warehouse-sync.ts
@@ -139,7 +140,11 @@ function mergeWithDbtCatalog(existingCatalog, warehouseModels) {
139
140
  updatedColumns.push(wc);
140
141
  }
141
142
  }
142
- mergedModels.push({ ...model, columns: updatedColumns });
143
+ const mergedModel = { ...model, columns: updatedColumns };
144
+ if (warehouseMatch.sampleRows && !model.sampleRows) {
145
+ mergedModel.sampleRows = warehouseMatch.sampleRows;
146
+ }
147
+ mergedModels.push(mergedModel);
143
148
  consumedWarehouseTables.add(tableKey);
144
149
  } else {
145
150
  mergedModels.push(model);
@@ -391,4 +396,4 @@ async function runSyncWarehouse(projectDir, options) {
391
396
  export {
392
397
  runSyncWarehouse
393
398
  };
394
- //# sourceMappingURL=sync-warehouse-26L6JDSV.js.map
399
+ //# sourceMappingURL=sync-warehouse-PK7HXW7U.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/commands/warehouse-sync.ts","../src/commands/sync-warehouse.ts"],"sourcesContent":["/**\n * Core warehouse sync logic.\n *\n * Pure functions for diffing, grouping, building models, and merging catalogs,\n * plus an async orchestrator (syncWarehouse) that does I/O.\n */\n\nimport { readFile, writeFile, mkdir } from 'fs/promises';\nimport { join } from 'path';\nimport type { Connector } from '@yamchart/query';\nimport type { NormalizedColumnWithTable, NormalizedTable } from './introspection.js';\nimport { getTablesQuery, getColumnsQuery, getDescribeQuery } from './introspection.js';\nimport type { CatalogModel, CatalogData } from '../dbt/catalog.js';\nimport { generateCatalogMd, generateCatalogJson, generateWarehouseSection } from '../dbt/catalog.js';\n\n// ---------------------------------------------------------------------------\n// Interfaces\n// ---------------------------------------------------------------------------\n\nexport interface SyncState {\n syncedAt: string;\n connection: string;\n schemas: string[];\n skipSamples: boolean;\n tables: Record<string, { columnCount: number; lastAltered?: string }>;\n}\n\nexport interface WarehouseTable {\n qualifiedName: string; // \"SCHEMA.TABLE\"\n schema: string;\n name: string;\n type: string; // \"TABLE\" | \"VIEW\"\n columnCount: number;\n}\n\nexport interface SyncDiff {\n newTables: string[];\n changedTables: string[];\n unchangedTables: string[];\n removedTables: string[];\n}\n\nexport interface SyncWarehouseResult {\n tablesTotal: number;\n tablesNew: number;\n tablesChanged: number;\n tablesUnchanged: number;\n tablesRemoved: number;\n errors: string[];\n durationMs: number;\n}\n\nexport interface SyncWarehouseOptions {\n schemas?: string[];\n database?: string;\n skipSamples?: boolean;\n full?: boolean;\n onProgress?: (table: string, index: number, total: number) => void;\n}\n\n// ---------------------------------------------------------------------------\n// Pure functions\n// ---------------------------------------------------------------------------\n\n/**\n * Group a flat column list into a Map keyed by \"SCHEMA.TABLE\".\n */\nexport function groupColumnsByTable(\n columns: NormalizedColumnWithTable[],\n): Map<string, NormalizedColumnWithTable[]> {\n const map = new Map<string, NormalizedColumnWithTable[]>();\n for (const col of columns) {\n const key = `${col.schema}.${col.table}`;\n const existing = map.get(key);\n if (existing) {\n existing.push(col);\n } else {\n map.set(key, [col]);\n }\n }\n return map;\n}\n\n/**\n * Compare current warehouse tables against previous sync state.\n * All tables are \"new\" when prev is null.\n * Detects changed by column count mismatch.\n * Detects removed tables (in prev but not in current).\n */\nexport function diffSyncState(\n current: WarehouseTable[],\n prev: SyncState | null,\n): SyncDiff {\n const newTables: string[] = [];\n const changedTables: string[] = [];\n const unchangedTables: string[] = [];\n const removedTables: string[] = [];\n\n if (!prev) {\n return {\n newTables: current.map((t) => t.qualifiedName),\n changedTables: [],\n unchangedTables: [],\n removedTables: [],\n };\n }\n\n const currentNames = new Set(current.map((t) => t.qualifiedName));\n\n for (const table of current) {\n const prevEntry = prev.tables[table.qualifiedName];\n if (!prevEntry) {\n newTables.push(table.qualifiedName);\n } else if (prevEntry.columnCount !== table.columnCount) {\n changedTables.push(table.qualifiedName);\n } else {\n unchangedTables.push(table.qualifiedName);\n }\n }\n\n // Detect removed tables\n for (const name of Object.keys(prev.tables)) {\n if (!currentNames.has(name)) {\n removedTables.push(name);\n }\n }\n\n return { newTables, changedTables, unchangedTables, removedTables };\n}\n\n/**\n * Build CatalogModel entries from warehouse metadata.\n */\nexport function buildWarehouseModels(\n tables: WarehouseTable[],\n columnMap: Map<string, NormalizedColumnWithTable[]>,\n samples: Record<string, Record<string, unknown>[]>,\n): CatalogModel[] {\n const now = new Date().toISOString();\n\n return tables.map((table) => {\n const cols = columnMap.get(table.qualifiedName) || [];\n const sampleRows = samples[table.qualifiedName];\n\n return {\n name: table.name,\n path: '',\n description: '',\n table: table.qualifiedName,\n tags: ['warehouse'],\n meta: {},\n columns: cols.map((c) => ({\n name: c.name,\n data_type: c.type,\n description: '',\n hints: [],\n })),\n yamchartModels: [],\n source: 'warehouse' as const,\n tableType: table.type as 'TABLE' | 'VIEW',\n ...(sampleRows ? { sampleRows } : {}),\n lastSynced: now,\n };\n });\n}\n\n/**\n * Merge warehouse models into an existing dbt catalog.\n *\n * 1. If no existing catalog, create new with warehouseModels.\n * 2. Remove stale warehouse entries from existing.\n * 3. For tables in both dbt and warehouse (matched by `table` field, case-insensitive):\n * - dbt entry wins (keep it)\n * - Backfill data_type from warehouse columns where missing\n * - Add any warehouse columns that don't exist in the dbt entry\n * 4. Append remaining warehouse-only models.\n * 5. Return updated CatalogData.\n */\nexport function mergeWithDbtCatalog(\n existingCatalog: CatalogData | null,\n warehouseModels: CatalogModel[],\n): CatalogData {\n if (!existingCatalog) {\n return {\n syncedAt: new Date().toISOString(),\n source: { type: 'warehouse' },\n stats: { modelsIncluded: warehouseModels.length, modelsExcluded: 0 },\n models: warehouseModels,\n };\n }\n\n // Build a lookup of warehouse models by normalized table name\n const warehouseByTable = new Map<string, CatalogModel>();\n for (const wm of warehouseModels) {\n if (wm.table) {\n warehouseByTable.set(wm.table.toUpperCase(), wm);\n }\n }\n\n // Track which warehouse models were consumed by dbt merge\n const consumedWarehouseTables = new Set<string>();\n\n // Process existing catalog: keep non-warehouse entries, merge dbt+warehouse matches\n const mergedModels: CatalogModel[] = [];\n\n for (const model of existingCatalog.models) {\n // Remove stale warehouse entries — they'll be replaced by current warehouseModels\n if (model.source === 'warehouse') {\n continue;\n }\n\n // Check if this dbt model matches a warehouse table\n const tableKey = (model.table || '').toUpperCase();\n const warehouseMatch = tableKey ? warehouseByTable.get(tableKey) : undefined;\n\n if (warehouseMatch) {\n // dbt entry wins — backfill data_type and add missing columns\n const warehouseColMap = new Map<string, { data_type?: string; description: string; hints: string[] }>();\n for (const wc of warehouseMatch.columns) {\n warehouseColMap.set(wc.name.toLowerCase(), wc);\n }\n\n // Backfill data_type on existing dbt columns\n const updatedColumns = model.columns.map((col) => {\n const wc = warehouseColMap.get(col.name.toLowerCase());\n if (wc && !col.data_type && wc.data_type) {\n return { ...col, data_type: wc.data_type };\n }\n return col;\n });\n\n // Add warehouse columns not present in dbt entry\n const existingColNames = new Set(model.columns.map((c) => c.name.toLowerCase()));\n for (const wc of warehouseMatch.columns) {\n if (!existingColNames.has(wc.name.toLowerCase())) {\n updatedColumns.push(wc);\n }\n }\n\n // Carry sampleRows from the warehouse entry into the merged dbt model\n const mergedModel: typeof model = { ...model, columns: updatedColumns };\n if (warehouseMatch.sampleRows && !model.sampleRows) {\n mergedModel.sampleRows = warehouseMatch.sampleRows;\n }\n mergedModels.push(mergedModel);\n consumedWarehouseTables.add(tableKey);\n } else {\n mergedModels.push(model);\n }\n }\n\n // Append warehouse-only models (not consumed by dbt merge)\n for (const wm of warehouseModels) {\n const tableKey = (wm.table || '').toUpperCase();\n if (!consumedWarehouseTables.has(tableKey)) {\n mergedModels.push(wm);\n }\n }\n\n return {\n ...existingCatalog,\n syncedAt: new Date().toISOString(),\n models: mergedModels,\n };\n}\n\n// ---------------------------------------------------------------------------\n// Async orchestrator\n// ---------------------------------------------------------------------------\n\n/**\n * Main warehouse sync orchestrator.\n *\n * 1. Fetch tables and columns from the warehouse.\n * 2. Diff against previous sync state.\n * 3. Sample new/changed tables (unless skipSamples).\n * 4. Build warehouse CatalogModel entries.\n * 5. Merge with existing catalog, write files.\n */\nexport async function syncWarehouse(\n projectDir: string,\n connector: Connector,\n connectionType: string,\n connectionName: string,\n options?: SyncWarehouseOptions,\n): Promise<SyncWarehouseResult> {\n const start = performance.now();\n const errors: string[] = [];\n\n // 1. Fetch tables\n let normalizedTables: NormalizedTable[] = [];\n\n if (connectionType === 'bigquery') {\n // BigQuery INFORMATION_SCHEMA is dataset-scoped — the dataset must be baked\n // into the query, so we run one query per dataset rather than filtering\n // client-side.\n if (!options?.schemas || options.schemas.length === 0) {\n throw new Error(\n 'BigQuery sync requires a dataset. Pass --schema <dataset> (or set config.dataset).',\n );\n }\n for (const dataset of options.schemas) {\n const q = getTablesQuery(connectionType, { schema: dataset });\n const res = await connector.execute(q.sql);\n normalizedTables.push(...q.normalize(res.rows));\n }\n } else {\n const tablesQuery = getTablesQuery(connectionType, {\n database: options?.database,\n });\n const tablesResult = await connector.execute(tablesQuery.sql);\n normalizedTables = tablesQuery.normalize(tablesResult.rows);\n\n // Filter by schemas if specified\n if (options?.schemas && options.schemas.length > 0) {\n const schemaSet = new Set(options.schemas.map((s) => s.toUpperCase()));\n normalizedTables = normalizedTables.filter((t) => schemaSet.has(t.schema.toUpperCase()));\n }\n }\n\n // 2. Fetch columns\n let allColumns: NormalizedColumnWithTable[] = [];\n\n if (connectionType === 'sqlite') {\n // SQLite: describe each table individually\n for (const table of normalizedTables) {\n try {\n const describeQuery = getDescribeQuery('sqlite', table.name);\n const descResult = await connector.execute(describeQuery.sql);\n const cols = describeQuery.normalize(descResult.rows);\n for (const col of cols) {\n allColumns.push({\n schema: table.schema,\n table: table.name,\n name: col.name,\n type: col.type,\n nullable: col.nullable,\n });\n }\n } catch (err) {\n errors.push(`Failed to describe ${table.name}: ${err instanceof Error ? err.message : String(err)}`);\n }\n }\n } else if (connectionType === 'bigquery') {\n // Dataset-scoped, same as the tables query above.\n for (const dataset of options!.schemas!) {\n const q = getColumnsQuery(connectionType, { schema: dataset });\n const res = await connector.execute(q.sql);\n allColumns.push(...q.normalize(res.rows));\n }\n } else {\n const columnsQuery = getColumnsQuery(connectionType, {\n database: options?.database,\n });\n const columnsResult = await connector.execute(columnsQuery.sql);\n allColumns = columnsQuery.normalize(columnsResult.rows);\n\n // Filter columns by schemas if specified\n if (options?.schemas && options.schemas.length > 0) {\n const schemaSet = new Set(options.schemas.map((s) => s.toUpperCase()));\n allColumns = allColumns.filter((c) => schemaSet.has(c.schema.toUpperCase()));\n }\n }\n\n // Group columns by table\n const columnMap = groupColumnsByTable(allColumns);\n\n // Build WarehouseTable entries with column counts\n const warehouseTables: WarehouseTable[] = normalizedTables.map((t) => {\n const qualifiedName = t.schema ? `${t.schema}.${t.name}` : t.name;\n return {\n qualifiedName,\n schema: t.schema,\n name: t.name,\n type: t.type,\n columnCount: columnMap.get(qualifiedName)?.length || 0,\n };\n });\n\n // 3. Load previous sync state, compute diff\n let prevState: SyncState | null = null;\n if (!options?.full) {\n try {\n const raw = await readFile(join(projectDir, '.yamchart', 'warehouse-sync.json'), 'utf-8');\n prevState = JSON.parse(raw);\n } catch {\n /* no previous state */\n }\n }\n\n const diff = diffSyncState(warehouseTables, prevState);\n\n // 4. Sample new/changed tables (unless skipSamples)\n const samples: Record<string, Record<string, unknown>[]> = {};\n const tablesToSample = options?.skipSamples\n ? []\n : [...diff.newTables, ...diff.changedTables];\n\n for (let i = 0; i < tablesToSample.length; i++) {\n const tableName = tablesToSample[i]!;\n options?.onProgress?.(tableName, i + 1, tablesToSample.length);\n\n try {\n const sampleSql = `SELECT * FROM ${tableName} LIMIT 3`;\n const samplePromise = connector.execute(sampleSql);\n const timeoutPromise = new Promise<never>((_, reject) =>\n setTimeout(() => reject(new Error(`Timeout sampling ${tableName} (5s)`)), 5000),\n );\n const result = await Promise.race([samplePromise, timeoutPromise]);\n samples[tableName] = result.rows;\n } catch (err) {\n errors.push(`Failed to sample ${tableName}: ${err instanceof Error ? err.message : String(err)}`);\n }\n }\n\n // 5. For unchanged tables: carry forward sampleRows from existing catalog\n let existingCatalog: CatalogData | null = null;\n try {\n const raw = await readFile(join(projectDir, '.yamchart', 'catalog.json'), 'utf-8');\n existingCatalog = JSON.parse(raw);\n } catch {\n /* no existing catalog */\n }\n\n if (existingCatalog && !options?.skipSamples) {\n for (const tableName of diff.unchangedTables) {\n const existingModel = existingCatalog.models.find(\n (m) => m.table?.toUpperCase() === tableName.toUpperCase() && m.source === 'warehouse',\n );\n if (existingModel?.sampleRows) {\n samples[tableName] = existingModel.sampleRows;\n }\n }\n }\n\n // 6. Build warehouse CatalogModel entries\n const warehouseModels = buildWarehouseModels(warehouseTables, columnMap, samples);\n\n // 7. Merge with existing catalog, write files\n const merged = mergeWithDbtCatalog(existingCatalog, warehouseModels);\n\n await mkdir(join(projectDir, '.yamchart'), { recursive: true });\n await writeFile(join(projectDir, '.yamchart', 'catalog.json'), generateCatalogJson(merged));\n\n const catalogMd = generateCatalogMd(merged);\n const syncDate = new Date().toISOString().split('T')[0]!;\n const warehouseSection = generateWarehouseSection(merged.models, connectionName, syncDate);\n const fullMd = warehouseSection ? catalogMd + '\\n' + warehouseSection : catalogMd;\n await writeFile(join(projectDir, '.yamchart', 'catalog.md'), fullMd);\n\n // Write sync state\n const syncState: SyncState = {\n syncedAt: new Date().toISOString(),\n connection: connectionName,\n schemas: options?.schemas || [],\n skipSamples: options?.skipSamples || false,\n tables: Object.fromEntries(\n warehouseTables.map((t) => [t.qualifiedName, { columnCount: t.columnCount }]),\n ),\n };\n await writeFile(join(projectDir, '.yamchart', 'warehouse-sync.json'), JSON.stringify(syncState, null, 2));\n\n const durationMs = Math.round(performance.now() - start);\n\n return {\n tablesTotal: warehouseTables.length,\n tablesNew: diff.newTables.length,\n tablesChanged: diff.changedTables.length,\n tablesUnchanged: diff.unchangedTables.length,\n tablesRemoved: diff.removedTables.length,\n errors,\n durationMs,\n };\n}\n","/**\n * CLI handler for `yamchart sync-warehouse`.\n *\n * Thin wrapper: resolves connection, creates connector, delegates to syncWarehouse().\n */\n\nimport * as output from '../utils/output.js';\nimport { resolveConnection, createConnector } from './connection-utils.js';\nimport { syncWarehouse } from './warehouse-sync.js';\nimport { readFile } from 'fs/promises';\nimport { join } from 'path';\nimport type { SyncState } from './warehouse-sync.js';\n\nexport interface SyncWarehouseCliOptions {\n connection?: string;\n schema?: string; // comma-separated → split into array\n database?: string;\n skipSamples?: boolean;\n refresh?: boolean;\n full?: boolean;\n json?: boolean;\n}\n\nexport async function runSyncWarehouse(\n projectDir: string,\n options: SyncWarehouseCliOptions,\n): Promise<void> {\n // Handle --refresh: load saved connection/schemas from previous sync state\n let connectionOverride = options.connection;\n let schemasOverride = options.schema;\n\n if (options.refresh) {\n try {\n const raw = await readFile(join(projectDir, '.yamchart', 'warehouse-sync.json'), 'utf-8');\n const prevState: SyncState = JSON.parse(raw);\n connectionOverride = connectionOverride || prevState.connection;\n if (!schemasOverride && prevState.schemas.length > 0) {\n schemasOverride = prevState.schemas.join(',');\n }\n if (!options.json) {\n output.info(`Re-syncing from ${prevState.connection} (${prevState.schemas.join(', ') || 'all schemas'})`);\n }\n } catch {\n output.error('No previous sync state found. Run sync-warehouse without --refresh first.');\n process.exit(1);\n }\n }\n\n // Resolve connection\n const connection = await resolveConnection(projectDir, connectionOverride);\n const connector = createConnector(connection, projectDir);\n\n let schemas = schemasOverride\n ? schemasOverride.split(',').map((s) => s.trim())\n : undefined;\n\n // BigQuery INFORMATION_SCHEMA is dataset-scoped; fall back to the connection's\n // configured dataset when no --schema is provided.\n if ((!schemas || schemas.length === 0) && connection.type === 'bigquery') {\n const dataset = (connection.config as { dataset?: string }).dataset;\n if (dataset) {\n schemas = [dataset];\n }\n }\n\n const spin = options.json ? null : output.spinner(`Connecting to ${connection.name} ...`);\n\n try {\n await connector.connect();\n\n if (spin) {\n spin.text = 'Fetching table metadata...';\n }\n\n const result = await syncWarehouse(\n projectDir,\n connector,\n connection.type,\n connection.name,\n {\n schemas,\n database: options.database,\n skipSamples: options.skipSamples,\n full: options.full,\n onProgress: spin\n ? (table, index, total) => {\n spin.text = `Sampling tables... ${index}/${total} (${table})`;\n }\n : undefined,\n },\n );\n\n if (spin) {\n spin.stop();\n }\n\n if (options.json) {\n console.log(JSON.stringify(result, null, 2));\n } else {\n const parts = [\n `${result.tablesNew} new`,\n `${result.tablesChanged} changed`,\n `${result.tablesUnchanged} unchanged`,\n ];\n if (result.tablesRemoved > 0) {\n parts.push(`${result.tablesRemoved} removed`);\n }\n output.success(\n `Synced ${result.tablesTotal} tables (${parts.join(', ')}) in ${(result.durationMs / 1000).toFixed(1)}s`,\n );\n output.detail('Written to .yamchart/catalog.json');\n\n if (result.errors.length > 0) {\n output.warning(`${result.errors.length} table(s) had sampling errors:`);\n for (const err of result.errors.slice(0, 5)) {\n output.detail(err);\n }\n if (result.errors.length > 5) {\n output.detail(`... and ${result.errors.length - 5} more`);\n }\n }\n }\n } finally {\n await connector.disconnect();\n }\n}\n"],"mappings":"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","names":["readFile","join"]}
@@ -1,12 +1,13 @@
1
+ import { createRequire as __yamchartCreateRequire } from 'module'; if (!globalThis.require) globalThis.require = __yamchartCreateRequire(import.meta.url);
1
2
  import {
2
3
  resolveTablesSource
3
- } from "./chunk-ZBCQNWVN.js";
4
- import "./chunk-VJC24RKT.js";
4
+ } from "./chunk-WVSDQNAN.js";
5
5
  import "./chunk-EAQXUGP6.js";
6
- import "./chunk-5FHV22X2.js";
7
- import "./chunk-QUIDZO5G.js";
8
- import "./chunk-UFDQ3C7Q.js";
9
- import "./chunk-ZIY22VO7.js";
6
+ import "./chunk-VJC24RKT.js";
7
+ import "./chunk-PYVROL7Z.js";
8
+ import "./chunk-5CRXV5PQ.js";
9
+ import "./chunk-X3UG6T3Q.js";
10
+ import "./chunk-7HWFVUGP.js";
10
11
  import "./chunk-7D4SUZUM.js";
11
12
 
12
13
  // src/commands/tables.ts
@@ -27,4 +28,4 @@ async function listTables(projectDir, options) {
27
28
  export {
28
29
  listTables
29
30
  };
30
- //# sourceMappingURL=tables-K5NAN2WK.js.map
31
+ //# sourceMappingURL=tables-WQTRZSXR.js.map
@@ -828,6 +828,32 @@ auth:
828
828
  - **RLS in SQL:** `{{ user.email }}`, `{{ user.role }}`, `{{ user.department }}` etc.
829
829
  - **CLI recovery:** `yamchart reset-password --email user@example.com`
830
830
 
831
+ ### Editing config from the UI (admin only)
832
+
833
+ Admins can add/edit/delete **data sources**, change the **knowledge database**, and edit
834
+ **AI providers** from the Data workspace. Edits are stored in a
835
+ runtime config layer (`<data-dir>/runtime-config.json`) that overrides Git config by name;
836
+ secret values (passwords, connection credentials, the knowledge DB URL) are encrypted at rest.
837
+ Saving a change triggers a brief automatic restart to apply it.
838
+
839
+ Set `YAMCHART_CONFIG_SECRET` (a base64-encoded 32-byte key, e.g. `openssl rand -base64 32`)
840
+ so encrypted secrets remain readable across restarts/redeploys. Without it, a machine-local
841
+ key is generated next to the runtime config file.
842
+
843
+ Git-defined connections remain read-only in the UI (edit them via Git); only
844
+ UI-created (runtime) sources can be edited or deleted there.
845
+
846
+ **Knowledge database.** Admins can change the knowledge-base Postgres URL under Data → Settings:
847
+ test the connection (runs migrations), optionally **Copy existing knowledge** into the new database
848
+ (hunches, blindspots, docs, embeddings — preserving ids and status), and **Rebuild embeddings now**.
849
+ Saving the URL restarts the server to reconnect. The URL is stored encrypted in the runtime config layer.
850
+
851
+ **AI providers.** Under Data → Settings, admins can edit the LLM providers (type, model,
852
+ endpoint, API key), the per-task routing (hunch generation, blindspot scan, answer, advisor),
853
+ and the embedding provider/model. A **Test** button does a tiny live call to verify the key +
854
+ endpoint. API keys are encrypted at rest; leaving a key field blank keeps the stored value.
855
+ Saving restarts the server to rebuild the providers.
856
+
831
857
  ## Project Config (`yamchart.yaml`)
832
858
 
833
859
  ```yaml
@@ -1,7 +1,8 @@
1
+ import { createRequire as __yamchartCreateRequire } from 'module'; if (!globalThis.require) globalThis.require = __yamchartCreateRequire(import.meta.url);
1
2
  import {
2
3
  createConnector,
3
4
  resolveConnection
4
- } from "./chunk-5FHV22X2.js";
5
+ } from "./chunk-PYVROL7Z.js";
5
6
  import {
6
7
  detail,
7
8
  error,
@@ -16,12 +17,16 @@ import {
16
17
  renderTemplate,
17
18
  resolveDynamicDefault,
18
19
  runAll
19
- } from "./chunk-QUIDZO5G.js";
20
+ } from "./chunk-5CRXV5PQ.js";
20
21
  import {
22
+ expandCustomDateRange,
21
23
  expandDatePreset,
22
- isDatePreset
23
- } from "./chunk-UFDQ3C7Q.js";
24
- import "./chunk-ZIY22VO7.js";
24
+ expandRelativeDateRange,
25
+ isCustomDateRange,
26
+ isDatePreset,
27
+ isRelativeDateRange
28
+ } from "./chunk-X3UG6T3Q.js";
29
+ import "./chunk-7HWFVUGP.js";
25
30
  import "./chunk-7D4SUZUM.js";
26
31
 
27
32
  // src/commands/test.ts
@@ -69,7 +74,15 @@ function compileWithDefaults(sql, metadata, refs) {
69
74
  }
70
75
  }
71
76
  }
72
- if (typeof params.date_range === "string" && isDatePreset(params.date_range)) {
77
+ if (isRelativeDateRange(params.date_range)) {
78
+ const range = expandRelativeDateRange(params.date_range);
79
+ params.start_date = range.start_date;
80
+ params.end_date = range.end_date;
81
+ } else if (isCustomDateRange(params.date_range)) {
82
+ const range = expandCustomDateRange(params.date_range);
83
+ params.start_date = range.start_date;
84
+ params.end_date = range.end_date;
85
+ } else if (typeof params.date_range === "string" && isDatePreset(params.date_range)) {
73
86
  const range = expandDatePreset(params.date_range);
74
87
  if (range) {
75
88
  params.start_date = range.start_date;
@@ -181,4 +194,4 @@ export {
181
194
  formatTestOutput,
182
195
  testProject
183
196
  };
184
- //# sourceMappingURL=test-SRHVOXZB.js.map
197
+ //# sourceMappingURL=test-MKNKUR3N.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/commands/test.ts"],"sourcesContent":["import { readFile, readdir } from 'fs/promises';\nimport { join, extname } from 'path';\nimport {\n parseModelMetadata,\n runAll,\n renderTemplate,\n createTemplateContext,\n expandDatePreset,\n isDatePreset,\n isCustomDateRange,\n expandCustomDateRange,\n isRelativeDateRange,\n expandRelativeDateRange,\n resolveDynamicDefault,\n type TestSuiteResult,\n type TestModelInput,\n} from '@yamchart/query';\nimport type { ModelMetadata } from '@yamchart/schema';\nimport * as output from '../utils/output.js';\nimport { resolveConnection, createConnector } from './connection-utils.js';\n\nexport interface TestOptions {\n connection?: string;\n json?: boolean;\n}\n\nexport interface TestResult {\n success: boolean;\n suite: TestSuiteResult;\n connectionName: string;\n}\n\nexport async function testProject(\n projectDir: string,\n modelFilter: string | undefined,\n options: TestOptions,\n): Promise<TestResult> {\n const connection = await resolveConnection(projectDir, options.connection);\n const connector = createConnector(connection, projectDir);\n\n const modelsDir = join(projectDir, 'models');\n const allModels = await loadModels(modelsDir);\n\n let modelsToTest = allModels;\n if (modelFilter) {\n modelsToTest = allModels.filter((m) => m.name === modelFilter);\n if (modelsToTest.length === 0) {\n throw new Error(`Model \"${modelFilter}\" not found`);\n }\n }\n\n // Build refs map: model name -> model name (identity for standalone execution)\n const refs: Record<string, string> = {};\n for (const m of allModels) {\n refs[m.name] = m.name;\n }\n\n const testInputs: TestModelInput[] = [];\n for (const model of modelsToTest) {\n try {\n const compiledSql = compileWithDefaults(model.sql, model.metadata, refs);\n testInputs.push({ compiledSql, metadata: model.metadata });\n } catch {\n // If compilation fails, include raw SQL so the error is reported during test execution\n testInputs.push({ compiledSql: model.sql, metadata: model.metadata });\n }\n }\n\n try {\n await connector.connect();\n const suite = await runAll(testInputs, connector);\n return { success: suite.failed === 0, suite, connectionName: connection.name };\n } finally {\n await connector.disconnect();\n }\n}\n\nfunction compileWithDefaults(\n sql: string,\n metadata: ModelMetadata,\n refs: Record<string, string>,\n): string {\n const params: Record<string, unknown> = {};\n if (metadata.params) {\n for (const p of metadata.params) {\n if (p.default !== undefined) {\n params[p.name] = resolveDynamicDefault(p.default);\n }\n }\n }\n\n // Expand date_range default into start_date/end_date — handles all three forms:\n // preset string (\"last_30_days\"), custom range object, or relative range object.\n if (isRelativeDateRange(params.date_range)) {\n const range = expandRelativeDateRange(params.date_range);\n params.start_date = range.start_date;\n params.end_date = range.end_date;\n } else if (isCustomDateRange(params.date_range)) {\n const range = expandCustomDateRange(params.date_range);\n params.start_date = range.start_date;\n params.end_date = range.end_date;\n } else if (typeof params.date_range === 'string' && isDatePreset(params.date_range)) {\n const range = expandDatePreset(params.date_range);\n if (range) {\n params.start_date = range.start_date;\n params.end_date = range.end_date;\n }\n }\n\n const context = createTemplateContext(params, refs);\n return renderTemplate(sql, context);\n}\n\ninterface LoadedModel {\n name: string;\n sql: string;\n metadata: ModelMetadata;\n}\n\nasync function loadModels(dir: string): Promise<LoadedModel[]> {\n const models: LoadedModel[] = [];\n\n let entries;\n try {\n entries = await readdir(dir, { withFileTypes: true });\n } catch {\n return models;\n }\n\n for (const entry of entries) {\n const fullPath = join(dir, entry.name);\n if (entry.isDirectory()) {\n const subModels = await loadModels(fullPath);\n models.push(...subModels);\n } else if (extname(entry.name) === '.sql') {\n const content = await readFile(fullPath, 'utf-8');\n try {\n const parsed = parseModelMetadata(content);\n models.push({ name: parsed.name, sql: parsed.sql, metadata: parsed });\n } catch {\n // Skip unparseable models\n }\n }\n }\n\n return models;\n}\n\nexport function formatTestOutput(result: TestResult, connectionName: string): void {\n const { suite } = result;\n\n const testedModels = suite.models.filter(\n (m) => m.schemaCheck || m.assertions.length > 0 || m.error,\n );\n\n output.header(`Testing ${suite.models.length} model(s) against ${connectionName}...`);\n\n for (const model of suite.models) {\n const hasChecks = model.schemaCheck || model.assertions.length > 0 || model.error;\n if (!hasChecks) continue;\n\n console.log(` ${model.modelName}`);\n\n if (model.error) {\n output.error(` error: ${model.error}`);\n continue;\n }\n\n if (model.schemaCheck) {\n formatSchemaCheck(model.schemaCheck);\n }\n\n for (const assertion of model.assertions) {\n formatAssertion(assertion);\n }\n\n output.newline();\n }\n\n // Summary line\n const totalChecks = suite.passed + suite.failed;\n const summary = `${testedModels.length} model(s), ${totalChecks} check(s): ${suite.passed} passed, ${suite.failed} failed`;\n const skippedSuffix = suite.skipped > 0 ? ` (${suite.skipped} skipped)` : '';\n const durationSuffix = ` (${suite.durationMs.toFixed(0)}ms)`;\n\n if (suite.failed === 0) {\n output.success(`${summary}${skippedSuffix}${durationSuffix}`);\n } else {\n output.error(`${summary}${skippedSuffix}${durationSuffix}`);\n }\n}\n\nfunction formatSchemaCheck(check: NonNullable<TestSuiteResult['models'][0]['schemaCheck']>): void {\n if (check.passed) {\n output.success(` schema: returns expected columns (${check.expectedColumns.join(', ')})`);\n return;\n }\n\n const issues: string[] = [];\n if (check.missingColumns.length > 0) {\n issues.push(`missing: ${check.missingColumns.join(', ')}`);\n }\n for (const m of check.typeMismatches) {\n issues.push(`${m.column}: expected ${m.expected}, got ${m.actual}`);\n }\n output.error(` schema: ${issues.join('; ')}`);\n}\n\nfunction formatAssertion(assertion: TestSuiteResult['models'][0]['assertions'][0]): void {\n const label = extractAssertionLabel(assertion.sql);\n\n if (assertion.warning) {\n output.warning(` ${label}`);\n output.detail(` ${assertion.warning}`);\n }\n\n if (assertion.error) {\n output.error(` test: ${label} -- error`);\n output.detail(` ${assertion.error}`);\n } else if (assertion.passed) {\n output.success(` test: ${label}`);\n } else {\n output.error(` test: ${label} -- ${assertion.violationCount} failing row(s)`);\n if (assertion.sampleViolations) {\n for (const row of assertion.sampleViolations.slice(0, 3)) {\n output.detail(` ${JSON.stringify(row)}`);\n }\n }\n }\n}\n\nfunction extractAssertionLabel(sql: string): string {\n const whereMatch = sql.match(/WHERE\\s+(.+?)$/i);\n if (whereMatch?.[1]) {\n const clause = whereMatch[1].trim();\n return clause.length > 60 ? clause.slice(0, 57) + '...' : clause;\n }\n return sql.length > 60 ? sql.slice(0, 57) + '...' : sql;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,SAAS,UAAU,eAAe;AAClC,SAAS,MAAM,eAAe;AA+B9B,eAAsB,YACpB,YACA,aACA,SACqB;AACrB,QAAM,aAAa,MAAM,kBAAkB,YAAY,QAAQ,UAAU;AACzE,QAAM,YAAY,gBAAgB,YAAY,UAAU;AAExD,QAAM,YAAY,KAAK,YAAY,QAAQ;AAC3C,QAAM,YAAY,MAAM,WAAW,SAAS;AAE5C,MAAI,eAAe;AACnB,MAAI,aAAa;AACf,mBAAe,UAAU,OAAO,CAAC,MAAM,EAAE,SAAS,WAAW;AAC7D,QAAI,aAAa,WAAW,GAAG;AAC7B,YAAM,IAAI,MAAM,UAAU,WAAW,aAAa;AAAA,IACpD;AAAA,EACF;AAGA,QAAM,OAA+B,CAAC;AACtC,aAAW,KAAK,WAAW;AACzB,SAAK,EAAE,IAAI,IAAI,EAAE;AAAA,EACnB;AAEA,QAAM,aAA+B,CAAC;AACtC,aAAW,SAAS,cAAc;AAChC,QAAI;AACF,YAAM,cAAc,oBAAoB,MAAM,KAAK,MAAM,UAAU,IAAI;AACvE,iBAAW,KAAK,EAAE,aAAa,UAAU,MAAM,SAAS,CAAC;AAAA,IAC3D,QAAQ;AAEN,iBAAW,KAAK,EAAE,aAAa,MAAM,KAAK,UAAU,MAAM,SAAS,CAAC;AAAA,IACtE;AAAA,EACF;AAEA,MAAI;AACF,UAAM,UAAU,QAAQ;AACxB,UAAM,QAAQ,MAAM,OAAO,YAAY,SAAS;AAChD,WAAO,EAAE,SAAS,MAAM,WAAW,GAAG,OAAO,gBAAgB,WAAW,KAAK;AAAA,EAC/E,UAAE;AACA,UAAM,UAAU,WAAW;AAAA,EAC7B;AACF;AAEA,SAAS,oBACP,KACA,UACA,MACQ;AACR,QAAM,SAAkC,CAAC;AACzC,MAAI,SAAS,QAAQ;AACnB,eAAW,KAAK,SAAS,QAAQ;AAC/B,UAAI,EAAE,YAAY,QAAW;AAC3B,eAAO,EAAE,IAAI,IAAI,sBAAsB,EAAE,OAAO;AAAA,MAClD;AAAA,IACF;AAAA,EACF;AAIA,MAAI,oBAAoB,OAAO,UAAU,GAAG;AAC1C,UAAM,QAAQ,wBAAwB,OAAO,UAAU;AACvD,WAAO,aAAa,MAAM;AAC1B,WAAO,WAAW,MAAM;AAAA,EAC1B,WAAW,kBAAkB,OAAO,UAAU,GAAG;AAC/C,UAAM,QAAQ,sBAAsB,OAAO,UAAU;AACrD,WAAO,aAAa,MAAM;AAC1B,WAAO,WAAW,MAAM;AAAA,EAC1B,WAAW,OAAO,OAAO,eAAe,YAAY,aAAa,OAAO,UAAU,GAAG;AACnF,UAAM,QAAQ,iBAAiB,OAAO,UAAU;AAChD,QAAI,OAAO;AACT,aAAO,aAAa,MAAM;AAC1B,aAAO,WAAW,MAAM;AAAA,IAC1B;AAAA,EACF;AAEA,QAAM,UAAU,sBAAsB,QAAQ,IAAI;AAClD,SAAO,eAAe,KAAK,OAAO;AACpC;AAQA,eAAe,WAAW,KAAqC;AAC7D,QAAM,SAAwB,CAAC;AAE/B,MAAI;AACJ,MAAI;AACF,cAAU,MAAM,QAAQ,KAAK,EAAE,eAAe,KAAK,CAAC;AAAA,EACtD,QAAQ;AACN,WAAO;AAAA,EACT;AAEA,aAAW,SAAS,SAAS;AAC3B,UAAM,WAAW,KAAK,KAAK,MAAM,IAAI;AACrC,QAAI,MAAM,YAAY,GAAG;AACvB,YAAM,YAAY,MAAM,WAAW,QAAQ;AAC3C,aAAO,KAAK,GAAG,SAAS;AAAA,IAC1B,WAAW,QAAQ,MAAM,IAAI,MAAM,QAAQ;AACzC,YAAM,UAAU,MAAM,SAAS,UAAU,OAAO;AAChD,UAAI;AACF,cAAM,SAAS,mBAAmB,OAAO;AACzC,eAAO,KAAK,EAAE,MAAM,OAAO,MAAM,KAAK,OAAO,KAAK,UAAU,OAAO,CAAC;AAAA,MACtE,QAAQ;AAAA,MAER;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;AAEO,SAAS,iBAAiB,QAAoB,gBAA8B;AACjF,QAAM,EAAE,MAAM,IAAI;AAElB,QAAM,eAAe,MAAM,OAAO;AAAA,IAChC,CAAC,MAAM,EAAE,eAAe,EAAE,WAAW,SAAS,KAAK,EAAE;AAAA,EACvD;AAEA,EAAO,OAAO,WAAW,MAAM,OAAO,MAAM,qBAAqB,cAAc,KAAK;AAEpF,aAAW,SAAS,MAAM,QAAQ;AAChC,UAAM,YAAY,MAAM,eAAe,MAAM,WAAW,SAAS,KAAK,MAAM;AAC5E,QAAI,CAAC,UAAW;AAEhB,YAAQ,IAAI,KAAK,MAAM,SAAS,EAAE;AAElC,QAAI,MAAM,OAAO;AACf,MAAO,MAAM,cAAc,MAAM,KAAK,EAAE;AACxC;AAAA,IACF;AAEA,QAAI,MAAM,aAAa;AACrB,wBAAkB,MAAM,WAAW;AAAA,IACrC;AAEA,eAAW,aAAa,MAAM,YAAY;AACxC,sBAAgB,SAAS;AAAA,IAC3B;AAEA,IAAO,QAAQ;AAAA,EACjB;AAGA,QAAM,cAAc,MAAM,SAAS,MAAM;AACzC,QAAM,UAAU,GAAG,aAAa,MAAM,cAAc,WAAW,cAAc,MAAM,MAAM,YAAY,MAAM,MAAM;AACjH,QAAM,gBAAgB,MAAM,UAAU,IAAI,KAAK,MAAM,OAAO,cAAc;AAC1E,QAAM,iBAAiB,KAAK,MAAM,WAAW,QAAQ,CAAC,CAAC;AAEvD,MAAI,MAAM,WAAW,GAAG;AACtB,IAAO,QAAQ,GAAG,OAAO,GAAG,aAAa,GAAG,cAAc,EAAE;AAAA,EAC9D,OAAO;AACL,IAAO,MAAM,GAAG,OAAO,GAAG,aAAa,GAAG,cAAc,EAAE;AAAA,EAC5D;AACF;AAEA,SAAS,kBAAkB,OAAuE;AAChG,MAAI,MAAM,QAAQ;AAChB,IAAO,QAAQ,yCAAyC,MAAM,gBAAgB,KAAK,IAAI,CAAC,GAAG;AAC3F;AAAA,EACF;AAEA,QAAM,SAAmB,CAAC;AAC1B,MAAI,MAAM,eAAe,SAAS,GAAG;AACnC,WAAO,KAAK,YAAY,MAAM,eAAe,KAAK,IAAI,CAAC,EAAE;AAAA,EAC3D;AACA,aAAW,KAAK,MAAM,gBAAgB;AACpC,WAAO,KAAK,GAAG,EAAE,MAAM,cAAc,EAAE,QAAQ,SAAS,EAAE,MAAM,EAAE;AAAA,EACpE;AACA,EAAO,MAAM,eAAe,OAAO,KAAK,IAAI,CAAC,EAAE;AACjD;AAEA,SAAS,gBAAgB,WAAgE;AACvF,QAAM,QAAQ,sBAAsB,UAAU,GAAG;AAEjD,MAAI,UAAU,SAAS;AACrB,IAAO,QAAQ,OAAO,KAAK,EAAE;AAC7B,IAAO,OAAO,SAAS,UAAU,OAAO,EAAE;AAAA,EAC5C;AAEA,MAAI,UAAU,OAAO;AACnB,IAAO,MAAM,aAAa,KAAK,WAAW;AAC1C,IAAO,OAAO,SAAS,UAAU,KAAK,EAAE;AAAA,EAC1C,WAAW,UAAU,QAAQ;AAC3B,IAAO,QAAQ,aAAa,KAAK,EAAE;AAAA,EACrC,OAAO;AACL,IAAO,MAAM,aAAa,KAAK,OAAO,UAAU,cAAc,iBAAiB;AAC/E,QAAI,UAAU,kBAAkB;AAC9B,iBAAW,OAAO,UAAU,iBAAiB,MAAM,GAAG,CAAC,GAAG;AACxD,QAAO,OAAO,SAAS,KAAK,UAAU,GAAG,CAAC,EAAE;AAAA,MAC9C;AAAA,IACF;AAAA,EACF;AACF;AAEA,SAAS,sBAAsB,KAAqB;AAClD,QAAM,aAAa,IAAI,MAAM,iBAAiB;AAC9C,MAAI,aAAa,CAAC,GAAG;AACnB,UAAM,SAAS,WAAW,CAAC,EAAE,KAAK;AAClC,WAAO,OAAO,SAAS,KAAK,OAAO,MAAM,GAAG,EAAE,IAAI,QAAQ;AAAA,EAC5D;AACA,SAAO,IAAI,SAAS,KAAK,IAAI,MAAM,GAAG,EAAE,IAAI,QAAQ;AACtD;","names":[]}
@@ -1,3 +1,4 @@
1
+ import { createRequire as __yamchartCreateRequire } from 'module'; if (!globalThis.require) globalThis.require = __yamchartCreateRequire(import.meta.url);
1
2
  import {
2
3
  checkForUpdate,
3
4
  fetchReleaseNotes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "yamchart",
3
- "version": "0.10.0",
3
+ "version": "0.10.2",
4
4
  "description": "Git-native business intelligence dashboards",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -62,7 +62,9 @@
62
62
  "simple-git": "^3.30.0",
63
63
  "uuid": "^11.0.0",
64
64
  "yaml": "^2.7.0",
65
- "zod": "^3.24.0"
65
+ "zod": "^3.24.0",
66
+ "openai": "^4.104.0",
67
+ "pg": "^8.13.0"
66
68
  },
67
69
  "devDependencies": {
68
70
  "@types/node": "^22.0.0",
@@ -71,13 +73,13 @@
71
73
  "tsup": "^8.0.0",
72
74
  "typescript": "^5.7.0",
73
75
  "vitest": "^2.1.0",
74
- "@yamchart/advisor": "0.1.0",
75
- "@yamchart/auth-local": "0.1.0",
76
76
  "@yamchart/chat": "0.1.0",
77
77
  "@yamchart/config": "0.1.2",
78
- "@yamchart/query": "0.1.2",
79
78
  "@yamchart/schema": "0.1.2",
80
- "@yamchart/server": "0.1.2"
79
+ "@yamchart/server": "0.1.2",
80
+ "@yamchart/auth-local": "0.1.0",
81
+ "@yamchart/advisor": "0.1.0",
82
+ "@yamchart/query": "0.1.2"
81
83
  },
82
84
  "files": [
83
85
  "dist",
@@ -88,7 +90,7 @@
88
90
  "access": "public"
89
91
  },
90
92
  "scripts": {
91
- "build": "tsup",
93
+ "build": "tsup && node scripts/post-build.mjs",
92
94
  "dev": "tsup --watch",
93
95
  "test": "vitest run",
94
96
  "test:watch": "vitest",