yamchart 0.9.1 → 0.9.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{advisor-HVD4FJ56.js → advisor-SC64RTZO.js} +11 -11
- package/dist/agent-TZZHNDPK.js +8 -0
- package/dist/{chunk-4P5UHWYK.js → chunk-7CD6UQAV.js} +102 -2
- package/dist/chunk-7CD6UQAV.js.map +1 -0
- package/dist/chunk-7D4SUZUM.js +38 -0
- package/dist/{chunk-EHM6AMMA.js → chunk-EAQXUGP6.js} +65 -2
- package/dist/chunk-EAQXUGP6.js.map +1 -0
- package/dist/{chunk-LQANFANB.js → chunk-H4L3FNLS.js} +16 -6
- package/dist/chunk-H4L3FNLS.js.map +1 -0
- package/dist/{chunk-R22XWFKX.js → chunk-NXQ6ZO3V.js} +19 -4
- package/dist/chunk-NXQ6ZO3V.js.map +1 -0
- package/dist/{chunk-LQN2HNQZ.js → chunk-RM6MNDVF.js} +36 -5
- package/dist/chunk-RM6MNDVF.js.map +1 -0
- package/dist/{chunk-XDDBDJQL.js → chunk-RMIDEBHD.js} +4 -4
- package/dist/{chunk-CWAWATL4.js → chunk-S7YQXEKM.js} +159 -2
- package/dist/chunk-S7YQXEKM.js.map +1 -0
- package/dist/{chunk-ZA6AOQVZ.js → chunk-ZMJPRNOA.js} +2 -2
- package/dist/{compare-ZN6RUOOQ.js → compare-RQFCEZIK.js} +2 -2
- package/dist/{connection-utils-WVQGWJ7H.js → connection-utils-C4FQGBW6.js} +5 -5
- package/dist/{describe-UETE5XYO.js → describe-X75C2VDU.js} +7 -7
- package/dist/{dev-2WLFE37D.js → dev-KDNXUNME.js} +27978 -13314
- package/dist/dev-KDNXUNME.js.map +1 -0
- package/dist/{dist-VNX77VV5.js → dist-JMLAZUL7.js} +9 -3
- package/dist/{dist-7CRX2GIR.js → dist-MNXSMGV6.js} +3 -3
- package/dist/{dist-OAKQOG6H.js → dist-MX5K2ABB.js} +3 -3
- package/dist/{dist-JH7OL7U4.js → dist-NGQG7Z4G.js} +7 -3
- package/dist/{generate-KNER36CB.js → generate-B7FAWVIQ.js} +2 -2
- package/dist/index.js +33 -33
- package/dist/{init-GVBYCLJT.js → init-SECXKD5G.js} +2 -2
- package/dist/{lineage-T5NRHHZN.js → lineage-HYO4RKZT.js} +2 -2
- package/dist/public/assets/{EventManagement-CWrv68To.js → EventManagement-B7leMxfo.js} +1 -1
- package/dist/public/assets/{ExplorePage-2wblm-7t.js → ExplorePage-zI1OiYlH.js} +1 -1
- package/dist/public/assets/{LoginPage-J48L4t6I.js → LoginPage-Dyk2ILmo.js} +1 -1
- package/dist/public/assets/{PublicViewer-BrjKKW5m.js → PublicViewer-C2tNYBR2.js} +1 -1
- package/dist/public/assets/{SetupWizard-fRVi5bF4.js → SetupWizard-BzZSJlbt.js} +1 -1
- package/dist/public/assets/{ShareManagement-DUdL-Diq.js → ShareManagement-C7RIZRWe.js} +1 -1
- package/dist/public/assets/{UserManagement-BlwTHdH4.js → UserManagement-BD-lLbVH.js} +1 -1
- package/dist/public/assets/index-lklRbe2I.js +195 -0
- package/dist/public/assets/{index.es-BtmplkrJ.js → index.es-CLyC5-GY.js} +1 -1
- package/dist/public/assets/{jspdf.es.min-D0I_3frr.js → jspdf.es.min-CTZVk96E.js} +3 -3
- package/dist/public/index.html +1 -1
- package/dist/{query-E6NFXKV6.js → query-QNRDS74I.js} +5 -5
- package/dist/{reset-password-IZQTDTU7.js → reset-password-HDCLH7PZ.js} +3 -3
- package/dist/{rewrite-database-FDJIXKZ2.js → rewrite-database-BOA4QPUR.js} +2 -2
- package/dist/{sample-YLJC5H5X.js → sample-SKLHBZBU.js} +5 -5
- package/dist/{search-QDOSNM2R.js → search-4KMETZVX.js} +7 -7
- package/dist/{semantic-RAP3S5PQ.js → semantic-6WKELH5V.js} +2 -2
- package/dist/source-resolver-R7WBIL7M.js +18 -0
- package/dist/{sync-dbt-22QQKT3A.js → sync-dbt-72GVO75P.js} +2 -2
- package/dist/{sync-warehouse-5HEGZJHG.js → sync-warehouse-UWRNUXE7.js} +41 -15
- package/dist/sync-warehouse-UWRNUXE7.js.map +1 -0
- package/dist/{tables-6TODJHM5.js → tables-V65QUGHK.js} +7 -7
- package/dist/templates/default/docs/yamchart-reference.md +74 -9
- package/dist/{test-MXNBCQ3G.js → test-UE5OWG3E.js} +5 -5
- package/dist/{update-WMATDZTO.js → update-HWCJNQRP.js} +2 -2
- package/package.json +11 -5
- package/dist/agent-KWKPAYT2.js +0 -8
- package/dist/chunk-4P5UHWYK.js.map +0 -1
- package/dist/chunk-CWAWATL4.js.map +0 -1
- package/dist/chunk-DGUM43GV.js +0 -11
- package/dist/chunk-EHM6AMMA.js.map +0 -1
- package/dist/chunk-LQANFANB.js.map +0 -1
- package/dist/chunk-LQN2HNQZ.js.map +0 -1
- package/dist/chunk-R22XWFKX.js.map +0 -1
- package/dist/dev-2WLFE37D.js.map +0 -1
- package/dist/public/assets/index-CJ01RqZ2.js +0 -195
- package/dist/source-resolver-VAXDVSDF.js +0 -18
- package/dist/sync-warehouse-5HEGZJHG.js.map +0 -1
- /package/dist/{advisor-HVD4FJ56.js.map → advisor-SC64RTZO.js.map} +0 -0
- /package/dist/{agent-KWKPAYT2.js.map → agent-TZZHNDPK.js.map} +0 -0
- /package/dist/{chunk-DGUM43GV.js.map → chunk-7D4SUZUM.js.map} +0 -0
- /package/dist/{chunk-XDDBDJQL.js.map → chunk-RMIDEBHD.js.map} +0 -0
- /package/dist/{chunk-ZA6AOQVZ.js.map → chunk-ZMJPRNOA.js.map} +0 -0
- /package/dist/{compare-ZN6RUOOQ.js.map → compare-RQFCEZIK.js.map} +0 -0
- /package/dist/{connection-utils-WVQGWJ7H.js.map → connection-utils-C4FQGBW6.js.map} +0 -0
- /package/dist/{describe-UETE5XYO.js.map → describe-X75C2VDU.js.map} +0 -0
- /package/dist/{dist-JH7OL7U4.js.map → dist-JMLAZUL7.js.map} +0 -0
- /package/dist/{dist-7CRX2GIR.js.map → dist-MNXSMGV6.js.map} +0 -0
- /package/dist/{dist-OAKQOG6H.js.map → dist-MX5K2ABB.js.map} +0 -0
- /package/dist/{dist-VNX77VV5.js.map → dist-NGQG7Z4G.js.map} +0 -0
- /package/dist/{generate-KNER36CB.js.map → generate-B7FAWVIQ.js.map} +0 -0
- /package/dist/{init-GVBYCLJT.js.map → init-SECXKD5G.js.map} +0 -0
- /package/dist/{lineage-T5NRHHZN.js.map → lineage-HYO4RKZT.js.map} +0 -0
- /package/dist/{query-E6NFXKV6.js.map → query-QNRDS74I.js.map} +0 -0
- /package/dist/{reset-password-IZQTDTU7.js.map → reset-password-HDCLH7PZ.js.map} +0 -0
- /package/dist/{rewrite-database-FDJIXKZ2.js.map → rewrite-database-BOA4QPUR.js.map} +0 -0
- /package/dist/{sample-YLJC5H5X.js.map → sample-SKLHBZBU.js.map} +0 -0
- /package/dist/{search-QDOSNM2R.js.map → search-4KMETZVX.js.map} +0 -0
- /package/dist/{semantic-RAP3S5PQ.js.map → semantic-6WKELH5V.js.map} +0 -0
- /package/dist/{source-resolver-VAXDVSDF.js.map → source-resolver-R7WBIL7M.js.map} +0 -0
- /package/dist/{sync-dbt-22QQKT3A.js.map → sync-dbt-72GVO75P.js.map} +0 -0
- /package/dist/{tables-6TODJHM5.js.map → tables-V65QUGHK.js.map} +0 -0
- /package/dist/{test-MXNBCQ3G.js.map → test-UE5OWG3E.js.map} +0 -0
- /package/dist/{update-WMATDZTO.js.map → update-HWCJNQRP.js.map} +0 -0
|
@@ -5,14 +5,14 @@ import {
|
|
|
5
5
|
newline,
|
|
6
6
|
success
|
|
7
7
|
} from "./chunk-HJVVHYVN.js";
|
|
8
|
-
import "./chunk-
|
|
8
|
+
import "./chunk-7D4SUZUM.js";
|
|
9
9
|
|
|
10
10
|
// src/commands/reset-password.ts
|
|
11
11
|
import { resolve } from "path";
|
|
12
12
|
import { homedir } from "os";
|
|
13
13
|
import { randomBytes } from "crypto";
|
|
14
14
|
async function resetPassword(projectDir, email) {
|
|
15
|
-
const { AuthDatabase, hashPassword } = await import("./dist-
|
|
15
|
+
const { AuthDatabase, hashPassword } = await import("./dist-NGQG7Z4G.js");
|
|
16
16
|
const { readFileSync } = await import("fs");
|
|
17
17
|
const { parse } = await import("yaml");
|
|
18
18
|
const projectPath = resolve(projectDir, "yamchart.yaml");
|
|
@@ -57,4 +57,4 @@ async function resetPassword(projectDir, email) {
|
|
|
57
57
|
export {
|
|
58
58
|
resetPassword
|
|
59
59
|
};
|
|
60
|
-
//# sourceMappingURL=reset-password-
|
|
60
|
+
//# sourceMappingURL=reset-password-HDCLH7PZ.js.map
|
|
@@ -3,10 +3,10 @@ import {
|
|
|
3
3
|
extractDatabase,
|
|
4
4
|
rewriteTableDatabase
|
|
5
5
|
} from "./chunk-IVD4OP3K.js";
|
|
6
|
-
import "./chunk-
|
|
6
|
+
import "./chunk-7D4SUZUM.js";
|
|
7
7
|
export {
|
|
8
8
|
detectDatabaseMismatch,
|
|
9
9
|
extractDatabase,
|
|
10
10
|
rewriteTableDatabase
|
|
11
11
|
};
|
|
12
|
-
//# sourceMappingURL=rewrite-database-
|
|
12
|
+
//# sourceMappingURL=rewrite-database-BOA4QPUR.js.map
|
|
@@ -4,11 +4,11 @@ import {
|
|
|
4
4
|
import {
|
|
5
5
|
createConnector,
|
|
6
6
|
resolveConnection
|
|
7
|
-
} from "./chunk-
|
|
8
|
-
import "./chunk-
|
|
9
|
-
import "./chunk-
|
|
7
|
+
} from "./chunk-NXQ6ZO3V.js";
|
|
8
|
+
import "./chunk-RM6MNDVF.js";
|
|
9
|
+
import "./chunk-S7YQXEKM.js";
|
|
10
10
|
import "./chunk-UND73EOB.js";
|
|
11
|
-
import "./chunk-
|
|
11
|
+
import "./chunk-7D4SUZUM.js";
|
|
12
12
|
|
|
13
13
|
// src/commands/sample.ts
|
|
14
14
|
import { performance } from "perf_hooks";
|
|
@@ -38,4 +38,4 @@ async function sampleTable(projectDir, table, options) {
|
|
|
38
38
|
export {
|
|
39
39
|
sampleTable
|
|
40
40
|
};
|
|
41
|
-
//# sourceMappingURL=sample-
|
|
41
|
+
//# sourceMappingURL=sample-SKLHBZBU.js.map
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import {
|
|
2
2
|
resolveSearchSource
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-H4L3FNLS.js";
|
|
4
4
|
import "./chunk-VJC24RKT.js";
|
|
5
|
-
import "./chunk-
|
|
6
|
-
import "./chunk-
|
|
7
|
-
import "./chunk-
|
|
8
|
-
import "./chunk-
|
|
5
|
+
import "./chunk-EAQXUGP6.js";
|
|
6
|
+
import "./chunk-NXQ6ZO3V.js";
|
|
7
|
+
import "./chunk-RM6MNDVF.js";
|
|
8
|
+
import "./chunk-S7YQXEKM.js";
|
|
9
9
|
import "./chunk-UND73EOB.js";
|
|
10
|
-
import "./chunk-
|
|
10
|
+
import "./chunk-7D4SUZUM.js";
|
|
11
11
|
|
|
12
12
|
// src/commands/search.ts
|
|
13
13
|
async function searchDatabase(projectDir, keyword, options) {
|
|
@@ -25,4 +25,4 @@ async function searchDatabase(projectDir, keyword, options) {
|
|
|
25
25
|
export {
|
|
26
26
|
searchDatabase
|
|
27
27
|
};
|
|
28
|
-
//# sourceMappingURL=search-
|
|
28
|
+
//# sourceMappingURL=search-4KMETZVX.js.map
|
|
@@ -2,7 +2,7 @@ import {
|
|
|
2
2
|
SemanticModelBuilder,
|
|
3
3
|
SemanticQueryCompiler
|
|
4
4
|
} from "./chunk-UND73EOB.js";
|
|
5
|
-
import "./chunk-
|
|
5
|
+
import "./chunk-7D4SUZUM.js";
|
|
6
6
|
|
|
7
7
|
// src/commands/semantic.ts
|
|
8
8
|
function listSemanticEntities(catalog) {
|
|
@@ -36,4 +36,4 @@ export {
|
|
|
36
36
|
listSemanticEntities,
|
|
37
37
|
querySemanticEntity
|
|
38
38
|
};
|
|
39
|
-
//# sourceMappingURL=semantic-
|
|
39
|
+
//# sourceMappingURL=semantic-6WKELH5V.js.map
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import {
|
|
2
|
+
resolveDescribeSource,
|
|
3
|
+
resolveSearchSource,
|
|
4
|
+
resolveTablesSource
|
|
5
|
+
} from "./chunk-H4L3FNLS.js";
|
|
6
|
+
import "./chunk-VJC24RKT.js";
|
|
7
|
+
import "./chunk-EAQXUGP6.js";
|
|
8
|
+
import "./chunk-NXQ6ZO3V.js";
|
|
9
|
+
import "./chunk-RM6MNDVF.js";
|
|
10
|
+
import "./chunk-S7YQXEKM.js";
|
|
11
|
+
import "./chunk-UND73EOB.js";
|
|
12
|
+
import "./chunk-7D4SUZUM.js";
|
|
13
|
+
export {
|
|
14
|
+
resolveDescribeSource,
|
|
15
|
+
resolveSearchSource,
|
|
16
|
+
resolveTablesSource
|
|
17
|
+
};
|
|
18
|
+
//# sourceMappingURL=source-resolver-R7WBIL7M.js.map
|
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
import {
|
|
6
6
|
rewriteTableDatabase
|
|
7
7
|
} from "./chunk-IVD4OP3K.js";
|
|
8
|
-
import "./chunk-
|
|
8
|
+
import "./chunk-7D4SUZUM.js";
|
|
9
9
|
|
|
10
10
|
// src/commands/sync-dbt.ts
|
|
11
11
|
import { mkdir, writeFile, readFile as readFile3, access as access3 } from "fs/promises";
|
|
@@ -569,4 +569,4 @@ export {
|
|
|
569
569
|
loadSyncConfig,
|
|
570
570
|
syncDbt
|
|
571
571
|
};
|
|
572
|
-
//# sourceMappingURL=sync-dbt-
|
|
572
|
+
//# sourceMappingURL=sync-dbt-72GVO75P.js.map
|
|
@@ -7,11 +7,11 @@ import {
|
|
|
7
7
|
getColumnsQuery,
|
|
8
8
|
getDescribeQuery,
|
|
9
9
|
getTablesQuery
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-EAQXUGP6.js";
|
|
11
11
|
import {
|
|
12
12
|
createConnector,
|
|
13
13
|
resolveConnection
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-NXQ6ZO3V.js";
|
|
15
15
|
import {
|
|
16
16
|
detail,
|
|
17
17
|
error,
|
|
@@ -20,10 +20,10 @@ import {
|
|
|
20
20
|
success,
|
|
21
21
|
warning
|
|
22
22
|
} from "./chunk-HJVVHYVN.js";
|
|
23
|
-
import "./chunk-
|
|
24
|
-
import "./chunk-
|
|
23
|
+
import "./chunk-RM6MNDVF.js";
|
|
24
|
+
import "./chunk-S7YQXEKM.js";
|
|
25
25
|
import "./chunk-UND73EOB.js";
|
|
26
|
-
import "./chunk-
|
|
26
|
+
import "./chunk-7D4SUZUM.js";
|
|
27
27
|
|
|
28
28
|
// src/commands/warehouse-sync.ts
|
|
29
29
|
import { readFile, writeFile, mkdir } from "fs/promises";
|
|
@@ -160,14 +160,28 @@ function mergeWithDbtCatalog(existingCatalog, warehouseModels) {
|
|
|
160
160
|
async function syncWarehouse(projectDir, connector, connectionType, connectionName, options) {
|
|
161
161
|
const start = performance.now();
|
|
162
162
|
const errors = [];
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
163
|
+
let normalizedTables = [];
|
|
164
|
+
if (connectionType === "bigquery") {
|
|
165
|
+
if (!options?.schemas || options.schemas.length === 0) {
|
|
166
|
+
throw new Error(
|
|
167
|
+
"BigQuery sync requires a dataset. Pass --schema <dataset> (or set config.dataset)."
|
|
168
|
+
);
|
|
169
|
+
}
|
|
170
|
+
for (const dataset of options.schemas) {
|
|
171
|
+
const q = getTablesQuery(connectionType, { schema: dataset });
|
|
172
|
+
const res = await connector.execute(q.sql);
|
|
173
|
+
normalizedTables.push(...q.normalize(res.rows));
|
|
174
|
+
}
|
|
175
|
+
} else {
|
|
176
|
+
const tablesQuery = getTablesQuery(connectionType, {
|
|
177
|
+
database: options?.database
|
|
178
|
+
});
|
|
179
|
+
const tablesResult = await connector.execute(tablesQuery.sql);
|
|
180
|
+
normalizedTables = tablesQuery.normalize(tablesResult.rows);
|
|
181
|
+
if (options?.schemas && options.schemas.length > 0) {
|
|
182
|
+
const schemaSet = new Set(options.schemas.map((s) => s.toUpperCase()));
|
|
183
|
+
normalizedTables = normalizedTables.filter((t) => schemaSet.has(t.schema.toUpperCase()));
|
|
184
|
+
}
|
|
171
185
|
}
|
|
172
186
|
let allColumns = [];
|
|
173
187
|
if (connectionType === "sqlite") {
|
|
@@ -189,6 +203,12 @@ async function syncWarehouse(projectDir, connector, connectionType, connectionNa
|
|
|
189
203
|
errors.push(`Failed to describe ${table.name}: ${err instanceof Error ? err.message : String(err)}`);
|
|
190
204
|
}
|
|
191
205
|
}
|
|
206
|
+
} else if (connectionType === "bigquery") {
|
|
207
|
+
for (const dataset of options.schemas) {
|
|
208
|
+
const q = getColumnsQuery(connectionType, { schema: dataset });
|
|
209
|
+
const res = await connector.execute(q.sql);
|
|
210
|
+
allColumns.push(...q.normalize(res.rows));
|
|
211
|
+
}
|
|
192
212
|
} else {
|
|
193
213
|
const columnsQuery = getColumnsQuery(connectionType, {
|
|
194
214
|
database: options?.database
|
|
@@ -308,7 +328,13 @@ async function runSyncWarehouse(projectDir, options) {
|
|
|
308
328
|
}
|
|
309
329
|
const connection = await resolveConnection(projectDir, connectionOverride);
|
|
310
330
|
const connector = createConnector(connection, projectDir);
|
|
311
|
-
|
|
331
|
+
let schemas = schemasOverride ? schemasOverride.split(",").map((s) => s.trim()) : void 0;
|
|
332
|
+
if ((!schemas || schemas.length === 0) && connection.type === "bigquery") {
|
|
333
|
+
const dataset = connection.config.dataset;
|
|
334
|
+
if (dataset) {
|
|
335
|
+
schemas = [dataset];
|
|
336
|
+
}
|
|
337
|
+
}
|
|
312
338
|
const spin = options.json ? null : spinner(`Connecting to ${connection.name} ...`);
|
|
313
339
|
try {
|
|
314
340
|
await connector.connect();
|
|
@@ -365,4 +391,4 @@ async function runSyncWarehouse(projectDir, options) {
|
|
|
365
391
|
export {
|
|
366
392
|
runSyncWarehouse
|
|
367
393
|
};
|
|
368
|
-
//# sourceMappingURL=sync-warehouse-
|
|
394
|
+
//# sourceMappingURL=sync-warehouse-UWRNUXE7.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 mergedModels.push({ ...model, columns: updatedColumns });\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,13 +1,13 @@
|
|
|
1
1
|
import {
|
|
2
2
|
resolveTablesSource
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-H4L3FNLS.js";
|
|
4
4
|
import "./chunk-VJC24RKT.js";
|
|
5
|
-
import "./chunk-
|
|
6
|
-
import "./chunk-
|
|
7
|
-
import "./chunk-
|
|
8
|
-
import "./chunk-
|
|
5
|
+
import "./chunk-EAQXUGP6.js";
|
|
6
|
+
import "./chunk-NXQ6ZO3V.js";
|
|
7
|
+
import "./chunk-RM6MNDVF.js";
|
|
8
|
+
import "./chunk-S7YQXEKM.js";
|
|
9
9
|
import "./chunk-UND73EOB.js";
|
|
10
|
-
import "./chunk-
|
|
10
|
+
import "./chunk-7D4SUZUM.js";
|
|
11
11
|
|
|
12
12
|
// src/commands/tables.ts
|
|
13
13
|
async function listTables(projectDir, options) {
|
|
@@ -27,4 +27,4 @@ async function listTables(projectDir, options) {
|
|
|
27
27
|
export {
|
|
28
28
|
listTables
|
|
29
29
|
};
|
|
30
|
-
//# sourceMappingURL=tables-
|
|
30
|
+
//# sourceMappingURL=tables-V65QUGHK.js.map
|
|
@@ -705,13 +705,29 @@ config: { account: xy12345, warehouse: COMPUTE_WH, database: ANALYTICS, schema:
|
|
|
705
705
|
auth: { type: env, user_var: SF_USER, password_var: SF_PASSWORD }
|
|
706
706
|
# SSO: auth: { type: externalbrowser, user_var: SF_USER }
|
|
707
707
|
|
|
708
|
+
# BigQuery
|
|
709
|
+
name: warehouse
|
|
710
|
+
type: bigquery
|
|
711
|
+
config:
|
|
712
|
+
project_id: my-gcp-project # required
|
|
713
|
+
dataset: analytics # optional default dataset
|
|
714
|
+
location: US # optional (US | EU | region)
|
|
715
|
+
max_bytes_billed: 1000000000 # optional per-query cost cap (bytes)
|
|
716
|
+
auth:
|
|
717
|
+
type: service_account
|
|
718
|
+
credentials_var: GCP_SERVICE_ACCOUNT_JSON # env var holding the SA key JSON contents
|
|
719
|
+
# or: key_file: ./secrets/sa.json # path to a key file (local dev)
|
|
720
|
+
# or: omit both to use Application Default Credentials (gcloud / workload identity)
|
|
721
|
+
|
|
708
722
|
# SQLite
|
|
709
723
|
name: local-sqlite
|
|
710
724
|
type: sqlite
|
|
711
725
|
path: ./data/app.db
|
|
712
726
|
```
|
|
713
727
|
|
|
714
|
-
**Supported:** DuckDB, PostgreSQL, MySQL, SQLite, Snowflake
|
|
728
|
+
**Supported:** DuckDB, PostgreSQL, MySQL, SQLite, Snowflake, BigQuery
|
|
729
|
+
|
|
730
|
+
BigQuery models must be written in **BigQuery Standard SQL** (e.g. `DATE_TRUNC(d, MONTH)`); yamchart runs model SQL as-is and does not transpile dialects. The CLI introspection commands (`yamchart tables/describe/search`) are dataset-scoped — they use the connection's `dataset` by default, or pass `--schema <dataset>`. `@google-cloud/bigquery` is an optional dependency: install it with `npm install @google-cloud/bigquery`.
|
|
715
731
|
|
|
716
732
|
Use `${ENV_VAR}` for credentials. Never commit secrets.
|
|
717
733
|
|
|
@@ -777,20 +793,32 @@ auth:
|
|
|
777
793
|
session_ttl: "30d" # Optional (default: 30 days)
|
|
778
794
|
providers: # Optional SSO
|
|
779
795
|
google:
|
|
780
|
-
client_id:
|
|
781
|
-
|
|
796
|
+
client_id: "abc.apps.googleusercontent.com" # not secret — safe in git
|
|
797
|
+
client_secret_var: GOOGLE_OAUTH_CLIENT_SECRET # env var NAME holding the secret
|
|
798
|
+
allowed_emails: # invite-only: only these may sign in
|
|
799
|
+
- owner@example.com
|
|
800
|
+
admin_emails: # provisioned as admin (implicitly allowed)
|
|
801
|
+
- owner@example.com
|
|
782
802
|
microsoft:
|
|
783
|
-
client_id:
|
|
784
|
-
|
|
785
|
-
tenant:
|
|
803
|
+
client_id: "..."
|
|
804
|
+
client_secret_var: MS_OAUTH_CLIENT_SECRET
|
|
805
|
+
tenant: "..."
|
|
786
806
|
oidc:
|
|
787
|
-
client_id:
|
|
788
|
-
|
|
807
|
+
client_id: "..."
|
|
808
|
+
client_secret_var: OIDC_OAUTH_CLIENT_SECRET
|
|
789
809
|
issuer: https://auth.example.com
|
|
790
810
|
display_name: "Company SSO"
|
|
791
811
|
```
|
|
792
812
|
|
|
793
|
-
- First visit prompts a setup wizard to create an admin account
|
|
813
|
+
- First visit prompts a setup wizard to create an admin account (password). With
|
|
814
|
+
SSO configured, users can also sign in via the provider.
|
|
815
|
+
- **Secrets:** give the client secret directly via `client_secret`, or name an env
|
|
816
|
+
var with `client_secret_var` so the secret stays out of git. Redirect URI is
|
|
817
|
+
`<BASE_URL>/api/auth/sso/<provider>/callback`.
|
|
818
|
+
- **Invite-only:** if `allowed_emails` is set, only those addresses may sign in via
|
|
819
|
+
SSO — anyone else is rejected, not auto-provisioned. Without it, any authenticated
|
|
820
|
+
account is auto-provisioned as a viewer. `admin_emails` are provisioned as admin
|
|
821
|
+
and are always allowed.
|
|
794
822
|
- **Roles:** admin (manage users + content), editor (content only), viewer (read-only)
|
|
795
823
|
- **User attributes:** Admins can set key-value pairs per user (e.g. `department: Sales`) for row-level security
|
|
796
824
|
- **RLS in SQL:** `{{ user.email }}`, `{{ user.role }}`, `{{ user.department }}` etc.
|
|
@@ -1232,3 +1260,40 @@ models: # optional - restrict accessible models
|
|
|
1232
1260
|
| `.2%` | 12.34% | Percentages |
|
|
1233
1261
|
| `.2s` | 1.2M | SI prefix |
|
|
1234
1262
|
| `.2f` | 1.23 | Fixed decimals |
|
|
1263
|
+
|
|
1264
|
+
## MCP server (experimental)
|
|
1265
|
+
|
|
1266
|
+
When the server is running, an MCP endpoint is available at `POST /mcp`
|
|
1267
|
+
(Streamable HTTP). It exposes tools for LLM clients to explore and query your
|
|
1268
|
+
data: `list_charts`, `list_models`, `run_model`, `run_sql`, `list_tables`,
|
|
1269
|
+
`describe_table`, `sample_table`, `visualize` (returns a chart image), and
|
|
1270
|
+
`save_chart` (editor/admin only). The endpoint runs as the authenticated
|
|
1271
|
+
yamchart user: role gating applies (only editor/admin can `save_chart`), and
|
|
1272
|
+
row-level security applies to governed queries via `run_model` (the user context
|
|
1273
|
+
is passed to the model's Jinja templating). Note that `run_sql` executes raw
|
|
1274
|
+
ad-hoc SQL **without** RLS filtering — it reads whatever the connection can
|
|
1275
|
+
access, so only grant MCP access to users you trust with direct read access to
|
|
1276
|
+
the warehouse.
|
|
1277
|
+
|
|
1278
|
+
### Interactive chart embeds
|
|
1279
|
+
|
|
1280
|
+
The `visualize` tool returns an **interactive chart** (live ECharts: hover, tooltip,
|
|
1281
|
+
zoom) for clients that support MCP Apps — Claude (web/desktop/mobile) and ChatGPT
|
|
1282
|
+
(Apps SDK) — alongside a **static PNG image** that always renders as a fallback.
|
|
1283
|
+
The chart is delivered as a `ui://yamchart/chart` resource plus `structuredContent`;
|
|
1284
|
+
ECharts loads from a CDN, so a client that blocks external scripts will show the
|
|
1285
|
+
PNG instead. Interactive rendering depends on the client's MCP Apps support, which
|
|
1286
|
+
is still stabilizing in some clients — the image guarantees a visual everywhere.
|
|
1287
|
+
|
|
1288
|
+
### Connecting ChatGPT / Claude (OAuth)
|
|
1289
|
+
|
|
1290
|
+
When local auth is enabled (`auth.enabled: true`), the MCP endpoint is protected
|
|
1291
|
+
by OAuth 2.1. Add yamchart as a custom connector in your client using the base
|
|
1292
|
+
URL of your yamchart server; the client discovers the endpoints via
|
|
1293
|
+
`/.well-known/oauth-protected-resource` and `/.well-known/oauth-authorization-server`,
|
|
1294
|
+
registers itself automatically (dynamic client registration), and opens a
|
|
1295
|
+
yamchart login + consent page. After you approve, the client receives a token
|
|
1296
|
+
and operates as your yamchart user — your role and row-level security apply
|
|
1297
|
+
(remember: `run_sql` runs raw SQL without RLS; only grant MCP access to trusted
|
|
1298
|
+
users). Set `BASE_URL` (or `defaults.base_url`) so the OAuth metadata advertises
|
|
1299
|
+
correct absolute URLs.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
createConnector,
|
|
3
3
|
resolveConnection
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-NXQ6ZO3V.js";
|
|
5
5
|
import {
|
|
6
6
|
detail,
|
|
7
7
|
error,
|
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
success,
|
|
11
11
|
warning
|
|
12
12
|
} from "./chunk-HJVVHYVN.js";
|
|
13
|
-
import "./chunk-
|
|
13
|
+
import "./chunk-RM6MNDVF.js";
|
|
14
14
|
import {
|
|
15
15
|
createTemplateContext,
|
|
16
16
|
expandDatePreset,
|
|
@@ -19,9 +19,9 @@ import {
|
|
|
19
19
|
renderTemplate,
|
|
20
20
|
resolveDynamicDefault,
|
|
21
21
|
runAll
|
|
22
|
-
} from "./chunk-
|
|
22
|
+
} from "./chunk-S7YQXEKM.js";
|
|
23
23
|
import "./chunk-UND73EOB.js";
|
|
24
|
-
import "./chunk-
|
|
24
|
+
import "./chunk-7D4SUZUM.js";
|
|
25
25
|
|
|
26
26
|
// src/commands/test.ts
|
|
27
27
|
import { readFile, readdir } from "fs/promises";
|
|
@@ -180,4 +180,4 @@ export {
|
|
|
180
180
|
formatTestOutput,
|
|
181
181
|
testProject
|
|
182
182
|
};
|
|
183
|
-
//# sourceMappingURL=test-
|
|
183
|
+
//# sourceMappingURL=test-UE5OWG3E.js.map
|
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
spinner,
|
|
12
12
|
success
|
|
13
13
|
} from "./chunk-HJVVHYVN.js";
|
|
14
|
-
import "./chunk-
|
|
14
|
+
import "./chunk-7D4SUZUM.js";
|
|
15
15
|
|
|
16
16
|
// src/commands/update.ts
|
|
17
17
|
import { execSync } from "child_process";
|
|
@@ -217,4 +217,4 @@ export {
|
|
|
217
217
|
refreshSkills,
|
|
218
218
|
runUpdate
|
|
219
219
|
};
|
|
220
|
-
//# sourceMappingURL=update-
|
|
220
|
+
//# sourceMappingURL=update-HWCJNQRP.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "yamchart",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.3",
|
|
4
4
|
"description": "Git-native business intelligence dashboards",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -36,8 +36,12 @@
|
|
|
36
36
|
"@anthropic-ai/sdk": "^0.39.0",
|
|
37
37
|
"@fastify/cookie": "^11.0.0",
|
|
38
38
|
"@fastify/cors": "^10.0.0",
|
|
39
|
+
"@fastify/formbody": "^8.0.0",
|
|
39
40
|
"@fastify/static": "^8.0.0",
|
|
40
41
|
"@inquirer/prompts": "^8.2.0",
|
|
42
|
+
"@mcp-ui/server": "^6.1.0",
|
|
43
|
+
"@modelcontextprotocol/ext-apps": "^0.3.1",
|
|
44
|
+
"@resvg/resvg-js": "^2.6.2",
|
|
41
45
|
"bcryptjs": "^2.4.3",
|
|
42
46
|
"better-sqlite3": "^12.6.0",
|
|
43
47
|
"chokidar": "^4.0.0",
|
|
@@ -45,6 +49,7 @@
|
|
|
45
49
|
"date-fns": "^4.1.0",
|
|
46
50
|
"dotenv": "^16.4.0",
|
|
47
51
|
"duckdb": "^1.1.0",
|
|
52
|
+
"echarts": "^5.5.0",
|
|
48
53
|
"fast-glob": "^3.3.3",
|
|
49
54
|
"fastify": "^5.2.0",
|
|
50
55
|
"lru-cache": "^11.0.0",
|
|
@@ -61,17 +66,18 @@
|
|
|
61
66
|
},
|
|
62
67
|
"devDependencies": {
|
|
63
68
|
"@types/node": "^22.0.0",
|
|
69
|
+
"@google-cloud/bigquery": "^8.3.1",
|
|
64
70
|
"snowflake-sdk": "^2.3.4",
|
|
65
71
|
"tsup": "^8.0.0",
|
|
66
72
|
"typescript": "^5.7.0",
|
|
67
73
|
"vitest": "^2.1.0",
|
|
68
|
-
"@yamchart/advisor": "0.1.0",
|
|
69
74
|
"@yamchart/auth-local": "0.1.0",
|
|
70
|
-
"@yamchart/chat": "0.1.0",
|
|
71
|
-
"@yamchart/config": "0.1.2",
|
|
72
75
|
"@yamchart/query": "0.1.2",
|
|
76
|
+
"@yamchart/config": "0.1.2",
|
|
73
77
|
"@yamchart/schema": "0.1.2",
|
|
74
|
-
"@yamchart/
|
|
78
|
+
"@yamchart/advisor": "0.1.0",
|
|
79
|
+
"@yamchart/server": "0.1.2",
|
|
80
|
+
"@yamchart/chat": "0.1.0"
|
|
75
81
|
},
|
|
76
82
|
"files": [
|
|
77
83
|
"dist",
|
package/dist/agent-KWKPAYT2.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../packages/auth-local/src/passwords.ts","../../../packages/auth-local/src/database.ts","../../../packages/auth-local/src/sessions.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';\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`;\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","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"],"mappings":"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","names":["randomBytes"]}
|